Home | History | Annotate | Download | only in css
      1 /*
      2  * Copyright (C) 2003 Lars Knoll (knoll (at) kde.org)
      3  * Copyright (C) 2005 Allan Sandfeld Jensen (kde (at) carewolf.com)
      4  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
      5  * Copyright (C) 2007 Nicholas Shanks <webkit (at) nickshanks.com>
      6  * Copyright (C) 2008 Eric Seidel <eric (at) webkit.org>
      7  * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      8  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
      9  * Copyright (C) 2012 Intel Corporation. All rights reserved.
     10  *
     11  * This library is free software; you can redistribute it and/or
     12  * modify it under the terms of the GNU Library General Public
     13  * License as published by the Free Software Foundation; either
     14  * version 2 of the License, or (at your option) any later version.
     15  *
     16  * This library is distributed in the hope that it will be useful,
     17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     19  * Library General Public License for more details.
     20  *
     21  * You should have received a copy of the GNU Library General Public License
     22  * along with this library; see the file COPYING.LIB.  If not, write to
     23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     24  * Boston, MA 02110-1301, USA.
     25  */
     26 
     27 #include "config.h"
     28 #include "core/css/CSSParser.h"
     29 
     30 #include "CSSValueKeywords.h"
     31 #include "RuntimeEnabledFeatures.h"
     32 #include "StylePropertyShorthand.h"
     33 #include "core/css/CSSArrayFunctionValue.h"
     34 #include "core/css/CSSAspectRatioValue.h"
     35 #include "core/css/CSSBasicShapes.h"
     36 #include "core/css/CSSBorderImage.h"
     37 #include "core/css/CSSCanvasValue.h"
     38 #include "core/css/CSSCrossfadeValue.h"
     39 #include "core/css/CSSCursorImageValue.h"
     40 #include "core/css/CSSFontFaceSrcValue.h"
     41 #include "core/css/CSSGradientValue.h"
     42 #include "core/css/CSSGridTemplateValue.h"
     43 #include "core/css/CSSImageSetValue.h"
     44 #include "core/css/CSSImageValue.h"
     45 #include "core/css/CSSInheritedValue.h"
     46 #include "core/css/CSSInitialValue.h"
     47 #include "core/css/CSSKeyframeRule.h"
     48 #include "core/css/CSSKeyframesRule.h"
     49 #include "core/css/CSSLineBoxContainValue.h"
     50 #include "core/css/CSSMixFunctionValue.h"
     51 #include "core/css/CSSPrimitiveValue.h"
     52 #include "core/css/CSSPropertySourceData.h"
     53 #include "core/css/CSSReflectValue.h"
     54 #include "core/css/CSSSVGDocumentValue.h"
     55 #include "core/css/CSSSelector.h"
     56 #include "core/css/CSSShaderValue.h"
     57 #include "core/css/CSSStyleSheet.h"
     58 #include "core/css/CSSTimingFunctionValue.h"
     59 #include "core/css/CSSTransformValue.h"
     60 #include "core/css/CSSUnicodeRangeValue.h"
     61 #include "core/css/CSSValueList.h"
     62 #include "core/css/CSSValuePool.h"
     63 #include "core/css/CSSVariableValue.h"
     64 #include "core/css/Counter.h"
     65 #include "core/css/FontFeatureValue.h"
     66 #include "core/css/MediaList.h"
     67 #include "core/css/MediaQueryExp.h"
     68 #include "core/css/Pair.h"
     69 #include "core/css/Rect.h"
     70 #include "core/css/ShadowValue.h"
     71 #include "core/css/StylePropertySet.h"
     72 #include "core/css/StyleRule.h"
     73 #include "core/css/StyleRuleImport.h"
     74 #include "core/css/StyleSheetContents.h"
     75 #include "core/dom/Document.h"
     76 #include "core/html/parser/HTMLParserIdioms.h"
     77 #include "core/inspector/InspectorInstrumentation.h"
     78 #include "core/page/Page.h"
     79 #include "core/page/PageConsole.h"
     80 #include "core/page/Settings.h"
     81 #include "core/platform/FloatConversion.h"
     82 #include "core/platform/HashTools.h"
     83 #include "core/rendering/RenderTheme.h"
     84 #include "core/svg/SVGParserUtilities.h"
     85 #include "wtf/BitArray.h"
     86 #include "wtf/HexNumber.h"
     87 #include "wtf/text/StringBuffer.h"
     88 #include "wtf/text/StringBuilder.h"
     89 #include "wtf/text/StringImpl.h"
     90 #include "wtf/text/TextEncoding.h"
     91 #include <limits.h>
     92 
     93 #define YYDEBUG 0
     94 
     95 #if YYDEBUG > 0
     96 extern int cssyydebug;
     97 #endif
     98 
     99 extern int cssyyparse(WebCore::CSSParser*);
    100 
    101 using namespace std;
    102 using namespace WTF;
    103 
    104 namespace WebCore {
    105 
    106 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
    107 static const double MAX_SCALE = 1000000;
    108 
    109 template <unsigned N>
    110 static bool equal(const CSSParserString& a, const char (&b)[N])
    111 {
    112     unsigned length = N - 1; // Ignore the trailing null character
    113     if (a.length() != length)
    114         return false;
    115 
    116     return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
    117 }
    118 
    119 template <unsigned N>
    120 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
    121 {
    122     unsigned length = N - 1; // Ignore the trailing null character
    123     if (a.length() != length)
    124         return false;
    125 
    126     return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
    127 }
    128 
    129 template <unsigned N>
    130 static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
    131 {
    132     ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
    133     return equalIgnoringCase(value->string, b);
    134 }
    135 
    136 static bool hasPrefix(const char* string, unsigned length, const char* prefix)
    137 {
    138     for (unsigned i = 0; i < length; ++i) {
    139         if (!prefix[i])
    140             return true;
    141         if (string[i] != prefix[i])
    142             return false;
    143     }
    144     return false;
    145 }
    146 
    147 static PassRefPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtr<CSSPrimitiveValue> first, PassRefPtr<CSSPrimitiveValue> second)
    148 {
    149     return cssValuePool().createValue(Pair::create(first, second));
    150 }
    151 
    152 class AnimationParseContext {
    153 public:
    154     AnimationParseContext()
    155         : m_animationPropertyKeywordAllowed(true)
    156         , m_firstAnimationCommitted(false)
    157         , m_hasSeenAnimationPropertyKeyword(false)
    158     {
    159     }
    160 
    161     void commitFirstAnimation()
    162     {
    163         m_firstAnimationCommitted = true;
    164     }
    165 
    166     bool hasCommittedFirstAnimation() const
    167     {
    168         return m_firstAnimationCommitted;
    169     }
    170 
    171     void commitAnimationPropertyKeyword()
    172     {
    173         m_animationPropertyKeywordAllowed = false;
    174     }
    175 
    176     bool animationPropertyKeywordAllowed() const
    177     {
    178         return m_animationPropertyKeywordAllowed;
    179     }
    180 
    181     bool hasSeenAnimationPropertyKeyword() const
    182     {
    183         return m_hasSeenAnimationPropertyKeyword;
    184     }
    185 
    186     void sawAnimationPropertyKeyword()
    187     {
    188         m_hasSeenAnimationPropertyKeyword = true;
    189     }
    190 
    191 private:
    192     bool m_animationPropertyKeywordAllowed;
    193     bool m_firstAnimationCommitted;
    194     bool m_hasSeenAnimationPropertyKeyword;
    195 };
    196 
    197 const CSSParserContext& strictCSSParserContext()
    198 {
    199     DEFINE_STATIC_LOCAL(CSSParserContext, strictContext, (CSSStrictMode));
    200     return strictContext;
    201 }
    202 
    203 CSSParserContext::CSSParserContext(CSSParserMode mode, const KURL& baseURL)
    204     : baseURL(baseURL)
    205     , mode(mode)
    206     , isHTMLDocument(false)
    207     , isCSSCustomFilterEnabled(false)
    208     , isCSSStickyPositionEnabled(false)
    209     , needsSiteSpecificQuirks(false)
    210     , useLegacyBackgroundSizeShorthandBehavior(false)
    211 {
    212 }
    213 
    214 CSSParserContext::CSSParserContext(Document* document, const KURL& baseURL, const String& charset)
    215     : baseURL(baseURL.isNull() ? document->baseURL() : baseURL)
    216     , charset(charset)
    217     , mode(document->inQuirksMode() ? CSSQuirksMode : CSSStrictMode)
    218     , isHTMLDocument(document->isHTMLDocument())
    219     , isCSSCustomFilterEnabled(document->settings() ? document->settings()->isCSSCustomFilterEnabled() : false)
    220     , isCSSStickyPositionEnabled(document->cssStickyPositionEnabled())
    221     , needsSiteSpecificQuirks(document->settings() ? document->settings()->needsSiteSpecificQuirks() : false)
    222     , useLegacyBackgroundSizeShorthandBehavior(document->settings() ? document->settings()->useLegacyBackgroundSizeShorthandBehavior() : false)
    223 {
    224 }
    225 
    226 bool operator==(const CSSParserContext& a, const CSSParserContext& b)
    227 {
    228     return a.baseURL == b.baseURL
    229         && a.charset == b.charset
    230         && a.mode == b.mode
    231         && a.isHTMLDocument == b.isHTMLDocument
    232         && a.isCSSCustomFilterEnabled == b.isCSSCustomFilterEnabled
    233         && a.isCSSStickyPositionEnabled == b.isCSSStickyPositionEnabled
    234         && a.needsSiteSpecificQuirks == b.needsSiteSpecificQuirks
    235         && a.useLegacyBackgroundSizeShorthandBehavior == b.useLegacyBackgroundSizeShorthandBehavior;
    236 }
    237 
    238 CSSParser::CSSParser(const CSSParserContext& context, UseCounter* counter)
    239     : m_context(context)
    240     , m_important(false)
    241     , m_id(CSSPropertyInvalid)
    242     , m_styleSheet(0)
    243     , m_supportsCondition(false)
    244     , m_selectorListForParseSelector(0)
    245     , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
    246     , m_inParseShorthand(0)
    247     , m_currentShorthand(CSSPropertyInvalid)
    248     , m_implicitShorthand(false)
    249     , m_hasFontFaceOnlyValues(false)
    250     , m_hadSyntacticallyValidCSSRule(false)
    251     , m_logErrors(false)
    252     , m_ignoreErrors(false)
    253     , m_inFilterRule(false)
    254     , m_defaultNamespace(starAtom)
    255     , m_parsedTextPrefixLength(0)
    256     , m_parsedTextSuffixLength(0)
    257     , m_sourceDataHandler(0)
    258     , m_parsingMode(NormalMode)
    259     , m_is8BitSource(false)
    260     , m_currentCharacter8(0)
    261     , m_currentCharacter16(0)
    262     , m_source(0)
    263     , m_length(0)
    264     , m_token(0)
    265     , m_lineNumber(0)
    266     , m_tokenStartLineNumber(0)
    267     , m_ruleHeaderType(CSSRuleSourceData::UNKNOWN_RULE)
    268     , m_allowImportRules(true)
    269     , m_allowNamespaceDeclarations(true)
    270     , m_inViewport(false)
    271     , m_useCounter(counter)
    272 {
    273 #if YYDEBUG > 0
    274     cssyydebug = 1;
    275 #endif
    276     m_tokenStart.ptr8 = 0;
    277     CSSPropertySourceData::init();
    278 }
    279 
    280 CSSParser::~CSSParser()
    281 {
    282     clearProperties();
    283 
    284     deleteAllValues(m_floatingSelectors);
    285     deleteAllValues(m_floatingSelectorVectors);
    286     deleteAllValues(m_floatingValueLists);
    287     deleteAllValues(m_floatingFunctions);
    288 }
    289 
    290 AtomicString CSSParserString::atomicSubstring(unsigned position, unsigned length) const
    291 {
    292     ASSERT(m_length >= position + length);
    293 
    294     if (is8Bit())
    295         return AtomicString(characters8() + position, length);
    296     return AtomicString(characters16() + position, length);
    297 }
    298 
    299 void CSSParserString::trimTrailingWhitespace()
    300 {
    301     if (is8Bit()) {
    302         while (m_length > 0 && isHTMLSpace(m_data.characters8[m_length - 1]))
    303             --m_length;
    304     } else {
    305         while (m_length > 0 && isHTMLSpace(m_data.characters16[m_length - 1]))
    306             --m_length;
    307     }
    308 }
    309 
    310 void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
    311 {
    312     m_parsedTextPrefixLength = prefixLength;
    313     m_parsedTextSuffixLength = suffixLength;
    314     unsigned stringLength = string.length();
    315     unsigned length = stringLength + m_parsedTextPrefixLength + m_parsedTextSuffixLength + 1;
    316     m_length = length;
    317 
    318     if (!stringLength || string.is8Bit()) {
    319         m_dataStart8 = adoptArrayPtr(new LChar[length]);
    320         for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
    321             m_dataStart8[i] = prefix[i];
    322 
    323         if (stringLength)
    324             memcpy(m_dataStart8.get() + m_parsedTextPrefixLength, string.characters8(), stringLength * sizeof(LChar));
    325 
    326         unsigned start = m_parsedTextPrefixLength + stringLength;
    327         unsigned end = start + suffixLength;
    328         for (unsigned i = start; i < end; i++)
    329             m_dataStart8[i] = suffix[i - start];
    330 
    331         m_dataStart8[length - 1] = 0;
    332 
    333         m_is8BitSource = true;
    334         m_currentCharacter8 = m_dataStart8.get();
    335         m_currentCharacter16 = 0;
    336         setTokenStart<LChar>(m_currentCharacter8);
    337         m_lexFunc = &CSSParser::realLex<LChar>;
    338         return;
    339     }
    340 
    341     m_dataStart16 = adoptArrayPtr(new UChar[length]);
    342     for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
    343         m_dataStart16[i] = prefix[i];
    344 
    345     ASSERT(stringLength);
    346     memcpy(m_dataStart16.get() + m_parsedTextPrefixLength, string.characters16(), stringLength * sizeof(UChar));
    347 
    348     unsigned start = m_parsedTextPrefixLength + stringLength;
    349     unsigned end = start + suffixLength;
    350     for (unsigned i = start; i < end; i++)
    351         m_dataStart16[i] = suffix[i - start];
    352 
    353     m_dataStart16[length - 1] = 0;
    354 
    355     m_is8BitSource = false;
    356     m_currentCharacter8 = 0;
    357     m_currentCharacter16 = m_dataStart16.get();
    358     setTokenStart<UChar>(m_currentCharacter16);
    359     m_lexFunc = &CSSParser::realLex<UChar>;
    360 }
    361 
    362 void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, const TextPosition& startPosition, SourceDataHandler* sourceDataHandler, bool logErrors)
    363 {
    364     setStyleSheet(sheet);
    365     m_defaultNamespace = starAtom; // Reset the default namespace.
    366     m_sourceDataHandler = sourceDataHandler;
    367     m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->page();
    368     m_ignoreErrors = false;
    369     m_lineNumber = 0;
    370     m_startPosition = startPosition;
    371     m_source = &string;
    372     setupParser("", string, "");
    373     cssyyparse(this);
    374     sheet->shrinkToFit();
    375     m_source = 0;
    376     m_sourceDataHandler = 0;
    377     m_rule = 0;
    378     m_lineEndings.clear();
    379     m_ignoreErrors = false;
    380     m_logErrors = false;
    381 }
    382 
    383 PassRefPtr<StyleRuleBase> CSSParser::parseRule(StyleSheetContents* sheet, const String& string)
    384 {
    385     setStyleSheet(sheet);
    386     m_allowNamespaceDeclarations = false;
    387     setupParser("@-internal-rule ", string, "");
    388     cssyyparse(this);
    389     return m_rule.release();
    390 }
    391 
    392 PassRefPtr<StyleKeyframe> CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
    393 {
    394     setStyleSheet(sheet);
    395     setupParser("@-internal-keyframe-rule ", string, "");
    396     cssyyparse(this);
    397     return m_keyframe.release();
    398 }
    399 
    400 bool CSSParser::parseSupportsCondition(const String& string)
    401 {
    402     m_supportsCondition = false;
    403     setupParser("@-internal-supports-condition ", string, "");
    404     cssyyparse(this);
    405     return m_supportsCondition;
    406 }
    407 
    408 static inline bool isColorPropertyID(CSSPropertyID propertyId)
    409 {
    410     switch (propertyId) {
    411     case CSSPropertyColor:
    412     case CSSPropertyBackgroundColor:
    413     case CSSPropertyBorderBottomColor:
    414     case CSSPropertyBorderLeftColor:
    415     case CSSPropertyBorderRightColor:
    416     case CSSPropertyBorderTopColor:
    417     case CSSPropertyOutlineColor:
    418     case CSSPropertyTextLineThroughColor:
    419     case CSSPropertyTextOverlineColor:
    420     case CSSPropertyTextUnderlineColor:
    421     case CSSPropertyWebkitBorderAfterColor:
    422     case CSSPropertyWebkitBorderBeforeColor:
    423     case CSSPropertyWebkitBorderEndColor:
    424     case CSSPropertyWebkitBorderStartColor:
    425     case CSSPropertyWebkitColumnRuleColor:
    426     case CSSPropertyWebkitTextEmphasisColor:
    427     case CSSPropertyWebkitTextFillColor:
    428     case CSSPropertyWebkitTextStrokeColor:
    429         return true;
    430     case CSSPropertyTextDecorationColor:
    431         return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
    432     default:
    433         return false;
    434     }
    435 }
    436 
    437 static bool parseColorValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
    438 {
    439     ASSERT(!string.isEmpty());
    440     bool strict = isStrictParserMode(cssParserMode);
    441     if (!isColorPropertyID(propertyId))
    442         return false;
    443     CSSParserString cssString;
    444     cssString.init(string);
    445     CSSValueID valueID = cssValueKeywordID(cssString);
    446     bool validPrimitive = false;
    447     if (valueID == CSSValueWebkitText)
    448         validPrimitive = true;
    449     else if (valueID == CSSValueCurrentcolor)
    450         validPrimitive = true;
    451     else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
    452              || (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict)) {
    453         validPrimitive = true;
    454     }
    455 
    456     if (validPrimitive) {
    457         RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
    458         declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
    459         return true;
    460     }
    461     RGBA32 color;
    462     if (!CSSParser::fastParseColor(color, string, strict && string[0] != '#'))
    463         return false;
    464     RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
    465     declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
    466     return true;
    467 }
    468 
    469 static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
    470 {
    471     switch (propertyId) {
    472     case CSSPropertyFontSize:
    473     case CSSPropertyHeight:
    474     case CSSPropertyWidth:
    475     case CSSPropertyMinHeight:
    476     case CSSPropertyMinWidth:
    477     case CSSPropertyPaddingBottom:
    478     case CSSPropertyPaddingLeft:
    479     case CSSPropertyPaddingRight:
    480     case CSSPropertyPaddingTop:
    481     case CSSPropertyWebkitLogicalWidth:
    482     case CSSPropertyWebkitLogicalHeight:
    483     case CSSPropertyWebkitMinLogicalWidth:
    484     case CSSPropertyWebkitMinLogicalHeight:
    485     case CSSPropertyWebkitPaddingAfter:
    486     case CSSPropertyWebkitPaddingBefore:
    487     case CSSPropertyWebkitPaddingEnd:
    488     case CSSPropertyWebkitPaddingStart:
    489         acceptsNegativeNumbers = false;
    490         return true;
    491     case CSSPropertyWebkitShapeMargin:
    492     case CSSPropertyWebkitShapePadding:
    493         acceptsNegativeNumbers = false;
    494         return RuntimeEnabledFeatures::cssExclusionsEnabled();
    495     case CSSPropertyBottom:
    496     case CSSPropertyLeft:
    497     case CSSPropertyMarginBottom:
    498     case CSSPropertyMarginLeft:
    499     case CSSPropertyMarginRight:
    500     case CSSPropertyMarginTop:
    501     case CSSPropertyRight:
    502     case CSSPropertyTop:
    503     case CSSPropertyWebkitMarginAfter:
    504     case CSSPropertyWebkitMarginBefore:
    505     case CSSPropertyWebkitMarginEnd:
    506     case CSSPropertyWebkitMarginStart:
    507         acceptsNegativeNumbers = true;
    508         return true;
    509     default:
    510         return false;
    511     }
    512 }
    513 
    514 template <typename CharacterType>
    515 static inline bool parseSimpleLength(const CharacterType* characters, unsigned& length, CSSPrimitiveValue::UnitTypes& unit, double& number)
    516 {
    517     if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
    518         length -= 2;
    519         unit = CSSPrimitiveValue::CSS_PX;
    520     } else if (length > 1 && characters[length - 1] == '%') {
    521         length -= 1;
    522         unit = CSSPrimitiveValue::CSS_PERCENTAGE;
    523     }
    524 
    525     // We rely on charactersToDouble for validation as well. The function
    526     // will set "ok" to "false" if the entire passed-in character range does
    527     // not represent a double.
    528     bool ok;
    529     number = charactersToDouble(characters, length, &ok);
    530     return ok;
    531 }
    532 
    533 static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
    534 {
    535     ASSERT(!string.isEmpty());
    536     bool acceptsNegativeNumbers;
    537     if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
    538         return false;
    539 
    540     unsigned length = string.length();
    541     double number;
    542     CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
    543 
    544     if (string.is8Bit()) {
    545         if (!parseSimpleLength(string.characters8(), length, unit, number))
    546             return false;
    547     } else {
    548         if (!parseSimpleLength(string.characters16(), length, unit, number))
    549             return false;
    550     }
    551 
    552     if (unit == CSSPrimitiveValue::CSS_NUMBER) {
    553         if (number && isStrictParserMode(cssParserMode))
    554             return false;
    555         unit = CSSPrimitiveValue::CSS_PX;
    556     }
    557     if (number < 0 && !acceptsNegativeNumbers)
    558         return false;
    559 
    560     RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
    561     declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
    562     return true;
    563 }
    564 
    565 static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
    566 {
    567     if (!valueID)
    568         return false;
    569 
    570     switch (propertyId) {
    571     case CSSPropertyBorderCollapse: // collapse | separate | inherit
    572         if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
    573             return true;
    574         break;
    575     case CSSPropertyBorderTopStyle: // <border-style> | inherit
    576     case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
    577     case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
    578     case CSSPropertyBorderLeftStyle:
    579     case CSSPropertyWebkitBorderAfterStyle:
    580     case CSSPropertyWebkitBorderBeforeStyle:
    581     case CSSPropertyWebkitBorderEndStyle:
    582     case CSSPropertyWebkitBorderStartStyle:
    583     case CSSPropertyWebkitColumnRuleStyle:
    584         if (valueID >= CSSValueNone && valueID <= CSSValueDouble)
    585             return true;
    586         break;
    587     case CSSPropertyBoxSizing:
    588          if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox)
    589              return true;
    590          break;
    591     case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
    592         if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom)
    593             return true;
    594         break;
    595     case CSSPropertyClear: // none | left | right | both | inherit
    596         if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth)
    597             return true;
    598         break;
    599     case CSSPropertyDirection: // ltr | rtl | inherit
    600         if (valueID == CSSValueLtr || valueID == CSSValueRtl)
    601             return true;
    602         break;
    603     case CSSPropertyDisplay:
    604         // inline | block | list-item | run-in | inline-block | table |
    605         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
    606         // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit
    607         // flex | inline-flex | -webkit-flex | -webkit-inline-flex | grid | inline-grid | lazy-block
    608         if ((valueID >= CSSValueInline && valueID <= CSSValueInlineFlex) || valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex || valueID == CSSValueNone)
    609             return true;
    610         if (valueID == CSSValueGrid || valueID == CSSValueInlineGrid)
    611             return RuntimeEnabledFeatures::cssGridLayoutEnabled();
    612         if (valueID == CSSValueLazyBlock)
    613             return RuntimeEnabledFeatures::lazyLayoutEnabled();
    614         break;
    615 
    616     case CSSPropertyEmptyCells: // show | hide | inherit
    617         if (valueID == CSSValueShow || valueID == CSSValueHide)
    618             return true;
    619         break;
    620     case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
    621         if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter)
    622             return true;
    623         break;
    624     case CSSPropertyFontStyle: // normal | italic | oblique | inherit
    625         if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique)
    626             return true;
    627         break;
    628     case CSSPropertyImageRendering: // auto | optimizeContrast
    629         if (valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast)
    630             return true;
    631         break;
    632     case CSSPropertyListStylePosition: // inside | outside | inherit
    633         if (valueID == CSSValueInside || valueID == CSSValueOutside)
    634             return true;
    635         break;
    636     case CSSPropertyListStyleType:
    637         // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
    638         // for the list of supported list-style-types.
    639         if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone)
    640             return true;
    641         break;
    642     case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
    643         if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble))
    644             return true;
    645         break;
    646     case CSSPropertyOverflowWrap: // normal | break-word
    647     case CSSPropertyWordWrap:
    648         if (valueID == CSSValueNormal || valueID == CSSValueBreakWord)
    649             return true;
    650         break;
    651     case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay | inherit
    652         if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay)
    653             return true;
    654         break;
    655     case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | inherit | -webkit-paged-x | -webkit-paged-y
    656         if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY)
    657             return true;
    658         break;
    659     case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
    660     case CSSPropertyPageBreakBefore:
    661     case CSSPropertyWebkitColumnBreakAfter:
    662     case CSSPropertyWebkitColumnBreakBefore:
    663         if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)
    664             return true;
    665         break;
    666     case CSSPropertyPageBreakInside: // avoid | auto | inherit
    667     case CSSPropertyWebkitColumnBreakInside:
    668         if (valueID == CSSValueAuto || valueID == CSSValueAvoid)
    669             return true;
    670         break;
    671     case CSSPropertyPointerEvents:
    672         // none | visiblePainted | visibleFill | visibleStroke | visible |
    673         // painted | fill | stroke | auto | all | inherit
    674         if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueStroke))
    675             return true;
    676         break;
    677     case CSSPropertyPosition: // static | relative | absolute | fixed | sticky | inherit
    678         if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed
    679             || (parserContext.isCSSStickyPositionEnabled && valueID == CSSValueSticky))
    680             return true;
    681         break;
    682     case CSSPropertyResize: // none | both | horizontal | vertical | auto
    683         if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto)
    684             return true;
    685         break;
    686     case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
    687         if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation)
    688             return true;
    689         break;
    690     case CSSPropertyTableLayout: // auto | fixed | inherit
    691         if (valueID == CSSValueAuto || valueID == CSSValueFixed)
    692             return true;
    693         break;
    694     case CSSPropertyTextAlignLast:
    695         // auto | start | end | left | right | center | justify
    696         if (RuntimeEnabledFeatures::css3TextEnabled()
    697             && ((valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto))
    698             return true;
    699         break;
    700     case CSSPropertyTextLineThroughMode:
    701     case CSSPropertyTextOverlineMode:
    702     case CSSPropertyTextUnderlineMode:
    703         if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace)
    704             return true;
    705         break;
    706     case CSSPropertyTextLineThroughStyle:
    707     case CSSPropertyTextOverlineStyle:
    708     case CSSPropertyTextUnderlineStyle:
    709         if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave)
    710             return true;
    711         break;
    712     case CSSPropertyTextOverflow: // clip | ellipsis
    713         if (valueID == CSSValueClip || valueID == CSSValueEllipsis)
    714             return true;
    715         break;
    716     case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
    717         if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision)
    718             return true;
    719         break;
    720     case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
    721         if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone)
    722             return true;
    723         break;
    724     case CSSPropertyTouchAction: // auto | none
    725         if (RuntimeEnabledFeatures::cssTouchActionEnabled() && (valueID == CSSValueAuto || valueID == CSSValueNone))
    726             return true;
    727         break;
    728     case CSSPropertyVisibility: // visible | hidden | collapse | inherit
    729         if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse)
    730             return true;
    731         break;
    732     case CSSPropertyWebkitAppearance:
    733         if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone)
    734             return true;
    735         break;
    736     case CSSPropertyWebkitBackfaceVisibility:
    737         if (valueID == CSSValueVisible || valueID == CSSValueHidden)
    738             return true;
    739         break;
    740     case CSSPropertyMixBlendMode:
    741         if (RuntimeEnabledFeatures::cssCompositingEnabled() && (valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen
    742             || valueID == CSSValueOverlay || valueID == CSSValueDarken || valueID == CSSValueLighten ||  valueID == CSSValueColorDodge
    743             || valueID == CSSValueColorBurn || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference
    744             || valueID == CSSValueExclusion || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor
    745             || valueID == CSSValueLuminosity))
    746             return true;
    747         break;
    748     case CSSPropertyWebkitBorderFit:
    749         if (valueID == CSSValueBorder || valueID == CSSValueLines)
    750             return true;
    751         break;
    752     case CSSPropertyWebkitBoxAlign:
    753         if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline)
    754             return true;
    755         break;
    756     case CSSPropertyWebkitBoxDecorationBreak:
    757          if (valueID == CSSValueClone || valueID == CSSValueSlice)
    758              return true;
    759          break;
    760     case CSSPropertyWebkitBoxDirection:
    761         if (valueID == CSSValueNormal || valueID == CSSValueReverse)
    762             return true;
    763         break;
    764     case CSSPropertyWebkitBoxLines:
    765         if (valueID == CSSValueSingle || valueID == CSSValueMultiple)
    766                 return true;
    767         break;
    768     case CSSPropertyWebkitBoxOrient:
    769         if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis)
    770             return true;
    771         break;
    772     case CSSPropertyWebkitBoxPack:
    773         if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify)
    774             return true;
    775         break;
    776     case CSSPropertyAlignContent:
    777          if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch)
    778              return true;
    779          break;
    780     case CSSPropertyAlignItems:
    781         if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
    782             return true;
    783         break;
    784     case CSSPropertyAlignSelf:
    785         if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
    786             return true;
    787         break;
    788     case CSSPropertyFlexDirection:
    789         if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse)
    790             return true;
    791         break;
    792     case CSSPropertyFlexWrap:
    793         if (valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse)
    794              return true;
    795         break;
    796     case CSSPropertyJustifyContent:
    797         if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround)
    798             return true;
    799         break;
    800     case CSSPropertyWebkitFontKerning:
    801         if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone)
    802             return true;
    803         break;
    804     case CSSPropertyWebkitFontSmoothing:
    805         if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased)
    806             return true;
    807         break;
    808     case CSSPropertyGridAutoFlow:
    809         if (valueID == CSSValueNone || valueID == CSSValueRow || valueID == CSSValueColumn)
    810             return RuntimeEnabledFeatures::cssGridLayoutEnabled();
    811         break;
    812     case CSSPropertyWebkitLineAlign:
    813         if (valueID == CSSValueNone || valueID == CSSValueEdges)
    814             return true;
    815         break;
    816     case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
    817         if (valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace)
    818             return true;
    819         break;
    820     case CSSPropertyWebkitLineSnap:
    821         if (valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain)
    822             return true;
    823         break;
    824     case CSSPropertyWebkitMarginAfterCollapse:
    825     case CSSPropertyWebkitMarginBeforeCollapse:
    826     case CSSPropertyWebkitMarginBottomCollapse:
    827     case CSSPropertyWebkitMarginTopCollapse:
    828         if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard)
    829             return true;
    830         break;
    831     case CSSPropertyWebkitMarqueeDirection:
    832         if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
    833             || valueID == CSSValueUp || valueID == CSSValueAuto)
    834             return true;
    835         break;
    836     case CSSPropertyWebkitMarqueeStyle:
    837         if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate)
    838             return true;
    839         break;
    840     case CSSPropertyWebkitPrintColorAdjust:
    841         if (valueID == CSSValueExact || valueID == CSSValueEconomy)
    842             return true;
    843         break;
    844     case CSSPropertyWebkitRegionBreakAfter:
    845     case CSSPropertyWebkitRegionBreakBefore:
    846         if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight))
    847             return true;
    848         break;
    849     case CSSPropertyWebkitRegionBreakInside:
    850         if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueAvoid))
    851             return true;
    852         break;
    853     case CSSPropertyWebkitRegionFragment:
    854         if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueBreak))
    855             return true;
    856         break;
    857     case CSSPropertyWebkitRtlOrdering:
    858         if (valueID == CSSValueLogical || valueID == CSSValueVisual)
    859             return true;
    860         break;
    861 
    862     case CSSPropertyWebkitRubyPosition:
    863         if (valueID == CSSValueBefore || valueID == CSSValueAfter)
    864             return true;
    865         break;
    866 
    867     case CSSPropertyWebkitTextCombine:
    868         if (valueID == CSSValueNone || valueID == CSSValueHorizontal)
    869             return true;
    870         break;
    871     case CSSPropertyWebkitTextEmphasisPosition:
    872         if (valueID == CSSValueOver || valueID == CSSValueUnder)
    873             return true;
    874         break;
    875     case CSSPropertyWebkitTextSecurity:
    876         // disc | circle | square | none | inherit
    877         if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone)
    878             return true;
    879         break;
    880     case CSSPropertyWebkitTransformStyle:
    881         if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d)
    882             return true;
    883         break;
    884     case CSSPropertyWebkitUserDrag: // auto | none | element
    885         if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement)
    886             return true;
    887         break;
    888     case CSSPropertyWebkitUserModify: // read-only | read-write
    889         if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly)
    890             return true;
    891         break;
    892     case CSSPropertyWebkitUserSelect: // auto | none | text | all
    893         if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll)
    894             return true;
    895         break;
    896     case CSSPropertyWebkitWrapFlow:
    897         if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
    898             return false;
    899         if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear)
    900             return true;
    901         break;
    902     case CSSPropertyWebkitWrapThrough:
    903         if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
    904             return false;
    905         if (valueID == CSSValueWrap || valueID == CSSValueNone)
    906             return true;
    907         break;
    908     case CSSPropertyWebkitWritingMode:
    909         if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
    910             return true;
    911         break;
    912     case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
    913         if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
    914             return true;
    915         break;
    916     case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
    917         if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
    918             return true;
    919         break;
    920     default:
    921         ASSERT_NOT_REACHED();
    922         return false;
    923     }
    924     return false;
    925 }
    926 
    927 static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
    928 {
    929     switch (propertyId) {
    930     case CSSPropertyMixBlendMode:
    931         return RuntimeEnabledFeatures::cssCompositingEnabled();
    932     case CSSPropertyTextAlignLast:
    933         return RuntimeEnabledFeatures::css3TextEnabled();
    934     case CSSPropertyBorderBottomStyle:
    935     case CSSPropertyBorderCollapse:
    936     case CSSPropertyBorderLeftStyle:
    937     case CSSPropertyBorderRightStyle:
    938     case CSSPropertyBorderTopStyle:
    939     case CSSPropertyBoxSizing:
    940     case CSSPropertyCaptionSide:
    941     case CSSPropertyClear:
    942     case CSSPropertyDirection:
    943     case CSSPropertyDisplay:
    944     case CSSPropertyEmptyCells:
    945     case CSSPropertyFloat:
    946     case CSSPropertyFontStyle:
    947     case CSSPropertyImageRendering:
    948     case CSSPropertyListStylePosition:
    949     case CSSPropertyListStyleType:
    950     case CSSPropertyOutlineStyle:
    951     case CSSPropertyOverflowWrap:
    952     case CSSPropertyOverflowX:
    953     case CSSPropertyOverflowY:
    954     case CSSPropertyPageBreakAfter:
    955     case CSSPropertyPageBreakBefore:
    956     case CSSPropertyPageBreakInside:
    957     case CSSPropertyPointerEvents:
    958     case CSSPropertyPosition:
    959     case CSSPropertyResize:
    960     case CSSPropertySpeak:
    961     case CSSPropertyTableLayout:
    962     case CSSPropertyTextLineThroughMode:
    963     case CSSPropertyTextLineThroughStyle:
    964     case CSSPropertyTextOverflow:
    965     case CSSPropertyTextOverlineMode:
    966     case CSSPropertyTextOverlineStyle:
    967     case CSSPropertyTextRendering:
    968     case CSSPropertyTextTransform:
    969     case CSSPropertyTextUnderlineMode:
    970     case CSSPropertyTextUnderlineStyle:
    971     case CSSPropertyTouchAction:
    972     case CSSPropertyVisibility:
    973     case CSSPropertyWebkitAppearance:
    974     case CSSPropertyWebkitBackfaceVisibility:
    975     case CSSPropertyWebkitBorderAfterStyle:
    976     case CSSPropertyWebkitBorderBeforeStyle:
    977     case CSSPropertyWebkitBorderEndStyle:
    978     case CSSPropertyWebkitBorderFit:
    979     case CSSPropertyWebkitBorderStartStyle:
    980     case CSSPropertyWebkitBoxAlign:
    981     case CSSPropertyWebkitBoxDecorationBreak:
    982     case CSSPropertyWebkitBoxDirection:
    983     case CSSPropertyWebkitBoxLines:
    984     case CSSPropertyWebkitBoxOrient:
    985     case CSSPropertyWebkitBoxPack:
    986     case CSSPropertyWebkitColumnBreakAfter:
    987     case CSSPropertyWebkitColumnBreakBefore:
    988     case CSSPropertyWebkitColumnBreakInside:
    989     case CSSPropertyWebkitColumnRuleStyle:
    990     case CSSPropertyAlignContent:
    991     case CSSPropertyAlignItems:
    992     case CSSPropertyAlignSelf:
    993     case CSSPropertyFlexDirection:
    994     case CSSPropertyFlexWrap:
    995     case CSSPropertyJustifyContent:
    996     case CSSPropertyWebkitFontKerning:
    997     case CSSPropertyWebkitFontSmoothing:
    998     case CSSPropertyGridAutoFlow:
    999     case CSSPropertyWebkitLineAlign:
   1000     case CSSPropertyWebkitLineBreak:
   1001     case CSSPropertyWebkitLineSnap:
   1002     case CSSPropertyWebkitMarginAfterCollapse:
   1003     case CSSPropertyWebkitMarginBeforeCollapse:
   1004     case CSSPropertyWebkitMarginBottomCollapse:
   1005     case CSSPropertyWebkitMarginTopCollapse:
   1006     case CSSPropertyWebkitMarqueeDirection:
   1007     case CSSPropertyWebkitMarqueeStyle:
   1008     case CSSPropertyWebkitPrintColorAdjust:
   1009     case CSSPropertyWebkitRegionBreakAfter:
   1010     case CSSPropertyWebkitRegionBreakBefore:
   1011     case CSSPropertyWebkitRegionBreakInside:
   1012     case CSSPropertyWebkitRegionFragment:
   1013     case CSSPropertyWebkitRtlOrdering:
   1014     case CSSPropertyWebkitRubyPosition:
   1015     case CSSPropertyWebkitTextCombine:
   1016     case CSSPropertyWebkitTextEmphasisPosition:
   1017     case CSSPropertyWebkitTextSecurity:
   1018     case CSSPropertyWebkitTransformStyle:
   1019     case CSSPropertyWebkitUserDrag:
   1020     case CSSPropertyWebkitUserModify:
   1021     case CSSPropertyWebkitUserSelect:
   1022     case CSSPropertyWebkitWrapFlow:
   1023     case CSSPropertyWebkitWrapThrough:
   1024     case CSSPropertyWebkitWritingMode:
   1025     case CSSPropertyWhiteSpace:
   1026     case CSSPropertyWordBreak:
   1027     case CSSPropertyWordWrap:
   1028         return true;
   1029     default:
   1030         return false;
   1031     }
   1032 }
   1033 
   1034 static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
   1035 {
   1036     ASSERT(!string.isEmpty());
   1037 
   1038     if (!isKeywordPropertyID(propertyId)) {
   1039         // All properties accept the values of "initial" and "inherit".
   1040         String lowerCaseString = string.lower();
   1041         if (lowerCaseString != "initial" && lowerCaseString != "inherit")
   1042             return false;
   1043 
   1044         // Parse initial/inherit shorthands using the CSSParser.
   1045         if (shorthandForProperty(propertyId).length())
   1046             return false;
   1047     }
   1048 
   1049     CSSParserString cssString;
   1050     cssString.init(string);
   1051     CSSValueID valueID = cssValueKeywordID(cssString);
   1052 
   1053     if (!valueID)
   1054         return false;
   1055 
   1056     RefPtr<CSSValue> value;
   1057     if (valueID == CSSValueInherit)
   1058         value = cssValuePool().createInheritedValue();
   1059     else if (valueID == CSSValueInitial)
   1060         value = cssValuePool().createExplicitInitialValue();
   1061     else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
   1062         value = cssValuePool().createIdentifierValue(valueID);
   1063     else
   1064         return false;
   1065 
   1066     declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
   1067     return true;
   1068 }
   1069 
   1070 template <typename CharacterType>
   1071 static bool parseTransformArguments(CSSTransformValue* transformValue, CharacterType* characters, unsigned length, unsigned start, unsigned expectedCount)
   1072 {
   1073     while (expectedCount) {
   1074         size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start);
   1075         if (end == notFound || (expectedCount == 1 && end != length - 1))
   1076             return false;
   1077         unsigned argumentLength = end - start;
   1078         CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
   1079         double number;
   1080         if (!parseSimpleLength(characters + start, argumentLength, unit, number))
   1081             return false;
   1082         if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
   1083             return false;
   1084         transformValue->append(cssValuePool().createValue(number, unit));
   1085         start = end + 1;
   1086         --expectedCount;
   1087     }
   1088     return true;
   1089 }
   1090 
   1091 static bool parseTranslateTransformValue(MutableStylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important)
   1092 {
   1093     if (propertyID != CSSPropertyWebkitTransform)
   1094         return false;
   1095     static const unsigned shortestValidTransformStringLength = 12;
   1096     static const unsigned likelyMultipartTransformStringLengthCutoff = 32;
   1097     if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff)
   1098         return false;
   1099     if (!string.startsWith("translate", false))
   1100         return false;
   1101     UChar c9 = toASCIILower(string[9]);
   1102     UChar c10 = toASCIILower(string[10]);
   1103 
   1104     CSSTransformValue::TransformOperationType transformType;
   1105     unsigned expectedArgumentCount = 1;
   1106     unsigned argumentStart = 11;
   1107     if (c9 == 'x' && c10 == '(')
   1108         transformType = CSSTransformValue::TranslateXTransformOperation;
   1109     else if (c9 == 'y' && c10 == '(')
   1110         transformType = CSSTransformValue::TranslateYTransformOperation;
   1111     else if (c9 == 'z' && c10 == '(')
   1112         transformType = CSSTransformValue::TranslateZTransformOperation;
   1113     else if (c9 == '(') {
   1114         transformType = CSSTransformValue::TranslateTransformOperation;
   1115         expectedArgumentCount = 2;
   1116         argumentStart = 10;
   1117     } else if (c9 == '3' && c10 == 'd' && string[11] == '(') {
   1118         transformType = CSSTransformValue::Translate3DTransformOperation;
   1119         expectedArgumentCount = 3;
   1120         argumentStart = 12;
   1121     } else
   1122         return false;
   1123 
   1124     RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(transformType);
   1125     bool success;
   1126     if (string.is8Bit())
   1127         success = parseTransformArguments(transformValue.get(), string.characters8(), string.length(), argumentStart, expectedArgumentCount);
   1128     else
   1129         success = parseTransformArguments(transformValue.get(), string.characters16(), string.length(), argumentStart, expectedArgumentCount);
   1130     if (!success)
   1131         return false;
   1132     RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
   1133     result->append(transformValue.release());
   1134     properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, result.release(), important));
   1135     return true;
   1136 }
   1137 
   1138 PassRefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string)
   1139 {
   1140     if (string.isEmpty())
   1141         return 0;
   1142     RefPtr<MutableStylePropertySet> dummyStyle = MutableStylePropertySet::create();
   1143     if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, CSSQuirksMode, 0))
   1144         return 0;
   1145 
   1146     RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily);
   1147     if (!fontFamily->isValueList())
   1148         return 0;
   1149 
   1150     return toCSSValueList(dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily).get());
   1151 }
   1152 
   1153 bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, Document* document)
   1154 {
   1155     ASSERT(!string.isEmpty());
   1156 
   1157     CSSParserContext context(document);
   1158 
   1159     if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode))
   1160         return true;
   1161     if (parseColorValue(declaration, propertyID, string, important, context.mode))
   1162         return true;
   1163     if (parseKeywordValue(declaration, propertyID, string, important, context))
   1164         return true;
   1165 
   1166     CSSParser parser(context, UseCounter::getFrom(document));
   1167     return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0));
   1168 }
   1169 
   1170 bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
   1171 {
   1172     ASSERT(!string.isEmpty());
   1173     if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
   1174         return true;
   1175     if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
   1176         return true;
   1177 
   1178     CSSParserContext context(cssParserMode);
   1179     if (contextStyleSheet) {
   1180         context = contextStyleSheet->parserContext();
   1181         context.mode = cssParserMode;
   1182     }
   1183 
   1184     if (parseKeywordValue(declaration, propertyID, string, important, context))
   1185         return true;
   1186     if (parseTranslateTransformValue(declaration, propertyID, string, important))
   1187         return true;
   1188 
   1189     CSSParser parser(context);
   1190     return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
   1191 }
   1192 
   1193 bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
   1194 {
   1195     // FIXME: Check RuntimeCSSEnabled::isPropertyEnabled or isValueEnabledForProperty.
   1196 
   1197     if (m_useCounter)
   1198         m_useCounter->count(propertyID);
   1199 
   1200     setStyleSheet(contextStyleSheet);
   1201 
   1202     setupParser("@-internal-value ", string, "");
   1203 
   1204     m_id = propertyID;
   1205     m_important = important;
   1206 
   1207     cssyyparse(this);
   1208 
   1209     m_rule = 0;
   1210     m_id = CSSPropertyInvalid;
   1211 
   1212     bool ok = false;
   1213     if (m_hasFontFaceOnlyValues)
   1214         deleteFontFaceOnlyValues();
   1215     if (!m_parsedProperties.isEmpty()) {
   1216         ok = true;
   1217         declaration->addParsedProperties(m_parsedProperties);
   1218         clearProperties();
   1219     }
   1220 
   1221     return ok;
   1222 }
   1223 
   1224 // The color will only be changed when string contains a valid CSS color, so callers
   1225 // can set it to a default color and ignore the boolean result.
   1226 bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
   1227 {
   1228     // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
   1229     if (fastParseColor(color, string, strict))
   1230         return true;
   1231 
   1232     CSSParser parser(CSSStrictMode);
   1233 
   1234     // In case the fast-path parser didn't understand the color, try the full parser.
   1235     if (!parser.parseColor(string))
   1236         return false;
   1237 
   1238     CSSValue* value = parser.m_parsedProperties.first().value();
   1239     if (!value->isPrimitiveValue())
   1240         return false;
   1241 
   1242     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
   1243     if (!primitiveValue->isRGBColor())
   1244         return false;
   1245 
   1246     color = primitiveValue->getRGBA32Value();
   1247     return true;
   1248 }
   1249 
   1250 bool CSSParser::parseColor(const String& string)
   1251 {
   1252     setupParser("@-internal-decls color:", string, "");
   1253     cssyyparse(this);
   1254     m_rule = 0;
   1255 
   1256     return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
   1257 }
   1258 
   1259 bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
   1260 {
   1261     if (!document || !document->page())
   1262         return false;
   1263 
   1264     CSSParserString cssColor;
   1265     cssColor.init(string);
   1266     CSSValueID id = cssValueKeywordID(cssColor);
   1267     if (id <= 0)
   1268         return false;
   1269 
   1270     color = document->page()->theme()->systemColor(id).rgb();
   1271     return true;
   1272 }
   1273 
   1274 void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
   1275 {
   1276     m_selectorListForParseSelector = &selectorList;
   1277 
   1278     setupParser("@-internal-selector ", string, "");
   1279 
   1280     cssyyparse(this);
   1281 
   1282     m_selectorListForParseSelector = 0;
   1283 }
   1284 
   1285 PassRefPtr<ImmutableStylePropertySet> CSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
   1286 {
   1287     Document* document = element->document();
   1288     CSSParserContext context = document->elementSheet()->contents()->parserContext();
   1289     context.mode = strictToCSSParserMode(element->isHTMLElement() && !document->inQuirksMode());
   1290     return CSSParser(context, UseCounter::getFrom(document)).parseDeclaration(string, document->elementSheet()->contents());
   1291 }
   1292 
   1293 PassRefPtr<ImmutableStylePropertySet> CSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
   1294 {
   1295     setStyleSheet(contextStyleSheet);
   1296 
   1297     setupParser("@-internal-decls ", string, "");
   1298     cssyyparse(this);
   1299     m_rule = 0;
   1300 
   1301     if (m_hasFontFaceOnlyValues)
   1302         deleteFontFaceOnlyValues();
   1303 
   1304     RefPtr<ImmutableStylePropertySet> style = createStylePropertySet();
   1305     clearProperties();
   1306     return style.release();
   1307 }
   1308 
   1309 
   1310 bool CSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, SourceDataHandler* sourceDataHandler, StyleSheetContents* contextStyleSheet)
   1311 {
   1312     setStyleSheet(contextStyleSheet);
   1313 
   1314     m_sourceDataHandler = sourceDataHandler;
   1315 
   1316     setupParser("@-internal-decls ", string, "");
   1317     if (m_sourceDataHandler) {
   1318         m_sourceDataHandler->startRuleHeader(CSSRuleSourceData::STYLE_RULE, 0);
   1319         m_sourceDataHandler->endRuleHeader(1);
   1320         m_sourceDataHandler->startRuleBody(0);
   1321     }
   1322     cssyyparse(this);
   1323     m_rule = 0;
   1324 
   1325     bool ok = false;
   1326     if (m_hasFontFaceOnlyValues)
   1327         deleteFontFaceOnlyValues();
   1328     if (!m_parsedProperties.isEmpty()) {
   1329         ok = true;
   1330         declaration->addParsedProperties(m_parsedProperties);
   1331         clearProperties();
   1332     }
   1333 
   1334     if (m_sourceDataHandler)
   1335         m_sourceDataHandler->endRuleBody(string.length(), false);
   1336     m_sourceDataHandler = 0;
   1337 
   1338     return ok;
   1339 }
   1340 
   1341 PassRefPtr<MediaQuerySet> CSSParser::parseMediaQueryList(const String& string)
   1342 {
   1343     ASSERT(!m_mediaList);
   1344 
   1345     // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
   1346     // instead insert one " " (which is caught by maybe_space in CSSGrammar.y)
   1347     setupParser("@-internal-medialist ", string, "");
   1348     cssyyparse(this);
   1349 
   1350     ASSERT(m_mediaList.get());
   1351     return m_mediaList.release();
   1352 }
   1353 
   1354 static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenVariables)
   1355 {
   1356     // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
   1357     for (int i = input.size() - 1; i >= 0; --i) {
   1358         const CSSProperty& property = input[i];
   1359         if (property.isImportant() != important)
   1360             continue;
   1361         if (property.id() == CSSPropertyVariable) {
   1362             const AtomicString& name = toCSSVariableValue(property.value())->name();
   1363             if (!seenVariables.add(name).isNewEntry)
   1364                 continue;
   1365             output[--unusedEntries] = property;
   1366             continue;
   1367         }
   1368         const unsigned propertyIDIndex = property.id() - firstCSSProperty;
   1369         if (seenProperties.get(propertyIDIndex))
   1370             continue;
   1371         seenProperties.set(propertyIDIndex);
   1372         output[--unusedEntries] = property;
   1373     }
   1374 }
   1375 
   1376 PassRefPtr<ImmutableStylePropertySet> CSSParser::createStylePropertySet()
   1377 {
   1378     BitArray<numCSSProperties> seenProperties;
   1379     size_t unusedEntries = m_parsedProperties.size();
   1380     Vector<CSSProperty, 256> results(unusedEntries);
   1381 
   1382     // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
   1383     HashSet<AtomicString> seenVariables;
   1384     filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
   1385     filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
   1386     if (unusedEntries)
   1387         results.remove(0, unusedEntries);
   1388 
   1389     return ImmutableStylePropertySet::create(results.data(), results.size(), m_context.mode);
   1390 }
   1391 
   1392 void CSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
   1393 {
   1394     RefPtr<CSSValue> val = value.get();
   1395     addProperty(propId, value, important, implicit);
   1396 
   1397     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
   1398     if (prefixingVariant == propId)
   1399         return;
   1400 
   1401     if (m_currentShorthand) {
   1402         // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
   1403         m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
   1404         addProperty(prefixingVariant, val.release(), important, implicit);
   1405         m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
   1406     } else {
   1407         addProperty(prefixingVariant, val.release(), important, implicit);
   1408     }
   1409 }
   1410 
   1411 void CSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
   1412 {
   1413     CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? toCSSPrimitiveValue(value.get()) : 0;
   1414     // This property doesn't belong to a shorthand or is a CSS variable (which will be resolved later).
   1415     if (!m_currentShorthand || (primitiveValue && primitiveValue->isVariableName())) {
   1416         m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
   1417         return;
   1418     }
   1419 
   1420     const Vector<StylePropertyShorthand> shorthands = matchingShorthandsForLonghand(propId);
   1421     // The longhand does not belong to multiple shorthands.
   1422     if (shorthands.size() == 1)
   1423         m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
   1424     else
   1425         m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
   1426 }
   1427 
   1428 void CSSParser::rollbackLastProperties(int num)
   1429 {
   1430     ASSERT(num >= 0);
   1431     ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
   1432     m_parsedProperties.shrink(m_parsedProperties.size() - num);
   1433 }
   1434 
   1435 void CSSParser::clearProperties()
   1436 {
   1437     m_parsedProperties.clear();
   1438     m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
   1439     m_hasFontFaceOnlyValues = false;
   1440 }
   1441 
   1442 KURL CSSParser::completeURL(const CSSParserContext& context, const String& url)
   1443 {
   1444     if (url.isNull())
   1445         return KURL();
   1446     if (context.charset.isEmpty())
   1447         return KURL(context.baseURL, url);
   1448     return KURL(context.baseURL, url, context.charset);
   1449 }
   1450 
   1451 KURL CSSParser::completeURL(const String& url) const
   1452 {
   1453     return completeURL(m_context, url);
   1454 }
   1455 
   1456 bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
   1457 {
   1458     bool mustBeNonNegative = unitflags & FNonNeg;
   1459 
   1460     if (!parseCalculation(value, mustBeNonNegative ? CalculationRangeNonNegative : CalculationRangeAll))
   1461         return false;
   1462 
   1463     bool b = false;
   1464     switch (m_parsedCalculation->category()) {
   1465     case CalcLength:
   1466         b = (unitflags & FLength);
   1467         break;
   1468     case CalcPercent:
   1469         b = (unitflags & FPercent);
   1470         if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
   1471             b = false;
   1472         break;
   1473     case CalcNumber:
   1474         b = (unitflags & FNumber);
   1475         if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
   1476             b = true;
   1477         if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
   1478             b = false;
   1479         break;
   1480     case CalcPercentLength:
   1481         b = (unitflags & FPercent) && (unitflags & FLength);
   1482         break;
   1483     case CalcPercentNumber:
   1484         b = (unitflags & FPercent) && (unitflags & FNumber);
   1485         break;
   1486     case CalcVariable:
   1487         b = true;
   1488         break;
   1489     case CalcOther:
   1490         break;
   1491     }
   1492     if (!b || releaseCalc == ReleaseParsedCalcValue)
   1493         m_parsedCalculation.release();
   1494     return b;
   1495 }
   1496 
   1497 inline bool CSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
   1498 {
   1499     // Qirks mode and svg presentation attributes accept unit less values.
   1500     return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || cssParserMode == CSSQuirksMode || cssParserMode == SVGAttributeMode);
   1501 }
   1502 
   1503 bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
   1504 {
   1505     if (isCalculation(value))
   1506         return validCalculationUnit(value, unitflags, releaseCalc);
   1507 
   1508     bool b = false;
   1509     switch (value->unit) {
   1510     case CSSPrimitiveValue::CSS_VARIABLE_NAME:
   1511         // Variables are checked at the point they are dereferenced because unit type is not available here.
   1512         b = true;
   1513         break;
   1514     case CSSPrimitiveValue::CSS_NUMBER:
   1515         b = (unitflags & FNumber);
   1516         if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
   1517             value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
   1518                           ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
   1519             b = true;
   1520         }
   1521         if (!b && (unitflags & FInteger) && value->isInt)
   1522             b = true;
   1523         if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
   1524             b = true;
   1525         break;
   1526     case CSSPrimitiveValue::CSS_PERCENTAGE:
   1527         b = (unitflags & FPercent);
   1528         break;
   1529     case CSSParserValue::Q_EMS:
   1530     case CSSPrimitiveValue::CSS_EMS:
   1531     case CSSPrimitiveValue::CSS_REMS:
   1532     case CSSPrimitiveValue::CSS_CHS:
   1533     case CSSPrimitiveValue::CSS_EXS:
   1534     case CSSPrimitiveValue::CSS_PX:
   1535     case CSSPrimitiveValue::CSS_CM:
   1536     case CSSPrimitiveValue::CSS_MM:
   1537     case CSSPrimitiveValue::CSS_IN:
   1538     case CSSPrimitiveValue::CSS_PT:
   1539     case CSSPrimitiveValue::CSS_PC:
   1540     case CSSPrimitiveValue::CSS_VW:
   1541     case CSSPrimitiveValue::CSS_VH:
   1542     case CSSPrimitiveValue::CSS_VMIN:
   1543     case CSSPrimitiveValue::CSS_VMAX:
   1544         b = (unitflags & FLength);
   1545         break;
   1546     case CSSPrimitiveValue::CSS_MS:
   1547     case CSSPrimitiveValue::CSS_S:
   1548         b = (unitflags & FTime);
   1549         break;
   1550     case CSSPrimitiveValue::CSS_DEG:
   1551     case CSSPrimitiveValue::CSS_RAD:
   1552     case CSSPrimitiveValue::CSS_GRAD:
   1553     case CSSPrimitiveValue::CSS_TURN:
   1554         b = (unitflags & FAngle);
   1555         break;
   1556     case CSSPrimitiveValue::CSS_DPPX:
   1557     case CSSPrimitiveValue::CSS_DPI:
   1558     case CSSPrimitiveValue::CSS_DPCM:
   1559         b = (unitflags & FResolution);
   1560         break;
   1561     case CSSPrimitiveValue::CSS_HZ:
   1562     case CSSPrimitiveValue::CSS_KHZ:
   1563     case CSSPrimitiveValue::CSS_DIMENSION:
   1564     default:
   1565         break;
   1566     }
   1567     if (b && unitflags & FNonNeg && value->fValue < 0)
   1568         b = false;
   1569     return b;
   1570 }
   1571 
   1572 inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(CSSParserValue* value)
   1573 {
   1574     if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
   1575         return createPrimitiveVariableNameValue(value);
   1576 
   1577     if (m_parsedCalculation) {
   1578         ASSERT(isCalculation(value));
   1579         return CSSPrimitiveValue::create(m_parsedCalculation.release());
   1580     }
   1581 
   1582     ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
   1583         || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
   1584         || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
   1585         || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
   1586     return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
   1587 }
   1588 
   1589 inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue* value)
   1590 {
   1591     ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
   1592     return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
   1593 }
   1594 
   1595 inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveVariableNameValue(CSSParserValue* value)
   1596 {
   1597     ASSERT(value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME);
   1598     return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_VARIABLE_NAME);
   1599 }
   1600 
   1601 static inline bool isComma(CSSParserValue* value)
   1602 {
   1603     return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
   1604 }
   1605 
   1606 static inline bool isForwardSlashOperator(CSSParserValue* value)
   1607 {
   1608     ASSERT(value);
   1609     return value->unit == CSSParserValue::Operator && value->iValue == '/';
   1610 }
   1611 
   1612 bool CSSParser::validWidthOrHeight(CSSParserValue* value)
   1613 {
   1614     int id = value->id;
   1615     if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
   1616         return true;
   1617     return !id && validUnit(value, FLength | FPercent | FNonNeg);
   1618 }
   1619 
   1620 inline PassRefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
   1621 {
   1622     if (identifier)
   1623         return cssValuePool().createIdentifierValue(identifier);
   1624     if (value->unit == CSSPrimitiveValue::CSS_STRING)
   1625         return createPrimitiveStringValue(value);
   1626     if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
   1627         return createPrimitiveNumericValue(value);
   1628     if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
   1629         return createPrimitiveNumericValue(value);
   1630     if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
   1631         return createPrimitiveNumericValue(value);
   1632     if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
   1633         return createPrimitiveNumericValue(value);
   1634     if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
   1635         return createPrimitiveVariableNameValue(value);
   1636     if (value->unit >= CSSParserValue::Q_EMS)
   1637         return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
   1638     if (isCalculation(value))
   1639         return CSSPrimitiveValue::create(m_parsedCalculation.release());
   1640 
   1641     return 0;
   1642 }
   1643 
   1644 void CSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr<CSSValue> prpValue, bool important)
   1645 {
   1646     const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
   1647     unsigned shorthandLength = shorthand.length();
   1648     if (!shorthandLength) {
   1649         addProperty(propId, prpValue, important);
   1650         return;
   1651     }
   1652 
   1653     RefPtr<CSSValue> value = prpValue;
   1654     ShorthandScope scope(this, propId);
   1655     const CSSPropertyID* longhands = shorthand.properties();
   1656     for (unsigned i = 0; i < shorthandLength; ++i)
   1657         addProperty(longhands[i], value, important);
   1658 }
   1659 
   1660 void CSSParser::setCurrentProperty(CSSPropertyID propId)
   1661 {
   1662     m_id = propId;
   1663 }
   1664 
   1665 bool CSSParser::parseValue(CSSPropertyID propId, bool important)
   1666 {
   1667     if (m_useCounter)
   1668         m_useCounter->count(propId);
   1669 
   1670     if (!m_valueList)
   1671         return false;
   1672 
   1673     CSSParserValue* value = m_valueList->current();
   1674 
   1675     if (!value)
   1676         return false;
   1677 
   1678     if (inViewport()) {
   1679         if (!RuntimeEnabledFeatures::cssViewportEnabled())
   1680             return false;
   1681 
   1682         return parseViewportProperty(propId, important);
   1683     }
   1684 
   1685     // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
   1686     // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
   1687     ASSERT(!m_parsedCalculation);
   1688 
   1689     CSSValueID id = value->id;
   1690 
   1691     int num = inShorthand() ? 1 : m_valueList->size();
   1692 
   1693     if (id == CSSValueInherit) {
   1694         if (num != 1)
   1695             return false;
   1696         addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
   1697         return true;
   1698     }
   1699     else if (id == CSSValueInitial) {
   1700         if (num != 1)
   1701             return false;
   1702         addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
   1703         return true;
   1704     }
   1705 
   1706     if (!id && value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME && num == 1) {
   1707         addProperty(propId, createPrimitiveVariableNameValue(value), important);
   1708         m_valueList->next();
   1709         return true;
   1710     }
   1711     ASSERT(propId != CSSPropertyVariable);
   1712 
   1713     if (isKeywordPropertyID(propId)) {
   1714         if (!isValidKeywordPropertyAndValue(propId, id, m_context))
   1715             return false;
   1716         if (m_valueList->next() && !inShorthand())
   1717             return false;
   1718         addProperty(propId, cssValuePool().createIdentifierValue(id), important);
   1719         return true;
   1720     }
   1721 
   1722     bool validPrimitive = false;
   1723     RefPtr<CSSValue> parsedValue;
   1724 
   1725     switch (propId) {
   1726     case CSSPropertySize:                 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
   1727         return parseSize(propId, important);
   1728 
   1729     case CSSPropertyQuotes:               // [<string> <string>]+ | none | inherit
   1730         if (id)
   1731             validPrimitive = true;
   1732         else
   1733             return parseQuotes(propId, important);
   1734         break;
   1735     case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
   1736         if (id == CSSValueNormal
   1737             || id == CSSValueEmbed
   1738             || id == CSSValueBidiOverride
   1739             || id == CSSValueWebkitIsolate
   1740             || id == CSSValueWebkitIsolateOverride
   1741             || id == CSSValueWebkitPlaintext)
   1742             validPrimitive = true;
   1743         break;
   1744 
   1745     case CSSPropertyContent:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
   1746         // close-quote | no-open-quote | no-close-quote ]+ | inherit
   1747         return parseContent(propId, important);
   1748 
   1749     case CSSPropertyClip:                 // <shape> | auto | inherit
   1750         if (id == CSSValueAuto)
   1751             validPrimitive = true;
   1752         else if (value->unit == CSSParserValue::Function)
   1753             return parseClipShape(propId, important);
   1754         break;
   1755 
   1756     /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
   1757      * correctly and allows optimization in WebCore::applyRule(..)
   1758      */
   1759     case CSSPropertyOverflow: {
   1760         ShorthandScope scope(this, propId);
   1761         if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
   1762             return false;
   1763 
   1764         RefPtr<CSSValue> overflowXValue;
   1765 
   1766         // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
   1767         // set using the shorthand, then for now overflow-x will default to auto, but once we implement
   1768         // pagination controls, it should default to hidden. If the overflow-y value is anything but
   1769         // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
   1770         if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
   1771             overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
   1772         else
   1773             overflowXValue = m_parsedProperties.last().value();
   1774         addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
   1775         return true;
   1776     }
   1777 
   1778     case CSSPropertyTextAlign:
   1779         // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
   1780         // | start | end | <string> | inherit | -webkit-auto (converted to start)
   1781         if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
   1782             || value->unit == CSSPrimitiveValue::CSS_STRING)
   1783             validPrimitive = true;
   1784         break;
   1785 
   1786     case CSSPropertyFontWeight:  { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
   1787         if (m_valueList->size() != 1)
   1788             return false;
   1789         return parseFontWeight(important);
   1790     }
   1791     case CSSPropertyBorderSpacing: {
   1792         if (num == 1) {
   1793             ShorthandScope scope(this, CSSPropertyBorderSpacing);
   1794             if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
   1795                 return false;
   1796             CSSValue* value = m_parsedProperties.last().value();
   1797             addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
   1798             return true;
   1799         }
   1800         else if (num == 2) {
   1801             ShorthandScope scope(this, CSSPropertyBorderSpacing);
   1802             if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
   1803                 return false;
   1804             return true;
   1805         }
   1806         return false;
   1807     }
   1808     case CSSPropertyWebkitBorderHorizontalSpacing:
   1809     case CSSPropertyWebkitBorderVerticalSpacing:
   1810         validPrimitive = validUnit(value, FLength | FNonNeg);
   1811         break;
   1812     case CSSPropertyOutlineColor:        // <color> | invert | inherit
   1813         // Outline color has "invert" as additional keyword.
   1814         // Also, we want to allow the special focus color even in strict parsing mode.
   1815         if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
   1816             validPrimitive = true;
   1817             break;
   1818         }
   1819         /* nobreak */
   1820     case CSSPropertyBackgroundColor: // <color> | inherit
   1821     case CSSPropertyBorderTopColor: // <color> | inherit
   1822     case CSSPropertyBorderRightColor:
   1823     case CSSPropertyBorderBottomColor:
   1824     case CSSPropertyBorderLeftColor:
   1825     case CSSPropertyWebkitBorderStartColor:
   1826     case CSSPropertyWebkitBorderEndColor:
   1827     case CSSPropertyWebkitBorderBeforeColor:
   1828     case CSSPropertyWebkitBorderAfterColor:
   1829     case CSSPropertyColor: // <color> | inherit
   1830     case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
   1831     case CSSPropertyTextLineThroughColor:
   1832     case CSSPropertyTextUnderlineColor:
   1833     case CSSPropertyTextOverlineColor:
   1834     case CSSPropertyWebkitColumnRuleColor:
   1835     case CSSPropertyWebkitTextEmphasisColor:
   1836     case CSSPropertyWebkitTextFillColor:
   1837     case CSSPropertyWebkitTextStrokeColor:
   1838         if (propId == CSSPropertyTextDecorationColor
   1839             && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
   1840             return false;
   1841 
   1842         if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMenu) {
   1843             validPrimitive = isValueAllowedInMode(id, m_context.mode);
   1844         } else {
   1845             parsedValue = parseColor();
   1846             if (parsedValue)
   1847                 m_valueList->next();
   1848         }
   1849         break;
   1850 
   1851     case CSSPropertyCursor: {
   1852         // Grammar defined by CSS3 UI and modified by CSS4 images:
   1853         // [ [<image> [<x> <y>]?,]*
   1854         // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
   1855         // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
   1856         // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
   1857         // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
   1858         // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
   1859         RefPtr<CSSValueList> list;
   1860         while (value) {
   1861             RefPtr<CSSValue> image = 0;
   1862             if (value->unit == CSSPrimitiveValue::CSS_URI) {
   1863                 String uri = value->string;
   1864                 if (!uri.isNull())
   1865                     image = CSSImageValue::create(completeURL(uri));
   1866             } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
   1867                 image = parseImageSet(m_valueList.get());
   1868                 if (!image)
   1869                     break;
   1870             } else
   1871                 break;
   1872 
   1873             Vector<int> coords;
   1874             value = m_valueList->next();
   1875             while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
   1876                 coords.append(int(value->fValue));
   1877                 value = m_valueList->next();
   1878             }
   1879             bool hasHotSpot = false;
   1880             IntPoint hotSpot(-1, -1);
   1881             int nrcoords = coords.size();
   1882             if (nrcoords > 0 && nrcoords != 2)
   1883                 return false;
   1884             if (nrcoords == 2) {
   1885                 hasHotSpot = true;
   1886                 hotSpot = IntPoint(coords[0], coords[1]);
   1887             }
   1888 
   1889             if (!list)
   1890                 list = CSSValueList::createCommaSeparated();
   1891 
   1892             if (image)
   1893                 list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
   1894 
   1895             if ((inStrictMode() && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
   1896                 return false;
   1897             value = m_valueList->next(); // comma
   1898         }
   1899         if (list) {
   1900             if (!value) { // no value after url list (MSIE 5 compatibility)
   1901                 if (list->length() != 1)
   1902                     return false;
   1903             } else if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
   1904                 list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
   1905             else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
   1906                 list->append(cssValuePool().createIdentifierValue(value->id));
   1907             m_valueList->next();
   1908             parsedValue = list.release();
   1909             break;
   1910         } else if (value) {
   1911             id = value->id;
   1912             if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
   1913                 id = CSSValuePointer;
   1914                 validPrimitive = true;
   1915             } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
   1916                 validPrimitive = true;
   1917         } else {
   1918             ASSERT_NOT_REACHED();
   1919             return false;
   1920         }
   1921         break;
   1922     }
   1923 
   1924     case CSSPropertyBackgroundBlendMode:
   1925     case CSSPropertyBackgroundAttachment:
   1926     case CSSPropertyBackgroundClip:
   1927     case CSSPropertyWebkitBackgroundClip:
   1928     case CSSPropertyWebkitBackgroundComposite:
   1929     case CSSPropertyBackgroundImage:
   1930     case CSSPropertyBackgroundOrigin:
   1931     case CSSPropertyWebkitBackgroundOrigin:
   1932     case CSSPropertyBackgroundPosition:
   1933     case CSSPropertyBackgroundPositionX:
   1934     case CSSPropertyBackgroundPositionY:
   1935     case CSSPropertyBackgroundSize:
   1936     case CSSPropertyWebkitBackgroundSize:
   1937     case CSSPropertyBackgroundRepeat:
   1938     case CSSPropertyBackgroundRepeatX:
   1939     case CSSPropertyBackgroundRepeatY:
   1940     case CSSPropertyWebkitMaskClip:
   1941     case CSSPropertyWebkitMaskComposite:
   1942     case CSSPropertyWebkitMaskImage:
   1943     case CSSPropertyWebkitMaskOrigin:
   1944     case CSSPropertyWebkitMaskPosition:
   1945     case CSSPropertyWebkitMaskPositionX:
   1946     case CSSPropertyWebkitMaskPositionY:
   1947     case CSSPropertyWebkitMaskSize:
   1948     case CSSPropertyWebkitMaskRepeat:
   1949     case CSSPropertyWebkitMaskRepeatX:
   1950     case CSSPropertyWebkitMaskRepeatY:
   1951     {
   1952         RefPtr<CSSValue> val1;
   1953         RefPtr<CSSValue> val2;
   1954         CSSPropertyID propId1, propId2;
   1955         bool result = false;
   1956         if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
   1957             OwnPtr<ShorthandScope> shorthandScope;
   1958             if (propId == CSSPropertyBackgroundPosition ||
   1959                 propId == CSSPropertyBackgroundRepeat ||
   1960                 propId == CSSPropertyWebkitMaskPosition ||
   1961                 propId == CSSPropertyWebkitMaskRepeat) {
   1962                 shorthandScope = adoptPtr(new ShorthandScope(this, propId));
   1963             }
   1964             addProperty(propId1, val1.release(), important);
   1965             if (val2)
   1966                 addProperty(propId2, val2.release(), important);
   1967             result = true;
   1968         }
   1969         m_implicitShorthand = false;
   1970         return result;
   1971     }
   1972     case CSSPropertyListStyleImage:     // <uri> | none | inherit
   1973     case CSSPropertyBorderImageSource:
   1974     case CSSPropertyWebkitMaskBoxImageSource:
   1975         if (id == CSSValueNone) {
   1976             parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
   1977             m_valueList->next();
   1978         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
   1979             parsedValue = CSSImageValue::create(completeURL(value->string));
   1980             m_valueList->next();
   1981         } else if (isGeneratedImageValue(value)) {
   1982             if (parseGeneratedImage(m_valueList.get(), parsedValue))
   1983                 m_valueList->next();
   1984             else
   1985                 return false;
   1986         }
   1987         else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
   1988             parsedValue = parseImageSet(m_valueList.get());
   1989             if (!parsedValue)
   1990                 return false;
   1991             m_valueList->next();
   1992         }
   1993         break;
   1994 
   1995     case CSSPropertyWebkitTextStrokeWidth:
   1996     case CSSPropertyOutlineWidth:        // <border-width> | inherit
   1997     case CSSPropertyBorderTopWidth:     //// <border-width> | inherit
   1998     case CSSPropertyBorderRightWidth:   //   Which is defined as
   1999     case CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
   2000     case CSSPropertyBorderLeftWidth:
   2001     case CSSPropertyWebkitBorderStartWidth:
   2002     case CSSPropertyWebkitBorderEndWidth:
   2003     case CSSPropertyWebkitBorderBeforeWidth:
   2004     case CSSPropertyWebkitBorderAfterWidth:
   2005     case CSSPropertyWebkitColumnRuleWidth:
   2006         if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
   2007             validPrimitive = true;
   2008         else
   2009             validPrimitive = validUnit(value, FLength | FNonNeg);
   2010         break;
   2011 
   2012     case CSSPropertyLetterSpacing:       // normal | <length> | inherit
   2013     case CSSPropertyWordSpacing:         // normal | <length> | inherit
   2014         if (id == CSSValueNormal)
   2015             validPrimitive = true;
   2016         else
   2017             validPrimitive = validUnit(value, FLength);
   2018         break;
   2019 
   2020     case CSSPropertyTextIndent:
   2021         parsedValue = parseTextIndent();
   2022         break;
   2023 
   2024     case CSSPropertyPaddingTop:          //// <padding-width> | inherit
   2025     case CSSPropertyPaddingRight:        //   Which is defined as
   2026     case CSSPropertyPaddingBottom:       //   <length> | <percentage>
   2027     case CSSPropertyPaddingLeft:         ////
   2028     case CSSPropertyWebkitPaddingStart:
   2029     case CSSPropertyWebkitPaddingEnd:
   2030     case CSSPropertyWebkitPaddingBefore:
   2031     case CSSPropertyWebkitPaddingAfter:
   2032         validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
   2033         break;
   2034 
   2035     case CSSPropertyMaxWidth:
   2036     case CSSPropertyWebkitMaxLogicalWidth:
   2037     case CSSPropertyMaxHeight:
   2038     case CSSPropertyWebkitMaxLogicalHeight:
   2039         validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
   2040         break;
   2041 
   2042     case CSSPropertyMinWidth:
   2043     case CSSPropertyWebkitMinLogicalWidth:
   2044     case CSSPropertyMinHeight:
   2045     case CSSPropertyWebkitMinLogicalHeight:
   2046         validPrimitive = validWidthOrHeight(value);
   2047         break;
   2048 
   2049     case CSSPropertyWidth:
   2050     case CSSPropertyWebkitLogicalWidth:
   2051     case CSSPropertyHeight:
   2052     case CSSPropertyWebkitLogicalHeight:
   2053         validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
   2054         break;
   2055 
   2056     case CSSPropertyFontSize:
   2057         return parseFontSize(important);
   2058 
   2059     case CSSPropertyFontVariant:         // normal | small-caps | inherit
   2060         return parseFontVariant(important);
   2061 
   2062     case CSSPropertyVerticalAlign:
   2063         // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
   2064         // <percentage> | <length> | inherit
   2065 
   2066         if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
   2067             validPrimitive = true;
   2068         else
   2069             validPrimitive = (!id && validUnit(value, FLength | FPercent));
   2070         break;
   2071 
   2072     case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
   2073     case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
   2074     case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
   2075     case CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
   2076     case CSSPropertyMarginTop:           //// <margin-width> | inherit
   2077     case CSSPropertyMarginRight:         //   Which is defined as
   2078     case CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
   2079     case CSSPropertyMarginLeft:          ////
   2080     case CSSPropertyWebkitMarginStart:
   2081     case CSSPropertyWebkitMarginEnd:
   2082     case CSSPropertyWebkitMarginBefore:
   2083     case CSSPropertyWebkitMarginAfter:
   2084         if (id == CSSValueAuto)
   2085             validPrimitive = true;
   2086         else
   2087             validPrimitive = (!id && validUnit(value, FLength | FPercent));
   2088         break;
   2089 
   2090     case CSSPropertyZIndex:              // auto | <integer> | inherit
   2091         if (id == CSSValueAuto) {
   2092             validPrimitive = true;
   2093             break;
   2094         }
   2095         /* nobreak */
   2096     case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
   2097     case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
   2098         if (id == CSSValueAuto)
   2099             validPrimitive = true;
   2100         else
   2101             validPrimitive = (!id && validUnit(value, FInteger, CSSQuirksMode));
   2102         break;
   2103 
   2104     case CSSPropertyLineHeight:
   2105         return parseLineHeight(important);
   2106     case CSSPropertyCounterIncrement:    // [ <identifier> <integer>? ]+ | none | inherit
   2107         if (id != CSSValueNone)
   2108             return parseCounter(propId, 1, important);
   2109         validPrimitive = true;
   2110         break;
   2111     case CSSPropertyCounterReset:        // [ <identifier> <integer>? ]+ | none | inherit
   2112         if (id != CSSValueNone)
   2113             return parseCounter(propId, 0, important);
   2114         validPrimitive = true;
   2115         break;
   2116     case CSSPropertyFontFamily:
   2117         // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
   2118     {
   2119         parsedValue = parseFontFamily();
   2120         break;
   2121     }
   2122 
   2123     case CSSPropertyTextDecoration:
   2124     case CSSPropertyWebkitTextDecorationsInEffect:
   2125     case CSSPropertyTextDecorationLine:
   2126         // none | [ underline || overline || line-through || blink ] | inherit
   2127         return parseTextDecoration(propId, important);
   2128 
   2129     case CSSPropertyTextDecorationStyle:
   2130         // solid | double | dotted | dashed | wavy
   2131         if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
   2132             && (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy))
   2133             validPrimitive = true;
   2134         break;
   2135 
   2136 #if ENABLE(CSS3_TEXT)
   2137     case CSSPropertyWebkitTextUnderlinePosition:
   2138         // auto | alphabetic | under
   2139         return parseTextUnderlinePosition(important);
   2140 #endif // CSS3_TEXT
   2141 
   2142     case CSSPropertyZoom:          // normal | reset | document | <number> | <percentage> | inherit
   2143         if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
   2144             validPrimitive = true;
   2145         else
   2146             validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode));
   2147         break;
   2148 
   2149     case CSSPropertySrc: // Only used within @font-face and @-webkit-filter, so cannot use inherit | initial or be !important. This is a list of urls or local references.
   2150         if (m_inFilterRule)
   2151             return parseFilterRuleSrc();
   2152         return parseFontFaceSrc();
   2153 
   2154     case CSSPropertyUnicodeRange:
   2155         return parseFontFaceUnicodeRange();
   2156 
   2157     /* CSS3 properties */
   2158 
   2159     case CSSPropertyBorderImage: {
   2160         RefPtr<CSSValue> result;
   2161         return parseBorderImage(propId, result, important);
   2162     }
   2163     case CSSPropertyWebkitBorderImage:
   2164     case CSSPropertyWebkitMaskBoxImage: {
   2165         RefPtr<CSSValue> result;
   2166         if (parseBorderImage(propId, result)) {
   2167             addProperty(propId, result, important);
   2168             return true;
   2169         }
   2170         break;
   2171     }
   2172     case CSSPropertyBorderImageOutset:
   2173     case CSSPropertyWebkitMaskBoxImageOutset: {
   2174         RefPtr<CSSPrimitiveValue> result;
   2175         if (parseBorderImageOutset(result)) {
   2176             addProperty(propId, result, important);
   2177             return true;
   2178         }
   2179         break;
   2180     }
   2181     case CSSPropertyBorderImageRepeat:
   2182     case CSSPropertyWebkitMaskBoxImageRepeat: {
   2183         RefPtr<CSSValue> result;
   2184         if (parseBorderImageRepeat(result)) {
   2185             addProperty(propId, result, important);
   2186             return true;
   2187         }
   2188         break;
   2189     }
   2190     case CSSPropertyBorderImageSlice:
   2191     case CSSPropertyWebkitMaskBoxImageSlice: {
   2192         RefPtr<CSSBorderImageSliceValue> result;
   2193         if (parseBorderImageSlice(propId, result)) {
   2194             addProperty(propId, result, important);
   2195             return true;
   2196         }
   2197         break;
   2198     }
   2199     case CSSPropertyBorderImageWidth:
   2200     case CSSPropertyWebkitMaskBoxImageWidth: {
   2201         RefPtr<CSSPrimitiveValue> result;
   2202         if (parseBorderImageWidth(result)) {
   2203             addProperty(propId, result, important);
   2204             return true;
   2205         }
   2206         break;
   2207     }
   2208     case CSSPropertyBorderTopRightRadius:
   2209     case CSSPropertyBorderTopLeftRadius:
   2210     case CSSPropertyBorderBottomLeftRadius:
   2211     case CSSPropertyBorderBottomRightRadius: {
   2212         if (num != 1 && num != 2)
   2213             return false;
   2214         validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
   2215         if (!validPrimitive)
   2216             return false;
   2217         RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
   2218         RefPtr<CSSPrimitiveValue> parsedValue2;
   2219         if (num == 2) {
   2220             value = m_valueList->next();
   2221             validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
   2222             if (!validPrimitive)
   2223                 return false;
   2224             parsedValue2 = createPrimitiveNumericValue(value);
   2225         } else
   2226             parsedValue2 = parsedValue1;
   2227 
   2228         addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
   2229         return true;
   2230     }
   2231     case CSSPropertyTabSize:
   2232         validPrimitive = validUnit(value, FInteger | FNonNeg);
   2233         break;
   2234     case CSSPropertyWebkitAspectRatio:
   2235         return parseAspectRatio(important);
   2236     case CSSPropertyBorderRadius:
   2237     case CSSPropertyWebkitBorderRadius:
   2238         return parseBorderRadius(propId, important);
   2239     case CSSPropertyOutlineOffset:
   2240         validPrimitive = validUnit(value, FLength | FPercent);
   2241         break;
   2242     case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
   2243     case CSSPropertyBoxShadow:
   2244     case CSSPropertyWebkitBoxShadow:
   2245         if (id == CSSValueNone)
   2246             validPrimitive = true;
   2247         else {
   2248             RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
   2249             if (shadowValueList) {
   2250                 addProperty(propId, shadowValueList.release(), important);
   2251                 m_valueList->next();
   2252                 return true;
   2253             }
   2254             return false;
   2255         }
   2256         break;
   2257     case CSSPropertyWebkitBoxReflect:
   2258         if (id == CSSValueNone)
   2259             validPrimitive = true;
   2260         else
   2261             return parseReflect(propId, important);
   2262         break;
   2263     case CSSPropertyOpacity:
   2264         validPrimitive = validUnit(value, FNumber);
   2265         break;
   2266     case CSSPropertyWebkitBoxFlex:
   2267         validPrimitive = validUnit(value, FNumber);
   2268         break;
   2269     case CSSPropertyWebkitBoxFlexGroup:
   2270         validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode);
   2271         break;
   2272     case CSSPropertyWebkitBoxOrdinalGroup:
   2273         validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode) && value->fValue;
   2274         break;
   2275     case CSSPropertyWebkitFilter:
   2276         if (id == CSSValueNone)
   2277             validPrimitive = true;
   2278         else {
   2279             RefPtr<CSSValue> val = parseFilter();
   2280             if (val) {
   2281                 addProperty(propId, val, important);
   2282                 return true;
   2283             }
   2284             return false;
   2285         }
   2286         break;
   2287     case CSSPropertyMixBlendMode:
   2288         if (!RuntimeEnabledFeatures::cssCompositingEnabled())
   2289             return false;
   2290 
   2291         validPrimitive = true;
   2292         break;
   2293     case CSSPropertyFlex: {
   2294         ShorthandScope scope(this, propId);
   2295         if (id == CSSValueNone) {
   2296             addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
   2297             addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
   2298             addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
   2299             return true;
   2300         }
   2301         return parseFlex(m_valueList.get(), important);
   2302     }
   2303     case CSSPropertyFlexBasis:
   2304         // FIXME: Support intrinsic dimensions too.
   2305         if (id == CSSValueAuto)
   2306             validPrimitive = true;
   2307         else
   2308             validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
   2309         break;
   2310     case CSSPropertyFlexGrow:
   2311     case CSSPropertyFlexShrink:
   2312         validPrimitive = validUnit(value, FNumber | FNonNeg);
   2313         break;
   2314     case CSSPropertyOrder:
   2315         if (validUnit(value, FInteger, CSSStrictMode)) {
   2316             if (value->unit != CSSPrimitiveValue::CSS_VARIABLE_NAME) {
   2317                 // We restrict the smallest value to int min + 2 because we use int min and int min + 1 as special values in a hash set.
   2318                 parsedValue = cssValuePool().createValue(max(static_cast<double>(std::numeric_limits<int>::min() + 2), value->fValue),
   2319                     static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
   2320                 m_valueList->next();
   2321             } else {
   2322                 validPrimitive = true;
   2323             }
   2324         }
   2325         break;
   2326     case CSSPropertyWebkitMarquee:
   2327         return parseShorthand(propId, webkitMarqueeShorthand(), important);
   2328     case CSSPropertyWebkitMarqueeIncrement:
   2329         if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
   2330             validPrimitive = true;
   2331         else
   2332             validPrimitive = validUnit(value, FLength | FPercent);
   2333         break;
   2334     case CSSPropertyWebkitMarqueeRepetition:
   2335         if (id == CSSValueInfinite)
   2336             validPrimitive = true;
   2337         else
   2338             validPrimitive = validUnit(value, FInteger | FNonNeg);
   2339         break;
   2340     case CSSPropertyWebkitMarqueeSpeed:
   2341         if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
   2342             validPrimitive = true;
   2343         else
   2344             validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
   2345         break;
   2346     case CSSPropertyWebkitFlowInto:
   2347         if (!RuntimeEnabledFeatures::cssRegionsEnabled())
   2348             return false;
   2349         return parseFlowThread(propId, important);
   2350     case CSSPropertyWebkitFlowFrom:
   2351         if (!RuntimeEnabledFeatures::cssRegionsEnabled())
   2352             return false;
   2353         return parseRegionThread(propId, important);
   2354     case CSSPropertyWebkitTransform:
   2355         if (id == CSSValueNone)
   2356             validPrimitive = true;
   2357         else {
   2358             RefPtr<CSSValue> transformValue = parseTransform();
   2359             if (transformValue) {
   2360                 addProperty(propId, transformValue.release(), important);
   2361                 return true;
   2362             }
   2363             return false;
   2364         }
   2365         break;
   2366     case CSSPropertyWebkitTransformOrigin:
   2367     case CSSPropertyWebkitTransformOriginX:
   2368     case CSSPropertyWebkitTransformOriginY:
   2369     case CSSPropertyWebkitTransformOriginZ: {
   2370         RefPtr<CSSValue> val1;
   2371         RefPtr<CSSValue> val2;
   2372         RefPtr<CSSValue> val3;
   2373         CSSPropertyID propId1, propId2, propId3;
   2374         if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
   2375             addProperty(propId1, val1.release(), important);
   2376             if (val2)
   2377                 addProperty(propId2, val2.release(), important);
   2378             if (val3)
   2379                 addProperty(propId3, val3.release(), important);
   2380             return true;
   2381         }
   2382         return false;
   2383     }
   2384     case CSSPropertyWebkitPerspective:
   2385         if (id == CSSValueNone)
   2386             validPrimitive = true;
   2387         else {
   2388             // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
   2389             if (validUnit(value, FNumber | FLength | FNonNeg)) {
   2390                 RefPtr<CSSValue> val = createPrimitiveNumericValue(value);
   2391                 if (val) {
   2392                     addProperty(propId, val.release(), important);
   2393                     return true;
   2394                 }
   2395                 return false;
   2396             }
   2397         }
   2398         break;
   2399     case CSSPropertyWebkitPerspectiveOrigin:
   2400     case CSSPropertyWebkitPerspectiveOriginX:
   2401     case CSSPropertyWebkitPerspectiveOriginY: {
   2402         RefPtr<CSSValue> val1;
   2403         RefPtr<CSSValue> val2;
   2404         CSSPropertyID propId1, propId2;
   2405         if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
   2406             addProperty(propId1, val1.release(), important);
   2407             if (val2)
   2408                 addProperty(propId2, val2.release(), important);
   2409             return true;
   2410         }
   2411         return false;
   2412     }
   2413     case CSSPropertyWebkitAnimationDelay:
   2414     case CSSPropertyWebkitAnimationDirection:
   2415     case CSSPropertyWebkitAnimationDuration:
   2416     case CSSPropertyWebkitAnimationFillMode:
   2417     case CSSPropertyWebkitAnimationName:
   2418     case CSSPropertyWebkitAnimationPlayState:
   2419     case CSSPropertyWebkitAnimationIterationCount:
   2420     case CSSPropertyWebkitAnimationTimingFunction:
   2421     case CSSPropertyTransitionDelay:
   2422     case CSSPropertyTransitionDuration:
   2423     case CSSPropertyTransitionTimingFunction:
   2424     case CSSPropertyTransitionProperty:
   2425     case CSSPropertyWebkitTransitionDelay:
   2426     case CSSPropertyWebkitTransitionDuration:
   2427     case CSSPropertyWebkitTransitionTimingFunction:
   2428     case CSSPropertyWebkitTransitionProperty: {
   2429         RefPtr<CSSValue> val;
   2430         AnimationParseContext context;
   2431         if (parseAnimationProperty(propId, val, context)) {
   2432             addPropertyWithPrefixingVariant(propId, val.release(), important);
   2433             return true;
   2434         }
   2435         return false;
   2436     }
   2437 
   2438     case CSSPropertyGridAutoColumns:
   2439     case CSSPropertyGridAutoRows:
   2440         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   2441             return false;
   2442         parsedValue = parseGridTrackSize(*m_valueList);
   2443         break;
   2444 
   2445     case CSSPropertyGridDefinitionColumns:
   2446     case CSSPropertyGridDefinitionRows:
   2447         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   2448             return false;
   2449         return parseGridTrackList(propId, important);
   2450 
   2451     case CSSPropertyGridColumnEnd:
   2452     case CSSPropertyGridColumnStart:
   2453     case CSSPropertyGridRowEnd:
   2454     case CSSPropertyGridRowStart:
   2455         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   2456             return false;
   2457         parsedValue = parseGridPosition();
   2458         break;
   2459 
   2460     case CSSPropertyGridColumn:
   2461     case CSSPropertyGridRow:
   2462         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   2463             return false;
   2464         return parseGridItemPositionShorthand(propId, important);
   2465 
   2466     case CSSPropertyGridArea:
   2467         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   2468             return false;
   2469         return parseGridAreaShorthand(important);
   2470 
   2471     case CSSPropertyGridTemplate:
   2472         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   2473             return false;
   2474         parsedValue = parseGridTemplate();
   2475         break;
   2476 
   2477     case CSSPropertyWebkitMarginCollapse: {
   2478         if (num == 1) {
   2479             ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
   2480             if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
   2481                 return false;
   2482             CSSValue* value = m_parsedProperties.last().value();
   2483             addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
   2484             return true;
   2485         }
   2486         else if (num == 2) {
   2487             ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
   2488             if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
   2489                 return false;
   2490             return true;
   2491         }
   2492         return false;
   2493     }
   2494     case CSSPropertyTextLineThroughWidth:
   2495     case CSSPropertyTextOverlineWidth:
   2496     case CSSPropertyTextUnderlineWidth:
   2497         if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
   2498             id == CSSValueMedium || id == CSSValueThick)
   2499             validPrimitive = true;
   2500         else
   2501             validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
   2502         break;
   2503     case CSSPropertyWebkitColumnCount:
   2504         parsedValue = parseColumnCount();
   2505         break;
   2506     case CSSPropertyWebkitColumnGap:         // normal | <length>
   2507         if (id == CSSValueNormal)
   2508             validPrimitive = true;
   2509         else
   2510             validPrimitive = validUnit(value, FLength | FNonNeg);
   2511         break;
   2512     case CSSPropertyWebkitColumnAxis:
   2513         if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
   2514             validPrimitive = true;
   2515         break;
   2516     case CSSPropertyWebkitColumnProgression:
   2517         if (id == CSSValueNormal || id == CSSValueReverse)
   2518             validPrimitive = true;
   2519         break;
   2520     case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
   2521         if (id == CSSValueAll || id == CSSValueNone)
   2522             validPrimitive = true;
   2523         else
   2524             validPrimitive = validUnit(value, FNumber | FNonNeg) && value->fValue == 1;
   2525         break;
   2526     case CSSPropertyWebkitColumnWidth:         // auto | <length>
   2527         parsedValue = parseColumnWidth();
   2528         break;
   2529     // End of CSS3 properties
   2530 
   2531     // Apple specific properties.  These will never be standardized and are purely to
   2532     // support custom WebKit-based Apple applications.
   2533     case CSSPropertyWebkitLineClamp:
   2534         // When specifying number of lines, don't allow 0 as a valid value
   2535         // When specifying either type of unit, require non-negative integers
   2536         validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, CSSQuirksMode));
   2537         break;
   2538 
   2539     case CSSPropertyWebkitFontSizeDelta:           // <length>
   2540         validPrimitive = validUnit(value, FLength);
   2541         break;
   2542 
   2543     case CSSPropertyWebkitHighlight:
   2544         if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
   2545             validPrimitive = true;
   2546         break;
   2547 
   2548     case CSSPropertyWebkitHyphenateCharacter:
   2549         if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
   2550             validPrimitive = true;
   2551         break;
   2552 
   2553     case CSSPropertyWebkitLineGrid:
   2554         if (id == CSSValueNone)
   2555             validPrimitive = true;
   2556         else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
   2557             String lineGridValue = String(value->string);
   2558             if (!lineGridValue.isEmpty()) {
   2559                 addProperty(propId, cssValuePool().createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important);
   2560                 return true;
   2561             }
   2562         }
   2563         break;
   2564     case CSSPropertyWebkitLocale:
   2565         if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
   2566             validPrimitive = true;
   2567         break;
   2568 
   2569     // End Apple-specific properties
   2570 
   2571     case CSSPropertyWebkitAppRegion:
   2572         if (id >= CSSValueDrag && id <= CSSValueNoDrag)
   2573             validPrimitive = true;
   2574         break;
   2575 
   2576     case CSSPropertyWebkitTapHighlightColor:
   2577         if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
   2578             || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
   2579             validPrimitive = true;
   2580         } else {
   2581             parsedValue = parseColor();
   2582             if (parsedValue)
   2583                 m_valueList->next();
   2584         }
   2585         break;
   2586 
   2587         /* shorthand properties */
   2588     case CSSPropertyBackground: {
   2589         // Position must come before color in this array because a plain old "0" is a legal color
   2590         // in quirks mode but it's usually the X coordinate of a position.
   2591         const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
   2592                                    CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
   2593                                    CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
   2594         return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
   2595     }
   2596     case CSSPropertyWebkitMask: {
   2597         const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
   2598             CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
   2599         return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
   2600     }
   2601     case CSSPropertyBorder:
   2602         // [ 'border-width' || 'border-style' || <color> ] | inherit
   2603     {
   2604         if (parseShorthand(propId, borderShorthandForParsing(), important)) {
   2605             // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
   2606             // though a value of none was specified for the image.
   2607             addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
   2608             return true;
   2609         }
   2610         return false;
   2611     }
   2612     case CSSPropertyBorderTop:
   2613         // [ 'border-top-width' || 'border-style' || <color> ] | inherit
   2614         return parseShorthand(propId, borderTopShorthand(), important);
   2615     case CSSPropertyBorderRight:
   2616         // [ 'border-right-width' || 'border-style' || <color> ] | inherit
   2617         return parseShorthand(propId, borderRightShorthand(), important);
   2618     case CSSPropertyBorderBottom:
   2619         // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
   2620         return parseShorthand(propId, borderBottomShorthand(), important);
   2621     case CSSPropertyBorderLeft:
   2622         // [ 'border-left-width' || 'border-style' || <color> ] | inherit
   2623         return parseShorthand(propId, borderLeftShorthand(), important);
   2624     case CSSPropertyWebkitBorderStart:
   2625         return parseShorthand(propId, webkitBorderStartShorthand(), important);
   2626     case CSSPropertyWebkitBorderEnd:
   2627         return parseShorthand(propId, webkitBorderEndShorthand(), important);
   2628     case CSSPropertyWebkitBorderBefore:
   2629         return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
   2630     case CSSPropertyWebkitBorderAfter:
   2631         return parseShorthand(propId, webkitBorderAfterShorthand(), important);
   2632     case CSSPropertyOutline:
   2633         // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
   2634         return parseShorthand(propId, outlineShorthand(), important);
   2635     case CSSPropertyBorderColor:
   2636         // <color>{1,4} | inherit
   2637         return parse4Values(propId, borderColorShorthand().properties(), important);
   2638     case CSSPropertyBorderWidth:
   2639         // <border-width>{1,4} | inherit
   2640         return parse4Values(propId, borderWidthShorthand().properties(), important);
   2641     case CSSPropertyBorderStyle:
   2642         // <border-style>{1,4} | inherit
   2643         return parse4Values(propId, borderStyleShorthand().properties(), important);
   2644     case CSSPropertyMargin:
   2645         // <margin-width>{1,4} | inherit
   2646         return parse4Values(propId, marginShorthand().properties(), important);
   2647     case CSSPropertyPadding:
   2648         // <padding-width>{1,4} | inherit
   2649         return parse4Values(propId, paddingShorthand().properties(), important);
   2650     case CSSPropertyFlexFlow:
   2651         return parseShorthand(propId, flexFlowShorthand(), important);
   2652     case CSSPropertyFont:
   2653         // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
   2654         // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
   2655         if (id >= CSSValueCaption && id <= CSSValueStatusBar)
   2656             validPrimitive = true;
   2657         else
   2658             return parseFont(important);
   2659         break;
   2660     case CSSPropertyListStyle:
   2661         return parseShorthand(propId, listStyleShorthand(), important);
   2662     case CSSPropertyWebkitColumns:
   2663         return parseColumnsShorthand(important);
   2664     case CSSPropertyWebkitColumnRule:
   2665         return parseShorthand(propId, webkitColumnRuleShorthand(), important);
   2666     case CSSPropertyWebkitTextStroke:
   2667         return parseShorthand(propId, webkitTextStrokeShorthand(), important);
   2668     case CSSPropertyWebkitAnimation:
   2669         return parseAnimationShorthand(important);
   2670     case CSSPropertyTransition:
   2671     case CSSPropertyWebkitTransition:
   2672         return parseTransitionShorthand(propId, important);
   2673     case CSSPropertyInvalid:
   2674         return false;
   2675     case CSSPropertyPage:
   2676         return parsePage(propId, important);
   2677     case CSSPropertyFontStretch:
   2678         return false;
   2679     // CSS Text Layout Module Level 3: Vertical writing support
   2680     case CSSPropertyWebkitTextEmphasis:
   2681         return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
   2682 
   2683     case CSSPropertyWebkitTextEmphasisStyle:
   2684         return parseTextEmphasisStyle(important);
   2685 
   2686     case CSSPropertyWebkitTextOrientation:
   2687         // FIXME: For now just support sideways, sideways-right, upright and vertical-right.
   2688         if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright)
   2689             validPrimitive = true;
   2690         break;
   2691 
   2692     case CSSPropertyWebkitLineBoxContain:
   2693         if (id == CSSValueNone)
   2694             validPrimitive = true;
   2695         else
   2696             return parseLineBoxContain(important);
   2697         break;
   2698     case CSSPropertyWebkitFontFeatureSettings:
   2699         if (id == CSSValueNormal)
   2700             validPrimitive = true;
   2701         else
   2702             return parseFontFeatureSettings(important);
   2703         break;
   2704 
   2705     case CSSPropertyWebkitFontVariantLigatures:
   2706         if (id == CSSValueNormal)
   2707             validPrimitive = true;
   2708         else
   2709             return parseFontVariantLigatures(important);
   2710         break;
   2711     case CSSPropertyWebkitClipPath:
   2712         if (id == CSSValueNone) {
   2713             validPrimitive = true;
   2714         } else if (value->unit == CSSParserValue::Function) {
   2715             return parseBasicShape(propId, important);
   2716         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
   2717             parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
   2718             addProperty(propId, parsedValue.release(), important);
   2719             return true;
   2720         }
   2721         break;
   2722     case CSSPropertyWebkitShapeInside:
   2723     case CSSPropertyWebkitShapeOutside:
   2724         if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
   2725             return false;
   2726         if (id == CSSValueAuto)
   2727             validPrimitive = true;
   2728         else if (propId == CSSPropertyWebkitShapeInside && id == CSSValueOutsideShape)
   2729             validPrimitive = true;
   2730         else if (value->unit == CSSParserValue::Function)
   2731             return parseBasicShape(propId, important);
   2732         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
   2733             parsedValue = CSSImageValue::create(completeURL(value->string));
   2734             m_valueList->next();
   2735         }
   2736         break;
   2737     case CSSPropertyWebkitShapeMargin:
   2738     case CSSPropertyWebkitShapePadding:
   2739         validPrimitive = (RuntimeEnabledFeatures::cssExclusionsEnabled() && !id && validUnit(value, FLength | FNonNeg));
   2740         break;
   2741     case CSSPropertyBorderBottomStyle:
   2742     case CSSPropertyBorderCollapse:
   2743     case CSSPropertyBorderLeftStyle:
   2744     case CSSPropertyBorderRightStyle:
   2745     case CSSPropertyBorderTopStyle:
   2746     case CSSPropertyBoxSizing:
   2747     case CSSPropertyCaptionSide:
   2748     case CSSPropertyClear:
   2749     case CSSPropertyDirection:
   2750     case CSSPropertyDisplay:
   2751     case CSSPropertyEmptyCells:
   2752     case CSSPropertyFloat:
   2753     case CSSPropertyFontStyle:
   2754     case CSSPropertyImageRendering:
   2755     case CSSPropertyListStylePosition:
   2756     case CSSPropertyListStyleType:
   2757     case CSSPropertyOutlineStyle:
   2758     case CSSPropertyOverflowWrap:
   2759     case CSSPropertyOverflowX:
   2760     case CSSPropertyOverflowY:
   2761     case CSSPropertyPageBreakAfter:
   2762     case CSSPropertyPageBreakBefore:
   2763     case CSSPropertyPageBreakInside:
   2764     case CSSPropertyPointerEvents:
   2765     case CSSPropertyPosition:
   2766     case CSSPropertyResize:
   2767     case CSSPropertySpeak:
   2768     case CSSPropertyTableLayout:
   2769     case CSSPropertyTextAlignLast:
   2770     case CSSPropertyTextLineThroughMode:
   2771     case CSSPropertyTextLineThroughStyle:
   2772     case CSSPropertyTextOverflow:
   2773     case CSSPropertyTextOverlineMode:
   2774     case CSSPropertyTextOverlineStyle:
   2775     case CSSPropertyTextRendering:
   2776     case CSSPropertyTextTransform:
   2777     case CSSPropertyTextUnderlineMode:
   2778     case CSSPropertyTextUnderlineStyle:
   2779     case CSSPropertyTouchAction:
   2780     case CSSPropertyVariable:
   2781     case CSSPropertyVisibility:
   2782     case CSSPropertyWebkitAppearance:
   2783     case CSSPropertyWebkitBackfaceVisibility:
   2784     case CSSPropertyWebkitBorderAfterStyle:
   2785     case CSSPropertyWebkitBorderBeforeStyle:
   2786     case CSSPropertyWebkitBorderEndStyle:
   2787     case CSSPropertyWebkitBorderFit:
   2788     case CSSPropertyWebkitBorderStartStyle:
   2789     case CSSPropertyWebkitBoxAlign:
   2790     case CSSPropertyWebkitBoxDecorationBreak:
   2791     case CSSPropertyWebkitBoxDirection:
   2792     case CSSPropertyWebkitBoxLines:
   2793     case CSSPropertyWebkitBoxOrient:
   2794     case CSSPropertyWebkitBoxPack:
   2795     case CSSPropertyWebkitColumnBreakAfter:
   2796     case CSSPropertyWebkitColumnBreakBefore:
   2797     case CSSPropertyWebkitColumnBreakInside:
   2798     case CSSPropertyWebkitColumnRuleStyle:
   2799     case CSSPropertyAlignContent:
   2800     case CSSPropertyAlignItems:
   2801     case CSSPropertyAlignSelf:
   2802     case CSSPropertyFlexDirection:
   2803     case CSSPropertyFlexWrap:
   2804     case CSSPropertyJustifyContent:
   2805     case CSSPropertyWebkitFontKerning:
   2806     case CSSPropertyWebkitFontSmoothing:
   2807     case CSSPropertyGridAutoFlow:
   2808     case CSSPropertyWebkitLineAlign:
   2809     case CSSPropertyWebkitLineBreak:
   2810     case CSSPropertyWebkitLineSnap:
   2811     case CSSPropertyWebkitMarginAfterCollapse:
   2812     case CSSPropertyWebkitMarginBeforeCollapse:
   2813     case CSSPropertyWebkitMarginBottomCollapse:
   2814     case CSSPropertyWebkitMarginTopCollapse:
   2815     case CSSPropertyWebkitMarqueeDirection:
   2816     case CSSPropertyWebkitMarqueeStyle:
   2817     case CSSPropertyWebkitPrintColorAdjust:
   2818     case CSSPropertyWebkitRegionBreakAfter:
   2819     case CSSPropertyWebkitRegionBreakBefore:
   2820     case CSSPropertyWebkitRegionBreakInside:
   2821     case CSSPropertyWebkitRegionFragment:
   2822     case CSSPropertyWebkitRtlOrdering:
   2823     case CSSPropertyWebkitRubyPosition:
   2824     case CSSPropertyWebkitTextCombine:
   2825     case CSSPropertyWebkitTextEmphasisPosition:
   2826     case CSSPropertyWebkitTextSecurity:
   2827     case CSSPropertyWebkitTransformStyle:
   2828     case CSSPropertyWebkitUserDrag:
   2829     case CSSPropertyWebkitUserModify:
   2830     case CSSPropertyWebkitUserSelect:
   2831     case CSSPropertyWebkitWrapFlow:
   2832     case CSSPropertyWebkitWrapThrough:
   2833     case CSSPropertyWebkitWritingMode:
   2834     case CSSPropertyWhiteSpace:
   2835     case CSSPropertyWordBreak:
   2836     case CSSPropertyWordWrap:
   2837         // These properties should be handled before in isValidKeywordPropertyAndValue().
   2838         ASSERT_NOT_REACHED();
   2839         return false;
   2840     // Properties bellow are validated inside parseViewportProperty, because we
   2841     // check for parser state inViewportScope. We need to invalidate if someone
   2842     // adds them outside a @viewport rule.
   2843     case CSSPropertyMaxZoom:
   2844     case CSSPropertyMinZoom:
   2845     case CSSPropertyOrientation:
   2846     case CSSPropertyUserZoom:
   2847         validPrimitive = false;
   2848         break;
   2849     default:
   2850         return parseSVGValue(propId, important);
   2851     }
   2852 
   2853     if (validPrimitive) {
   2854         parsedValue = parseValidPrimitive(id, value);
   2855         m_valueList->next();
   2856     }
   2857     ASSERT(!m_parsedCalculation);
   2858     if (parsedValue) {
   2859         if (!m_valueList->current() || inShorthand()) {
   2860             addProperty(propId, parsedValue.release(), important);
   2861             return true;
   2862         }
   2863     }
   2864     return false;
   2865 }
   2866 
   2867 void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
   2868 {
   2869     if (lval) {
   2870         if (lval->isBaseValueList())
   2871             toCSSValueList(lval.get())->append(rval);
   2872         else {
   2873             PassRefPtr<CSSValue> oldlVal(lval.release());
   2874             PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   2875             list->append(oldlVal);
   2876             list->append(rval);
   2877             lval = list;
   2878         }
   2879     }
   2880     else
   2881         lval = rval;
   2882 }
   2883 
   2884 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
   2885 {
   2886     if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
   2887         || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
   2888         cssValue = cssValuePool().createIdentifierValue(parserValue->id);
   2889         return true;
   2890     }
   2891     return false;
   2892 }
   2893 
   2894 bool CSSParser::useLegacyBackgroundSizeShorthandBehavior() const
   2895 {
   2896     return m_context.useLegacyBackgroundSizeShorthandBehavior;
   2897 }
   2898 
   2899 const int cMaxFillProperties = 9;
   2900 
   2901 bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
   2902 {
   2903     ASSERT(numProperties <= cMaxFillProperties);
   2904     if (numProperties > cMaxFillProperties)
   2905         return false;
   2906 
   2907     ShorthandScope scope(this, propId);
   2908 
   2909     bool parsedProperty[cMaxFillProperties] = { false };
   2910     RefPtr<CSSValue> values[cMaxFillProperties];
   2911     RefPtr<CSSValue> clipValue;
   2912     RefPtr<CSSValue> positionYValue;
   2913     RefPtr<CSSValue> repeatYValue;
   2914     bool foundClip = false;
   2915     int i;
   2916     bool foundPositionCSSProperty = false;
   2917 
   2918     while (m_valueList->current()) {
   2919         CSSParserValue* val = m_valueList->current();
   2920         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   2921             // We hit the end.  Fill in all remaining values with the initial value.
   2922             m_valueList->next();
   2923             for (i = 0; i < numProperties; ++i) {
   2924                 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
   2925                     // Color is not allowed except as the last item in a list for backgrounds.
   2926                     // Reject the entire property.
   2927                     return false;
   2928 
   2929                 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
   2930                     addFillValue(values[i], cssValuePool().createImplicitInitialValue());
   2931                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   2932                         addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
   2933                     if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
   2934                         addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
   2935                     if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
   2936                         // If background-origin wasn't present, then reset background-clip also.
   2937                         addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
   2938                     }
   2939                 }
   2940                 parsedProperty[i] = false;
   2941             }
   2942             if (!m_valueList->current())
   2943                 break;
   2944         }
   2945 
   2946         bool sizeCSSPropertyExpected = false;
   2947         if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
   2948             sizeCSSPropertyExpected = true;
   2949             m_valueList->next();
   2950         }
   2951 
   2952         foundPositionCSSProperty = false;
   2953         bool found = false;
   2954         for (i = 0; !found && i < numProperties; ++i) {
   2955 
   2956             if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
   2957                 continue;
   2958             if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
   2959                 continue;
   2960 
   2961             if (!parsedProperty[i]) {
   2962                 RefPtr<CSSValue> val1;
   2963                 RefPtr<CSSValue> val2;
   2964                 CSSPropertyID propId1, propId2;
   2965                 CSSParserValue* parserValue = m_valueList->current();
   2966                 // parseFillProperty() may modify m_implicitShorthand, so we MUST reset it
   2967                 // before EACH return below.
   2968                 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
   2969                     parsedProperty[i] = found = true;
   2970                     addFillValue(values[i], val1.release());
   2971                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   2972                         addFillValue(positionYValue, val2.release());
   2973                     if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
   2974                         addFillValue(repeatYValue, val2.release());
   2975                     if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
   2976                         // Reparse the value as a clip, and see if we succeed.
   2977                         if (parseBackgroundClip(parserValue, val1))
   2978                             addFillValue(clipValue, val1.release()); // The property parsed successfully.
   2979                         else
   2980                             addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
   2981                     }
   2982                     if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
   2983                         // Update clipValue
   2984                         addFillValue(clipValue, val1.release());
   2985                         foundClip = true;
   2986                     }
   2987                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   2988                         foundPositionCSSProperty = true;
   2989                 }
   2990             }
   2991         }
   2992 
   2993         // if we didn't find at least one match, this is an
   2994         // invalid shorthand and we have to ignore it
   2995         if (!found) {
   2996             m_implicitShorthand = false;
   2997             return false;
   2998         }
   2999     }
   3000 
   3001     // Now add all of the properties we found.
   3002     for (i = 0; i < numProperties; i++) {
   3003         // Fill in any remaining properties with the initial value.
   3004         if (!parsedProperty[i]) {
   3005             addFillValue(values[i], cssValuePool().createImplicitInitialValue());
   3006             if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   3007                 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
   3008             if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
   3009                 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
   3010             if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
   3011                 // If background-origin wasn't present, then reset background-clip also.
   3012                 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
   3013             }
   3014         }
   3015         if (properties[i] == CSSPropertyBackgroundPosition) {
   3016             addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
   3017             // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
   3018             addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
   3019         } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
   3020             addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
   3021             // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
   3022             addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
   3023         } else if (properties[i] == CSSPropertyBackgroundRepeat) {
   3024             addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
   3025             // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
   3026             addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
   3027         } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
   3028             addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
   3029             // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
   3030             addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
   3031         } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
   3032             // Value is already set while updating origin
   3033             continue;
   3034         else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && useLegacyBackgroundSizeShorthandBehavior())
   3035             continue;
   3036         else
   3037             addProperty(properties[i], values[i].release(), important);
   3038 
   3039         // Add in clip values when we hit the corresponding origin property.
   3040         if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
   3041             addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
   3042         else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
   3043             addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
   3044     }
   3045 
   3046     m_implicitShorthand = false;
   3047     return true;
   3048 }
   3049 
   3050 void CSSParser::storeVariableDeclaration(const CSSParserString& name, PassOwnPtr<CSSParserValueList> value, bool important)
   3051 {
   3052     // When CSSGrammar.y encounters an invalid declaration it passes null for the CSSParserValueList, just bail.
   3053     if (!value)
   3054         return;
   3055 
   3056     static const unsigned prefixLength = sizeof("var-") - 1;
   3057 
   3058     ASSERT(name.length() > prefixLength);
   3059     AtomicString variableName = name.atomicSubstring(prefixLength, name.length() - prefixLength);
   3060 
   3061     StringBuilder builder;
   3062     for (unsigned i = 0, size = value->size(); i < size; i++) {
   3063         if (i)
   3064             builder.append(' ');
   3065         RefPtr<CSSValue> cssValue = value->valueAt(i)->createCSSValue();
   3066         if (!cssValue)
   3067             return;
   3068         builder.append(cssValue->cssText());
   3069     }
   3070 
   3071     addProperty(CSSPropertyVariable, CSSVariableValue::create(variableName, builder.toString()), important, false);
   3072 }
   3073 
   3074 void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
   3075 {
   3076     if (lval) {
   3077         if (lval->isValueList())
   3078             toCSSValueList(lval.get())->append(rval);
   3079         else {
   3080             PassRefPtr<CSSValue> oldVal(lval.release());
   3081             PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   3082             list->append(oldVal);
   3083             list->append(rval);
   3084             lval = list;
   3085         }
   3086     }
   3087     else
   3088         lval = rval;
   3089 }
   3090 
   3091 bool CSSParser::parseAnimationShorthand(bool important)
   3092 {
   3093     const StylePropertyShorthand& animationProperties = webkitAnimationShorthandForParsing();
   3094     const unsigned numProperties = 7;
   3095 
   3096     // The list of properties in the shorthand should be the same
   3097     // length as the list with animation name in last position, even though they are
   3098     // in a different order.
   3099     ASSERT(numProperties == webkitAnimationShorthandForParsing().length());
   3100     ASSERT(numProperties == webkitAnimationShorthand().length());
   3101 
   3102     ShorthandScope scope(this, CSSPropertyWebkitAnimation);
   3103 
   3104     bool parsedProperty[numProperties] = { false };
   3105     AnimationParseContext context;
   3106     RefPtr<CSSValue> values[numProperties];
   3107 
   3108     unsigned i;
   3109     while (m_valueList->current()) {
   3110         CSSParserValue* val = m_valueList->current();
   3111         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   3112             // We hit the end.  Fill in all remaining values with the initial value.
   3113             m_valueList->next();
   3114             for (i = 0; i < numProperties; ++i) {
   3115                 if (!parsedProperty[i])
   3116                     addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
   3117                 parsedProperty[i] = false;
   3118             }
   3119             if (!m_valueList->current())
   3120                 break;
   3121             context.commitFirstAnimation();
   3122         }
   3123 
   3124         bool found = false;
   3125         for (i = 0; i < numProperties; ++i) {
   3126             if (!parsedProperty[i]) {
   3127                 RefPtr<CSSValue> val;
   3128                 if (parseAnimationProperty(animationProperties.properties()[i], val, context)) {
   3129                     parsedProperty[i] = found = true;
   3130                     addAnimationValue(values[i], val.release());
   3131                     break;
   3132                 }
   3133             }
   3134 
   3135             // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
   3136             if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
   3137                 return false;
   3138         }
   3139 
   3140         // if we didn't find at least one match, this is an
   3141         // invalid shorthand and we have to ignore it
   3142         if (!found)
   3143             return false;
   3144     }
   3145 
   3146     for (i = 0; i < numProperties; ++i) {
   3147         // If we didn't find the property, set an intial value.
   3148         if (!parsedProperty[i])
   3149             addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
   3150 
   3151         addProperty(animationProperties.properties()[i], values[i].release(), important);
   3152     }
   3153 
   3154     return true;
   3155 }
   3156 
   3157 bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
   3158 {
   3159     const unsigned numProperties = 4;
   3160     const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
   3161     ASSERT(numProperties == shorthand.length());
   3162 
   3163     ShorthandScope scope(this, propId);
   3164 
   3165     bool parsedProperty[numProperties] = { false };
   3166     AnimationParseContext context;
   3167     RefPtr<CSSValue> values[numProperties];
   3168 
   3169     unsigned i;
   3170     while (m_valueList->current()) {
   3171         CSSParserValue* val = m_valueList->current();
   3172         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   3173             // We hit the end. Fill in all remaining values with the initial value.
   3174             m_valueList->next();
   3175             for (i = 0; i < numProperties; ++i) {
   3176                 if (!parsedProperty[i])
   3177                     addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
   3178                 parsedProperty[i] = false;
   3179             }
   3180             if (!m_valueList->current())
   3181                 break;
   3182             context.commitFirstAnimation();
   3183         }
   3184 
   3185         bool found = false;
   3186         for (i = 0; !found && i < numProperties; ++i) {
   3187             if (!parsedProperty[i]) {
   3188                 RefPtr<CSSValue> val;
   3189                 if (parseAnimationProperty(shorthand.properties()[i], val, context)) {
   3190                     parsedProperty[i] = found = true;
   3191                     addAnimationValue(values[i], val.release());
   3192                 }
   3193 
   3194                 // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid.
   3195                 if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation())
   3196                     return false;
   3197             }
   3198         }
   3199 
   3200         // if we didn't find at least one match, this is an
   3201         // invalid shorthand and we have to ignore it
   3202         if (!found)
   3203             return false;
   3204     }
   3205 
   3206     // Fill in any remaining properties with the initial value.
   3207     for (i = 0; i < numProperties; ++i) {
   3208         if (!parsedProperty[i])
   3209             addAnimationValue(values[i], cssValuePool().createImplicitInitialValue());
   3210     }
   3211 
   3212     // Now add all of the properties we found.
   3213     for (i = 0; i < numProperties; i++)
   3214         addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
   3215 
   3216     return true;
   3217 }
   3218 
   3219 PassRefPtr<CSSValue> CSSParser::parseColumnWidth()
   3220 {
   3221     CSSParserValue* value = m_valueList->current();
   3222     // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
   3223     // the 'columns' shorthand property.
   3224     if (value->id == CSSValueAuto
   3225         || (validUnit(value, FLength | FNonNeg, CSSStrictMode) && value->fValue)) {
   3226         RefPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
   3227         m_valueList->next();
   3228         return parsedValue;
   3229     }
   3230     return 0;
   3231 }
   3232 
   3233 PassRefPtr<CSSValue> CSSParser::parseColumnCount()
   3234 {
   3235     CSSParserValue* value = m_valueList->current();
   3236     if (value->id == CSSValueAuto
   3237         || (!value->id && validUnit(value, FPositiveInteger, CSSQuirksMode))) {
   3238         RefPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
   3239         m_valueList->next();
   3240         return parsedValue;
   3241     }
   3242     return 0;
   3243 }
   3244 
   3245 bool CSSParser::parseColumnsShorthand(bool important)
   3246 {
   3247     RefPtr <CSSValue> columnWidth;
   3248     RefPtr <CSSValue> columnCount;
   3249     bool hasPendingExplicitAuto = false;
   3250 
   3251     for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->current(); propertiesParsed++) {
   3252         if (propertiesParsed >= 2)
   3253             return false; // Too many values for this shorthand. Invalid declaration.
   3254         if (!propertiesParsed && value->id == CSSValueAuto) {
   3255             // 'auto' is a valid value for any of the two longhands, and at this point we
   3256             // don't know which one(s) it is meant for. We need to see if there are other
   3257             // values first.
   3258             m_valueList->next();
   3259             hasPendingExplicitAuto = true;
   3260         } else {
   3261             if (!columnWidth) {
   3262                 if ((columnWidth = parseColumnWidth()))
   3263                     continue;
   3264             }
   3265             if (!columnCount) {
   3266                 if ((columnCount = parseColumnCount()))
   3267                     continue;
   3268             }
   3269             // If we didn't find at least one match, this is an
   3270             // invalid shorthand and we have to ignore it.
   3271             return false;
   3272         }
   3273     }
   3274     if (hasPendingExplicitAuto) {
   3275         // Time to assign the previously skipped 'auto' value to a property. If both properties are
   3276         // unassigned at this point (i.e. 'columns:auto'), it doesn't matter that much which one we
   3277         // set (although it does make a slight difference to web-inspector). The one we don't set
   3278         // here will get an implicit 'auto' value further down.
   3279         if (!columnWidth) {
   3280             columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
   3281         } else {
   3282             ASSERT(!columnCount);
   3283             columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
   3284         }
   3285     }
   3286     ASSERT(columnCount || columnWidth);
   3287 
   3288     // Any unassigned property at this point will become implicit 'auto'.
   3289     if (columnWidth)
   3290         addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
   3291     else
   3292         addProperty(CSSPropertyWebkitColumnWidth, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
   3293     if (columnCount)
   3294         addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
   3295     else
   3296         addProperty(CSSPropertyWebkitColumnCount, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
   3297     return true;
   3298 }
   3299 
   3300 bool CSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
   3301 {
   3302     // We try to match as many properties as possible
   3303     // We set up an array of booleans to mark which property has been found,
   3304     // and we try to search for properties until it makes no longer any sense.
   3305     ShorthandScope scope(this, propId);
   3306 
   3307     bool found = false;
   3308     unsigned propertiesParsed = 0;
   3309     bool propertyFound[6]= { false, false, false, false, false, false }; // 6 is enough size.
   3310 
   3311     while (m_valueList->current()) {
   3312         found = false;
   3313         for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
   3314             if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
   3315                     propertyFound[propIndex] = found = true;
   3316                     propertiesParsed++;
   3317             }
   3318         }
   3319 
   3320         // if we didn't find at least one match, this is an
   3321         // invalid shorthand and we have to ignore it
   3322         if (!found)
   3323             return false;
   3324     }
   3325 
   3326     if (propertiesParsed == shorthand.length())
   3327         return true;
   3328 
   3329     // Fill in any remaining properties with the initial value.
   3330     ImplicitScope implicitScope(this, PropertyImplicit);
   3331     const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
   3332     for (unsigned i = 0; i < shorthand.length(); ++i) {
   3333         if (propertyFound[i])
   3334             continue;
   3335 
   3336         if (propertiesForInitialization) {
   3337             const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
   3338             for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
   3339                 addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
   3340         } else
   3341             addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
   3342     }
   3343 
   3344     return true;
   3345 }
   3346 
   3347 bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties,  bool important)
   3348 {
   3349     /* From the CSS 2 specs, 8.3
   3350      * If there is only one value, it applies to all sides. If there are two values, the top and
   3351      * bottom margins are set to the first value and the right and left margins are set to the second.
   3352      * If there are three values, the top is set to the first value, the left and right are set to the
   3353      * second, and the bottom is set to the third. If there are four values, they apply to the top,
   3354      * right, bottom, and left, respectively.
   3355      */
   3356 
   3357     int num = inShorthand() ? 1 : m_valueList->size();
   3358 
   3359     ShorthandScope scope(this, propId);
   3360 
   3361     // the order is top, right, bottom, left
   3362     switch (num) {
   3363         case 1: {
   3364             if (!parseValue(properties[0], important))
   3365                 return false;
   3366             CSSValue* value = m_parsedProperties.last().value();
   3367             ImplicitScope implicitScope(this, PropertyImplicit);
   3368             addProperty(properties[1], value, important);
   3369             addProperty(properties[2], value, important);
   3370             addProperty(properties[3], value, important);
   3371             break;
   3372         }
   3373         case 2: {
   3374             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
   3375                 return false;
   3376             CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
   3377             ImplicitScope implicitScope(this, PropertyImplicit);
   3378             addProperty(properties[2], value, important);
   3379             value = m_parsedProperties[m_parsedProperties.size() - 2].value();
   3380             addProperty(properties[3], value, important);
   3381             break;
   3382         }
   3383         case 3: {
   3384             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
   3385                 return false;
   3386             CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
   3387             ImplicitScope implicitScope(this, PropertyImplicit);
   3388             addProperty(properties[3], value, important);
   3389             break;
   3390         }
   3391         case 4: {
   3392             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
   3393                 !parseValue(properties[2], important) || !parseValue(properties[3], important))
   3394                 return false;
   3395             break;
   3396         }
   3397         default: {
   3398             return false;
   3399         }
   3400     }
   3401 
   3402     return true;
   3403 }
   3404 
   3405 // auto | <identifier>
   3406 bool CSSParser::parsePage(CSSPropertyID propId, bool important)
   3407 {
   3408     ASSERT(propId == CSSPropertyPage);
   3409 
   3410     if (m_valueList->size() != 1)
   3411         return false;
   3412 
   3413     CSSParserValue* value = m_valueList->current();
   3414     if (!value)
   3415         return false;
   3416 
   3417     if (value->id == CSSValueAuto) {
   3418         addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
   3419         return true;
   3420     } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
   3421         addProperty(propId, createPrimitiveStringValue(value), important);
   3422         return true;
   3423     }
   3424     return false;
   3425 }
   3426 
   3427 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
   3428 bool CSSParser::parseSize(CSSPropertyID propId, bool important)
   3429 {
   3430     ASSERT(propId == CSSPropertySize);
   3431 
   3432     if (m_valueList->size() > 2)
   3433         return false;
   3434 
   3435     CSSParserValue* value = m_valueList->current();
   3436     if (!value)
   3437         return false;
   3438 
   3439     RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
   3440 
   3441     // First parameter.
   3442     SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
   3443     if (paramType == None)
   3444         return false;
   3445 
   3446     // Second parameter, if any.
   3447     value = m_valueList->next();
   3448     if (value) {
   3449         paramType = parseSizeParameter(parsedValues.get(), value, paramType);
   3450         if (paramType == None)
   3451             return false;
   3452     }
   3453 
   3454     addProperty(propId, parsedValues.release(), important);
   3455     return true;
   3456 }
   3457 
   3458 CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
   3459 {
   3460     switch (value->id) {
   3461     case CSSValueAuto:
   3462         if (prevParamType == None) {
   3463             parsedValues->append(cssValuePool().createIdentifierValue(value->id));
   3464             return Auto;
   3465         }
   3466         return None;
   3467     case CSSValueLandscape:
   3468     case CSSValuePortrait:
   3469         if (prevParamType == None || prevParamType == PageSize) {
   3470             parsedValues->append(cssValuePool().createIdentifierValue(value->id));
   3471             return Orientation;
   3472         }
   3473         return None;
   3474     case CSSValueA3:
   3475     case CSSValueA4:
   3476     case CSSValueA5:
   3477     case CSSValueB4:
   3478     case CSSValueB5:
   3479     case CSSValueLedger:
   3480     case CSSValueLegal:
   3481     case CSSValueLetter:
   3482         if (prevParamType == None || prevParamType == Orientation) {
   3483             // Normalize to Page Size then Orientation order by prepending.
   3484             // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
   3485             parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
   3486             return PageSize;
   3487         }
   3488         return None;
   3489     case 0:
   3490         if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
   3491             parsedValues->append(createPrimitiveNumericValue(value));
   3492             return Length;
   3493         }
   3494         return None;
   3495     default:
   3496         return None;
   3497     }
   3498 }
   3499 
   3500 // [ <string> <string> ]+ | inherit | none
   3501 // inherit and none are handled in parseValue.
   3502 bool CSSParser::parseQuotes(CSSPropertyID propId, bool important)
   3503 {
   3504     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   3505     while (CSSParserValue* val = m_valueList->current()) {
   3506         RefPtr<CSSValue> parsedValue;
   3507         if (val->unit == CSSPrimitiveValue::CSS_STRING)
   3508             parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
   3509         else
   3510             break;
   3511         values->append(parsedValue.release());
   3512         m_valueList->next();
   3513     }
   3514     if (values->length()) {
   3515         addProperty(propId, values.release(), important);
   3516         m_valueList->next();
   3517         return true;
   3518     }
   3519     return false;
   3520 }
   3521 
   3522 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
   3523 // in CSS 2.1 this got somewhat reduced:
   3524 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
   3525 bool CSSParser::parseContent(CSSPropertyID propId, bool important)
   3526 {
   3527     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   3528 
   3529     while (CSSParserValue* val = m_valueList->current()) {
   3530         RefPtr<CSSValue> parsedValue;
   3531         if (val->unit == CSSPrimitiveValue::CSS_URI) {
   3532             // url
   3533             parsedValue = CSSImageValue::create(completeURL(val->string));
   3534         } else if (val->unit == CSSParserValue::Function) {
   3535             // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
   3536             CSSParserValueList* args = val->function->args.get();
   3537             if (!args)
   3538                 return false;
   3539             if (equalIgnoringCase(val->function->name, "attr(")) {
   3540                 parsedValue = parseAttr(args);
   3541                 if (!parsedValue)
   3542                     return false;
   3543             } else if (equalIgnoringCase(val->function->name, "counter(")) {
   3544                 parsedValue = parseCounterContent(args, false);
   3545                 if (!parsedValue)
   3546                     return false;
   3547             } else if (equalIgnoringCase(val->function->name, "counters(")) {
   3548                 parsedValue = parseCounterContent(args, true);
   3549                 if (!parsedValue)
   3550                     return false;
   3551             } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
   3552                 parsedValue = parseImageSet(m_valueList.get());
   3553                 if (!parsedValue)
   3554                     return false;
   3555             } else if (isGeneratedImageValue(val)) {
   3556                 if (!parseGeneratedImage(m_valueList.get(), parsedValue))
   3557                     return false;
   3558             } else
   3559                 return false;
   3560         } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
   3561             // open-quote
   3562             // close-quote
   3563             // no-open-quote
   3564             // no-close-quote
   3565             // inherit
   3566             // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
   3567             // none
   3568             // normal
   3569             switch (val->id) {
   3570             case CSSValueOpenQuote:
   3571             case CSSValueCloseQuote:
   3572             case CSSValueNoOpenQuote:
   3573             case CSSValueNoCloseQuote:
   3574             case CSSValueNone:
   3575             case CSSValueNormal:
   3576                 parsedValue = cssValuePool().createIdentifierValue(val->id);
   3577             default:
   3578                 break;
   3579             }
   3580         } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
   3581             parsedValue = createPrimitiveStringValue(val);
   3582         }
   3583         if (!parsedValue)
   3584             break;
   3585         values->append(parsedValue.release());
   3586         m_valueList->next();
   3587     }
   3588 
   3589     if (values->length()) {
   3590         addProperty(propId, values.release(), important);
   3591         m_valueList->next();
   3592         return true;
   3593     }
   3594 
   3595     return false;
   3596 }
   3597 
   3598 PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
   3599 {
   3600     if (args->size() != 1)
   3601         return 0;
   3602 
   3603     CSSParserValue* a = args->current();
   3604 
   3605     if (a->unit != CSSPrimitiveValue::CSS_IDENT)
   3606         return 0;
   3607 
   3608     String attrName = a->string;
   3609     // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
   3610     // But HTML attribute names can't have those characters, and we should not
   3611     // even parse them inside attr().
   3612     if (attrName[0] == '-')
   3613         return 0;
   3614 
   3615     if (m_context.isHTMLDocument)
   3616         attrName = attrName.lower();
   3617 
   3618     return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
   3619 }
   3620 
   3621 PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
   3622 {
   3623     CSSValueID id = m_valueList->current()->id;
   3624     if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
   3625         (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
   3626         return cssValuePool().createIdentifierValue(id);
   3627     return parseColor();
   3628 }
   3629 
   3630 bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
   3631 {
   3632     if (valueList->current()->id == CSSValueNone) {
   3633         value = cssValuePool().createIdentifierValue(CSSValueNone);
   3634         return true;
   3635     }
   3636     if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
   3637         value = CSSImageValue::create(completeURL(valueList->current()->string));
   3638         return true;
   3639     }
   3640 
   3641     if (isGeneratedImageValue(valueList->current()))
   3642         return parseGeneratedImage(valueList, value);
   3643 
   3644     if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
   3645         value = parseImageSet(m_valueList.get());
   3646         if (value)
   3647             return true;
   3648     }
   3649 
   3650     return false;
   3651 }
   3652 
   3653 PassRefPtr<CSSValue> CSSParser::parseFillPositionX(CSSParserValueList* valueList)
   3654 {
   3655     int id = valueList->current()->id;
   3656     if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
   3657         int percent = 0;
   3658         if (id == CSSValueRight)
   3659             percent = 100;
   3660         else if (id == CSSValueCenter)
   3661             percent = 50;
   3662         return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
   3663     }
   3664     if (validUnit(valueList->current(), FPercent | FLength))
   3665         return createPrimitiveNumericValue(valueList->current());
   3666     return 0;
   3667 }
   3668 
   3669 PassRefPtr<CSSValue> CSSParser::parseFillPositionY(CSSParserValueList* valueList)
   3670 {
   3671     int id = valueList->current()->id;
   3672     if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
   3673         int percent = 0;
   3674         if (id == CSSValueBottom)
   3675             percent = 100;
   3676         else if (id == CSSValueCenter)
   3677             percent = 50;
   3678         return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
   3679     }
   3680     if (validUnit(valueList->current(), FPercent | FLength))
   3681         return createPrimitiveNumericValue(valueList->current());
   3682     return 0;
   3683 }
   3684 
   3685 PassRefPtr<CSSPrimitiveValue> CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
   3686 {
   3687     CSSValueID id = valueList->current()->id;
   3688     if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
   3689         int percent = 0;
   3690         if (id == CSSValueLeft || id == CSSValueRight) {
   3691             if (cumulativeFlags & XFillPosition)
   3692                 return 0;
   3693             cumulativeFlags |= XFillPosition;
   3694             individualFlag = XFillPosition;
   3695             if (id == CSSValueRight)
   3696                 percent = 100;
   3697         }
   3698         else if (id == CSSValueTop || id == CSSValueBottom) {
   3699             if (cumulativeFlags & YFillPosition)
   3700                 return 0;
   3701             cumulativeFlags |= YFillPosition;
   3702             individualFlag = YFillPosition;
   3703             if (id == CSSValueBottom)
   3704                 percent = 100;
   3705         } else if (id == CSSValueCenter) {
   3706             // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
   3707             percent = 50;
   3708             cumulativeFlags |= AmbiguousFillPosition;
   3709             individualFlag = AmbiguousFillPosition;
   3710         }
   3711 
   3712         if (parsingMode == ResolveValuesAsKeyword)
   3713             return cssValuePool().createIdentifierValue(id);
   3714 
   3715         return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
   3716     }
   3717     if (validUnit(valueList->current(), FPercent | FLength)) {
   3718         if (!cumulativeFlags) {
   3719             cumulativeFlags |= XFillPosition;
   3720             individualFlag = XFillPosition;
   3721         } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
   3722             cumulativeFlags |= YFillPosition;
   3723             individualFlag = YFillPosition;
   3724         } else {
   3725             if (m_parsedCalculation)
   3726                 m_parsedCalculation.release();
   3727             return 0;
   3728         }
   3729         return createPrimitiveNumericValue(valueList->current());
   3730     }
   3731     return 0;
   3732 }
   3733 
   3734 static bool isValueConflictingWithCurrentEdge(int value1, int value2)
   3735 {
   3736     if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
   3737         return true;
   3738 
   3739     if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
   3740         return true;
   3741 
   3742     return false;
   3743 }
   3744 
   3745 static bool isFillPositionKeyword(CSSValueID value)
   3746 {
   3747     return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
   3748 }
   3749 
   3750 void CSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
   3751 {
   3752     // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
   3753     // In the case of 4 values <position> requires the second value to be a length or a percentage.
   3754     if (isFillPositionKeyword(parsedValue2->getValueID()))
   3755         return;
   3756 
   3757     unsigned cumulativeFlags = 0;
   3758     FillPositionFlag value3Flag = InvalidFillPosition;
   3759     RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
   3760     if (!value3)
   3761         return;
   3762 
   3763     CSSValueID ident1 = parsedValue1->getValueID();
   3764     CSSValueID ident3 = value3->getValueID();
   3765 
   3766     if (ident1 == CSSValueCenter)
   3767         return;
   3768 
   3769     if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
   3770         return;
   3771 
   3772     // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
   3773     // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
   3774     // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
   3775     if (isValueConflictingWithCurrentEdge(ident1, ident3))
   3776         return;
   3777 
   3778     valueList->next();
   3779 
   3780     cumulativeFlags = 0;
   3781     FillPositionFlag value4Flag = InvalidFillPosition;
   3782     RefPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
   3783     if (!value4)
   3784         return;
   3785 
   3786     // 4th value must be a length or a percentage.
   3787     if (isFillPositionKeyword(value4->getValueID()))
   3788         return;
   3789 
   3790     value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
   3791     value2 = createPrimitiveValuePair(value3, value4);
   3792 
   3793     if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
   3794         value1.swap(value2);
   3795 
   3796     valueList->next();
   3797 }
   3798 void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, PassRefPtr<CSSPrimitiveValue> parsedValue1, PassRefPtr<CSSPrimitiveValue> parsedValue2)
   3799 {
   3800     unsigned cumulativeFlags = 0;
   3801     FillPositionFlag value3Flag = InvalidFillPosition;
   3802     RefPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
   3803 
   3804     // value3 is not an expected value, we return.
   3805     if (!value3)
   3806         return;
   3807 
   3808     valueList->next();
   3809 
   3810     bool swapNeeded = false;
   3811     CSSValueID ident1 = parsedValue1->getValueID();
   3812     CSSValueID ident2 = parsedValue2->getValueID();
   3813     CSSValueID ident3 = value3->getValueID();
   3814 
   3815     CSSValueID firstPositionKeyword;
   3816     CSSValueID secondPositionKeyword;
   3817 
   3818     if (ident1 == CSSValueCenter) {
   3819         // <position> requires the first 'center' to be followed by a keyword.
   3820         if (!isFillPositionKeyword(ident2))
   3821             return;
   3822 
   3823         // If 'center' is the first keyword then the last one needs to be a length.
   3824         if (isFillPositionKeyword(ident3))
   3825             return;
   3826 
   3827         firstPositionKeyword = CSSValueLeft;
   3828         if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
   3829             firstPositionKeyword = CSSValueTop;
   3830             swapNeeded = true;
   3831         }
   3832         value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
   3833         value2 = createPrimitiveValuePair(parsedValue2, value3);
   3834     } else if (ident3 == CSSValueCenter) {
   3835         if (isFillPositionKeyword(ident2))
   3836             return;
   3837 
   3838         secondPositionKeyword = CSSValueTop;
   3839         if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
   3840             secondPositionKeyword = CSSValueLeft;
   3841             swapNeeded = true;
   3842         }
   3843         value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
   3844         value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
   3845     } else {
   3846         RefPtr<CSSPrimitiveValue> firstPositionValue;
   3847         RefPtr<CSSPrimitiveValue> secondPositionValue;
   3848 
   3849         if (isFillPositionKeyword(ident2)) {
   3850             // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
   3851             ASSERT(ident2 != CSSValueCenter);
   3852 
   3853             if (isFillPositionKeyword(ident3))
   3854                 return;
   3855 
   3856             secondPositionValue = value3;
   3857             secondPositionKeyword = ident2;
   3858             firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
   3859         } else {
   3860             // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
   3861             if (!isFillPositionKeyword(ident3))
   3862                 return;
   3863 
   3864             firstPositionValue = parsedValue2;
   3865             secondPositionKeyword = ident3;
   3866             secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
   3867         }
   3868 
   3869         if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
   3870             return;
   3871 
   3872         value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
   3873         value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
   3874     }
   3875 
   3876     if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
   3877         value1.swap(value2);
   3878 
   3879 #ifndef NDEBUG
   3880     CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
   3881     CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
   3882     ident1 = first->getPairValue()->first()->getValueID();
   3883     ident2 = second->getPairValue()->first()->getValueID();
   3884     ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
   3885     ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
   3886 #endif
   3887 }
   3888 
   3889 inline bool CSSParser::isPotentialPositionValue(CSSParserValue* value)
   3890 {
   3891     return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
   3892 }
   3893 
   3894 void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
   3895 {
   3896     unsigned numberOfValues = 0;
   3897     for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
   3898         CSSParserValue* current = valueList->valueAt(i);
   3899         if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
   3900             break;
   3901     }
   3902 
   3903     if (numberOfValues > 4)
   3904         return;
   3905 
   3906     // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
   3907     if (numberOfValues <= 2) {
   3908         parse2ValuesFillPosition(valueList, value1, value2);
   3909         return;
   3910     }
   3911 
   3912     ASSERT(numberOfValues > 2 && numberOfValues <= 4);
   3913 
   3914     CSSParserValue* value = valueList->current();
   3915 
   3916     // <position> requires the first value to be a background keyword.
   3917     if (!isFillPositionKeyword(value->id))
   3918         return;
   3919 
   3920     // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
   3921     unsigned cumulativeFlags = 0;
   3922     FillPositionFlag value1Flag = InvalidFillPosition;
   3923     FillPositionFlag value2Flag = InvalidFillPosition;
   3924     value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
   3925     if (!value1)
   3926         return;
   3927 
   3928     value = valueList->next();
   3929 
   3930     // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
   3931     // a valid start for <position>.
   3932     cumulativeFlags = AmbiguousFillPosition;
   3933     value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
   3934     if (value2)
   3935         valueList->next();
   3936     else {
   3937         value1.clear();
   3938         return;
   3939     }
   3940 
   3941     RefPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
   3942     RefPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
   3943 
   3944     value1.clear();
   3945     value2.clear();
   3946 
   3947     // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
   3948     if (parsedValue2->getValueID() == CSSValueCenter)
   3949         return;
   3950 
   3951     if (numberOfValues == 3)
   3952         parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
   3953     else
   3954         parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
   3955 }
   3956 
   3957 void CSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
   3958 {
   3959     CSSParserValue* value = valueList->current();
   3960 
   3961     // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
   3962     unsigned cumulativeFlags = 0;
   3963     FillPositionFlag value1Flag = InvalidFillPosition;
   3964     FillPositionFlag value2Flag = InvalidFillPosition;
   3965     value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
   3966     if (!value1)
   3967         return;
   3968 
   3969     // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
   3970     // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
   3971     // value was explicitly specified for our property.
   3972     value = valueList->next();
   3973 
   3974     // First check for the comma.  If so, we are finished parsing this value or value pair.
   3975     if (isComma(value))
   3976         value = 0;
   3977 
   3978     if (value) {
   3979         value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
   3980         if (value2)
   3981             valueList->next();
   3982         else {
   3983             if (!inShorthand()) {
   3984                 value1.clear();
   3985                 return;
   3986             }
   3987         }
   3988     }
   3989 
   3990     if (!value2)
   3991         // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
   3992         // is simply 50%. This is our default.
   3993         // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
   3994         // For left/right/center, the default of 50% in the y is still correct.
   3995         value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
   3996 
   3997     if (value1Flag == YFillPosition || value2Flag == XFillPosition)
   3998         value1.swap(value2);
   3999 }
   4000 
   4001 void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
   4002 {
   4003     CSSValueID id = m_valueList->current()->id;
   4004     if (id == CSSValueRepeatX) {
   4005         m_implicitShorthand = true;
   4006         value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
   4007         value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
   4008         m_valueList->next();
   4009         return;
   4010     }
   4011     if (id == CSSValueRepeatY) {
   4012         m_implicitShorthand = true;
   4013         value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
   4014         value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
   4015         m_valueList->next();
   4016         return;
   4017     }
   4018     if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
   4019         value1 = cssValuePool().createIdentifierValue(id);
   4020     else {
   4021         value1 = 0;
   4022         return;
   4023     }
   4024 
   4025     CSSParserValue* value = m_valueList->next();
   4026 
   4027     // Parse the second value if one is available
   4028     if (value && !isComma(value)) {
   4029         id = value->id;
   4030         if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
   4031             value2 = cssValuePool().createIdentifierValue(id);
   4032             m_valueList->next();
   4033             return;
   4034         }
   4035     }
   4036 
   4037     // If only one value was specified, value2 is the same as value1.
   4038     m_implicitShorthand = true;
   4039     value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
   4040 }
   4041 
   4042 PassRefPtr<CSSValue> CSSParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
   4043 {
   4044     allowComma = true;
   4045     CSSParserValue* value = m_valueList->current();
   4046 
   4047     if (value->id == CSSValueContain || value->id == CSSValueCover)
   4048         return cssValuePool().createIdentifierValue(value->id);
   4049 
   4050     RefPtr<CSSPrimitiveValue> parsedValue1;
   4051 
   4052     if (value->id == CSSValueAuto)
   4053         parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
   4054     else {
   4055         if (!validUnit(value, FLength | FPercent))
   4056             return 0;
   4057         parsedValue1 = createPrimitiveNumericValue(value);
   4058     }
   4059 
   4060     RefPtr<CSSPrimitiveValue> parsedValue2;
   4061     if ((value = m_valueList->next())) {
   4062         if (value->unit == CSSParserValue::Operator && value->iValue == ',')
   4063             allowComma = false;
   4064         else if (value->id != CSSValueAuto) {
   4065             if (!validUnit(value, FLength | FPercent)) {
   4066                 if (!inShorthand())
   4067                     return 0;
   4068                 // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
   4069                 m_valueList->previous();
   4070             } else
   4071                 parsedValue2 = createPrimitiveNumericValue(value);
   4072         }
   4073     } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
   4074         // For backwards compatibility we set the second value to the first if it is omitted.
   4075         // We only need to do this for -webkit-background-size. It should be safe to let masks match
   4076         // the real property.
   4077         parsedValue2 = parsedValue1;
   4078     }
   4079 
   4080     if (!parsedValue2)
   4081         return parsedValue1;
   4082     return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release());
   4083 }
   4084 
   4085 bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
   4086                                   RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
   4087 {
   4088     RefPtr<CSSValueList> values;
   4089     RefPtr<CSSValueList> values2;
   4090     CSSParserValue* val;
   4091     RefPtr<CSSValue> value;
   4092     RefPtr<CSSValue> value2;
   4093 
   4094     bool allowComma = false;
   4095 
   4096     retValue1 = retValue2 = 0;
   4097     propId1 = propId;
   4098     propId2 = propId;
   4099     if (propId == CSSPropertyBackgroundPosition) {
   4100         propId1 = CSSPropertyBackgroundPositionX;
   4101         propId2 = CSSPropertyBackgroundPositionY;
   4102     } else if (propId == CSSPropertyWebkitMaskPosition) {
   4103         propId1 = CSSPropertyWebkitMaskPositionX;
   4104         propId2 = CSSPropertyWebkitMaskPositionY;
   4105     } else if (propId == CSSPropertyBackgroundRepeat) {
   4106         propId1 = CSSPropertyBackgroundRepeatX;
   4107         propId2 = CSSPropertyBackgroundRepeatY;
   4108     } else if (propId == CSSPropertyWebkitMaskRepeat) {
   4109         propId1 = CSSPropertyWebkitMaskRepeatX;
   4110         propId2 = CSSPropertyWebkitMaskRepeatY;
   4111     }
   4112 
   4113     while ((val = m_valueList->current())) {
   4114         RefPtr<CSSValue> currValue;
   4115         RefPtr<CSSValue> currValue2;
   4116 
   4117         if (allowComma) {
   4118             if (!isComma(val))
   4119                 return false;
   4120             m_valueList->next();
   4121             allowComma = false;
   4122         } else {
   4123             allowComma = true;
   4124             switch (propId) {
   4125                 case CSSPropertyBackgroundColor:
   4126                     currValue = parseBackgroundColor();
   4127                     if (currValue)
   4128                         m_valueList->next();
   4129                     break;
   4130                 case CSSPropertyBackgroundAttachment:
   4131                     if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
   4132                         currValue = cssValuePool().createIdentifierValue(val->id);
   4133                         m_valueList->next();
   4134                     }
   4135                     break;
   4136                 case CSSPropertyBackgroundImage:
   4137                 case CSSPropertyWebkitMaskImage:
   4138                     if (parseFillImage(m_valueList.get(), currValue))
   4139                         m_valueList->next();
   4140                     break;
   4141                 case CSSPropertyWebkitBackgroundClip:
   4142                 case CSSPropertyWebkitBackgroundOrigin:
   4143                 case CSSPropertyWebkitMaskClip:
   4144                 case CSSPropertyWebkitMaskOrigin:
   4145                     // The first three values here are deprecated and do not apply to the version of the property that has
   4146                     // the -webkit- prefix removed.
   4147                     if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
   4148                         val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
   4149                         ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
   4150                          (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
   4151                         currValue = cssValuePool().createIdentifierValue(val->id);
   4152                         m_valueList->next();
   4153                     }
   4154                     break;
   4155                 case CSSPropertyBackgroundClip:
   4156                     if (parseBackgroundClip(val, currValue))
   4157                         m_valueList->next();
   4158                     break;
   4159                 case CSSPropertyBackgroundOrigin:
   4160                     if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
   4161                         currValue = cssValuePool().createIdentifierValue(val->id);
   4162                         m_valueList->next();
   4163                     }
   4164                     break;
   4165                 case CSSPropertyBackgroundPosition:
   4166                 case CSSPropertyWebkitMaskPosition:
   4167                     parseFillPosition(m_valueList.get(), currValue, currValue2);
   4168                     // parseFillPosition advances the m_valueList pointer.
   4169                     break;
   4170                 case CSSPropertyBackgroundPositionX:
   4171                 case CSSPropertyWebkitMaskPositionX: {
   4172                     currValue = parseFillPositionX(m_valueList.get());
   4173                     if (currValue)
   4174                         m_valueList->next();
   4175                     break;
   4176                 }
   4177                 case CSSPropertyBackgroundPositionY:
   4178                 case CSSPropertyWebkitMaskPositionY: {
   4179                     currValue = parseFillPositionY(m_valueList.get());
   4180                     if (currValue)
   4181                         m_valueList->next();
   4182                     break;
   4183                 }
   4184                 case CSSPropertyWebkitBackgroundComposite:
   4185                 case CSSPropertyWebkitMaskComposite:
   4186                     if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
   4187                         currValue = cssValuePool().createIdentifierValue(val->id);
   4188                         m_valueList->next();
   4189                     }
   4190                     break;
   4191                 case CSSPropertyBackgroundBlendMode:
   4192                     if (RuntimeEnabledFeatures::cssCompositingEnabled() && (val->id == CSSValueNormal || val->id == CSSValueMultiply
   4193                         || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
   4194                         || val->id == CSSValueLighten ||  val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
   4195                         || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
   4196                         || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
   4197                         || val->id == CSSValueColor || val->id == CSSValueLuminosity)) {
   4198                         currValue = cssValuePool().createIdentifierValue(val->id);
   4199                         m_valueList->next();
   4200                     }
   4201                     break;
   4202                 case CSSPropertyBackgroundRepeat:
   4203                 case CSSPropertyWebkitMaskRepeat:
   4204                     parseFillRepeat(currValue, currValue2);
   4205                     // parseFillRepeat advances the m_valueList pointer
   4206                     break;
   4207                 case CSSPropertyBackgroundSize:
   4208                 case CSSPropertyWebkitBackgroundSize:
   4209                 case CSSPropertyWebkitMaskSize: {
   4210                     currValue = parseFillSize(propId, allowComma);
   4211                     if (currValue)
   4212                         m_valueList->next();
   4213                     break;
   4214                 }
   4215                 default:
   4216                     break;
   4217             }
   4218             if (!currValue)
   4219                 return false;
   4220 
   4221             if (value && !values) {
   4222                 values = CSSValueList::createCommaSeparated();
   4223                 values->append(value.release());
   4224             }
   4225 
   4226             if (value2 && !values2) {
   4227                 values2 = CSSValueList::createCommaSeparated();
   4228                 values2->append(value2.release());
   4229             }
   4230 
   4231             if (values)
   4232                 values->append(currValue.release());
   4233             else
   4234                 value = currValue.release();
   4235             if (currValue2) {
   4236                 if (values2)
   4237                     values2->append(currValue2.release());
   4238                 else
   4239                     value2 = currValue2.release();
   4240             }
   4241         }
   4242 
   4243         // When parsing any fill shorthand property, we let it handle building up the lists for all
   4244         // properties.
   4245         if (inShorthand())
   4246             break;
   4247     }
   4248 
   4249     if (values && values->length()) {
   4250         retValue1 = values.release();
   4251         if (values2 && values2->length())
   4252             retValue2 = values2.release();
   4253         return true;
   4254     }
   4255     if (value) {
   4256         retValue1 = value.release();
   4257         retValue2 = value2.release();
   4258         return true;
   4259     }
   4260     return false;
   4261 }
   4262 
   4263 PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
   4264 {
   4265     CSSParserValue* value = m_valueList->current();
   4266     if (validUnit(value, FTime))
   4267         return createPrimitiveNumericValue(value);
   4268     return 0;
   4269 }
   4270 
   4271 PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
   4272 {
   4273     CSSParserValue* value = m_valueList->current();
   4274     if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
   4275         return cssValuePool().createIdentifierValue(value->id);
   4276     return 0;
   4277 }
   4278 
   4279 PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
   4280 {
   4281     CSSParserValue* value = m_valueList->current();
   4282     if (validUnit(value, FTime | FNonNeg))
   4283         return createPrimitiveNumericValue(value);
   4284     return 0;
   4285 }
   4286 
   4287 PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
   4288 {
   4289     CSSParserValue* value = m_valueList->current();
   4290     if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
   4291         return cssValuePool().createIdentifierValue(value->id);
   4292     return 0;
   4293 }
   4294 
   4295 PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
   4296 {
   4297     CSSParserValue* value = m_valueList->current();
   4298     if (value->id == CSSValueInfinite)
   4299         return cssValuePool().createIdentifierValue(value->id);
   4300     if (validUnit(value, FNumber | FNonNeg))
   4301         return createPrimitiveNumericValue(value);
   4302     return 0;
   4303 }
   4304 
   4305 PassRefPtr<CSSValue> CSSParser::parseAnimationName()
   4306 {
   4307     CSSParserValue* value = m_valueList->current();
   4308     if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
   4309         if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
   4310             return cssValuePool().createIdentifierValue(CSSValueNone);
   4311         } else {
   4312             return createPrimitiveStringValue(value);
   4313         }
   4314     }
   4315     return 0;
   4316 }
   4317 
   4318 PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
   4319 {
   4320     CSSParserValue* value = m_valueList->current();
   4321     if (value->id == CSSValueRunning || value->id == CSSValuePaused)
   4322         return cssValuePool().createIdentifierValue(value->id);
   4323     return 0;
   4324 }
   4325 
   4326 PassRefPtr<CSSValue> CSSParser::parseAnimationProperty(AnimationParseContext& context)
   4327 {
   4328     CSSParserValue* value = m_valueList->current();
   4329     if (value->unit != CSSPrimitiveValue::CSS_IDENT)
   4330         return 0;
   4331     CSSPropertyID result = cssPropertyID(value->string);
   4332     if (result)
   4333         return cssValuePool().createIdentifierValue(result);
   4334     if (equalIgnoringCase(value, "all")) {
   4335         context.sawAnimationPropertyKeyword();
   4336         return cssValuePool().createIdentifierValue(CSSValueAll);
   4337     }
   4338     if (equalIgnoringCase(value, "none")) {
   4339         context.commitAnimationPropertyKeyword();
   4340         context.sawAnimationPropertyKeyword();
   4341         return cssValuePool().createIdentifierValue(CSSValueNone);
   4342     }
   4343     return 0;
   4344 }
   4345 
   4346 bool CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
   4347 {
   4348     parse2ValuesFillPosition(m_valueList.get(), value1, value2);
   4349 
   4350     // now get z
   4351     if (m_valueList->current()) {
   4352         if (validUnit(m_valueList->current(), FLength)) {
   4353             value3 = createPrimitiveNumericValue(m_valueList->current());
   4354             m_valueList->next();
   4355             return true;
   4356         }
   4357         return false;
   4358     }
   4359     value3 = cssValuePool().createImplicitInitialValue();
   4360     return true;
   4361 }
   4362 
   4363 bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
   4364 {
   4365     CSSParserValue* v = args->current();
   4366     if (!validUnit(v, FNumber))
   4367         return false;
   4368     result = v->fValue;
   4369     v = args->next();
   4370     if (!v)
   4371         // The last number in the function has no comma after it, so we're done.
   4372         return true;
   4373     if (!isComma(v))
   4374         return false;
   4375     args->next();
   4376     return true;
   4377 }
   4378 
   4379 PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
   4380 {
   4381     CSSParserValue* value = m_valueList->current();
   4382     if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
   4383         || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd)
   4384         return cssValuePool().createIdentifierValue(value->id);
   4385 
   4386     // We must be a function.
   4387     if (value->unit != CSSParserValue::Function)
   4388         return 0;
   4389 
   4390     CSSParserValueList* args = value->function->args.get();
   4391 
   4392     if (equalIgnoringCase(value->function->name, "steps(")) {
   4393         // For steps, 1 or 2 params must be specified (comma-separated)
   4394         if (!args || (args->size() != 1 && args->size() != 3))
   4395             return 0;
   4396 
   4397         // There are two values.
   4398         int numSteps;
   4399         bool stepAtStart = false;
   4400 
   4401         CSSParserValue* v = args->current();
   4402         if (!validUnit(v, FInteger))
   4403             return 0;
   4404         numSteps = clampToInteger(v->fValue);
   4405         if (numSteps < 1)
   4406             return 0;
   4407         v = args->next();
   4408 
   4409         if (v) {
   4410             // There is a comma so we need to parse the second value
   4411             if (!isComma(v))
   4412                 return 0;
   4413             v = args->next();
   4414             if (v->id != CSSValueStart && v->id != CSSValueEnd)
   4415                 return 0;
   4416             stepAtStart = v->id == CSSValueStart;
   4417         }
   4418 
   4419         return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart);
   4420     }
   4421 
   4422     if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
   4423         // For cubic bezier, 4 values must be specified.
   4424         if (!args || args->size() != 7)
   4425             return 0;
   4426 
   4427         // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
   4428         double x1, y1, x2, y2;
   4429 
   4430         if (!parseCubicBezierTimingFunctionValue(args, x1))
   4431             return 0;
   4432         if (x1 < 0 || x1 > 1)
   4433             return 0;
   4434         if (!parseCubicBezierTimingFunctionValue(args, y1))
   4435             return 0;
   4436         if (!parseCubicBezierTimingFunctionValue(args, x2))
   4437             return 0;
   4438         if (x2 < 0 || x2 > 1)
   4439             return 0;
   4440         if (!parseCubicBezierTimingFunctionValue(args, y2))
   4441             return 0;
   4442 
   4443         return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
   4444     }
   4445 
   4446     return 0;
   4447 }
   4448 
   4449 bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& result, AnimationParseContext& context)
   4450 {
   4451     RefPtr<CSSValueList> values;
   4452     CSSParserValue* val;
   4453     RefPtr<CSSValue> value;
   4454     bool allowComma = false;
   4455 
   4456     result = 0;
   4457 
   4458     while ((val = m_valueList->current())) {
   4459         RefPtr<CSSValue> currValue;
   4460         if (allowComma) {
   4461             if (!isComma(val))
   4462                 return false;
   4463             m_valueList->next();
   4464             allowComma = false;
   4465         }
   4466         else {
   4467             switch (propId) {
   4468                 case CSSPropertyWebkitAnimationDelay:
   4469                 case CSSPropertyTransitionDelay:
   4470                 case CSSPropertyWebkitTransitionDelay:
   4471                     currValue = parseAnimationDelay();
   4472                     if (currValue)
   4473                         m_valueList->next();
   4474                     break;
   4475                 case CSSPropertyWebkitAnimationDirection:
   4476                     currValue = parseAnimationDirection();
   4477                     if (currValue)
   4478                         m_valueList->next();
   4479                     break;
   4480                 case CSSPropertyWebkitAnimationDuration:
   4481                 case CSSPropertyTransitionDuration:
   4482                 case CSSPropertyWebkitTransitionDuration:
   4483                     currValue = parseAnimationDuration();
   4484                     if (currValue)
   4485                         m_valueList->next();
   4486                     break;
   4487                 case CSSPropertyWebkitAnimationFillMode:
   4488                     currValue = parseAnimationFillMode();
   4489                     if (currValue)
   4490                         m_valueList->next();
   4491                     break;
   4492                 case CSSPropertyWebkitAnimationIterationCount:
   4493                     currValue = parseAnimationIterationCount();
   4494                     if (currValue)
   4495                         m_valueList->next();
   4496                     break;
   4497                 case CSSPropertyWebkitAnimationName:
   4498                     currValue = parseAnimationName();
   4499                     if (currValue)
   4500                         m_valueList->next();
   4501                     break;
   4502                 case CSSPropertyWebkitAnimationPlayState:
   4503                     currValue = parseAnimationPlayState();
   4504                     if (currValue)
   4505                         m_valueList->next();
   4506                     break;
   4507                 case CSSPropertyTransitionProperty:
   4508                 case CSSPropertyWebkitTransitionProperty:
   4509                     currValue = parseAnimationProperty(context);
   4510                     if (value && !context.animationPropertyKeywordAllowed())
   4511                         return false;
   4512                     if (currValue)
   4513                         m_valueList->next();
   4514                     break;
   4515                 case CSSPropertyWebkitAnimationTimingFunction:
   4516                 case CSSPropertyTransitionTimingFunction:
   4517                 case CSSPropertyWebkitTransitionTimingFunction:
   4518                     currValue = parseAnimationTimingFunction();
   4519                     if (currValue)
   4520                         m_valueList->next();
   4521                     break;
   4522                 default:
   4523                     ASSERT_NOT_REACHED();
   4524                     return false;
   4525             }
   4526 
   4527             if (!currValue)
   4528                 return false;
   4529 
   4530             if (value && !values) {
   4531                 values = CSSValueList::createCommaSeparated();
   4532                 values->append(value.release());
   4533             }
   4534 
   4535             if (values)
   4536                 values->append(currValue.release());
   4537             else
   4538                 value = currValue.release();
   4539 
   4540             allowComma = true;
   4541         }
   4542 
   4543         // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
   4544         // properties.
   4545         if (inShorthand())
   4546             break;
   4547     }
   4548 
   4549     if (values && values->length()) {
   4550         result = values.release();
   4551         return true;
   4552     }
   4553     if (value) {
   4554         result = value.release();
   4555         return true;
   4556     }
   4557     return false;
   4558 }
   4559 
   4560 // The function parses [ <integer> || <string> ] in <grid-line> (which can be stand alone or with 'span').
   4561 bool CSSParser::parseIntegerOrStringFromGridPosition(RefPtr<CSSPrimitiveValue>& numericValue, RefPtr<CSSPrimitiveValue>& gridLineName)
   4562 {
   4563     CSSParserValue* value = m_valueList->current();
   4564     if (validUnit(value, FInteger) && value->fValue) {
   4565         numericValue = createPrimitiveNumericValue(value);
   4566         value = m_valueList->next();
   4567         if (value && value->unit == CSSPrimitiveValue::CSS_STRING) {
   4568             gridLineName = createPrimitiveStringValue(m_valueList->current());
   4569             m_valueList->next();
   4570         }
   4571         return true;
   4572     }
   4573 
   4574     if (value->unit == CSSPrimitiveValue::CSS_STRING) {
   4575         gridLineName = createPrimitiveStringValue(m_valueList->current());
   4576         value = m_valueList->next();
   4577         if (value && validUnit(value, FInteger) && value->fValue) {
   4578             numericValue = createPrimitiveNumericValue(value);
   4579             m_valueList->next();
   4580         }
   4581         return true;
   4582     }
   4583 
   4584     return false;
   4585 }
   4586 
   4587 PassRefPtr<CSSValue> CSSParser::parseGridPosition()
   4588 {
   4589     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   4590 
   4591     CSSParserValue* value = m_valueList->current();
   4592     if (value->id == CSSValueAuto) {
   4593         m_valueList->next();
   4594         return cssValuePool().createIdentifierValue(CSSValueAuto);
   4595     }
   4596 
   4597     if (value->id != CSSValueSpan && value->unit == CSSPrimitiveValue::CSS_IDENT) {
   4598         m_valueList->next();
   4599         return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
   4600     }
   4601 
   4602     RefPtr<CSSPrimitiveValue> numericValue;
   4603     RefPtr<CSSPrimitiveValue> gridLineName;
   4604     bool hasSeenSpanKeyword = false;
   4605 
   4606     if (parseIntegerOrStringFromGridPosition(numericValue, gridLineName)) {
   4607         value = m_valueList->current();
   4608         if (value && value->id == CSSValueSpan) {
   4609             hasSeenSpanKeyword = true;
   4610             m_valueList->next();
   4611         }
   4612     } else if (value->id == CSSValueSpan) {
   4613         hasSeenSpanKeyword = true;
   4614         if (m_valueList->next())
   4615             parseIntegerOrStringFromGridPosition(numericValue, gridLineName);
   4616     }
   4617 
   4618     // Check that we have consumed all the value list. For shorthands, the parser will pass
   4619     // the whole value list (including the opposite position).
   4620     if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
   4621         return 0;
   4622 
   4623     // If we didn't parse anything, this is not a valid grid position.
   4624     if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
   4625         return 0;
   4626 
   4627     // Negative numbers are not allowed for span (but are for <integer>).
   4628     if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
   4629         return 0;
   4630 
   4631     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
   4632     if (hasSeenSpanKeyword)
   4633         values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
   4634     if (numericValue)
   4635         values->append(numericValue.release());
   4636     if (gridLineName)
   4637         values->append(gridLineName.release());
   4638     ASSERT(values->length());
   4639     return values.release();
   4640 }
   4641 
   4642 static PassRefPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
   4643 {
   4644     if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
   4645         return value;
   4646 
   4647     return cssValuePool().createIdentifierValue(CSSValueAuto);
   4648 }
   4649 
   4650 bool CSSParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
   4651 {
   4652     ShorthandScope scope(this, shorthandId);
   4653     const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
   4654     ASSERT(shorthand.length() == 2);
   4655 
   4656     RefPtr<CSSValue> startValue = parseGridPosition();
   4657     if (!startValue)
   4658         return false;
   4659 
   4660     RefPtr<CSSValue> endValue;
   4661     if (m_valueList->current()) {
   4662         if (!isForwardSlashOperator(m_valueList->current()))
   4663             return false;
   4664 
   4665         if (!m_valueList->next())
   4666             return false;
   4667 
   4668         endValue = parseGridPosition();
   4669         if (!endValue || m_valueList->current())
   4670             return false;
   4671     } else {
   4672         endValue = gridMissingGridPositionValue(startValue.get());
   4673     }
   4674 
   4675     addProperty(shorthand.properties()[0], startValue, important);
   4676     addProperty(shorthand.properties()[1], endValue, important);
   4677     return true;
   4678 }
   4679 
   4680 bool CSSParser::parseGridAreaShorthand(bool important)
   4681 {
   4682     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   4683 
   4684     ShorthandScope scope(this, CSSPropertyGridArea);
   4685     const StylePropertyShorthand& shorthand = gridAreaShorthand();
   4686     ASSERT(shorthand.length() == 4);
   4687 
   4688     RefPtr<CSSValue> rowStartValue = parseGridPosition();
   4689     if (!rowStartValue)
   4690         return false;
   4691 
   4692     RefPtr<CSSValue> columnStartValue;
   4693     if (!parseSingleGridAreaLonghand(columnStartValue))
   4694         return false;
   4695 
   4696     RefPtr<CSSValue> rowEndValue;
   4697     if (!parseSingleGridAreaLonghand(rowEndValue))
   4698         return false;
   4699 
   4700     RefPtr<CSSValue> columnEndValue;
   4701     if (!parseSingleGridAreaLonghand(columnEndValue))
   4702         return false;
   4703 
   4704     if (!columnStartValue)
   4705         columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
   4706 
   4707     if (!rowEndValue)
   4708         rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
   4709 
   4710     if (!columnEndValue)
   4711         columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
   4712 
   4713     addProperty(CSSPropertyGridRowStart, rowStartValue, important);
   4714     addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
   4715     addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
   4716     addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
   4717     return true;
   4718 }
   4719 
   4720 bool CSSParser::parseSingleGridAreaLonghand(RefPtr<CSSValue>& property)
   4721 {
   4722     if (!m_valueList->current())
   4723         return true;
   4724 
   4725     if (!isForwardSlashOperator(m_valueList->current()))
   4726         return false;
   4727 
   4728     if (!m_valueList->next())
   4729         return false;
   4730 
   4731     property = parseGridPosition();
   4732     return true;
   4733 }
   4734 
   4735 bool CSSParser::parseGridTrackList(CSSPropertyID propId, bool important)
   4736 {
   4737     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   4738 
   4739     CSSParserValue* value = m_valueList->current();
   4740     if (value->id == CSSValueNone) {
   4741         if (m_valueList->next())
   4742             return false;
   4743 
   4744         addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
   4745         return true;
   4746     }
   4747 
   4748     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
   4749     // Handle leading <string>*.
   4750     while (m_valueList->current() && m_valueList->current()->unit == CSSPrimitiveValue::CSS_STRING) {
   4751         RefPtr<CSSPrimitiveValue> name = createPrimitiveStringValue(m_valueList->current());
   4752         values->append(name);
   4753         m_valueList->next();
   4754     }
   4755 
   4756     bool seenTrackSizeOrRepeatFunction = false;
   4757     while (CSSParserValue* currentValue = m_valueList->current()) {
   4758         if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) {
   4759             if (!parseGridTrackRepeatFunction(*values))
   4760                 return false;
   4761             seenTrackSizeOrRepeatFunction = true;
   4762         } else {
   4763             RefPtr<CSSPrimitiveValue> primitiveValue = parseGridTrackSize(*m_valueList);
   4764             if (!primitiveValue)
   4765                 return false;
   4766             values->append(primitiveValue);
   4767             seenTrackSizeOrRepeatFunction = true;
   4768         }
   4769 
   4770         // This will handle the trailing <string>* in the grammar.
   4771         while (m_valueList->current() && m_valueList->current()->unit == CSSPrimitiveValue::CSS_STRING) {
   4772             RefPtr<CSSPrimitiveValue> name = createPrimitiveStringValue(m_valueList->current());
   4773             values->append(name);
   4774             m_valueList->next();
   4775         }
   4776     }
   4777 
   4778     // We should have found a <track-size> or else it is not a valid <track-list>
   4779     if (!seenTrackSizeOrRepeatFunction)
   4780         return false;
   4781 
   4782     addProperty(propId, values.release(), important);
   4783     return true;
   4784 }
   4785 
   4786 bool CSSParser::parseGridTrackRepeatFunction(CSSValueList& list)
   4787 {
   4788     CSSParserValueList* arguments = m_valueList->current()->function->args.get();
   4789     if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
   4790         return false;
   4791 
   4792     ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
   4793     size_t repetitions = arguments->valueAt(0)->fValue;
   4794     RefPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
   4795     arguments->next(); // Skip the repetition count.
   4796     arguments->next(); // Skip the comma.
   4797 
   4798     // Handle leading <string>*.
   4799     while (arguments->current() && arguments->current()->unit == CSSPrimitiveValue::CSS_STRING) {
   4800         RefPtr<CSSPrimitiveValue> name = createPrimitiveStringValue(arguments->current());
   4801         repeatedValues->append(name);
   4802         arguments->next();
   4803     }
   4804 
   4805     while (CSSParserValue* argumentValue = arguments->current()) {
   4806         RefPtr<CSSPrimitiveValue> trackSize = parseGridTrackSize(*arguments);
   4807         if (!trackSize)
   4808             return false;
   4809 
   4810         repeatedValues->append(trackSize);
   4811 
   4812         // This takes care of any trailing <string>* in the grammar.
   4813         while (arguments->current() && arguments->current()->unit == CSSPrimitiveValue::CSS_STRING) {
   4814             RefPtr<CSSPrimitiveValue> name = createPrimitiveStringValue(arguments->current());
   4815             repeatedValues->append(name);
   4816             arguments->next();
   4817         }
   4818     }
   4819 
   4820     for (size_t i = 0; i < repetitions; ++i) {
   4821         for (size_t j = 0; j < repeatedValues->length(); ++j)
   4822             list.append(repeatedValues->itemWithoutBoundsCheck(j));
   4823     }
   4824 
   4825     // parseGridTrackSize iterated over the repeat arguments, move to the next value.
   4826     m_valueList->next();
   4827     return true;
   4828 }
   4829 
   4830 PassRefPtr<CSSPrimitiveValue> CSSParser::parseGridTrackSize(CSSParserValueList& inputList)
   4831 {
   4832     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   4833 
   4834     CSSParserValue* currentValue = inputList.current();
   4835     inputList.next();
   4836 
   4837     if (currentValue->id == CSSValueAuto)
   4838         return cssValuePool().createIdentifierValue(CSSValueAuto);
   4839 
   4840     if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
   4841         // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
   4842         CSSParserValueList* arguments = currentValue->function->args.get();
   4843         if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
   4844             return 0;
   4845 
   4846         RefPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
   4847         if (!minTrackBreadth)
   4848             return 0;
   4849 
   4850         RefPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
   4851         if (!maxTrackBreadth)
   4852             return 0;
   4853 
   4854         return createPrimitiveValuePair(minTrackBreadth, maxTrackBreadth);
   4855     }
   4856 
   4857     return parseGridBreadth(currentValue);
   4858 }
   4859 
   4860 PassRefPtr<CSSPrimitiveValue> CSSParser::parseGridBreadth(CSSParserValue* currentValue)
   4861 {
   4862     if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent)
   4863         return cssValuePool().createIdentifierValue(currentValue->id);
   4864 
   4865     if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
   4866         double flexValue = currentValue->fValue;
   4867 
   4868         // Fractional unit is a non-negative dimension.
   4869         if (flexValue <= 0)
   4870             return 0;
   4871 
   4872         return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
   4873     }
   4874 
   4875     if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
   4876         return 0;
   4877 
   4878     return createPrimitiveNumericValue(currentValue);
   4879 }
   4880 
   4881 PassRefPtr<CSSValue> CSSParser::parseGridTemplate()
   4882 {
   4883     NamedGridAreaMap gridAreaMap;
   4884     size_t rowCount = 0;
   4885     size_t columnCount = 0;
   4886 
   4887     while (CSSParserValue* currentValue = m_valueList->current()) {
   4888         if (currentValue->unit != CSSPrimitiveValue::CSS_STRING)
   4889             return 0;
   4890 
   4891         String gridRowNames = currentValue->string;
   4892         if (!gridRowNames.length())
   4893             return 0;
   4894 
   4895         Vector<String> columnNames;
   4896         gridRowNames.split(' ', columnNames);
   4897 
   4898         if (!columnCount) {
   4899             columnCount = columnNames.size();
   4900             ASSERT(columnCount);
   4901         } else if (columnCount != columnNames.size()) {
   4902             // The declaration is invalid is all the rows don't have the number of columns.
   4903             return 0;
   4904         }
   4905 
   4906         for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
   4907             const String& gridAreaName = columnNames[currentCol];
   4908 
   4909             // Unamed areas are always valid (we consider them to be 1x1).
   4910             if (gridAreaName == ".")
   4911                 continue;
   4912 
   4913             // We handle several grid areas with the same name at once to simplify the validation code.
   4914             size_t lookAheadCol;
   4915             for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++lookAheadCol) {
   4916                 if (columnNames[lookAheadCol + 1] != gridAreaName)
   4917                     break;
   4918             }
   4919 
   4920             NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
   4921             if (gridAreaIt == gridAreaMap.end()) {
   4922                 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
   4923             } else {
   4924                 GridCoordinate& gridCoordinate = gridAreaIt->value;
   4925 
   4926                 // The following checks test that the grid area is a single filled-in rectangle.
   4927                 // 1. The new row is adjacent to the previously parsed row.
   4928                 if (rowCount != gridCoordinate.rows.initialPositionIndex + 1)
   4929                     return 0;
   4930 
   4931                 // 2. The new area starts at the same position as the previously parsed area.
   4932                 if (currentCol != gridCoordinate.columns.initialPositionIndex)
   4933                     return 0;
   4934 
   4935                 // 3. The new area ends at the same position as the previously parsed area.
   4936                 if (lookAheadCol != gridCoordinate.columns.finalPositionIndex)
   4937                     return 0;
   4938 
   4939                 ++gridCoordinate.rows.finalPositionIndex;
   4940             }
   4941             currentCol = lookAheadCol;
   4942         }
   4943 
   4944         ++rowCount;
   4945         m_valueList->next();
   4946     }
   4947 
   4948     if (!rowCount || !columnCount)
   4949         return 0;
   4950 
   4951     return CSSGridTemplateValue::create(gridAreaMap, rowCount, columnCount);
   4952 }
   4953 
   4954 PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
   4955 {
   4956     unsigned numArgs = args->size();
   4957     if (counters && numArgs != 3 && numArgs != 5)
   4958         return 0;
   4959     if (!counters && numArgs != 1 && numArgs != 3)
   4960         return 0;
   4961 
   4962     CSSParserValue* i = args->current();
   4963     if (i->unit != CSSPrimitiveValue::CSS_IDENT)
   4964         return 0;
   4965     RefPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
   4966 
   4967     RefPtr<CSSPrimitiveValue> separator;
   4968     if (!counters)
   4969         separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
   4970     else {
   4971         i = args->next();
   4972         if (i->unit != CSSParserValue::Operator || i->iValue != ',')
   4973             return 0;
   4974 
   4975         i = args->next();
   4976         if (i->unit != CSSPrimitiveValue::CSS_STRING)
   4977             return 0;
   4978 
   4979         separator = createPrimitiveStringValue(i);
   4980     }
   4981 
   4982     RefPtr<CSSPrimitiveValue> listStyle;
   4983     i = args->next();
   4984     if (!i) // Make the list style default decimal
   4985         listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
   4986     else {
   4987         if (i->unit != CSSParserValue::Operator || i->iValue != ',')
   4988             return 0;
   4989 
   4990         i = args->next();
   4991         if (i->unit != CSSPrimitiveValue::CSS_IDENT)
   4992             return 0;
   4993 
   4994         CSSValueID listStyleID = CSSValueInvalid;
   4995         if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
   4996             listStyleID = i->id;
   4997         else
   4998             return 0;
   4999 
   5000         listStyle = cssValuePool().createIdentifierValue(listStyleID);
   5001     }
   5002 
   5003     return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
   5004 }
   5005 
   5006 bool CSSParser::parseClipShape(CSSPropertyID propId, bool important)
   5007 {
   5008     CSSParserValue* value = m_valueList->current();
   5009     CSSParserValueList* args = value->function->args.get();
   5010 
   5011     if (!equalIgnoringCase(value->function->name, "rect(") || !args)
   5012         return false;
   5013 
   5014     // rect(t, r, b, l) || rect(t r b l)
   5015     if (args->size() != 4 && args->size() != 7)
   5016         return false;
   5017     RefPtr<Rect> rect = Rect::create();
   5018     bool valid = true;
   5019     int i = 0;
   5020     CSSParserValue* a = args->current();
   5021     while (a) {
   5022         valid = a->id == CSSValueAuto || validUnit(a, FLength);
   5023         if (!valid)
   5024             break;
   5025         RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
   5026             cssValuePool().createIdentifierValue(CSSValueAuto) :
   5027             createPrimitiveNumericValue(a);
   5028         if (i == 0)
   5029             rect->setTop(length);
   5030         else if (i == 1)
   5031             rect->setRight(length);
   5032         else if (i == 2)
   5033             rect->setBottom(length);
   5034         else
   5035             rect->setLeft(length);
   5036         a = args->next();
   5037         if (a && args->size() == 7) {
   5038             if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
   5039                 a = args->next();
   5040             } else {
   5041                 valid = false;
   5042                 break;
   5043             }
   5044         }
   5045         i++;
   5046     }
   5047     if (valid) {
   5048         addProperty(propId, cssValuePool().createValue(rect.release()), important);
   5049         m_valueList->next();
   5050         return true;
   5051     }
   5052     return false;
   5053 }
   5054 
   5055 PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeRectangle(CSSParserValueList* args)
   5056 {
   5057     ASSERT(args);
   5058 
   5059     // rect(x, y, width, height, [[rx], ry])
   5060     if (args->size() != 7 && args->size() != 9 && args->size() != 11)
   5061         return 0;
   5062 
   5063     RefPtr<CSSBasicShapeRectangle> shape = CSSBasicShapeRectangle::create();
   5064 
   5065     unsigned argumentNumber = 0;
   5066     CSSParserValue* argument = args->current();
   5067     while (argument) {
   5068         Units unitFlags = FLength | FPercent;
   5069         if (argumentNumber > 1) {
   5070             // Arguments width, height, rx, and ry cannot be negative.
   5071             unitFlags = unitFlags | FNonNeg;
   5072         }
   5073         if (!validUnit(argument, unitFlags))
   5074             return 0;
   5075 
   5076         RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
   5077         ASSERT(argumentNumber < 6);
   5078         switch (argumentNumber) {
   5079         case 0:
   5080             shape->setX(length);
   5081             break;
   5082         case 1:
   5083             shape->setY(length);
   5084             break;
   5085         case 2:
   5086             shape->setWidth(length);
   5087             break;
   5088         case 3:
   5089             shape->setHeight(length);
   5090             break;
   5091         case 4:
   5092             shape->setRadiusX(length);
   5093             break;
   5094         case 5:
   5095             shape->setRadiusY(length);
   5096             break;
   5097         }
   5098         argument = args->next();
   5099         if (argument) {
   5100             if (!isComma(argument))
   5101                 return 0;
   5102 
   5103             argument = args->next();
   5104         }
   5105         argumentNumber++;
   5106     }
   5107 
   5108     if (argumentNumber < 4)
   5109         return 0;
   5110     return shape;
   5111 }
   5112 
   5113 PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeInsetRectangle(CSSParserValueList* args)
   5114 {
   5115     ASSERT(args);
   5116 
   5117     // inset-rectangle(top, right, bottom, left, [[rx], ry])
   5118     if (args->size() != 7 && args->size() != 9 && args->size() != 11)
   5119         return 0;
   5120 
   5121     RefPtr<CSSBasicShapeInsetRectangle> shape = CSSBasicShapeInsetRectangle::create();
   5122 
   5123     unsigned argumentNumber = 0;
   5124     CSSParserValue* argument = args->current();
   5125     while (argument) {
   5126         Units unitFlags = FLength | FPercent | FNonNeg;
   5127         if (!validUnit(argument, unitFlags))
   5128             return 0;
   5129 
   5130         RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
   5131         ASSERT(argumentNumber < 6);
   5132         switch (argumentNumber) {
   5133         case 0:
   5134             shape->setTop(length);
   5135             break;
   5136         case 1:
   5137             shape->setRight(length);
   5138             break;
   5139         case 2:
   5140             shape->setBottom(length);
   5141             break;
   5142         case 3:
   5143             shape->setLeft(length);
   5144             break;
   5145         case 4:
   5146             shape->setRadiusX(length);
   5147             break;
   5148         case 5:
   5149             shape->setRadiusY(length);
   5150             break;
   5151         }
   5152         argument = args->next();
   5153         if (argument) {
   5154             if (!isComma(argument))
   5155                 return 0;
   5156 
   5157             argument = args->next();
   5158         }
   5159         argumentNumber++;
   5160     }
   5161 
   5162     if (argumentNumber < 4)
   5163         return 0;
   5164     return shape;
   5165 }
   5166 
   5167 PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeCircle(CSSParserValueList* args)
   5168 {
   5169     ASSERT(args);
   5170 
   5171     // circle(centerX, centerY, radius)
   5172     if (args->size() != 5)
   5173         return 0;
   5174 
   5175     RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
   5176 
   5177     unsigned argumentNumber = 0;
   5178     CSSParserValue* argument = args->current();
   5179     while (argument) {
   5180         Units unitFlags = FLength | FPercent;
   5181         if (argumentNumber == 2) {
   5182             // Argument radius cannot be negative.
   5183             unitFlags = unitFlags | FNonNeg;
   5184         }
   5185 
   5186         if (!validUnit(argument, unitFlags))
   5187             return 0;
   5188 
   5189         RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
   5190         ASSERT(argumentNumber < 3);
   5191         switch (argumentNumber) {
   5192         case 0:
   5193             shape->setCenterX(length);
   5194             break;
   5195         case 1:
   5196             shape->setCenterY(length);
   5197             break;
   5198         case 2:
   5199             shape->setRadius(length);
   5200             break;
   5201         }
   5202 
   5203         argument = args->next();
   5204         if (argument) {
   5205             if (!isComma(argument))
   5206                 return 0;
   5207             argument = args->next();
   5208         }
   5209         argumentNumber++;
   5210     }
   5211 
   5212     if (argumentNumber < 3)
   5213         return 0;
   5214     return shape;
   5215 }
   5216 
   5217 PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeEllipse(CSSParserValueList* args)
   5218 {
   5219     ASSERT(args);
   5220 
   5221     // ellipse(centerX, centerY, radiusX, radiusY)
   5222     if (args->size() != 7)
   5223         return 0;
   5224 
   5225     RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
   5226     unsigned argumentNumber = 0;
   5227     CSSParserValue* argument = args->current();
   5228     while (argument) {
   5229         Units unitFlags = FLength | FPercent;
   5230         if (argumentNumber > 1) {
   5231             // Arguments radiusX and radiusY cannot be negative.
   5232             unitFlags = unitFlags | FNonNeg;
   5233         }
   5234         if (!validUnit(argument, unitFlags))
   5235             return 0;
   5236 
   5237         RefPtr<CSSPrimitiveValue> length = createPrimitiveNumericValue(argument);
   5238         ASSERT(argumentNumber < 4);
   5239         switch (argumentNumber) {
   5240         case 0:
   5241             shape->setCenterX(length);
   5242             break;
   5243         case 1:
   5244             shape->setCenterY(length);
   5245             break;
   5246         case 2:
   5247             shape->setRadiusX(length);
   5248             break;
   5249         case 3:
   5250             shape->setRadiusY(length);
   5251             break;
   5252         }
   5253 
   5254         argument = args->next();
   5255         if (argument) {
   5256             if (!isComma(argument))
   5257                 return 0;
   5258             argument = args->next();
   5259         }
   5260         argumentNumber++;
   5261     }
   5262 
   5263     if (argumentNumber < 4)
   5264         return 0;
   5265     return shape;
   5266 }
   5267 
   5268 PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapePolygon(CSSParserValueList* args)
   5269 {
   5270     ASSERT(args);
   5271 
   5272     unsigned size = args->size();
   5273     if (!size)
   5274         return 0;
   5275 
   5276     RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
   5277 
   5278     CSSParserValue* argument = args->current();
   5279     if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
   5280         shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
   5281 
   5282         if (!isComma(args->next()))
   5283             return 0;
   5284 
   5285         argument = args->next();
   5286         size -= 2;
   5287     }
   5288 
   5289     // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
   5290     if (!size || (size % 3) - 2)
   5291         return 0;
   5292 
   5293     CSSParserValue* argumentX = argument;
   5294     while (argumentX) {
   5295         if (!validUnit(argumentX, FLength | FPercent))
   5296             return 0;
   5297 
   5298         CSSParserValue* argumentY = args->next();
   5299         if (!argumentY || !validUnit(argumentY, FLength | FPercent))
   5300             return 0;
   5301 
   5302         RefPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
   5303         RefPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
   5304 
   5305         shape->appendPoint(xLength.release(), yLength.release());
   5306 
   5307         CSSParserValue* commaOrNull = args->next();
   5308         if (!commaOrNull)
   5309             argumentX = 0;
   5310         else if (!isComma(commaOrNull))
   5311             return 0;
   5312         else
   5313             argumentX = args->next();
   5314     }
   5315 
   5316     return shape;
   5317 }
   5318 
   5319 bool CSSParser::parseBasicShape(CSSPropertyID propId, bool important)
   5320 {
   5321     CSSParserValue* value = m_valueList->current();
   5322     ASSERT(value->unit == CSSParserValue::Function);
   5323     CSSParserValueList* args = value->function->args.get();
   5324 
   5325     if (!args)
   5326         return false;
   5327 
   5328     RefPtr<CSSBasicShape> shape;
   5329     if (equalIgnoringCase(value->function->name, "rectangle("))
   5330         shape = parseBasicShapeRectangle(args);
   5331     else if (equalIgnoringCase(value->function->name, "circle("))
   5332         shape = parseBasicShapeCircle(args);
   5333     else if (equalIgnoringCase(value->function->name, "ellipse("))
   5334         shape = parseBasicShapeEllipse(args);
   5335     else if (equalIgnoringCase(value->function->name, "polygon("))
   5336         shape = parseBasicShapePolygon(args);
   5337     else if (equalIgnoringCase(value->function->name, "inset-rectangle("))
   5338         shape = parseBasicShapeInsetRectangle(args);
   5339 
   5340     if (!shape)
   5341         return false;
   5342 
   5343     addProperty(propId, cssValuePool().createValue(shape.release()), important);
   5344     m_valueList->next();
   5345     return true;
   5346 }
   5347 
   5348 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
   5349 bool CSSParser::parseFont(bool important)
   5350 {
   5351     // Let's check if there is an inherit or initial somewhere in the shorthand.
   5352     for (unsigned i = 0; i < m_valueList->size(); ++i) {
   5353         if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
   5354             return false;
   5355     }
   5356 
   5357     ShorthandScope scope(this, CSSPropertyFont);
   5358     // Optional font-style, font-variant and font-weight.
   5359     bool fontStyleParsed = false;
   5360     bool fontVariantParsed = false;
   5361     bool fontWeightParsed = false;
   5362     CSSParserValue* value;
   5363     while ((value = m_valueList->current())) {
   5364         if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
   5365             addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
   5366             fontStyleParsed = true;
   5367         } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
   5368             // Font variant in the shorthand is particular, it only accepts normal or small-caps.
   5369             addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
   5370             fontVariantParsed = true;
   5371         } else if (!fontWeightParsed && parseFontWeight(important))
   5372             fontWeightParsed = true;
   5373         else
   5374             break;
   5375         m_valueList->next();
   5376     }
   5377 
   5378     if (!value)
   5379         return false;
   5380 
   5381     if (!fontStyleParsed)
   5382         addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
   5383     if (!fontVariantParsed)
   5384         addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
   5385     if (!fontWeightParsed)
   5386         addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
   5387 
   5388     // Now a font size _must_ come.
   5389     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
   5390     if (!parseFontSize(important))
   5391         return false;
   5392 
   5393     value = m_valueList->current();
   5394     if (!value)
   5395         return false;
   5396 
   5397     if (isForwardSlashOperator(value)) {
   5398         // The line-height property.
   5399         value = m_valueList->next();
   5400         if (!value)
   5401             return false;
   5402         if (!parseLineHeight(important))
   5403             return false;
   5404     } else
   5405         addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
   5406 
   5407     // Font family must come now.
   5408     RefPtr<CSSValue> parsedFamilyValue = parseFontFamily();
   5409     if (!parsedFamilyValue)
   5410         return false;
   5411 
   5412     addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
   5413 
   5414     // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
   5415     // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
   5416     // but we don't seem to support them at the moment. They should also be added here once implemented.
   5417     if (m_valueList->current())
   5418         return false;
   5419 
   5420     return true;
   5421 }
   5422 
   5423 class FontFamilyValueBuilder {
   5424 public:
   5425     FontFamilyValueBuilder(CSSValueList* list)
   5426         : m_list(list)
   5427     {
   5428     }
   5429 
   5430     void add(const CSSParserString& string)
   5431     {
   5432         if (!m_builder.isEmpty())
   5433             m_builder.append(' ');
   5434 
   5435         if (string.is8Bit()) {
   5436             m_builder.append(string.characters8(), string.length());
   5437             return;
   5438         }
   5439 
   5440         m_builder.append(string.characters16(), string.length());
   5441     }
   5442 
   5443     void commit()
   5444     {
   5445         if (m_builder.isEmpty())
   5446             return;
   5447         m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
   5448         m_builder.clear();
   5449     }
   5450 
   5451 private:
   5452     StringBuilder m_builder;
   5453     CSSValueList* m_list;
   5454 };
   5455 
   5456 PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
   5457 {
   5458     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   5459     CSSParserValue* value = m_valueList->current();
   5460 
   5461     FontFamilyValueBuilder familyBuilder(list.get());
   5462     bool inFamily = false;
   5463 
   5464     while (value) {
   5465         CSSParserValue* nextValue = m_valueList->next();
   5466         bool nextValBreaksFont = !nextValue ||
   5467                                  (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
   5468         bool nextValIsFontName = nextValue &&
   5469             ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
   5470             (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
   5471 
   5472         bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault;
   5473         if (valueIsKeyword && !inFamily) {
   5474             if (nextValBreaksFont)
   5475                 value = m_valueList->next();
   5476             else if (nextValIsFontName)
   5477                 value = nextValue;
   5478             continue;
   5479         }
   5480 
   5481         if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
   5482             if (inFamily)
   5483                 familyBuilder.add(value->string);
   5484             else if (nextValBreaksFont || !nextValIsFontName)
   5485                 list->append(cssValuePool().createIdentifierValue(value->id));
   5486             else {
   5487                 familyBuilder.commit();
   5488                 familyBuilder.add(value->string);
   5489                 inFamily = true;
   5490             }
   5491         } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
   5492             // Strings never share in a family name.
   5493             inFamily = false;
   5494             familyBuilder.commit();
   5495             list->append(cssValuePool().createFontFamilyValue(value->string));
   5496         } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
   5497             if (inFamily)
   5498                 familyBuilder.add(value->string);
   5499             else if (nextValBreaksFont || !nextValIsFontName)
   5500                 list->append(cssValuePool().createFontFamilyValue(value->string));
   5501             else {
   5502                 familyBuilder.commit();
   5503                 familyBuilder.add(value->string);
   5504                 inFamily = true;
   5505             }
   5506         } else {
   5507             break;
   5508         }
   5509 
   5510         if (!nextValue)
   5511             break;
   5512 
   5513         if (nextValBreaksFont) {
   5514             value = m_valueList->next();
   5515             familyBuilder.commit();
   5516             inFamily = false;
   5517         }
   5518         else if (nextValIsFontName)
   5519             value = nextValue;
   5520         else
   5521             break;
   5522     }
   5523     familyBuilder.commit();
   5524 
   5525     if (!list->length())
   5526         list = 0;
   5527     return list.release();
   5528 }
   5529 
   5530 bool CSSParser::parseLineHeight(bool important)
   5531 {
   5532     CSSParserValue* value = m_valueList->current();
   5533     CSSValueID id = value->id;
   5534     bool validPrimitive = false;
   5535     // normal | <number> | <length> | <percentage> | inherit
   5536     if (id == CSSValueNormal)
   5537         validPrimitive = true;
   5538     else
   5539         validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
   5540     if (validPrimitive && (!m_valueList->next() || inShorthand()))
   5541         addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
   5542     return validPrimitive;
   5543 }
   5544 
   5545 bool CSSParser::parseFontSize(bool important)
   5546 {
   5547     CSSParserValue* value = m_valueList->current();
   5548     CSSValueID id = value->id;
   5549     bool validPrimitive = false;
   5550     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
   5551     if (id >= CSSValueXxSmall && id <= CSSValueLarger)
   5552         validPrimitive = true;
   5553     else
   5554         validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
   5555     if (validPrimitive && (!m_valueList->next() || inShorthand()))
   5556         addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
   5557     return validPrimitive;
   5558 }
   5559 
   5560 bool CSSParser::parseFontVariant(bool important)
   5561 {
   5562     RefPtr<CSSValueList> values;
   5563     if (m_valueList->size() > 1)
   5564         values = CSSValueList::createCommaSeparated();
   5565     CSSParserValue* val;
   5566     bool expectComma = false;
   5567     while ((val = m_valueList->current())) {
   5568         RefPtr<CSSPrimitiveValue> parsedValue;
   5569         if (!expectComma) {
   5570             expectComma = true;
   5571             if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
   5572                 parsedValue = cssValuePool().createIdentifierValue(val->id);
   5573             else if (val->id == CSSValueAll && !values) {
   5574                 // 'all' is only allowed in @font-face and with no other values. Make a value list to
   5575                 // indicate that we are in the @font-face case.
   5576                 values = CSSValueList::createCommaSeparated();
   5577                 parsedValue = cssValuePool().createIdentifierValue(val->id);
   5578             }
   5579         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   5580             expectComma = false;
   5581             m_valueList->next();
   5582             continue;
   5583         }
   5584 
   5585         if (!parsedValue)
   5586             return false;
   5587 
   5588         m_valueList->next();
   5589 
   5590         if (values)
   5591             values->append(parsedValue.release());
   5592         else {
   5593             addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
   5594             return true;
   5595         }
   5596     }
   5597 
   5598     if (values && values->length()) {
   5599         m_hasFontFaceOnlyValues = true;
   5600         addProperty(CSSPropertyFontVariant, values.release(), important);
   5601         return true;
   5602     }
   5603 
   5604     return false;
   5605 }
   5606 
   5607 bool CSSParser::parseFontWeight(bool important)
   5608 {
   5609     CSSParserValue* value = m_valueList->current();
   5610     if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
   5611         addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
   5612         return true;
   5613     }
   5614     if (validUnit(value, FInteger | FNonNeg, CSSQuirksMode)) {
   5615         int weight = static_cast<int>(value->fValue);
   5616         if (!(weight % 100) && weight >= 100 && weight <= 900) {
   5617             addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
   5618             return true;
   5619         }
   5620     }
   5621     return false;
   5622 }
   5623 
   5624 bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList)
   5625 {
   5626     RefPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
   5627 
   5628     CSSParserValue* value = m_valueList->next();
   5629     if (!value) {
   5630         valueList->append(uriValue.release());
   5631         return true;
   5632     }
   5633     if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
   5634         m_valueList->next();
   5635         valueList->append(uriValue.release());
   5636         return true;
   5637     }
   5638 
   5639     if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
   5640         return false;
   5641 
   5642     // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
   5643     // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
   5644     CSSParserValueList* args = value->function->args.get();
   5645     if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
   5646         return false;
   5647     uriValue->setFormat(args->current()->string);
   5648     valueList->append(uriValue.release());
   5649     value = m_valueList->next();
   5650     if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
   5651         m_valueList->next();
   5652     return true;
   5653 }
   5654 
   5655 bool CSSParser::parseFontFaceSrcLocal(CSSValueList* valueList)
   5656 {
   5657     CSSParserValueList* args = m_valueList->current()->function->args.get();
   5658     if (!args || !args->size())
   5659         return false;
   5660 
   5661     if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
   5662         valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
   5663     else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
   5664         StringBuilder builder;
   5665         for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
   5666             if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
   5667                 return false;
   5668             if (!builder.isEmpty())
   5669                 builder.append(' ');
   5670             builder.append(localValue->string);
   5671         }
   5672         valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
   5673     } else
   5674         return false;
   5675 
   5676     if (CSSParserValue* value = m_valueList->next()) {
   5677         if (value->unit == CSSParserValue::Operator && value->iValue == ',')
   5678             m_valueList->next();
   5679     }
   5680     return true;
   5681 }
   5682 
   5683 bool CSSParser::parseFontFaceSrc()
   5684 {
   5685     RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
   5686 
   5687     while (CSSParserValue* value = m_valueList->current()) {
   5688         if (value->unit == CSSPrimitiveValue::CSS_URI) {
   5689             if (!parseFontFaceSrcURI(values.get()))
   5690                 return false;
   5691         } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
   5692             if (!parseFontFaceSrcLocal(values.get()))
   5693                 return false;
   5694         } else
   5695             return false;
   5696     }
   5697     if (!values->length())
   5698         return false;
   5699 
   5700     addProperty(CSSPropertySrc, values.release(), m_important);
   5701     m_valueList->next();
   5702     return true;
   5703 }
   5704 
   5705 bool CSSParser::parseFontFaceUnicodeRange()
   5706 {
   5707     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   5708     bool failed = false;
   5709     bool operatorExpected = false;
   5710     for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
   5711         if (operatorExpected) {
   5712             if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
   5713                 continue;
   5714             failed = true;
   5715             break;
   5716         }
   5717         if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
   5718             failed = true;
   5719             break;
   5720         }
   5721 
   5722         String rangeString = m_valueList->current()->string;
   5723         UChar32 from = 0;
   5724         UChar32 to = 0;
   5725         unsigned length = rangeString.length();
   5726 
   5727         if (length < 3) {
   5728             failed = true;
   5729             break;
   5730         }
   5731 
   5732         unsigned i = 2;
   5733         while (i < length) {
   5734             UChar c = rangeString[i];
   5735             if (c == '-' || c == '?')
   5736                 break;
   5737             from *= 16;
   5738             if (c >= '0' && c <= '9')
   5739                 from += c - '0';
   5740             else if (c >= 'A' && c <= 'F')
   5741                 from += 10 + c - 'A';
   5742             else if (c >= 'a' && c <= 'f')
   5743                 from += 10 + c - 'a';
   5744             else {
   5745                 failed = true;
   5746                 break;
   5747             }
   5748             i++;
   5749         }
   5750         if (failed)
   5751             break;
   5752 
   5753         if (i == length)
   5754             to = from;
   5755         else if (rangeString[i] == '?') {
   5756             unsigned span = 1;
   5757             while (i < length && rangeString[i] == '?') {
   5758                 span *= 16;
   5759                 from *= 16;
   5760                 i++;
   5761             }
   5762             if (i < length)
   5763                 failed = true;
   5764             to = from + span - 1;
   5765         } else {
   5766             if (length < i + 2) {
   5767                 failed = true;
   5768                 break;
   5769             }
   5770             i++;
   5771             while (i < length) {
   5772                 UChar c = rangeString[i];
   5773                 to *= 16;
   5774                 if (c >= '0' && c <= '9')
   5775                     to += c - '0';
   5776                 else if (c >= 'A' && c <= 'F')
   5777                     to += 10 + c - 'A';
   5778                 else if (c >= 'a' && c <= 'f')
   5779                     to += 10 + c - 'a';
   5780                 else {
   5781                     failed = true;
   5782                     break;
   5783                 }
   5784                 i++;
   5785             }
   5786             if (failed)
   5787                 break;
   5788         }
   5789         if (from <= to)
   5790             values->append(CSSUnicodeRangeValue::create(from, to));
   5791     }
   5792     if (failed || !values->length())
   5793         return false;
   5794     addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
   5795     return true;
   5796 }
   5797 
   5798 // Returns the number of characters which form a valid double
   5799 // and are terminated by the given terminator character
   5800 template <typename CharacterType>
   5801 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
   5802 {
   5803     int length = end - string;
   5804     if (length < 1)
   5805         return 0;
   5806 
   5807     bool decimalMarkSeen = false;
   5808     int processedLength = 0;
   5809 
   5810     for (int i = 0; i < length; ++i) {
   5811         if (string[i] == terminator) {
   5812             processedLength = i;
   5813             break;
   5814         }
   5815         if (!isASCIIDigit(string[i])) {
   5816             if (!decimalMarkSeen && string[i] == '.')
   5817                 decimalMarkSeen = true;
   5818             else
   5819                 return 0;
   5820         }
   5821     }
   5822 
   5823     if (decimalMarkSeen && processedLength == 1)
   5824         return 0;
   5825 
   5826     return processedLength;
   5827 }
   5828 
   5829 // Returns the number of characters consumed for parsing a valid double
   5830 // terminated by the given terminator character
   5831 template <typename CharacterType>
   5832 static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
   5833 {
   5834     int length = checkForValidDouble(string, end, terminator);
   5835     if (!length)
   5836         return 0;
   5837 
   5838     int position = 0;
   5839     double localValue = 0;
   5840 
   5841     // The consumed characters here are guaranteed to be
   5842     // ASCII digits with or without a decimal mark
   5843     for (; position < length; ++position) {
   5844         if (string[position] == '.')
   5845             break;
   5846         localValue = localValue * 10 + string[position] - '0';
   5847     }
   5848 
   5849     if (++position == length) {
   5850         value = localValue;
   5851         return length;
   5852     }
   5853 
   5854     double fraction = 0;
   5855     double scale = 1;
   5856 
   5857     while (position < length && scale < MAX_SCALE) {
   5858         fraction = fraction * 10 + string[position++] - '0';
   5859         scale *= 10;
   5860     }
   5861 
   5862     value = localValue + fraction / scale;
   5863     return length;
   5864 }
   5865 
   5866 template <typename CharacterType>
   5867 static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
   5868 {
   5869     const CharacterType* current = string;
   5870     double localValue = 0;
   5871     bool negative = false;
   5872     while (current != end && isHTMLSpace(*current))
   5873         current++;
   5874     if (current != end && *current == '-') {
   5875         negative = true;
   5876         current++;
   5877     }
   5878     if (current == end || !isASCIIDigit(*current))
   5879         return false;
   5880     while (current != end && isASCIIDigit(*current)) {
   5881         double newValue = localValue * 10 + *current++ - '0';
   5882         if (newValue >= 255) {
   5883             // Clamp values at 255.
   5884             localValue = 255;
   5885             while (current != end && isASCIIDigit(*current))
   5886                 ++current;
   5887             break;
   5888         }
   5889         localValue = newValue;
   5890     }
   5891 
   5892     if (current == end)
   5893         return false;
   5894 
   5895     if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
   5896         return false;
   5897 
   5898     if (*current == '.') {
   5899         // We already parsed the integral part, try to parse
   5900         // the fraction part of the percentage value.
   5901         double percentage = 0;
   5902         int numCharactersParsed = parseDouble(current, end, '%', percentage);
   5903         if (!numCharactersParsed)
   5904             return false;
   5905         current += numCharactersParsed;
   5906         if (*current != '%')
   5907             return false;
   5908         localValue += percentage;
   5909     }
   5910 
   5911     if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
   5912         return false;
   5913 
   5914     if (*current == '%') {
   5915         expect = CSSPrimitiveValue::CSS_PERCENTAGE;
   5916         localValue = localValue / 100.0 * 256.0;
   5917         // Clamp values at 255 for percentages over 100%
   5918         if (localValue > 255)
   5919             localValue = 255;
   5920         current++;
   5921     } else
   5922         expect = CSSPrimitiveValue::CSS_NUMBER;
   5923 
   5924     while (current != end && isHTMLSpace(*current))
   5925         current++;
   5926     if (current == end || *current++ != terminator)
   5927         return false;
   5928     // Clamp negative values at zero.
   5929     value = negative ? 0 : static_cast<int>(localValue);
   5930     string = current;
   5931     return true;
   5932 }
   5933 
   5934 template <typename CharacterType>
   5935 static inline bool isTenthAlpha(const CharacterType* string, const int length)
   5936 {
   5937     // "0.X"
   5938     if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
   5939         return true;
   5940 
   5941     // ".X"
   5942     if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
   5943         return true;
   5944 
   5945     return false;
   5946 }
   5947 
   5948 template <typename CharacterType>
   5949 static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
   5950 {
   5951     while (string != end && isHTMLSpace(*string))
   5952         string++;
   5953 
   5954     bool negative = false;
   5955 
   5956     if (string != end && *string == '-') {
   5957         negative = true;
   5958         string++;
   5959     }
   5960 
   5961     value = 0;
   5962 
   5963     int length = end - string;
   5964     if (length < 2)
   5965         return false;
   5966 
   5967     if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
   5968         return false;
   5969 
   5970     if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
   5971         if (checkForValidDouble(string, end, terminator)) {
   5972             value = negative ? 0 : 255;
   5973             string = end;
   5974             return true;
   5975         }
   5976         return false;
   5977     }
   5978 
   5979     if (length == 2 && string[0] != '.') {
   5980         value = !negative && string[0] == '1' ? 255 : 0;
   5981         string = end;
   5982         return true;
   5983     }
   5984 
   5985     if (isTenthAlpha(string, length - 1)) {
   5986         static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
   5987         value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
   5988         string = end;
   5989         return true;
   5990     }
   5991 
   5992     double alpha = 0;
   5993     if (!parseDouble(string, end, terminator, alpha))
   5994         return false;
   5995     value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
   5996     string = end;
   5997     return true;
   5998 }
   5999 
   6000 template <typename CharacterType>
   6001 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
   6002 {
   6003     if (length < 5)
   6004         return false;
   6005     return characters[4] == '('
   6006         && isASCIIAlphaCaselessEqual(characters[0], 'r')
   6007         && isASCIIAlphaCaselessEqual(characters[1], 'g')
   6008         && isASCIIAlphaCaselessEqual(characters[2], 'b')
   6009         && isASCIIAlphaCaselessEqual(characters[3], 'a');
   6010 }
   6011 
   6012 template <typename CharacterType>
   6013 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
   6014 {
   6015     if (length < 4)
   6016         return false;
   6017     return characters[3] == '('
   6018         && isASCIIAlphaCaselessEqual(characters[0], 'r')
   6019         && isASCIIAlphaCaselessEqual(characters[1], 'g')
   6020         && isASCIIAlphaCaselessEqual(characters[2], 'b');
   6021 }
   6022 
   6023 template <typename CharacterType>
   6024 static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
   6025 {
   6026     CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN;
   6027 
   6028     if (!strict && length >= 3) {
   6029         if (characters[0] == '#') {
   6030             if (Color::parseHexColor(characters + 1, length - 1, rgb))
   6031                 return true;
   6032         } else {
   6033             if (Color::parseHexColor(characters, length, rgb))
   6034                 return true;
   6035         }
   6036     }
   6037 
   6038     // Try rgba() syntax.
   6039     if (mightBeRGBA(characters, length)) {
   6040         const CharacterType* current = characters + 5;
   6041         const CharacterType* end = characters + length;
   6042         int red;
   6043         int green;
   6044         int blue;
   6045         int alpha;
   6046 
   6047         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
   6048             return false;
   6049         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
   6050             return false;
   6051         if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
   6052             return false;
   6053         if (!parseAlphaValue(current, end, ')', alpha))
   6054             return false;
   6055         if (current != end)
   6056             return false;
   6057         rgb = makeRGBA(red, green, blue, alpha);
   6058         return true;
   6059     }
   6060 
   6061     // Try rgb() syntax.
   6062     if (mightBeRGB(characters, length)) {
   6063         const CharacterType* current = characters + 4;
   6064         const CharacterType* end = characters + length;
   6065         int red;
   6066         int green;
   6067         int blue;
   6068         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
   6069             return false;
   6070         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
   6071             return false;
   6072         if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
   6073             return false;
   6074         if (current != end)
   6075             return false;
   6076         rgb = makeRGB(red, green, blue);
   6077         return true;
   6078     }
   6079 
   6080     return false;
   6081 }
   6082 
   6083 template<typename StringType>
   6084 bool CSSParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
   6085 {
   6086     unsigned length = name.length();
   6087     bool parseResult;
   6088 
   6089     if (!length)
   6090         return false;
   6091 
   6092     if (name.is8Bit())
   6093         parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
   6094     else
   6095         parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
   6096 
   6097     if (parseResult)
   6098         return true;
   6099 
   6100     // Try named colors.
   6101     StyleColor color;
   6102     color.setNamedColor(name);
   6103     if (color.isValid()) {
   6104         rgb = color.rgb();
   6105         return true;
   6106     }
   6107     return false;
   6108 }
   6109 
   6110 inline double CSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc)
   6111 {
   6112     const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue;
   6113     if (releaseCalc == ReleaseParsedCalcValue)
   6114         m_parsedCalculation.release();
   6115     return result;
   6116 }
   6117 
   6118 bool CSSParser::isCalculation(CSSParserValue* value)
   6119 {
   6120     return (value->unit == CSSParserValue::Function)
   6121         && (equalIgnoringCase(value->function->name, "calc(")
   6122             || equalIgnoringCase(value->function->name, "-webkit-calc(")
   6123             || equalIgnoringCase(value->function->name, "-webkit-min(")
   6124             || equalIgnoringCase(value->function->name, "-webkit-max("));
   6125 }
   6126 
   6127 inline int CSSParser::colorIntFromValue(CSSParserValue* v)
   6128 {
   6129     bool isPercent;
   6130 
   6131     if (m_parsedCalculation)
   6132         isPercent = m_parsedCalculation->category() == CalcPercent;
   6133     else
   6134         isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
   6135 
   6136     const double value = parsedDouble(v, ReleaseParsedCalcValue);
   6137 
   6138     if (value <= 0.0)
   6139         return 0;
   6140 
   6141     if (isPercent) {
   6142         if (value >= 100.0)
   6143             return 255;
   6144         return static_cast<int>(value * 256.0 / 100.0);
   6145     }
   6146 
   6147     if (value >= 255.0)
   6148         return 255;
   6149 
   6150     return static_cast<int>(value);
   6151 }
   6152 
   6153 bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
   6154 {
   6155     CSSParserValueList* args = value->function->args.get();
   6156     CSSParserValue* v = args->current();
   6157     Units unitType = FUnknown;
   6158     // Get the first value and its type
   6159     if (validUnit(v, FInteger, CSSStrictMode))
   6160         unitType = FInteger;
   6161     else if (validUnit(v, FPercent, CSSStrictMode))
   6162         unitType = FPercent;
   6163     else
   6164         return false;
   6165 
   6166     colorArray[0] = colorIntFromValue(v);
   6167     for (int i = 1; i < 3; i++) {
   6168         v = args->next();
   6169         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   6170             return false;
   6171         v = args->next();
   6172         if (!validUnit(v, unitType, CSSStrictMode))
   6173             return false;
   6174         colorArray[i] = colorIntFromValue(v);
   6175     }
   6176     if (parseAlpha) {
   6177         v = args->next();
   6178         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   6179             return false;
   6180         v = args->next();
   6181         if (!validUnit(v, FNumber, CSSStrictMode))
   6182             return false;
   6183         const double value = parsedDouble(v, ReleaseParsedCalcValue);
   6184         // Convert the floating pointer number of alpha to an integer in the range [0, 256),
   6185         // with an equal distribution across all 256 values.
   6186         colorArray[3] = static_cast<int>(max(0.0, min(1.0, value)) * nextafter(256.0, 0.0));
   6187     }
   6188     return true;
   6189 }
   6190 
   6191 // The CSS3 specification defines the format of a HSL color as
   6192 // hsl(<number>, <percent>, <percent>)
   6193 // and with alpha, the format is
   6194 // hsla(<number>, <percent>, <percent>, <number>)
   6195 // The first value, HUE, is in an angle with a value between 0 and 360
   6196 bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
   6197 {
   6198     CSSParserValueList* args = value->function->args.get();
   6199     CSSParserValue* v = args->current();
   6200     // Get the first value
   6201     if (!validUnit(v, FNumber, CSSStrictMode))
   6202         return false;
   6203     // normalize the Hue value and change it to be between 0 and 1.0
   6204     colorArray[0] = (((static_cast<int>(parsedDouble(v, ReleaseParsedCalcValue)) % 360) + 360) % 360) / 360.0;
   6205     for (int i = 1; i < 3; i++) {
   6206         v = args->next();
   6207         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   6208             return false;
   6209         v = args->next();
   6210         if (!validUnit(v, FPercent, CSSStrictMode))
   6211             return false;
   6212         colorArray[i] = max(0.0, min(100.0, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0
   6213     }
   6214     if (parseAlpha) {
   6215         v = args->next();
   6216         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   6217             return false;
   6218         v = args->next();
   6219         if (!validUnit(v, FNumber, CSSStrictMode))
   6220             return false;
   6221         colorArray[3] = max(0.0, min(1.0, parsedDouble(v, ReleaseParsedCalcValue)));
   6222     }
   6223     return true;
   6224 }
   6225 
   6226 PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
   6227 {
   6228     RGBA32 c = Color::transparent;
   6229     if (!parseColorFromValue(value ? value : m_valueList->current(), c))
   6230         return 0;
   6231     return cssValuePool().createColorValue(c);
   6232 }
   6233 
   6234 bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
   6235 {
   6236     if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
   6237         && value->fValue >= 0. && value->fValue < 1000000.) {
   6238         String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
   6239         // FIXME: This should be strict parsing for SVG as well.
   6240         if (!fastParseColor(c, str, inStrictMode()))
   6241             return false;
   6242     } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
   6243                 value->unit == CSSPrimitiveValue::CSS_IDENT ||
   6244                 (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
   6245         if (!fastParseColor(c, value->string, inStrictMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
   6246             return false;
   6247     } else if (value->unit == CSSParserValue::Function &&
   6248                 value->function->args != 0 &&
   6249                 value->function->args->size() == 5 /* rgb + two commas */ &&
   6250                 equalIgnoringCase(value->function->name, "rgb(")) {
   6251         int colorValues[3];
   6252         if (!parseColorParameters(value, colorValues, false))
   6253             return false;
   6254         c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
   6255     } else {
   6256         if (value->unit == CSSParserValue::Function &&
   6257                 value->function->args != 0 &&
   6258                 value->function->args->size() == 7 /* rgba + three commas */ &&
   6259                 equalIgnoringCase(value->function->name, "rgba(")) {
   6260             int colorValues[4];
   6261             if (!parseColorParameters(value, colorValues, true))
   6262                 return false;
   6263             c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
   6264         } else if (value->unit == CSSParserValue::Function &&
   6265                     value->function->args != 0 &&
   6266                     value->function->args->size() == 5 /* hsl + two commas */ &&
   6267                     equalIgnoringCase(value->function->name, "hsl(")) {
   6268             double colorValues[3];
   6269             if (!parseHSLParameters(value, colorValues, false))
   6270                 return false;
   6271             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
   6272         } else if (value->unit == CSSParserValue::Function &&
   6273                     value->function->args != 0 &&
   6274                     value->function->args->size() == 7 /* hsla + three commas */ &&
   6275                     equalIgnoringCase(value->function->name, "hsla(")) {
   6276             double colorValues[4];
   6277             if (!parseHSLParameters(value, colorValues, true))
   6278                 return false;
   6279             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
   6280         } else
   6281             return false;
   6282     }
   6283 
   6284     return true;
   6285 }
   6286 
   6287 // This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
   6288 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
   6289 struct ShadowParseContext {
   6290     ShadowParseContext(CSSPropertyID prop, CSSParser* parser)
   6291         : property(prop)
   6292         , m_parser(parser)
   6293         , allowX(true)
   6294         , allowY(false)
   6295         , allowBlur(false)
   6296         , allowSpread(false)
   6297         , allowColor(true)
   6298         , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
   6299         , allowBreak(true)
   6300     {
   6301     }
   6302 
   6303     bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
   6304 
   6305     void commitValue()
   6306     {
   6307         // Handle the ,, case gracefully by doing nothing.
   6308         if (x || y || blur || spread || color || style) {
   6309             if (!values)
   6310                 values = CSSValueList::createCommaSeparated();
   6311 
   6312             // Construct the current shadow value and add it to the list.
   6313             values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
   6314         }
   6315 
   6316         // Now reset for the next shadow value.
   6317         x = 0;
   6318         y = 0;
   6319         blur = 0;
   6320         spread = 0;
   6321         style = 0;
   6322         color = 0;
   6323 
   6324         allowX = true;
   6325         allowColor = true;
   6326         allowBreak = true;
   6327         allowY = false;
   6328         allowBlur = false;
   6329         allowSpread = false;
   6330         allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   6331     }
   6332 
   6333     void commitLength(CSSParserValue* v)
   6334     {
   6335         RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
   6336 
   6337         if (allowX) {
   6338             x = val.release();
   6339             allowX = false;
   6340             allowY = true;
   6341             allowColor = false;
   6342             allowStyle = false;
   6343             allowBreak = false;
   6344         } else if (allowY) {
   6345             y = val.release();
   6346             allowY = false;
   6347             allowBlur = true;
   6348             allowColor = true;
   6349             allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   6350             allowBreak = true;
   6351         } else if (allowBlur) {
   6352             blur = val.release();
   6353             allowBlur = false;
   6354             allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   6355         } else if (allowSpread) {
   6356             spread = val.release();
   6357             allowSpread = false;
   6358         }
   6359     }
   6360 
   6361     void commitColor(PassRefPtr<CSSPrimitiveValue> val)
   6362     {
   6363         color = val;
   6364         allowColor = false;
   6365         if (allowX) {
   6366             allowStyle = false;
   6367             allowBreak = false;
   6368         } else {
   6369             allowBlur = false;
   6370             allowSpread = false;
   6371             allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   6372         }
   6373     }
   6374 
   6375     void commitStyle(CSSParserValue* v)
   6376     {
   6377         style = cssValuePool().createIdentifierValue(v->id);
   6378         allowStyle = false;
   6379         if (allowX)
   6380             allowBreak = false;
   6381         else {
   6382             allowBlur = false;
   6383             allowSpread = false;
   6384             allowColor = false;
   6385         }
   6386     }
   6387 
   6388     CSSPropertyID property;
   6389     CSSParser* m_parser;
   6390 
   6391     RefPtr<CSSValueList> values;
   6392     RefPtr<CSSPrimitiveValue> x;
   6393     RefPtr<CSSPrimitiveValue> y;
   6394     RefPtr<CSSPrimitiveValue> blur;
   6395     RefPtr<CSSPrimitiveValue> spread;
   6396     RefPtr<CSSPrimitiveValue> style;
   6397     RefPtr<CSSPrimitiveValue> color;
   6398 
   6399     bool allowX;
   6400     bool allowY;
   6401     bool allowBlur;
   6402     bool allowSpread;
   6403     bool allowColor;
   6404     bool allowStyle; // inset or not.
   6405     bool allowBreak;
   6406 };
   6407 
   6408 PassRefPtr<CSSValueList> CSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
   6409 {
   6410     ShadowParseContext context(propId, this);
   6411     CSSParserValue* val;
   6412     while ((val = valueList->current())) {
   6413         // Check for a comma break first.
   6414         if (val->unit == CSSParserValue::Operator) {
   6415             if (val->iValue != ',' || !context.allowBreak)
   6416                 // Other operators aren't legal or we aren't done with the current shadow
   6417                 // value.  Treat as invalid.
   6418                 return 0;
   6419             // The value is good.  Commit it.
   6420             context.commitValue();
   6421         } else if (validUnit(val, FLength, CSSStrictMode)) {
   6422             // We required a length and didn't get one. Invalid.
   6423             if (!context.allowLength())
   6424                 return 0;
   6425 
   6426             // Blur radius must be non-negative.
   6427             if (context.allowBlur && !validUnit(val, FLength | FNonNeg, CSSStrictMode))
   6428                 return 0;
   6429 
   6430             // A length is allowed here.  Construct the value and add it.
   6431             context.commitLength(val);
   6432         } else if (val->id == CSSValueInset) {
   6433             if (!context.allowStyle)
   6434                 return 0;
   6435 
   6436             context.commitStyle(val);
   6437         } else {
   6438             // The only other type of value that's ok is a color value.
   6439             RefPtr<CSSPrimitiveValue> parsedColor;
   6440             bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
   6441                             || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
   6442                             || val->id == CSSValueCurrentcolor);
   6443             if (isColor) {
   6444                 if (!context.allowColor)
   6445                     return 0;
   6446                 parsedColor = cssValuePool().createIdentifierValue(val->id);
   6447             }
   6448 
   6449             if (!parsedColor)
   6450                 // It's not built-in. Try to parse it as a color.
   6451                 parsedColor = parseColor(val);
   6452 
   6453             if (!parsedColor || !context.allowColor)
   6454                 return 0; // This value is not a color or length and is invalid or
   6455                           // it is a color, but a color isn't allowed at this point.
   6456 
   6457             context.commitColor(parsedColor.release());
   6458         }
   6459 
   6460         valueList->next();
   6461     }
   6462 
   6463     if (context.allowBreak) {
   6464         context.commitValue();
   6465         if (context.values && context.values->length())
   6466             return context.values.release();
   6467     }
   6468 
   6469     return 0;
   6470 }
   6471 
   6472 bool CSSParser::parseReflect(CSSPropertyID propId, bool important)
   6473 {
   6474     // box-reflect: <direction> <offset> <mask>
   6475 
   6476     // Direction comes first.
   6477     CSSParserValue* val = m_valueList->current();
   6478     RefPtr<CSSPrimitiveValue> direction;
   6479     if (val->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
   6480         direction = createPrimitiveVariableNameValue(val);
   6481     else
   6482     switch (val->id) {
   6483         case CSSValueAbove:
   6484         case CSSValueBelow:
   6485         case CSSValueLeft:
   6486         case CSSValueRight:
   6487             direction = cssValuePool().createIdentifierValue(val->id);
   6488             break;
   6489         default:
   6490             return false;
   6491     }
   6492 
   6493     // The offset comes next.
   6494     val = m_valueList->next();
   6495     RefPtr<CSSPrimitiveValue> offset;
   6496     if (!val)
   6497         offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
   6498     else {
   6499         if (!validUnit(val, FLength | FPercent))
   6500             return false;
   6501         offset = createPrimitiveNumericValue(val);
   6502     }
   6503 
   6504     // Now for the mask.
   6505     RefPtr<CSSValue> mask;
   6506     val = m_valueList->next();
   6507     if (val) {
   6508         if (!parseBorderImage(propId, mask))
   6509             return false;
   6510     }
   6511 
   6512     RefPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release());
   6513     addProperty(propId, reflectValue.release(), important);
   6514     m_valueList->next();
   6515     return true;
   6516 }
   6517 
   6518 bool CSSParser::parseFlex(CSSParserValueList* args, bool important)
   6519 {
   6520     if (!args || !args->size() || args->size() > 3)
   6521         return false;
   6522     static const double unsetValue = -1;
   6523     double flexGrow = unsetValue;
   6524     double flexShrink = unsetValue;
   6525     RefPtr<CSSPrimitiveValue> flexBasis;
   6526 
   6527     while (CSSParserValue* arg = args->current()) {
   6528         if (validUnit(arg, FNumber | FNonNeg)) {
   6529             if (flexGrow == unsetValue)
   6530                 flexGrow = arg->fValue;
   6531             else if (flexShrink == unsetValue)
   6532                 flexShrink = arg->fValue;
   6533             else if (!arg->fValue) {
   6534                 // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
   6535                 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
   6536             } else {
   6537                 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
   6538                 return false;
   6539             }
   6540         } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
   6541             flexBasis = parseValidPrimitive(arg->id, arg);
   6542         else {
   6543             // Not a valid arg for flex.
   6544             return false;
   6545         }
   6546         args->next();
   6547     }
   6548 
   6549     if (flexGrow == unsetValue)
   6550         flexGrow = 1;
   6551     if (flexShrink == unsetValue)
   6552         flexShrink = 1;
   6553     if (!flexBasis)
   6554         flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
   6555 
   6556     addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
   6557     addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
   6558     addProperty(CSSPropertyFlexBasis, flexBasis, important);
   6559     return true;
   6560 }
   6561 
   6562 struct BorderImageParseContext {
   6563     BorderImageParseContext()
   6564     : m_canAdvance(false)
   6565     , m_allowCommit(true)
   6566     , m_allowImage(true)
   6567     , m_allowImageSlice(true)
   6568     , m_allowRepeat(true)
   6569     , m_allowForwardSlashOperator(false)
   6570     , m_requireWidth(false)
   6571     , m_requireOutset(false)
   6572     {}
   6573 
   6574     bool canAdvance() const { return m_canAdvance; }
   6575     void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
   6576 
   6577     bool allowCommit() const { return m_allowCommit; }
   6578     bool allowImage() const { return m_allowImage; }
   6579     bool allowImageSlice() const { return m_allowImageSlice; }
   6580     bool allowRepeat() const { return m_allowRepeat; }
   6581     bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
   6582 
   6583     bool requireWidth() const { return m_requireWidth; }
   6584     bool requireOutset() const { return m_requireOutset; }
   6585 
   6586     void commitImage(PassRefPtr<CSSValue> image)
   6587     {
   6588         m_image = image;
   6589         m_canAdvance = true;
   6590         m_allowCommit = true;
   6591         m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
   6592         m_allowImageSlice = !m_imageSlice;
   6593         m_allowRepeat = !m_repeat;
   6594     }
   6595     void commitImageSlice(PassRefPtr<CSSBorderImageSliceValue> slice)
   6596     {
   6597         m_imageSlice = slice;
   6598         m_canAdvance = true;
   6599         m_allowCommit = m_allowForwardSlashOperator = true;
   6600         m_allowImageSlice = m_requireWidth = m_requireOutset = false;
   6601         m_allowImage = !m_image;
   6602         m_allowRepeat = !m_repeat;
   6603     }
   6604     void commitForwardSlashOperator()
   6605     {
   6606         m_canAdvance = true;
   6607         m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
   6608         if (!m_borderSlice) {
   6609             m_requireWidth = true;
   6610             m_requireOutset = false;
   6611         } else {
   6612             m_requireOutset = true;
   6613             m_requireWidth = false;
   6614         }
   6615     }
   6616     void commitBorderWidth(PassRefPtr<CSSPrimitiveValue> slice)
   6617     {
   6618         m_borderSlice = slice;
   6619         m_canAdvance = true;
   6620         m_allowCommit = m_allowForwardSlashOperator = true;
   6621         m_allowImageSlice = m_requireWidth = m_requireOutset = false;
   6622         m_allowImage = !m_image;
   6623         m_allowRepeat = !m_repeat;
   6624     }
   6625     void commitBorderOutset(PassRefPtr<CSSPrimitiveValue> outset)
   6626     {
   6627         m_outset = outset;
   6628         m_canAdvance = true;
   6629         m_allowCommit = true;
   6630         m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
   6631         m_allowImage = !m_image;
   6632         m_allowRepeat = !m_repeat;
   6633     }
   6634     void commitRepeat(PassRefPtr<CSSValue> repeat)
   6635     {
   6636         m_repeat = repeat;
   6637         m_canAdvance = true;
   6638         m_allowCommit = true;
   6639         m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
   6640         m_allowImageSlice = !m_imageSlice;
   6641         m_allowImage = !m_image;
   6642     }
   6643 
   6644     PassRefPtr<CSSValue> commitWebKitBorderImage()
   6645     {
   6646         return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat);
   6647     }
   6648 
   6649     void commitBorderImage(CSSParser* parser, bool important)
   6650     {
   6651         commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
   6652         commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important);
   6653         commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice, important);
   6654         commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset, important);
   6655         commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
   6656     }
   6657 
   6658     void commitBorderImageProperty(CSSPropertyID propId, CSSParser* parser, PassRefPtr<CSSValue> value, bool important)
   6659     {
   6660         if (value)
   6661             parser->addProperty(propId, value, important);
   6662         else
   6663             parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
   6664     }
   6665 
   6666     bool m_canAdvance;
   6667 
   6668     bool m_allowCommit;
   6669     bool m_allowImage;
   6670     bool m_allowImageSlice;
   6671     bool m_allowRepeat;
   6672     bool m_allowForwardSlashOperator;
   6673 
   6674     bool m_requireWidth;
   6675     bool m_requireOutset;
   6676 
   6677     RefPtr<CSSValue> m_image;
   6678     RefPtr<CSSBorderImageSliceValue> m_imageSlice;
   6679     RefPtr<CSSPrimitiveValue> m_borderSlice;
   6680     RefPtr<CSSPrimitiveValue> m_outset;
   6681 
   6682     RefPtr<CSSValue> m_repeat;
   6683 };
   6684 
   6685 bool CSSParser::parseBorderImage(CSSPropertyID propId, RefPtr<CSSValue>& result, bool important)
   6686 {
   6687     ShorthandScope scope(this, propId);
   6688     BorderImageParseContext context;
   6689     while (CSSParserValue* val = m_valueList->current()) {
   6690         context.setCanAdvance(false);
   6691 
   6692         if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
   6693             context.commitForwardSlashOperator();
   6694 
   6695         if (!context.canAdvance() && context.allowImage()) {
   6696             if (val->unit == CSSPrimitiveValue::CSS_URI)
   6697                 context.commitImage(CSSImageValue::create(completeURL(val->string)));
   6698             else if (isGeneratedImageValue(val)) {
   6699                 RefPtr<CSSValue> value;
   6700                 if (parseGeneratedImage(m_valueList.get(), value))
   6701                     context.commitImage(value.release());
   6702                 else
   6703                     return false;
   6704             } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
   6705                 RefPtr<CSSValue> value = parseImageSet(m_valueList.get());
   6706                 if (value)
   6707                     context.commitImage(value.release());
   6708                 else
   6709                     return false;
   6710             } else if (val->id == CSSValueNone)
   6711                 context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
   6712         }
   6713 
   6714         if (!context.canAdvance() && context.allowImageSlice()) {
   6715             RefPtr<CSSBorderImageSliceValue> imageSlice;
   6716             if (parseBorderImageSlice(propId, imageSlice))
   6717                 context.commitImageSlice(imageSlice.release());
   6718         }
   6719 
   6720         if (!context.canAdvance() && context.allowRepeat()) {
   6721             RefPtr<CSSValue> repeat;
   6722             if (parseBorderImageRepeat(repeat))
   6723                 context.commitRepeat(repeat.release());
   6724         }
   6725 
   6726         if (!context.canAdvance() && context.requireWidth()) {
   6727             RefPtr<CSSPrimitiveValue> borderSlice;
   6728             if (parseBorderImageWidth(borderSlice))
   6729                 context.commitBorderWidth(borderSlice.release());
   6730         }
   6731 
   6732         if (!context.canAdvance() && context.requireOutset()) {
   6733             RefPtr<CSSPrimitiveValue> borderOutset;
   6734             if (parseBorderImageOutset(borderOutset))
   6735                 context.commitBorderOutset(borderOutset.release());
   6736         }
   6737 
   6738         if (!context.canAdvance())
   6739             return false;
   6740 
   6741         m_valueList->next();
   6742     }
   6743 
   6744     if (context.allowCommit()) {
   6745         if (propId == CSSPropertyBorderImage)
   6746             context.commitBorderImage(this, important);
   6747         else
   6748             // Need to fully commit as a single value.
   6749             result = context.commitWebKitBorderImage();
   6750         return true;
   6751     }
   6752 
   6753     return false;
   6754 }
   6755 
   6756 static bool isBorderImageRepeatKeyword(int id)
   6757 {
   6758     return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
   6759 }
   6760 
   6761 bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result)
   6762 {
   6763     RefPtr<CSSPrimitiveValue> firstValue;
   6764     RefPtr<CSSPrimitiveValue> secondValue;
   6765     CSSParserValue* val = m_valueList->current();
   6766     if (!val)
   6767         return false;
   6768     if (isBorderImageRepeatKeyword(val->id))
   6769         firstValue = cssValuePool().createIdentifierValue(val->id);
   6770     else
   6771         return false;
   6772 
   6773     val = m_valueList->next();
   6774     if (val) {
   6775         if (isBorderImageRepeatKeyword(val->id))
   6776             secondValue = cssValuePool().createIdentifierValue(val->id);
   6777         else if (!inShorthand()) {
   6778             // If we're not parsing a shorthand then we are invalid.
   6779             return false;
   6780         } else {
   6781             // We need to rewind the value list, so that when its advanced we'll
   6782             // end up back at this value.
   6783             m_valueList->previous();
   6784             secondValue = firstValue;
   6785         }
   6786     } else
   6787         secondValue = firstValue;
   6788 
   6789     result = createPrimitiveValuePair(firstValue, secondValue);
   6790     return true;
   6791 }
   6792 
   6793 class BorderImageSliceParseContext {
   6794 public:
   6795     BorderImageSliceParseContext(CSSParser* parser)
   6796     : m_parser(parser)
   6797     , m_allowNumber(true)
   6798     , m_allowFill(true)
   6799     , m_allowFinalCommit(false)
   6800     , m_fill(false)
   6801     { }
   6802 
   6803     bool allowNumber() const { return m_allowNumber; }
   6804     bool allowFill() const { return m_allowFill; }
   6805     bool allowFinalCommit() const { return m_allowFinalCommit; }
   6806     CSSPrimitiveValue* top() const { return m_top.get(); }
   6807 
   6808     void commitNumber(CSSParserValue* v)
   6809     {
   6810         RefPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
   6811         if (!m_top)
   6812             m_top = val;
   6813         else if (!m_right)
   6814             m_right = val;
   6815         else if (!m_bottom)
   6816             m_bottom = val;
   6817         else {
   6818             ASSERT(!m_left);
   6819             m_left = val;
   6820         }
   6821 
   6822         m_allowNumber = !m_left;
   6823         m_allowFinalCommit = true;
   6824     }
   6825 
   6826     void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
   6827 
   6828     PassRefPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
   6829     {
   6830         // We need to clone and repeat values for any omissions.
   6831         ASSERT(m_top);
   6832         if (!m_right) {
   6833             m_right = m_top;
   6834             m_bottom = m_top;
   6835             m_left = m_top;
   6836         }
   6837         if (!m_bottom) {
   6838             m_bottom = m_top;
   6839             m_left = m_right;
   6840         }
   6841         if (!m_left)
   6842             m_left = m_right;
   6843 
   6844         // Now build a rect value to hold all four of our primitive values.
   6845         RefPtr<Quad> quad = Quad::create();
   6846         quad->setTop(m_top);
   6847         quad->setRight(m_right);
   6848         quad->setBottom(m_bottom);
   6849         quad->setLeft(m_left);
   6850 
   6851         // Make our new border image value now.
   6852         return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
   6853     }
   6854 
   6855 private:
   6856     CSSParser* m_parser;
   6857 
   6858     bool m_allowNumber;
   6859     bool m_allowFill;
   6860     bool m_allowFinalCommit;
   6861 
   6862     RefPtr<CSSPrimitiveValue> m_top;
   6863     RefPtr<CSSPrimitiveValue> m_right;
   6864     RefPtr<CSSPrimitiveValue> m_bottom;
   6865     RefPtr<CSSPrimitiveValue> m_left;
   6866 
   6867     bool m_fill;
   6868 };
   6869 
   6870 bool CSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr<CSSBorderImageSliceValue>& result)
   6871 {
   6872     BorderImageSliceParseContext context(this);
   6873     CSSParserValue* val;
   6874     while ((val = m_valueList->current())) {
   6875         // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
   6876         if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, CSSStrictMode)) {
   6877             context.commitNumber(val);
   6878         } else if (context.allowFill() && val->id == CSSValueFill)
   6879             context.commitFill();
   6880         else if (!inShorthand()) {
   6881             // If we're not parsing a shorthand then we are invalid.
   6882             return false;
   6883         } else {
   6884             if (context.allowFinalCommit()) {
   6885                 // We're going to successfully parse, but we don't want to consume this token.
   6886                 m_valueList->previous();
   6887             }
   6888             break;
   6889         }
   6890         m_valueList->next();
   6891     }
   6892 
   6893     if (context.allowFinalCommit()) {
   6894         // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
   6895         // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
   6896         if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
   6897             context.commitFill();
   6898 
   6899         // Need to fully commit as a single value.
   6900         result = context.commitBorderImageSlice();
   6901         return true;
   6902     }
   6903 
   6904     return false;
   6905 }
   6906 
   6907 class BorderImageQuadParseContext {
   6908 public:
   6909     BorderImageQuadParseContext(CSSParser* parser)
   6910     : m_parser(parser)
   6911     , m_allowNumber(true)
   6912     , m_allowFinalCommit(false)
   6913     { }
   6914 
   6915     bool allowNumber() const { return m_allowNumber; }
   6916     bool allowFinalCommit() const { return m_allowFinalCommit; }
   6917     CSSPrimitiveValue* top() const { return m_top.get(); }
   6918 
   6919     void commitNumber(CSSParserValue* v)
   6920     {
   6921         RefPtr<CSSPrimitiveValue> val;
   6922         if (v->id == CSSValueAuto)
   6923             val = cssValuePool().createIdentifierValue(v->id);
   6924         else
   6925             val = m_parser->createPrimitiveNumericValue(v);
   6926 
   6927         if (!m_top)
   6928             m_top = val;
   6929         else if (!m_right)
   6930             m_right = val;
   6931         else if (!m_bottom)
   6932             m_bottom = val;
   6933         else {
   6934             ASSERT(!m_left);
   6935             m_left = val;
   6936         }
   6937 
   6938         m_allowNumber = !m_left;
   6939         m_allowFinalCommit = true;
   6940     }
   6941 
   6942     void setAllowFinalCommit() { m_allowFinalCommit = true; }
   6943     void setTop(PassRefPtr<CSSPrimitiveValue> val) { m_top = val; }
   6944 
   6945     PassRefPtr<CSSPrimitiveValue> commitBorderImageQuad()
   6946     {
   6947         // We need to clone and repeat values for any omissions.
   6948         ASSERT(m_top);
   6949         if (!m_right) {
   6950             m_right = m_top;
   6951             m_bottom = m_top;
   6952             m_left = m_top;
   6953         }
   6954         if (!m_bottom) {
   6955             m_bottom = m_top;
   6956             m_left = m_right;
   6957         }
   6958         if (!m_left)
   6959             m_left = m_right;
   6960 
   6961         // Now build a quad value to hold all four of our primitive values.
   6962         RefPtr<Quad> quad = Quad::create();
   6963         quad->setTop(m_top);
   6964         quad->setRight(m_right);
   6965         quad->setBottom(m_bottom);
   6966         quad->setLeft(m_left);
   6967 
   6968         // Make our new value now.
   6969         return cssValuePool().createValue(quad.release());
   6970     }
   6971 
   6972 private:
   6973     CSSParser* m_parser;
   6974 
   6975     bool m_allowNumber;
   6976     bool m_allowFinalCommit;
   6977 
   6978     RefPtr<CSSPrimitiveValue> m_top;
   6979     RefPtr<CSSPrimitiveValue> m_right;
   6980     RefPtr<CSSPrimitiveValue> m_bottom;
   6981     RefPtr<CSSPrimitiveValue> m_left;
   6982 };
   6983 
   6984 bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>& result)
   6985 {
   6986     BorderImageQuadParseContext context(this);
   6987     CSSParserValue* val;
   6988     while ((val = m_valueList->current())) {
   6989         if (context.allowNumber() && (validUnit(val, validUnits, CSSStrictMode) || val->id == CSSValueAuto)) {
   6990             context.commitNumber(val);
   6991         } else if (!inShorthand()) {
   6992             // If we're not parsing a shorthand then we are invalid.
   6993             return false;
   6994         } else {
   6995             if (context.allowFinalCommit())
   6996                 m_valueList->previous(); // The shorthand loop will advance back to this point.
   6997             break;
   6998         }
   6999         m_valueList->next();
   7000     }
   7001 
   7002     if (context.allowFinalCommit()) {
   7003         // Need to fully commit as a single value.
   7004         result = context.commitBorderImageQuad();
   7005         return true;
   7006     }
   7007     return false;
   7008 }
   7009 
   7010 bool CSSParser::parseBorderImageWidth(RefPtr<CSSPrimitiveValue>& result)
   7011 {
   7012     return parseBorderImageQuad(FLength | FInteger | FNonNeg | FPercent, result);
   7013 }
   7014 
   7015 bool CSSParser::parseBorderImageOutset(RefPtr<CSSPrimitiveValue>& result)
   7016 {
   7017     return parseBorderImageQuad(FLength | FInteger | FNonNeg, result);
   7018 }
   7019 
   7020 static void completeBorderRadii(RefPtr<CSSPrimitiveValue> radii[4])
   7021 {
   7022     if (radii[3])
   7023         return;
   7024     if (!radii[2]) {
   7025         if (!radii[1])
   7026             radii[1] = radii[0];
   7027         radii[2] = radii[0];
   7028     }
   7029     radii[3] = radii[1];
   7030 }
   7031 
   7032 bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important)
   7033 {
   7034     unsigned num = m_valueList->size();
   7035     if (num > 9)
   7036         return false;
   7037 
   7038     ShorthandScope scope(this, propId);
   7039     RefPtr<CSSPrimitiveValue> radii[2][4];
   7040 
   7041     unsigned indexAfterSlash = 0;
   7042     for (unsigned i = 0; i < num; ++i) {
   7043         CSSParserValue* value = m_valueList->valueAt(i);
   7044         if (value->unit == CSSParserValue::Operator) {
   7045             if (value->iValue != '/')
   7046                 return false;
   7047 
   7048             if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
   7049                 return false;
   7050 
   7051             indexAfterSlash = i + 1;
   7052             completeBorderRadii(radii[0]);
   7053             continue;
   7054         }
   7055 
   7056         if (i - indexAfterSlash >= 4)
   7057             return false;
   7058 
   7059         if (!validUnit(value, FLength | FPercent | FNonNeg))
   7060             return false;
   7061 
   7062         RefPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
   7063 
   7064         if (!indexAfterSlash) {
   7065             radii[0][i] = radius;
   7066 
   7067             // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
   7068             if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
   7069                 indexAfterSlash = 1;
   7070                 completeBorderRadii(radii[0]);
   7071             }
   7072         } else
   7073             radii[1][i - indexAfterSlash] = radius.release();
   7074     }
   7075 
   7076     if (!indexAfterSlash) {
   7077         completeBorderRadii(radii[0]);
   7078         for (unsigned i = 0; i < 4; ++i)
   7079             radii[1][i] = radii[0][i];
   7080     } else
   7081         completeBorderRadii(radii[1]);
   7082 
   7083     ImplicitScope implicitScope(this, PropertyImplicit);
   7084     addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
   7085     addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
   7086     addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
   7087     addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
   7088     return true;
   7089 }
   7090 
   7091 bool CSSParser::parseAspectRatio(bool important)
   7092 {
   7093     unsigned num = m_valueList->size();
   7094     if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
   7095         addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
   7096         return true;
   7097     }
   7098 
   7099     if (num != 3)
   7100         return false;
   7101 
   7102     CSSParserValue* lvalue = m_valueList->valueAt(0);
   7103     CSSParserValue* op = m_valueList->valueAt(1);
   7104     CSSParserValue* rvalue = m_valueList->valueAt(2);
   7105 
   7106     if (!isForwardSlashOperator(op))
   7107         return false;
   7108 
   7109     if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
   7110         return false;
   7111 
   7112     if (!lvalue->fValue || !rvalue->fValue)
   7113         return false;
   7114 
   7115     addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
   7116 
   7117     return true;
   7118 }
   7119 
   7120 bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
   7121 {
   7122     enum { ID, VAL } state = ID;
   7123 
   7124     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   7125     RefPtr<CSSPrimitiveValue> counterName;
   7126 
   7127     while (true) {
   7128         CSSParserValue* val = m_valueList->current();
   7129         switch (state) {
   7130             case ID:
   7131                 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
   7132                     counterName = createPrimitiveStringValue(val);
   7133                     state = VAL;
   7134                     m_valueList->next();
   7135                     continue;
   7136                 }
   7137                 break;
   7138             case VAL: {
   7139                 int i = defaultValue;
   7140                 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
   7141                     i = clampToInteger(val->fValue);
   7142                     m_valueList->next();
   7143                 }
   7144 
   7145                 list->append(createPrimitiveValuePair(counterName.release(),
   7146                     cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
   7147                 state = ID;
   7148                 continue;
   7149             }
   7150         }
   7151         break;
   7152     }
   7153 
   7154     if (list->length() > 0) {
   7155         addProperty(propId, list.release(), important);
   7156         return true;
   7157     }
   7158 
   7159     return false;
   7160 }
   7161 
   7162 // This should go away once we drop support for -webkit-gradient
   7163 static PassRefPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
   7164 {
   7165     RefPtr<CSSPrimitiveValue> result;
   7166     if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
   7167         if ((equalIgnoringCase(a, "left") && horizontal)
   7168             || (equalIgnoringCase(a, "top") && !horizontal))
   7169             result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
   7170         else if ((equalIgnoringCase(a, "right") && horizontal)
   7171                  || (equalIgnoringCase(a, "bottom") && !horizontal))
   7172             result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
   7173         else if (equalIgnoringCase(a, "center"))
   7174             result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
   7175     } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
   7176         result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(a->unit));
   7177     return result;
   7178 }
   7179 
   7180 static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
   7181 {
   7182     if (a->unit != CSSParserValue::Function)
   7183         return false;
   7184 
   7185     if (!equalIgnoringCase(a->function->name, "from(") &&
   7186         !equalIgnoringCase(a->function->name, "to(") &&
   7187         !equalIgnoringCase(a->function->name, "color-stop("))
   7188         return false;
   7189 
   7190     CSSParserValueList* args = a->function->args.get();
   7191     if (!args)
   7192         return false;
   7193 
   7194     if (equalIgnoringCase(a->function->name, "from(")
   7195         || equalIgnoringCase(a->function->name, "to(")) {
   7196         // The "from" and "to" stops expect 1 argument.
   7197         if (args->size() != 1)
   7198             return false;
   7199 
   7200         if (equalIgnoringCase(a->function->name, "from("))
   7201             stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
   7202         else
   7203             stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
   7204 
   7205         CSSValueID id = args->current()->id;
   7206         if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
   7207             stop.m_color = cssValuePool().createIdentifierValue(id);
   7208         else
   7209             stop.m_color = p->parseColor(args->current());
   7210         if (!stop.m_color)
   7211             return false;
   7212     }
   7213 
   7214     // The "color-stop" function expects 3 arguments.
   7215     if (equalIgnoringCase(a->function->name, "color-stop(")) {
   7216         if (args->size() != 3)
   7217             return false;
   7218 
   7219         CSSParserValue* stopArg = args->current();
   7220         if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
   7221             stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
   7222         else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
   7223             stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
   7224         else
   7225             return false;
   7226 
   7227         stopArg = args->next();
   7228         if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
   7229             return false;
   7230 
   7231         stopArg = args->next();
   7232         CSSValueID id = stopArg->id;
   7233         if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
   7234             stop.m_color = cssValuePool().createIdentifierValue(id);
   7235         else
   7236             stop.m_color = p->parseColor(stopArg);
   7237         if (!stop.m_color)
   7238             return false;
   7239     }
   7240 
   7241     return true;
   7242 }
   7243 
   7244 bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient)
   7245 {
   7246     // Walk the arguments.
   7247     CSSParserValueList* args = valueList->current()->function->args.get();
   7248     if (!args || args->size() == 0)
   7249         return false;
   7250 
   7251     // The first argument is the gradient type.  It is an identifier.
   7252     CSSGradientType gradientType;
   7253     CSSParserValue* a = args->current();
   7254     if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
   7255         return false;
   7256     if (equalIgnoringCase(a, "linear"))
   7257         gradientType = CSSDeprecatedLinearGradient;
   7258     else if (equalIgnoringCase(a, "radial"))
   7259         gradientType = CSSDeprecatedRadialGradient;
   7260     else
   7261         return false;
   7262 
   7263     RefPtr<CSSGradientValue> result;
   7264     switch (gradientType) {
   7265     case CSSDeprecatedLinearGradient:
   7266         result = CSSLinearGradientValue::create(NonRepeating, gradientType);
   7267         break;
   7268     case CSSDeprecatedRadialGradient:
   7269         result = CSSRadialGradientValue::create(NonRepeating, gradientType);
   7270         break;
   7271     default:
   7272         // The rest of the gradient types shouldn't appear here.
   7273         ASSERT_NOT_REACHED();
   7274     }
   7275 
   7276     // Comma.
   7277     a = args->next();
   7278     if (!isComma(a))
   7279         return false;
   7280 
   7281     // Next comes the starting point for the gradient as an x y pair.  There is no
   7282     // comma between the x and the y values.
   7283     // First X.  It can be left, right, number or percent.
   7284     a = args->next();
   7285     if (!a)
   7286         return false;
   7287     RefPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
   7288     if (!point)
   7289         return false;
   7290     result->setFirstX(point.release());
   7291 
   7292     // First Y.  It can be top, bottom, number or percent.
   7293     a = args->next();
   7294     if (!a)
   7295         return false;
   7296     point = parseDeprecatedGradientPoint(a, false);
   7297     if (!point)
   7298         return false;
   7299     result->setFirstY(point.release());
   7300 
   7301     // Comma after the first point.
   7302     a = args->next();
   7303     if (!isComma(a))
   7304         return false;
   7305 
   7306     // For radial gradients only, we now expect a numeric radius.
   7307     if (gradientType == CSSDeprecatedRadialGradient) {
   7308         a = args->next();
   7309         if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
   7310             return false;
   7311         static_cast<CSSRadialGradientValue*>(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
   7312 
   7313         // Comma after the first radius.
   7314         a = args->next();
   7315         if (!isComma(a))
   7316             return false;
   7317     }
   7318 
   7319     // Next is the ending point for the gradient as an x, y pair.
   7320     // Second X.  It can be left, right, number or percent.
   7321     a = args->next();
   7322     if (!a)
   7323         return false;
   7324     point = parseDeprecatedGradientPoint(a, true);
   7325     if (!point)
   7326         return false;
   7327     result->setSecondX(point.release());
   7328 
   7329     // Second Y.  It can be top, bottom, number or percent.
   7330     a = args->next();
   7331     if (!a)
   7332         return false;
   7333     point = parseDeprecatedGradientPoint(a, false);
   7334     if (!point)
   7335         return false;
   7336     result->setSecondY(point.release());
   7337 
   7338     // For radial gradients only, we now expect the second radius.
   7339     if (gradientType == CSSDeprecatedRadialGradient) {
   7340         // Comma after the second point.
   7341         a = args->next();
   7342         if (!isComma(a))
   7343             return false;
   7344 
   7345         a = args->next();
   7346         if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
   7347             return false;
   7348         static_cast<CSSRadialGradientValue*>(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
   7349     }
   7350 
   7351     // We now will accept any number of stops (0 or more).
   7352     a = args->next();
   7353     while (a) {
   7354         // Look for the comma before the next stop.
   7355         if (!isComma(a))
   7356             return false;
   7357 
   7358         // Now examine the stop itself.
   7359         a = args->next();
   7360         if (!a)
   7361             return false;
   7362 
   7363         // The function name needs to be one of "from", "to", or "color-stop."
   7364         CSSGradientColorStop stop;
   7365         if (!parseDeprecatedGradientColorStop(this, a, stop))
   7366             return false;
   7367         result->addStop(stop);
   7368 
   7369         // Advance
   7370         a = args->next();
   7371     }
   7372 
   7373     gradient = result.release();
   7374     return true;
   7375 }
   7376 
   7377 static PassRefPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
   7378 {
   7379     if (a->unit != CSSPrimitiveValue::CSS_IDENT)
   7380         return 0;
   7381 
   7382     switch (a->id) {
   7383         case CSSValueLeft:
   7384         case CSSValueRight:
   7385             isHorizontal = true;
   7386             break;
   7387         case CSSValueTop:
   7388         case CSSValueBottom:
   7389             isHorizontal = false;
   7390             break;
   7391         default:
   7392             return 0;
   7393     }
   7394     return cssValuePool().createIdentifierValue(a->id);
   7395 }
   7396 
   7397 static PassRefPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value)
   7398 {
   7399     CSSValueID id = value->id;
   7400     if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
   7401         return cssValuePool().createIdentifierValue(id);
   7402 
   7403     return p->parseColor(value);
   7404 }
   7405 
   7406 bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   7407 {
   7408     RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
   7409 
   7410     // Walk the arguments.
   7411     CSSParserValueList* args = valueList->current()->function->args.get();
   7412     if (!args || !args->size())
   7413         return false;
   7414 
   7415     CSSParserValue* a = args->current();
   7416     if (!a)
   7417         return false;
   7418 
   7419     bool expectComma = false;
   7420     // Look for angle.
   7421     if (validUnit(a, FAngle, CSSStrictMode)) {
   7422         result->setAngle(createPrimitiveNumericValue(a));
   7423 
   7424         args->next();
   7425         expectComma = true;
   7426     } else {
   7427         // Look one or two optional keywords that indicate a side or corner.
   7428         RefPtr<CSSPrimitiveValue> startX, startY;
   7429 
   7430         RefPtr<CSSPrimitiveValue> location;
   7431         bool isHorizontal = false;
   7432         if ((location = valueFromSideKeyword(a, isHorizontal))) {
   7433             if (isHorizontal)
   7434                 startX = location;
   7435             else
   7436                 startY = location;
   7437 
   7438             if ((a = args->next())) {
   7439                 if ((location = valueFromSideKeyword(a, isHorizontal))) {
   7440                     if (isHorizontal) {
   7441                         if (startX)
   7442                             return false;
   7443                         startX = location;
   7444                     } else {
   7445                         if (startY)
   7446                             return false;
   7447                         startY = location;
   7448                     }
   7449 
   7450                     args->next();
   7451                 }
   7452             }
   7453 
   7454             expectComma = true;
   7455         }
   7456 
   7457         if (!startX && !startY)
   7458             startY = cssValuePool().createIdentifierValue(CSSValueTop);
   7459 
   7460         result->setFirstX(startX.release());
   7461         result->setFirstY(startY.release());
   7462     }
   7463 
   7464     if (!parseGradientColorStops(args, result.get(), expectComma))
   7465         return false;
   7466 
   7467     if (!result->stopCount())
   7468         return false;
   7469 
   7470     gradient = result.release();
   7471     return true;
   7472 }
   7473 
   7474 bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   7475 {
   7476     RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
   7477 
   7478     // Walk the arguments.
   7479     CSSParserValueList* args = valueList->current()->function->args.get();
   7480     if (!args || !args->size())
   7481         return false;
   7482 
   7483     CSSParserValue* a = args->current();
   7484     if (!a)
   7485         return false;
   7486 
   7487     bool expectComma = false;
   7488 
   7489     // Optional background-position
   7490     RefPtr<CSSValue> centerX;
   7491     RefPtr<CSSValue> centerY;
   7492     // parse2ValuesFillPosition advances the args next pointer.
   7493     parse2ValuesFillPosition(args, centerX, centerY);
   7494     a = args->current();
   7495     if (!a)
   7496         return false;
   7497 
   7498     if (centerX || centerY) {
   7499         // Comma
   7500         if (!isComma(a))
   7501             return false;
   7502 
   7503         a = args->next();
   7504         if (!a)
   7505             return false;
   7506     }
   7507 
   7508     result->setFirstX(toCSSPrimitiveValue(centerX.get()));
   7509     result->setSecondX(toCSSPrimitiveValue(centerX.get()));
   7510     // CSS3 radial gradients always share the same start and end point.
   7511     result->setFirstY(toCSSPrimitiveValue(centerY.get()));
   7512     result->setSecondY(toCSSPrimitiveValue(centerY.get()));
   7513 
   7514     RefPtr<CSSPrimitiveValue> shapeValue;
   7515     RefPtr<CSSPrimitiveValue> sizeValue;
   7516 
   7517     // Optional shape and/or size in any order.
   7518     for (int i = 0; i < 2; ++i) {
   7519         if (a->unit != CSSPrimitiveValue::CSS_IDENT)
   7520             break;
   7521 
   7522         bool foundValue = false;
   7523         switch (a->id) {
   7524         case CSSValueCircle:
   7525         case CSSValueEllipse:
   7526             shapeValue = cssValuePool().createIdentifierValue(a->id);
   7527             foundValue = true;
   7528             break;
   7529         case CSSValueClosestSide:
   7530         case CSSValueClosestCorner:
   7531         case CSSValueFarthestSide:
   7532         case CSSValueFarthestCorner:
   7533         case CSSValueContain:
   7534         case CSSValueCover:
   7535             sizeValue = cssValuePool().createIdentifierValue(a->id);
   7536             foundValue = true;
   7537             break;
   7538         default:
   7539             break;
   7540         }
   7541 
   7542         if (foundValue) {
   7543             a = args->next();
   7544             if (!a)
   7545                 return false;
   7546 
   7547             expectComma = true;
   7548         }
   7549     }
   7550 
   7551     result->setShape(shapeValue);
   7552     result->setSizingBehavior(sizeValue);
   7553 
   7554     // Or, two lengths or percentages
   7555     RefPtr<CSSPrimitiveValue> horizontalSize;
   7556     RefPtr<CSSPrimitiveValue> verticalSize;
   7557 
   7558     if (!shapeValue && !sizeValue) {
   7559         if (validUnit(a, FLength | FPercent)) {
   7560             horizontalSize = createPrimitiveNumericValue(a);
   7561             a = args->next();
   7562             if (!a)
   7563                 return false;
   7564 
   7565             expectComma = true;
   7566         }
   7567 
   7568         if (validUnit(a, FLength | FPercent)) {
   7569             verticalSize = createPrimitiveNumericValue(a);
   7570 
   7571             a = args->next();
   7572             if (!a)
   7573                 return false;
   7574             expectComma = true;
   7575         }
   7576     }
   7577 
   7578     // Must have neither or both.
   7579     if (!horizontalSize != !verticalSize)
   7580         return false;
   7581 
   7582     result->setEndHorizontalSize(horizontalSize);
   7583     result->setEndVerticalSize(verticalSize);
   7584 
   7585     if (!parseGradientColorStops(args, result.get(), expectComma))
   7586         return false;
   7587 
   7588     gradient = result.release();
   7589     return true;
   7590 }
   7591 
   7592 bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   7593 {
   7594     RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
   7595 
   7596     CSSParserValueList* args = valueList->current()->function->args.get();
   7597     if (!args || !args->size())
   7598         return false;
   7599 
   7600     CSSParserValue* a = args->current();
   7601     if (!a)
   7602         return false;
   7603 
   7604     bool expectComma = false;
   7605     // Look for angle.
   7606     if (validUnit(a, FAngle, CSSStrictMode)) {
   7607         result->setAngle(createPrimitiveNumericValue(a));
   7608 
   7609         args->next();
   7610         expectComma = true;
   7611     } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
   7612         // to [ [left | right] || [top | bottom] ]
   7613         a = args->next();
   7614         if (!a)
   7615             return false;
   7616 
   7617         RefPtr<CSSPrimitiveValue> endX, endY;
   7618         RefPtr<CSSPrimitiveValue> location;
   7619         bool isHorizontal = false;
   7620 
   7621         location = valueFromSideKeyword(a, isHorizontal);
   7622         if (!location)
   7623             return false;
   7624 
   7625         if (isHorizontal)
   7626             endX = location;
   7627         else
   7628             endY = location;
   7629 
   7630         a = args->next();
   7631         if (!a)
   7632             return false;
   7633 
   7634         location = valueFromSideKeyword(a, isHorizontal);
   7635         if (location) {
   7636             if (isHorizontal) {
   7637                 if (endX)
   7638                     return false;
   7639                 endX = location;
   7640             } else {
   7641                 if (endY)
   7642                     return false;
   7643                 endY = location;
   7644             }
   7645 
   7646             args->next();
   7647         }
   7648 
   7649         expectComma = true;
   7650         result->setFirstX(endX.release());
   7651         result->setFirstY(endY.release());
   7652     }
   7653 
   7654     if (!parseGradientColorStops(args, result.get(), expectComma))
   7655         return false;
   7656 
   7657     if (!result->stopCount())
   7658         return false;
   7659 
   7660     gradient = result.release();
   7661     return true;
   7662 }
   7663 
   7664 bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   7665 {
   7666     RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
   7667 
   7668     CSSParserValueList* args = valueList->current()->function->args.get();
   7669     if (!args || !args->size())
   7670         return false;
   7671 
   7672     CSSParserValue* a = args->current();
   7673     if (!a)
   7674         return false;
   7675 
   7676     bool expectComma = false;
   7677 
   7678     RefPtr<CSSPrimitiveValue> shapeValue;
   7679     RefPtr<CSSPrimitiveValue> sizeValue;
   7680     RefPtr<CSSPrimitiveValue> horizontalSize;
   7681     RefPtr<CSSPrimitiveValue> verticalSize;
   7682 
   7683     // First part of grammar, the size/shape clause:
   7684     // [ circle || <length> ] |
   7685     // [ ellipse || [ <length> | <percentage> ]{2} ] |
   7686     // [ [ circle | ellipse] || <size-keyword> ]
   7687     for (int i = 0; i < 3; ++i) {
   7688         if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
   7689             bool badIdent = false;
   7690             switch (a->id) {
   7691             case CSSValueCircle:
   7692             case CSSValueEllipse:
   7693                 if (shapeValue)
   7694                     return false;
   7695                 shapeValue = cssValuePool().createIdentifierValue(a->id);
   7696                 break;
   7697             case CSSValueClosestSide:
   7698             case CSSValueClosestCorner:
   7699             case CSSValueFarthestSide:
   7700             case CSSValueFarthestCorner:
   7701                 if (sizeValue || horizontalSize)
   7702                     return false;
   7703                 sizeValue = cssValuePool().createIdentifierValue(a->id);
   7704                 break;
   7705             default:
   7706                 badIdent = true;
   7707             }
   7708 
   7709             if (badIdent)
   7710                 break;
   7711 
   7712             a = args->next();
   7713             if (!a)
   7714                 return false;
   7715         } else if (validUnit(a, FLength | FPercent)) {
   7716 
   7717             if (sizeValue || horizontalSize)
   7718                 return false;
   7719             horizontalSize = createPrimitiveNumericValue(a);
   7720 
   7721             a = args->next();
   7722             if (!a)
   7723                 return false;
   7724 
   7725             if (validUnit(a, FLength | FPercent)) {
   7726                 verticalSize = createPrimitiveNumericValue(a);
   7727                 ++i;
   7728                 a = args->next();
   7729                 if (!a)
   7730                     return false;
   7731             }
   7732         } else
   7733             break;
   7734     }
   7735 
   7736     // You can specify size as a keyword or a length/percentage, not both.
   7737     if (sizeValue && horizontalSize)
   7738         return false;
   7739     // Circles must have 0 or 1 lengths.
   7740     if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
   7741         return false;
   7742     // Ellipses must have 0 or 2 length/percentages.
   7743     if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
   7744         return false;
   7745     // If there's only one size, it must be a length.
   7746     if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
   7747         return false;
   7748 
   7749     result->setShape(shapeValue);
   7750     result->setSizingBehavior(sizeValue);
   7751     result->setEndHorizontalSize(horizontalSize);
   7752     result->setEndVerticalSize(verticalSize);
   7753 
   7754     // Second part of grammar, the center-position clause:
   7755     // at <position>
   7756     RefPtr<CSSValue> centerX;
   7757     RefPtr<CSSValue> centerY;
   7758     if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
   7759         a = args->next();
   7760         if (!a)
   7761             return false;
   7762 
   7763         parseFillPosition(args, centerX, centerY);
   7764         if (!(centerX && centerY))
   7765             return false;
   7766 
   7767         a = args->current();
   7768         if (!a)
   7769             return false;
   7770         result->setFirstX(toCSSPrimitiveValue(centerX.get()));
   7771         result->setFirstY(toCSSPrimitiveValue(centerY.get()));
   7772         // Right now, CSS radial gradients have the same start and end centers.
   7773         result->setSecondX(toCSSPrimitiveValue(centerX.get()));
   7774         result->setSecondY(toCSSPrimitiveValue(centerY.get()));
   7775     }
   7776 
   7777     if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
   7778         expectComma = true;
   7779 
   7780     if (!parseGradientColorStops(args, result.get(), expectComma))
   7781         return false;
   7782 
   7783     gradient = result.release();
   7784     return true;
   7785 }
   7786 
   7787 bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
   7788 {
   7789     CSSParserValue* a = valueList->current();
   7790 
   7791     // Now look for color stops.
   7792     while (a) {
   7793         // Look for the comma before the next stop.
   7794         if (expectComma) {
   7795             if (!isComma(a))
   7796                 return false;
   7797 
   7798             a = valueList->next();
   7799             if (!a)
   7800                 return false;
   7801         }
   7802 
   7803         // <color-stop> = <color> [ <percentage> | <length> ]?
   7804         CSSGradientColorStop stop;
   7805         stop.m_color = parseGradientColorOrKeyword(this, a);
   7806         if (!stop.m_color)
   7807             return false;
   7808 
   7809         a = valueList->next();
   7810         if (a) {
   7811             if (validUnit(a, FLength | FPercent)) {
   7812                 stop.m_position = createPrimitiveNumericValue(a);
   7813                 a = valueList->next();
   7814             }
   7815         }
   7816 
   7817         gradient->addStop(stop);
   7818         expectComma = true;
   7819     }
   7820 
   7821     // Must have 2 or more stops to be valid.
   7822     return gradient->stopCount() >= 2;
   7823 }
   7824 
   7825 bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const
   7826 {
   7827     if (val->unit != CSSParserValue::Function)
   7828         return false;
   7829 
   7830     return equalIgnoringCase(val->function->name, "-webkit-gradient(")
   7831         || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
   7832         || equalIgnoringCase(val->function->name, "linear-gradient(")
   7833         || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
   7834         || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
   7835         || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
   7836         || equalIgnoringCase(val->function->name, "radial-gradient(")
   7837         || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
   7838         || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
   7839         || equalIgnoringCase(val->function->name, "-webkit-canvas(")
   7840         || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
   7841 }
   7842 
   7843 bool CSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr<CSSValue>& value)
   7844 {
   7845     CSSParserValue* val = valueList->current();
   7846 
   7847     if (val->unit != CSSParserValue::Function)
   7848         return false;
   7849 
   7850     if (equalIgnoringCase(val->function->name, "-webkit-gradient("))
   7851         return parseDeprecatedGradient(valueList, value);
   7852 
   7853     if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient("))
   7854         return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
   7855 
   7856     if (equalIgnoringCase(val->function->name, "linear-gradient("))
   7857         return parseLinearGradient(valueList, value, NonRepeating);
   7858 
   7859     if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient("))
   7860         return parseDeprecatedLinearGradient(valueList, value, Repeating);
   7861 
   7862     if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
   7863         return parseLinearGradient(valueList, value, Repeating);
   7864 
   7865     if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient("))
   7866         return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
   7867 
   7868     if (equalIgnoringCase(val->function->name, "radial-gradient("))
   7869         return parseRadialGradient(valueList, value, NonRepeating);
   7870 
   7871     if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient("))
   7872         return parseDeprecatedRadialGradient(valueList, value, Repeating);
   7873 
   7874     if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
   7875         return parseRadialGradient(valueList, value, Repeating);
   7876 
   7877     if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
   7878         return parseCanvas(valueList, value);
   7879 
   7880     if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
   7881         return parseCrossfade(valueList, value);
   7882 
   7883     return false;
   7884 }
   7885 
   7886 bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr<CSSValue>& crossfade)
   7887 {
   7888     RefPtr<CSSCrossfadeValue> result;
   7889 
   7890     // Walk the arguments.
   7891     CSSParserValueList* args = valueList->current()->function->args.get();
   7892     if (!args || args->size() != 5)
   7893         return false;
   7894     CSSParserValue* a = args->current();
   7895     RefPtr<CSSValue> fromImageValue;
   7896     RefPtr<CSSValue> toImageValue;
   7897 
   7898     // The first argument is the "from" image. It is a fill image.
   7899     if (!a || !parseFillImage(args, fromImageValue))
   7900         return false;
   7901     a = args->next();
   7902 
   7903     // Skip a comma
   7904     if (!isComma(a))
   7905         return false;
   7906     a = args->next();
   7907 
   7908     // The second argument is the "to" image. It is a fill image.
   7909     if (!a || !parseFillImage(args, toImageValue))
   7910         return false;
   7911     a = args->next();
   7912 
   7913     // Skip a comma
   7914     if (!isComma(a))
   7915         return false;
   7916     a = args->next();
   7917 
   7918     // The third argument is the crossfade value. It is a percentage or a fractional number.
   7919     RefPtr<CSSPrimitiveValue> percentage;
   7920     if (!a)
   7921         return false;
   7922 
   7923     if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
   7924         percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
   7925     else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
   7926         percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
   7927     else
   7928         return false;
   7929 
   7930     result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
   7931     result->setPercentage(percentage);
   7932 
   7933     crossfade = result;
   7934 
   7935     return true;
   7936 }
   7937 
   7938 bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr<CSSValue>& canvas)
   7939 {
   7940     // Walk the arguments.
   7941     CSSParserValueList* args = valueList->current()->function->args.get();
   7942     if (!args || args->size() != 1)
   7943         return false;
   7944 
   7945     // The first argument is the canvas name.  It is an identifier.
   7946     CSSParserValue* value = args->current();
   7947     if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
   7948         return false;
   7949 
   7950     canvas = CSSCanvasValue::create(value->string);
   7951     return true;
   7952 }
   7953 
   7954 PassRefPtr<CSSValue> CSSParser::parseImageSet(CSSParserValueList* valueList)
   7955 {
   7956     CSSParserValue* function = valueList->current();
   7957 
   7958     if (function->unit != CSSParserValue::Function)
   7959         return 0;
   7960 
   7961     CSSParserValueList* functionArgs = valueList->current()->function->args.get();
   7962     if (!functionArgs || !functionArgs->size() || !functionArgs->current())
   7963         return 0;
   7964 
   7965     RefPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
   7966 
   7967     CSSParserValue* arg = functionArgs->current();
   7968     while (arg) {
   7969         if (arg->unit != CSSPrimitiveValue::CSS_URI)
   7970             return 0;
   7971 
   7972         RefPtr<CSSImageValue> image = CSSImageValue::create(completeURL(arg->string));
   7973         imageSet->append(image);
   7974 
   7975         arg = functionArgs->next();
   7976         if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
   7977             return 0;
   7978 
   7979         double imageScaleFactor = 0;
   7980         const String& string = arg->string;
   7981         unsigned length = string.length();
   7982         if (!length)
   7983             return 0;
   7984         if (string.is8Bit()) {
   7985             const LChar* start = string.characters8();
   7986             parseDouble(start, start + length, 'x', imageScaleFactor);
   7987         } else {
   7988             const UChar* start = string.characters16();
   7989             parseDouble(start, start + length, 'x', imageScaleFactor);
   7990         }
   7991         if (imageScaleFactor <= 0)
   7992             return 0;
   7993         imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
   7994 
   7995         // If there are no more arguments, we're done.
   7996         arg = functionArgs->next();
   7997         if (!arg)
   7998             break;
   7999 
   8000         // If there are more arguments, they should be after a comma.
   8001         if (!isComma(arg))
   8002             return 0;
   8003 
   8004         // Skip the comma and move on to the next argument.
   8005         arg = functionArgs->next();
   8006     }
   8007 
   8008     return imageSet.release();
   8009 }
   8010 
   8011 class TransformOperationInfo {
   8012 public:
   8013     TransformOperationInfo(const CSSParserString& name)
   8014         : m_type(CSSTransformValue::UnknownTransformOperation)
   8015         , m_argCount(1)
   8016         , m_allowSingleArgument(false)
   8017         , m_unit(CSSParser::FUnknown)
   8018     {
   8019         const UChar* characters;
   8020         unsigned nameLength = name.length();
   8021 
   8022         const unsigned longestNameLength = 12;
   8023         UChar characterBuffer[longestNameLength];
   8024         if (name.is8Bit()) {
   8025             unsigned length = std::min(longestNameLength, nameLength);
   8026             const LChar* characters8 = name.characters8();
   8027             for (unsigned i = 0; i < length; ++i)
   8028                 characterBuffer[i] = characters8[i];
   8029             characters = characterBuffer;
   8030         } else
   8031             characters = name.characters16();
   8032 
   8033         SWITCH(characters, nameLength) {
   8034             CASE("skew(") {
   8035                 m_unit = CSSParser::FAngle;
   8036                 m_type = CSSTransformValue::SkewTransformOperation;
   8037                 m_allowSingleArgument = true;
   8038                 m_argCount = 3;
   8039             }
   8040             CASE("scale(") {
   8041                 m_unit = CSSParser::FNumber;
   8042                 m_type = CSSTransformValue::ScaleTransformOperation;
   8043                 m_allowSingleArgument = true;
   8044                 m_argCount = 3;
   8045             }
   8046             CASE("skewx(") {
   8047                 m_unit = CSSParser::FAngle;
   8048                 m_type = CSSTransformValue::SkewXTransformOperation;
   8049             }
   8050             CASE("skewy(") {
   8051                 m_unit = CSSParser::FAngle;
   8052                 m_type = CSSTransformValue::SkewYTransformOperation;
   8053             }
   8054             CASE("matrix(") {
   8055                 m_unit = CSSParser::FNumber;
   8056                 m_type = CSSTransformValue::MatrixTransformOperation;
   8057                 m_argCount = 11;
   8058             }
   8059             CASE("rotate(") {
   8060                 m_unit = CSSParser::FAngle;
   8061                 m_type = CSSTransformValue::RotateTransformOperation;
   8062             }
   8063             CASE("scalex(") {
   8064                 m_unit = CSSParser::FNumber;
   8065                 m_type = CSSTransformValue::ScaleXTransformOperation;
   8066             }
   8067             CASE("scaley(") {
   8068                 m_unit = CSSParser::FNumber;
   8069                 m_type = CSSTransformValue::ScaleYTransformOperation;
   8070             }
   8071             CASE("scalez(") {
   8072                 m_unit = CSSParser::FNumber;
   8073                 m_type = CSSTransformValue::ScaleZTransformOperation;
   8074             }
   8075             CASE("scale3d(") {
   8076                 m_unit = CSSParser::FNumber;
   8077                 m_type = CSSTransformValue::Scale3DTransformOperation;
   8078                 m_argCount = 5;
   8079             }
   8080             CASE("rotatex(") {
   8081                 m_unit = CSSParser::FAngle;
   8082                 m_type = CSSTransformValue::RotateXTransformOperation;
   8083             }
   8084             CASE("rotatey(") {
   8085                 m_unit = CSSParser::FAngle;
   8086                 m_type = CSSTransformValue::RotateYTransformOperation;
   8087             }
   8088             CASE("rotatez(") {
   8089                 m_unit = CSSParser::FAngle;
   8090                 m_type = CSSTransformValue::RotateZTransformOperation;
   8091             }
   8092             CASE("matrix3d(") {
   8093                 m_unit = CSSParser::FNumber;
   8094                 m_type = CSSTransformValue::Matrix3DTransformOperation;
   8095                 m_argCount = 31;
   8096             }
   8097             CASE("rotate3d(") {
   8098                 m_unit = CSSParser::FNumber;
   8099                 m_type = CSSTransformValue::Rotate3DTransformOperation;
   8100                 m_argCount = 7;
   8101             }
   8102             CASE("translate(") {
   8103                 m_unit = CSSParser::FLength | CSSParser::FPercent;
   8104                 m_type = CSSTransformValue::TranslateTransformOperation;
   8105                 m_allowSingleArgument = true;
   8106                 m_argCount = 3;
   8107             }
   8108             CASE("translatex(") {
   8109                 m_unit = CSSParser::FLength | CSSParser::FPercent;
   8110                 m_type = CSSTransformValue::TranslateXTransformOperation;
   8111             }
   8112             CASE("translatey(") {
   8113                 m_unit = CSSParser::FLength | CSSParser::FPercent;
   8114                 m_type = CSSTransformValue::TranslateYTransformOperation;
   8115             }
   8116             CASE("translatez(") {
   8117                 m_unit = CSSParser::FLength | CSSParser::FPercent;
   8118                 m_type = CSSTransformValue::TranslateZTransformOperation;
   8119             }
   8120             CASE("perspective(") {
   8121                 m_unit = CSSParser::FNumber;
   8122                 m_type = CSSTransformValue::PerspectiveTransformOperation;
   8123             }
   8124             CASE("translate3d(") {
   8125                 m_unit = CSSParser::FLength | CSSParser::FPercent;
   8126                 m_type = CSSTransformValue::Translate3DTransformOperation;
   8127                 m_argCount = 5;
   8128             }
   8129         }
   8130     }
   8131 
   8132     CSSTransformValue::TransformOperationType type() const { return m_type; }
   8133     unsigned argCount() const { return m_argCount; }
   8134     CSSParser::Units unit() const { return m_unit; }
   8135 
   8136     bool unknown() const { return m_type == CSSTransformValue::UnknownTransformOperation; }
   8137     bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
   8138 
   8139 private:
   8140     CSSTransformValue::TransformOperationType m_type;
   8141     unsigned m_argCount;
   8142     bool m_allowSingleArgument;
   8143     CSSParser::Units m_unit;
   8144 };
   8145 
   8146 PassRefPtr<CSSValueList> CSSParser::parseTransform()
   8147 {
   8148     if (!m_valueList)
   8149         return 0;
   8150 
   8151     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   8152     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   8153         RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value);
   8154         if (!parsedTransformValue)
   8155             return 0;
   8156 
   8157         list->append(parsedTransformValue.release());
   8158     }
   8159 
   8160     return list.release();
   8161 }
   8162 
   8163 PassRefPtr<CSSValue> CSSParser::parseTransformValue(CSSParserValue *value)
   8164 {
   8165     if (value->unit != CSSParserValue::Function || !value->function)
   8166         return 0;
   8167 
   8168     // Every primitive requires at least one argument.
   8169     CSSParserValueList* args = value->function->args.get();
   8170     if (!args)
   8171         return 0;
   8172 
   8173     // See if the specified primitive is one we understand.
   8174     TransformOperationInfo info(value->function->name);
   8175     if (info.unknown())
   8176         return 0;
   8177 
   8178     if (!info.hasCorrectArgCount(args->size()))
   8179         return 0;
   8180 
   8181     // The transform is a list of functional primitives that specify transform operations.
   8182     // We collect a list of CSSTransformValues, where each value specifies a single operation.
   8183 
   8184     // Create the new CSSTransformValue for this operation and add it to our list.
   8185     RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(info.type());
   8186 
   8187     // Snag our values.
   8188     CSSParserValue* a = args->current();
   8189     unsigned argNumber = 0;
   8190     while (a) {
   8191         CSSParser::Units unit = info.unit();
   8192 
   8193         if (info.type() == CSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
   8194             // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
   8195             if (!validUnit(a, FAngle, CSSStrictMode))
   8196                 return 0;
   8197         } else if (info.type() == CSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
   8198             // 3rd param of translate3d() cannot be a percentage
   8199             if (!validUnit(a, FLength, CSSStrictMode))
   8200                 return 0;
   8201         } else if (info.type() == CSSTransformValue::TranslateZTransformOperation && !argNumber) {
   8202             // 1st param of translateZ() cannot be a percentage
   8203             if (!validUnit(a, FLength, CSSStrictMode))
   8204                 return 0;
   8205         } else if (info.type() == CSSTransformValue::PerspectiveTransformOperation && !argNumber) {
   8206             // 1st param of perspective() must be a non-negative number (deprecated) or length.
   8207             if (!validUnit(a, FNumber | FLength | FNonNeg, CSSStrictMode))
   8208                 return 0;
   8209         } else if (!validUnit(a, unit, CSSStrictMode))
   8210             return 0;
   8211 
   8212         // Add the value to the current transform operation.
   8213         transformValue->append(createPrimitiveNumericValue(a));
   8214 
   8215         a = args->next();
   8216         if (!a)
   8217             break;
   8218         if (a->unit != CSSParserValue::Operator || a->iValue != ',')
   8219             return 0;
   8220         a = args->next();
   8221 
   8222         argNumber++;
   8223     }
   8224 
   8225     return transformValue.release();
   8226 }
   8227 
   8228 bool CSSParser::isBlendMode(CSSValueID valueID)
   8229 {
   8230     return (valueID >= CSSValueMultiply && valueID <= CSSValueLuminosity)
   8231         || valueID == CSSValueNormal
   8232         || valueID == CSSValueOverlay;
   8233 }
   8234 
   8235 bool CSSParser::isCompositeOperator(CSSValueID valueID)
   8236 {
   8237     // FIXME: Add CSSValueDestination and CSSValueLighter when the Compositing spec updates.
   8238     return valueID >= CSSValueClear && valueID <= CSSValueXor;
   8239 }
   8240 
   8241 static void filterInfoForName(const CSSParserString& name, CSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
   8242 {
   8243     if (equalIgnoringCase(name, "grayscale("))
   8244         filterType = CSSFilterValue::GrayscaleFilterOperation;
   8245     else if (equalIgnoringCase(name, "sepia("))
   8246         filterType = CSSFilterValue::SepiaFilterOperation;
   8247     else if (equalIgnoringCase(name, "saturate("))
   8248         filterType = CSSFilterValue::SaturateFilterOperation;
   8249     else if (equalIgnoringCase(name, "hue-rotate("))
   8250         filterType = CSSFilterValue::HueRotateFilterOperation;
   8251     else if (equalIgnoringCase(name, "invert("))
   8252         filterType = CSSFilterValue::InvertFilterOperation;
   8253     else if (equalIgnoringCase(name, "opacity("))
   8254         filterType = CSSFilterValue::OpacityFilterOperation;
   8255     else if (equalIgnoringCase(name, "brightness("))
   8256         filterType = CSSFilterValue::BrightnessFilterOperation;
   8257     else if (equalIgnoringCase(name, "contrast("))
   8258         filterType = CSSFilterValue::ContrastFilterOperation;
   8259     else if (equalIgnoringCase(name, "blur("))
   8260         filterType = CSSFilterValue::BlurFilterOperation;
   8261     else if (equalIgnoringCase(name, "drop-shadow(")) {
   8262         filterType = CSSFilterValue::DropShadowFilterOperation;
   8263         maximumArgumentCount = 4;  // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
   8264     }
   8265     else if (equalIgnoringCase(name, "custom("))
   8266         filterType = CSSFilterValue::CustomFilterOperation;
   8267 }
   8268 
   8269 static bool acceptCommaOperator(CSSParserValueList* argsList)
   8270 {
   8271     if (CSSParserValue* arg = argsList->current()) {
   8272         if (!isComma(arg))
   8273             return false;
   8274         argsList->next();
   8275     }
   8276     return true;
   8277 }
   8278 
   8279 PassRefPtr<CSSArrayFunctionValue> CSSParser::parseCustomFilterArrayFunction(CSSParserValue* value)
   8280 {
   8281     ASSERT(value->unit == CSSParserValue::Function && value->function);
   8282 
   8283     if (!equalIgnoringCase(value->function->name, "array("))
   8284         return 0;
   8285 
   8286     CSSParserValueList* arrayArgsParserValueList = value->function->args.get();
   8287     if (!arrayArgsParserValueList || !arrayArgsParserValueList->size())
   8288         return 0;
   8289 
   8290     // array() values are comma separated.
   8291     RefPtr<CSSArrayFunctionValue> arrayFunction = CSSArrayFunctionValue::create();
   8292     while (true) {
   8293         // We parse pairs <Value, Comma> at each step.
   8294         CSSParserValue* currentParserValue = arrayArgsParserValueList->current();
   8295         if (!currentParserValue || !validUnit(currentParserValue, FNumber, CSSStrictMode))
   8296             return 0;
   8297 
   8298         RefPtr<CSSValue> arrayValue = cssValuePool().createValue(currentParserValue->fValue, CSSPrimitiveValue::CSS_NUMBER);
   8299         arrayFunction->append(arrayValue.release());
   8300 
   8301         CSSParserValue* nextParserValue = arrayArgsParserValueList->next();
   8302         if (!nextParserValue)
   8303             break;
   8304 
   8305         if (!isComma(nextParserValue))
   8306             return 0;
   8307 
   8308         arrayArgsParserValueList->next();
   8309     }
   8310 
   8311     return arrayFunction;
   8312 }
   8313 
   8314 PassRefPtr<CSSMixFunctionValue> CSSParser::parseMixFunction(CSSParserValue* value)
   8315 {
   8316     ASSERT(value->unit == CSSParserValue::Function && value->function);
   8317 
   8318     if (!equalIgnoringCase(value->function->name, "mix("))
   8319         return 0;
   8320 
   8321     CSSParserValueList* argsList = value->function->args.get();
   8322     if (!argsList)
   8323         return 0;
   8324 
   8325     unsigned numArgs = argsList->size();
   8326     if (numArgs < 1 || numArgs > 3)
   8327         return 0;
   8328 
   8329     RefPtr<CSSMixFunctionValue> mixFunction = CSSMixFunctionValue::create();
   8330 
   8331     bool hasBlendMode = false;
   8332     bool hasAlphaCompositing = false;
   8333 
   8334     for (CSSParserValue* arg = argsList->current(); arg; arg = argsList->next()) {
   8335         RefPtr<CSSValue> value;
   8336 
   8337         unsigned argNumber = argsList->currentIndex();
   8338         if (!argNumber) {
   8339             if (arg->unit == CSSPrimitiveValue::CSS_URI) {
   8340                 KURL shaderURL = completeURL(arg->string);
   8341                 value = CSSShaderValue::create(shaderURL.string());
   8342             }
   8343         } else if (argNumber == 1 || argNumber == 2) {
   8344             if (!hasBlendMode && isBlendMode(arg->id)) {
   8345                 hasBlendMode = true;
   8346                 value = cssValuePool().createIdentifierValue(arg->id);
   8347             } else if (!hasAlphaCompositing && isCompositeOperator(arg->id)) {
   8348                 hasAlphaCompositing = true;
   8349                 value = cssValuePool().createIdentifierValue(arg->id);
   8350             }
   8351         }
   8352 
   8353         if (!value)
   8354             return 0;
   8355 
   8356         mixFunction->append(value.release());
   8357     }
   8358 
   8359     return mixFunction;
   8360 }
   8361 
   8362 PassRefPtr<CSSValueList> CSSParser::parseCustomFilterParameters(CSSParserValueList* argsList)
   8363 {
   8364     //
   8365     // params:      [<param-def>[,<param-def>*]]
   8366     // param-def:   <param-name>wsp<param-value>
   8367     // param-name:  <ident>
   8368     // param-value: true|false[wsp+true|false]{0-3} |
   8369     //              <number>[wsp+<number>]{0-3} |
   8370     //              <array> |
   8371     //              <transform> |
   8372     //              <texture(<uri>)>
   8373     // array: 'array('<number>[wsp<number>]*')'
   8374     // css-3d-transform: <transform-function>;[<transform-function>]*
   8375     // transform:   <css-3d-transform> | <mat>
   8376     // mat:         'mat2('<number>(,<number>){3}')' |
   8377     //              'mat3('<number>(,<number>){8}')' |
   8378     //              'mat4('<number>(,<number>){15}')' )
   8379     //
   8380 
   8381     RefPtr<CSSValueList> paramList = CSSValueList::createCommaSeparated();
   8382 
   8383     while (CSSParserValue* arg = argsList->current()) {
   8384         if (arg->unit != CSSPrimitiveValue::CSS_IDENT)
   8385             return 0;
   8386 
   8387         RefPtr<CSSValueList> parameter = CSSValueList::createSpaceSeparated();
   8388         parameter->append(createPrimitiveStringValue(arg));
   8389 
   8390         arg = argsList->next();
   8391         if (!arg)
   8392             return 0;
   8393 
   8394         RefPtr<CSSValue> parameterValue;
   8395 
   8396         if (arg->unit == CSSParserValue::Function && arg->function) {
   8397             // FIXME: Implement parsing for the other parameter types.
   8398             // textures: https://bugs.webkit.org/show_bug.cgi?id=71442
   8399             // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444
   8400             if (equalIgnoringCase(arg->function->name, "array(")) {
   8401                 parameterValue = parseCustomFilterArrayFunction(arg);
   8402                 // This parsing step only consumes function arguments,
   8403                 // argsList is therefore moved forward explicitely.
   8404                 argsList->next();
   8405             } else
   8406                 parameterValue = parseCustomFilterTransform(argsList);
   8407         } else {
   8408             RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated();
   8409             arg = argsList->current();
   8410             while (arg) {
   8411                 // If we hit a comma, it means that we finished this parameter's values.
   8412                 if (isComma(arg))
   8413                     break;
   8414                 if (!validUnit(arg, FNumber, CSSStrictMode))
   8415                     return 0;
   8416                 paramValueList->append(cssValuePool().createValue(arg->fValue, CSSPrimitiveValue::CSS_NUMBER));
   8417                 arg = argsList->next();
   8418             }
   8419             if (!paramValueList->length() || paramValueList->length() > 4)
   8420                 return 0;
   8421             parameterValue = paramValueList.release();
   8422         }
   8423 
   8424         if (!parameterValue || !acceptCommaOperator(argsList))
   8425             return 0;
   8426 
   8427         parameter->append(parameterValue.release());
   8428         paramList->append(parameter.release());
   8429     }
   8430 
   8431     return paramList;
   8432 }
   8433 
   8434 PassRefPtr<CSSFilterValue> CSSParser::parseCustomFilterFunctionWithAtRuleReferenceSyntax(CSSParserValue* value)
   8435 {
   8436     //
   8437     // Custom filter function "at-rule reference" syntax:
   8438     //
   8439     // custom(<filter-name>wsp[,wsp<params>])
   8440     //
   8441     // filter-name: <filter-name>
   8442     // params: See the comment in CSSParser::parseCustomFilterParameters.
   8443     //
   8444 
   8445     ASSERT(value->function);
   8446 
   8447     CSSParserValueList* argsList = value->function->args.get();
   8448     if (!argsList || !argsList->size())
   8449         return 0;
   8450 
   8451     // 1. Parse the filter name.
   8452     CSSParserValue* arg = argsList->current();
   8453     if (arg->unit != CSSPrimitiveValue::CSS_IDENT)
   8454         return 0;
   8455 
   8456     RefPtr<CSSFilterValue> filterValue = CSSFilterValue::create(CSSFilterValue::CustomFilterOperation);
   8457 
   8458     RefPtr<CSSValue> filterName = createPrimitiveStringValue(arg);
   8459     filterValue->append(filterName);
   8460     argsList->next();
   8461 
   8462     if (!acceptCommaOperator(argsList))
   8463         return 0;
   8464 
   8465     // 2. Parse the parameters.
   8466     RefPtr<CSSValueList> paramList = parseCustomFilterParameters(argsList);
   8467     if (!paramList)
   8468         return 0;
   8469 
   8470     if (paramList->length())
   8471         filterValue->append(paramList.release());
   8472 
   8473     return filterValue;
   8474 }
   8475 
   8476 // FIXME: The custom filters "inline" syntax is deprecated. We will remove it eventually.
   8477 PassRefPtr<CSSFilterValue> CSSParser::parseCustomFilterFunctionWithInlineSyntax(CSSParserValue* value)
   8478 {
   8479     //
   8480     // Custom filter function "inline" syntax:
   8481     //
   8482     // custom(<vertex-shader>[wsp<fragment-shader>][,<vertex-mesh>][,<params>])
   8483     //
   8484     // vertexShader:    <uri> | none
   8485     // fragmentShader:  <uri> | none | mix(<uri> [ <blend-mode> || <alpha-compositing> ]?)
   8486     //
   8487     // blend-mode: normal | multiply | screen | overlay | darken | lighten | color-dodge |
   8488     //             color-burn | hard-light | soft-light | difference | exclusion | hue |
   8489     //             saturation | color | luminosity
   8490     // alpha-compositing: clear | src | dst | src-over | dst-over | src-in | dst-in |
   8491     //                    src-out | dst-out | src-atop | dst-atop | xor | plus
   8492     //
   8493     // vertexMesh:  +<integer>{1,2}[wsp<box>][wsp'detached']
   8494     // box: filter-box | border-box | padding-box | content-box
   8495     //
   8496     // params: See the comment in CSSParser::parseCustomFilterParameters.
   8497     //
   8498 
   8499     ASSERT(value->function);
   8500 
   8501     CSSParserValueList* argsList = value->function->args.get();
   8502     if (!argsList)
   8503         return 0;
   8504 
   8505     RefPtr<CSSFilterValue> filterValue = CSSFilterValue::create(CSSFilterValue::CustomFilterOperation);
   8506 
   8507     // 1. Parse the shader URLs: <vertex-shader>[wsp<fragment-shader>]
   8508     RefPtr<CSSValueList> shadersList = CSSValueList::createSpaceSeparated();
   8509     bool hadAtLeastOneCustomShader = false;
   8510     CSSParserValue* arg;
   8511     for (arg = argsList->current(); arg; arg = argsList->next()) {
   8512         RefPtr<CSSValue> value;
   8513         if (arg->id == CSSValueNone)
   8514             value = cssValuePool().createIdentifierValue(CSSValueNone);
   8515         else if (arg->unit == CSSPrimitiveValue::CSS_URI) {
   8516             KURL shaderURL = completeURL(arg->string);
   8517             value = CSSShaderValue::create(shaderURL.string());
   8518             hadAtLeastOneCustomShader = true;
   8519         } else if (argsList->currentIndex() == 1 && arg->unit == CSSParserValue::Function) {
   8520             if (!(value = parseMixFunction(arg)))
   8521                 return 0;
   8522             hadAtLeastOneCustomShader = true;
   8523         }
   8524 
   8525         if (!value)
   8526             break;
   8527         shadersList->append(value.release());
   8528     }
   8529 
   8530     if (!shadersList->length() || !hadAtLeastOneCustomShader || shadersList->length() > 2 || !acceptCommaOperator(argsList))
   8531         return 0;
   8532 
   8533     filterValue->append(shadersList.release());
   8534 
   8535     // 2. Parse the mesh size <vertex-mesh>
   8536     RefPtr<CSSValueList> meshSizeList = CSSValueList::createSpaceSeparated();
   8537 
   8538     for (arg = argsList->current(); arg; arg = argsList->next()) {
   8539         if (!validUnit(arg, FInteger | FNonNeg, CSSStrictMode))
   8540             break;
   8541         int integerValue = clampToInteger(arg->fValue);
   8542         // According to the specification we can only accept positive non-zero values.
   8543         if (integerValue < 1)
   8544             return 0;
   8545         meshSizeList->append(cssValuePool().createValue(integerValue, CSSPrimitiveValue::CSS_NUMBER));
   8546     }
   8547 
   8548     if (meshSizeList->length() > 2)
   8549         return 0;
   8550 
   8551     // FIXME: For legacy content, we accept the mesh box types. We don't do anything else with them.
   8552     // Eventually, we'll remove them completely.
   8553     // https://bugs.webkit.org/show_bug.cgi?id=103778
   8554     if ((arg = argsList->current()) && (arg->id == CSSValueBorderBox || arg->id == CSSValuePaddingBox
   8555         || arg->id == CSSValueContentBox || arg->id == CSSValueFilterBox))
   8556         argsList->next();
   8557 
   8558     if ((arg = argsList->current()) && arg->id == CSSValueDetached) {
   8559         meshSizeList->append(cssValuePool().createIdentifierValue(arg->id));
   8560         argsList->next();
   8561     }
   8562 
   8563     if (meshSizeList->length()) {
   8564         if (!acceptCommaOperator(argsList))
   8565             return 0;
   8566         filterValue->append(meshSizeList.release());
   8567     }
   8568 
   8569     // 3. Parse the parameters.
   8570     RefPtr<CSSValueList> paramList = parseCustomFilterParameters(argsList);
   8571     if (!paramList)
   8572         return 0;
   8573 
   8574     if (paramList->length())
   8575         filterValue->append(paramList.release());
   8576 
   8577     return filterValue;
   8578 }
   8579 
   8580 PassRefPtr<CSSFilterValue> CSSParser::parseCustomFilterFunction(CSSParserValue* value)
   8581 {
   8582     ASSERT(value->function);
   8583 
   8584     // Look ahead to determine which syntax the custom function is using.
   8585     // Both the at-rule reference syntax and the inline syntax require at least one argument.
   8586     CSSParserValueList* argsList = value->function->args.get();
   8587     if (!argsList || !argsList->size())
   8588         return 0;
   8589 
   8590     // The at-rule reference syntax expects a single ident or an ident followed by a comma.
   8591     // e.g. custom(my-filter) or custom(my-filter, ...)
   8592     // In contrast, when the inline syntax starts with an ident like "none", it expects a uri or a mix function next.
   8593     // e.g. custom(none url(...)) or custom(none mix(...)
   8594     bool isAtRuleReferenceSyntax = argsList->valueAt(0)->unit == CSSPrimitiveValue::CSS_IDENT
   8595         && (argsList->size() == 1 || isComma(argsList->valueAt(1)));
   8596     return isAtRuleReferenceSyntax ? parseCustomFilterFunctionWithAtRuleReferenceSyntax(value) : parseCustomFilterFunctionWithInlineSyntax(value);
   8597 }
   8598 
   8599 PassRefPtr<CSSValueList> CSSParser::parseCustomFilterTransform(CSSParserValueList* valueList)
   8600 {
   8601     if (!valueList)
   8602         return 0;
   8603 
   8604     // CSS Shaders' custom() transforms are space separated and comma terminated.
   8605     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   8606     for (CSSParserValue* value = valueList->current(); value; value = valueList->next()) {
   8607         if (isComma(value))
   8608             break;
   8609 
   8610         RefPtr<CSSValue> parsedTransformValue = parseTransformValue(value);
   8611         if (!parsedTransformValue)
   8612             return 0;
   8613 
   8614         list->append(parsedTransformValue.release());
   8615     }
   8616 
   8617     return list.release();
   8618 }
   8619 
   8620 PassRefPtr<CSSShaderValue> CSSParser::parseFilterRuleSrcUriAndFormat(CSSParserValueList* valueList)
   8621 {
   8622     CSSParserValue* value = valueList->current();
   8623     ASSERT(value && value->unit == CSSPrimitiveValue::CSS_URI);
   8624     RefPtr<CSSShaderValue> shaderValue = CSSShaderValue::create(completeURL(value->string));
   8625 
   8626     value = valueList->next();
   8627     if (value && value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "format(")) {
   8628         CSSParserValueList* args = value->function->args.get();
   8629         if (!args || args->size() != 1)
   8630             return 0;
   8631 
   8632         CSSParserValue* arg = args->current();
   8633         if (arg->unit != CSSPrimitiveValue::CSS_STRING)
   8634             return 0;
   8635 
   8636         shaderValue->setFormat(arg->string);
   8637         valueList->next();
   8638     }
   8639 
   8640     return shaderValue.release();
   8641 }
   8642 
   8643 bool CSSParser::parseFilterRuleSrc()
   8644 {
   8645     RefPtr<CSSValueList> srcList = CSSValueList::createCommaSeparated();
   8646 
   8647     CSSParserValue* value = m_valueList->current();
   8648     while (value) {
   8649         if (value->unit != CSSPrimitiveValue::CSS_URI)
   8650             return false;
   8651 
   8652         RefPtr<CSSShaderValue> shaderValue = parseFilterRuleSrcUriAndFormat(m_valueList.get());
   8653         if (!shaderValue)
   8654             return false;
   8655         srcList->append(shaderValue.release());
   8656 
   8657         if (!acceptCommaOperator(m_valueList.get()))
   8658             return false;
   8659 
   8660         value = m_valueList->current();
   8661     }
   8662 
   8663     if (!srcList->length())
   8664         return false;
   8665 
   8666     addProperty(CSSPropertySrc, srcList.release(), m_important);
   8667     return true;
   8668 }
   8669 
   8670 StyleRuleBase* CSSParser::createFilterRule(const CSSParserString& filterName)
   8671 {
   8672     RefPtr<StyleRuleFilter> rule = StyleRuleFilter::create(filterName);
   8673     rule->setProperties(createStylePropertySet());
   8674     clearProperties();
   8675     StyleRuleFilter* result = rule.get();
   8676     m_parsedRules.append(rule.release());
   8677     endRuleBody();
   8678     return result;
   8679 }
   8680 
   8681 
   8682 PassRefPtr<CSSFilterValue> CSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
   8683 {
   8684     RefPtr<CSSFilterValue> filterValue = CSSFilterValue::create(filterType);
   8685     ASSERT(args);
   8686 
   8687     switch (filterType) {
   8688     case CSSFilterValue::GrayscaleFilterOperation:
   8689     case CSSFilterValue::SepiaFilterOperation:
   8690     case CSSFilterValue::SaturateFilterOperation:
   8691     case CSSFilterValue::InvertFilterOperation:
   8692     case CSSFilterValue::OpacityFilterOperation:
   8693     case CSSFilterValue::ContrastFilterOperation: {
   8694         // One optional argument, 0-1 or 0%-100%, if missing use 100%.
   8695         if (args->size() > 1)
   8696             return 0;
   8697 
   8698         if (args->size()) {
   8699             CSSParserValue* value = args->current();
   8700             if (!validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode))
   8701                 return 0;
   8702 
   8703             double amount = value->fValue;
   8704 
   8705             // Saturate and Contrast allow values over 100%.
   8706             if (filterType != CSSFilterValue::SaturateFilterOperation
   8707                 && filterType != CSSFilterValue::ContrastFilterOperation) {
   8708                 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
   8709                 if (amount > maxAllowed)
   8710                     return 0;
   8711             }
   8712 
   8713             filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
   8714         }
   8715         break;
   8716     }
   8717     case CSSFilterValue::BrightnessFilterOperation: {
   8718         // One optional argument, if missing use 100%.
   8719         if (args->size() > 1)
   8720             return 0;
   8721 
   8722         if (args->size()) {
   8723             CSSParserValue* value = args->current();
   8724             if (!validUnit(value, FNumber | FPercent, CSSStrictMode))
   8725                 return 0;
   8726 
   8727             filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
   8728         }
   8729         break;
   8730     }
   8731     case CSSFilterValue::HueRotateFilterOperation: {
   8732         // hue-rotate() takes one optional angle.
   8733         if (args->size() > 1)
   8734             return 0;
   8735 
   8736         if (args->size()) {
   8737             CSSParserValue* argument = args->current();
   8738             if (!validUnit(argument, FAngle, CSSStrictMode))
   8739                 return 0;
   8740 
   8741             filterValue->append(createPrimitiveNumericValue(argument));
   8742         }
   8743         break;
   8744     }
   8745     case CSSFilterValue::BlurFilterOperation: {
   8746         // Blur takes a single length. Zero parameters are allowed.
   8747         if (args->size() > 1)
   8748             return 0;
   8749 
   8750         if (args->size()) {
   8751             CSSParserValue* argument = args->current();
   8752             if (!validUnit(argument, FLength | FNonNeg, CSSStrictMode))
   8753                 return 0;
   8754 
   8755             filterValue->append(createPrimitiveNumericValue(argument));
   8756         }
   8757         break;
   8758     }
   8759     case CSSFilterValue::DropShadowFilterOperation: {
   8760         // drop-shadow() takes a single shadow.
   8761         RefPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
   8762         if (!shadowValueList || shadowValueList->length() != 1)
   8763             return 0;
   8764 
   8765         filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
   8766         break;
   8767     }
   8768     default:
   8769         ASSERT_NOT_REACHED();
   8770     }
   8771     return filterValue.release();
   8772 }
   8773 
   8774 PassRefPtr<CSSValueList> CSSParser::parseFilter()
   8775 {
   8776     if (!m_valueList)
   8777         return 0;
   8778 
   8779     // The filter is a list of functional primitives that specify individual operations.
   8780     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   8781     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   8782         if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
   8783             return 0;
   8784 
   8785         CSSFilterValue::FilterOperationType filterType = CSSFilterValue::UnknownFilterOperation;
   8786 
   8787         // See if the specified primitive is one we understand.
   8788         if (value->unit == CSSPrimitiveValue::CSS_URI) {
   8789             RefPtr<CSSFilterValue> referenceFilterValue = CSSFilterValue::create(CSSFilterValue::ReferenceFilterOperation);
   8790             list->append(referenceFilterValue);
   8791             referenceFilterValue->append(CSSSVGDocumentValue::create(value->string));
   8792         } else {
   8793             const CSSParserString name = value->function->name;
   8794             unsigned maximumArgumentCount = 1;
   8795 
   8796             filterInfoForName(name, filterType, maximumArgumentCount);
   8797 
   8798             if (filterType == CSSFilterValue::UnknownFilterOperation)
   8799                 return 0;
   8800 
   8801             if (filterType == CSSFilterValue::CustomFilterOperation) {
   8802                 // Make sure parsing fails if custom filters are disabled.
   8803                 if (!m_context.isCSSCustomFilterEnabled)
   8804                     return 0;
   8805 
   8806                 RefPtr<CSSFilterValue> filterValue = parseCustomFilterFunction(value);
   8807                 if (!filterValue)
   8808                     return 0;
   8809                 list->append(filterValue.release());
   8810                 continue;
   8811             }
   8812             CSSParserValueList* args = value->function->args.get();
   8813             if (!args)
   8814                 return 0;
   8815 
   8816             RefPtr<CSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
   8817             if (!filterValue)
   8818                 return 0;
   8819 
   8820             list->append(filterValue);
   8821         }
   8822     }
   8823 
   8824     return list.release();
   8825 }
   8826 
   8827 static bool validFlowName(const String& flowName)
   8828 {
   8829     return !(equalIgnoringCase(flowName, "auto")
   8830             || equalIgnoringCase(flowName, "default")
   8831             || equalIgnoringCase(flowName, "inherit")
   8832             || equalIgnoringCase(flowName, "initial")
   8833             || equalIgnoringCase(flowName, "none"));
   8834 }
   8835 
   8836 bool CSSParser::parseFlowThread(const String& flowName)
   8837 {
   8838     setupParser("@-internal-decls -webkit-flow-into:", flowName, "");
   8839     cssyyparse(this);
   8840 
   8841     m_rule = 0;
   8842 
   8843     return ((m_parsedProperties.size() == 1) && (m_parsedProperties.first().id() == CSSPropertyWebkitFlowInto));
   8844 }
   8845 
   8846 // none | <ident>
   8847 bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important)
   8848 {
   8849     ASSERT(propId == CSSPropertyWebkitFlowInto);
   8850     ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled());
   8851 
   8852     if (m_valueList->size() != 1)
   8853         return false;
   8854 
   8855     CSSParserValue* value = m_valueList->current();
   8856     if (!value)
   8857         return false;
   8858 
   8859     if (value->unit != CSSPrimitiveValue::CSS_IDENT)
   8860         return false;
   8861 
   8862     if (value->id == CSSValueNone) {
   8863         addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
   8864         return true;
   8865     }
   8866 
   8867     String inputProperty = String(value->string);
   8868     if (!inputProperty.isEmpty()) {
   8869         if (!validFlowName(inputProperty))
   8870             return false;
   8871         addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
   8872     } else
   8873         addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
   8874 
   8875     return true;
   8876 }
   8877 
   8878 // -webkit-flow-from: none | <ident>
   8879 bool CSSParser::parseRegionThread(CSSPropertyID propId, bool important)
   8880 {
   8881     ASSERT(propId == CSSPropertyWebkitFlowFrom);
   8882     ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled());
   8883 
   8884     if (m_valueList->size() != 1)
   8885         return false;
   8886 
   8887     CSSParserValue* value = m_valueList->current();
   8888     if (!value)
   8889         return false;
   8890 
   8891     if (value->unit != CSSPrimitiveValue::CSS_IDENT)
   8892         return false;
   8893 
   8894     if (value->id == CSSValueNone)
   8895         addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
   8896     else {
   8897         String inputProperty = String(value->string);
   8898         if (!inputProperty.isEmpty()) {
   8899             if (!validFlowName(inputProperty))
   8900                 return false;
   8901             addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important);
   8902         } else
   8903             addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
   8904     }
   8905 
   8906     return true;
   8907 }
   8908 
   8909 bool CSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
   8910 {
   8911     propId1 = propId;
   8912     propId2 = propId;
   8913     propId3 = propId;
   8914     if (propId == CSSPropertyWebkitTransformOrigin) {
   8915         propId1 = CSSPropertyWebkitTransformOriginX;
   8916         propId2 = CSSPropertyWebkitTransformOriginY;
   8917         propId3 = CSSPropertyWebkitTransformOriginZ;
   8918     }
   8919 
   8920     switch (propId) {
   8921         case CSSPropertyWebkitTransformOrigin:
   8922             if (!parseTransformOriginShorthand(value, value2, value3))
   8923                 return false;
   8924             // parseTransformOriginShorthand advances the m_valueList pointer
   8925             break;
   8926         case CSSPropertyWebkitTransformOriginX: {
   8927             value = parseFillPositionX(m_valueList.get());
   8928             if (value)
   8929                 m_valueList->next();
   8930             break;
   8931         }
   8932         case CSSPropertyWebkitTransformOriginY: {
   8933             value = parseFillPositionY(m_valueList.get());
   8934             if (value)
   8935                 m_valueList->next();
   8936             break;
   8937         }
   8938         case CSSPropertyWebkitTransformOriginZ: {
   8939             if (validUnit(m_valueList->current(), FLength))
   8940                 value = createPrimitiveNumericValue(m_valueList->current());
   8941             if (value)
   8942                 m_valueList->next();
   8943             break;
   8944         }
   8945         default:
   8946             ASSERT_NOT_REACHED();
   8947             return false;
   8948     }
   8949 
   8950     return value;
   8951 }
   8952 
   8953 bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr<CSSValue>& value, RefPtr<CSSValue>& value2)
   8954 {
   8955     propId1 = propId;
   8956     propId2 = propId;
   8957     if (propId == CSSPropertyWebkitPerspectiveOrigin) {
   8958         propId1 = CSSPropertyWebkitPerspectiveOriginX;
   8959         propId2 = CSSPropertyWebkitPerspectiveOriginY;
   8960     }
   8961 
   8962     switch (propId) {
   8963         case CSSPropertyWebkitPerspectiveOrigin:
   8964             if (m_valueList->size() > 2)
   8965                 return false;
   8966             parse2ValuesFillPosition(m_valueList.get(), value, value2);
   8967             break;
   8968         case CSSPropertyWebkitPerspectiveOriginX: {
   8969             value = parseFillPositionX(m_valueList.get());
   8970             if (value)
   8971                 m_valueList->next();
   8972             break;
   8973         }
   8974         case CSSPropertyWebkitPerspectiveOriginY: {
   8975             value = parseFillPositionY(m_valueList.get());
   8976             if (value)
   8977                 m_valueList->next();
   8978             break;
   8979         }
   8980         default:
   8981             ASSERT_NOT_REACHED();
   8982             return false;
   8983     }
   8984 
   8985     return value;
   8986 }
   8987 
   8988 void CSSParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important)
   8989 {
   8990     // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
   8991     if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
   8992         for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
   8993             if (m_parsedProperties[i].id() == CSSPropertyTextDecorationLine)
   8994                 return;
   8995         }
   8996     }
   8997     addProperty(propId, value, important);
   8998 }
   8999 
   9000 bool CSSParser::parseTextDecoration(CSSPropertyID propId, bool important)
   9001 {
   9002     if (propId == CSSPropertyTextDecorationLine
   9003         && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
   9004         return false;
   9005 
   9006     CSSParserValue* value = m_valueList->current();
   9007     if (value && value->id == CSSValueNone) {
   9008         addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
   9009         m_valueList->next();
   9010         return true;
   9011     }
   9012 
   9013     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   9014     bool isValid = true;
   9015     while (isValid && value) {
   9016         switch (value->id) {
   9017         case CSSValueUnderline:
   9018         case CSSValueOverline:
   9019         case CSSValueLineThrough:
   9020         case CSSValueBlink:
   9021             list->append(cssValuePool().createIdentifierValue(value->id));
   9022             break;
   9023         default:
   9024             isValid = false;
   9025             break;
   9026         }
   9027         if (isValid)
   9028             value = m_valueList->next();
   9029     }
   9030 
   9031     if (list->length() && isValid) {
   9032         addTextDecorationProperty(propId, list.release(), important);
   9033         return true;
   9034     }
   9035 
   9036     return false;
   9037 }
   9038 
   9039 #if ENABLE(CSS3_TEXT)
   9040 bool CSSParser::parseTextUnderlinePosition(bool important)
   9041 {
   9042     // The text-underline-position property has sintax "auto | alphabetic | [ under || [ left | right ] ]".
   9043     // However, values 'left' and 'right' are not implemented yet, so we will parse sintax
   9044     // "auto | alphabetic | under" for now.
   9045     CSSParserValue* value = m_valueList->current();
   9046     switch (value->id) {
   9047     case CSSValueAuto:
   9048     case CSSValueAlphabetic:
   9049     case CSSValueUnder:
   9050         if (m_valueList->next())
   9051             return false;
   9052 
   9053         addProperty(CSSPropertyWebkitTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
   9054         return true;
   9055     }
   9056     return false;
   9057 }
   9058 #endif // CSS3_TEXT
   9059 
   9060 bool CSSParser::parseTextEmphasisStyle(bool important)
   9061 {
   9062     unsigned valueListSize = m_valueList->size();
   9063 
   9064     RefPtr<CSSPrimitiveValue> fill;
   9065     RefPtr<CSSPrimitiveValue> shape;
   9066 
   9067     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   9068         if (value->unit == CSSPrimitiveValue::CSS_STRING) {
   9069             if (fill || shape || (valueListSize != 1 && !inShorthand()))
   9070                 return false;
   9071             addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
   9072             m_valueList->next();
   9073             return true;
   9074         }
   9075 
   9076         if (value->id == CSSValueNone) {
   9077             if (fill || shape || (valueListSize != 1 && !inShorthand()))
   9078                 return false;
   9079             addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
   9080             m_valueList->next();
   9081             return true;
   9082         }
   9083 
   9084         if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
   9085             if (fill)
   9086                 return false;
   9087             fill = cssValuePool().createIdentifierValue(value->id);
   9088         } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
   9089             if (shape)
   9090                 return false;
   9091             shape = cssValuePool().createIdentifierValue(value->id);
   9092         } else if (!inShorthand())
   9093             return false;
   9094         else
   9095             break;
   9096     }
   9097 
   9098     if (fill && shape) {
   9099         RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
   9100         parsedValues->append(fill.release());
   9101         parsedValues->append(shape.release());
   9102         addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
   9103         return true;
   9104     }
   9105     if (fill) {
   9106         addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
   9107         return true;
   9108     }
   9109     if (shape) {
   9110         addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
   9111         return true;
   9112     }
   9113 
   9114     return false;
   9115 }
   9116 
   9117 PassRefPtr<CSSValue> CSSParser::parseTextIndent()
   9118 {
   9119     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   9120 
   9121     // <length> | <percentage> | inherit
   9122     if (m_valueList->size() == 1) {
   9123         CSSParserValue* value = m_valueList->current();
   9124         if (!value->id && validUnit(value, FLength | FPercent)) {
   9125             list->append(createPrimitiveNumericValue(value));
   9126             m_valueList->next();
   9127             return list.release();
   9128         }
   9129     }
   9130 
   9131 #if ENABLE(CSS3_TEXT)
   9132     // The case where text-indent has only <length>(or <percentage>) value
   9133     // is handled above if statement even though CSS3_TEXT is enabled.
   9134 
   9135     // [ [ <length> | <percentage> ] && -webkit-each-line ] | inherit
   9136     if (m_valueList->size() != 2)
   9137         return 0;
   9138 
   9139     CSSParserValue* firstValue = m_valueList->current();
   9140     CSSParserValue* secondValue = m_valueList->next();
   9141     CSSParserValue* lengthOrPercentageValue = 0;
   9142 
   9143     // [ <length> | <percentage> ] -webkit-each-line
   9144     if (validUnit(firstValue, FLength | FPercent) && secondValue->id == CSSValueWebkitEachLine)
   9145         lengthOrPercentageValue = firstValue;
   9146     // -webkit-each-line [ <length> | <percentage> ]
   9147     else if (firstValue->id == CSSValueWebkitEachLine && validUnit(secondValue, FLength | FPercent))
   9148         lengthOrPercentageValue = secondValue;
   9149 
   9150     if (lengthOrPercentageValue) {
   9151         list->append(createPrimitiveNumericValue(lengthOrPercentageValue));
   9152         list->append(cssValuePool().createIdentifierValue(CSSValueWebkitEachLine));
   9153         m_valueList->next();
   9154         return list.release();
   9155     }
   9156 #endif
   9157 
   9158     return 0;
   9159 }
   9160 
   9161 bool CSSParser::parseLineBoxContain(bool important)
   9162 {
   9163     LineBoxContain lineBoxContain = LineBoxContainNone;
   9164 
   9165     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   9166         if (value->id == CSSValueBlock) {
   9167             if (lineBoxContain & LineBoxContainBlock)
   9168                 return false;
   9169             lineBoxContain |= LineBoxContainBlock;
   9170         } else if (value->id == CSSValueInline) {
   9171             if (lineBoxContain & LineBoxContainInline)
   9172                 return false;
   9173             lineBoxContain |= LineBoxContainInline;
   9174         } else if (value->id == CSSValueFont) {
   9175             if (lineBoxContain & LineBoxContainFont)
   9176                 return false;
   9177             lineBoxContain |= LineBoxContainFont;
   9178         } else if (value->id == CSSValueGlyphs) {
   9179             if (lineBoxContain & LineBoxContainGlyphs)
   9180                 return false;
   9181             lineBoxContain |= LineBoxContainGlyphs;
   9182         } else if (value->id == CSSValueReplaced) {
   9183             if (lineBoxContain & LineBoxContainReplaced)
   9184                 return false;
   9185             lineBoxContain |= LineBoxContainReplaced;
   9186         } else if (value->id == CSSValueInlineBox) {
   9187             if (lineBoxContain & LineBoxContainInlineBox)
   9188                 return false;
   9189             lineBoxContain |= LineBoxContainInlineBox;
   9190         } else
   9191             return false;
   9192     }
   9193 
   9194     if (!lineBoxContain)
   9195         return false;
   9196 
   9197     addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
   9198     return true;
   9199 }
   9200 
   9201 bool CSSParser::parseFontFeatureTag(CSSValueList* settings)
   9202 {
   9203     // Feature tag name consists of 4-letter characters.
   9204     static const unsigned tagNameLength = 4;
   9205 
   9206     CSSParserValue* value = m_valueList->current();
   9207     // Feature tag name comes first
   9208     if (value->unit != CSSPrimitiveValue::CSS_STRING)
   9209         return false;
   9210     if (value->string.length() != tagNameLength)
   9211         return false;
   9212     for (unsigned i = 0; i < tagNameLength; ++i) {
   9213         // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
   9214         UChar character = value->string[i];
   9215         if (character < 0x20 || character > 0x7E)
   9216             return false;
   9217     }
   9218 
   9219     String tag = value->string;
   9220     int tagValue = 1;
   9221     // Feature tag values could follow: <integer> | on | off
   9222     value = m_valueList->next();
   9223     if (value) {
   9224         if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
   9225             tagValue = clampToInteger(value->fValue);
   9226             if (tagValue < 0)
   9227                 return false;
   9228             m_valueList->next();
   9229         } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
   9230             tagValue = value->id == CSSValueOn;
   9231             m_valueList->next();
   9232         }
   9233     }
   9234     settings->append(FontFeatureValue::create(tag, tagValue));
   9235     return true;
   9236 }
   9237 
   9238 bool CSSParser::parseFontFeatureSettings(bool important)
   9239 {
   9240     if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
   9241         RefPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
   9242         m_valueList->next();
   9243         addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
   9244         return true;
   9245     }
   9246 
   9247     RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
   9248     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   9249         if (!parseFontFeatureTag(settings.get()))
   9250             return false;
   9251 
   9252         // If the list isn't parsed fully, the current value should be comma.
   9253         value = m_valueList->current();
   9254         if (value && !isComma(value))
   9255             return false;
   9256     }
   9257     if (settings->length()) {
   9258         addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
   9259         return true;
   9260     }
   9261     return false;
   9262 }
   9263 
   9264 bool CSSParser::parseFontVariantLigatures(bool important)
   9265 {
   9266     RefPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
   9267     bool sawCommonLigaturesValue = false;
   9268     bool sawDiscretionaryLigaturesValue = false;
   9269     bool sawHistoricalLigaturesValue = false;
   9270 
   9271     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   9272         if (value->unit != CSSPrimitiveValue::CSS_IDENT)
   9273             return false;
   9274 
   9275         switch (value->id) {
   9276         case CSSValueNoCommonLigatures:
   9277         case CSSValueCommonLigatures:
   9278             if (sawCommonLigaturesValue)
   9279                 return false;
   9280             sawCommonLigaturesValue = true;
   9281             ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
   9282             break;
   9283         case CSSValueNoDiscretionaryLigatures:
   9284         case CSSValueDiscretionaryLigatures:
   9285             if (sawDiscretionaryLigaturesValue)
   9286                 return false;
   9287             sawDiscretionaryLigaturesValue = true;
   9288             ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
   9289             break;
   9290         case CSSValueNoHistoricalLigatures:
   9291         case CSSValueHistoricalLigatures:
   9292             if (sawHistoricalLigaturesValue)
   9293                 return false;
   9294             sawHistoricalLigaturesValue = true;
   9295             ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
   9296             break;
   9297         default:
   9298             return false;
   9299         }
   9300     }
   9301 
   9302     if (!ligatureValues->length())
   9303         return false;
   9304 
   9305     addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important);
   9306     return true;
   9307 }
   9308 
   9309 bool CSSParser::parseCalculation(CSSParserValue* value, CalculationPermittedValueRange range)
   9310 {
   9311     ASSERT(isCalculation(value));
   9312 
   9313     CSSParserValueList* args = value->function->args.get();
   9314     if (!args || !args->size())
   9315         return false;
   9316 
   9317     ASSERT(!m_parsedCalculation);
   9318     m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
   9319 
   9320     if (!m_parsedCalculation)
   9321         return false;
   9322 
   9323     return true;
   9324 }
   9325 
   9326 #define END_TOKEN 0
   9327 
   9328 #include "CSSGrammar.h"
   9329 
   9330 enum CharacterType {
   9331     // Types for the main switch.
   9332 
   9333     // The first 4 types must be grouped together, as they
   9334     // represent the allowed chars in an identifier.
   9335     CharacterCaselessU,
   9336     CharacterIdentifierStart,
   9337     CharacterNumber,
   9338     CharacterDash,
   9339 
   9340     CharacterOther,
   9341     CharacterNull,
   9342     CharacterWhiteSpace,
   9343     CharacterEndMediaQueryOrSupports,
   9344     CharacterEndNthChild,
   9345     CharacterQuote,
   9346     CharacterExclamationMark,
   9347     CharacterHashmark,
   9348     CharacterDollar,
   9349     CharacterAsterisk,
   9350     CharacterPlus,
   9351     CharacterDot,
   9352     CharacterSlash,
   9353     CharacterLess,
   9354     CharacterAt,
   9355     CharacterBackSlash,
   9356     CharacterXor,
   9357     CharacterVerticalBar,
   9358     CharacterTilde,
   9359 };
   9360 
   9361 // 128 ASCII codes
   9362 static const CharacterType typesOfASCIICharacters[128] = {
   9363 /*   0 - Null               */ CharacterNull,
   9364 /*   1 - Start of Heading   */ CharacterOther,
   9365 /*   2 - Start of Text      */ CharacterOther,
   9366 /*   3 - End of Text        */ CharacterOther,
   9367 /*   4 - End of Transm.     */ CharacterOther,
   9368 /*   5 - Enquiry            */ CharacterOther,
   9369 /*   6 - Acknowledgment     */ CharacterOther,
   9370 /*   7 - Bell               */ CharacterOther,
   9371 /*   8 - Back Space         */ CharacterOther,
   9372 /*   9 - Horizontal Tab     */ CharacterWhiteSpace,
   9373 /*  10 - Line Feed          */ CharacterWhiteSpace,
   9374 /*  11 - Vertical Tab       */ CharacterOther,
   9375 /*  12 - Form Feed          */ CharacterWhiteSpace,
   9376 /*  13 - Carriage Return    */ CharacterWhiteSpace,
   9377 /*  14 - Shift Out          */ CharacterOther,
   9378 /*  15 - Shift In           */ CharacterOther,
   9379 /*  16 - Data Line Escape   */ CharacterOther,
   9380 /*  17 - Device Control 1   */ CharacterOther,
   9381 /*  18 - Device Control 2   */ CharacterOther,
   9382 /*  19 - Device Control 3   */ CharacterOther,
   9383 /*  20 - Device Control 4   */ CharacterOther,
   9384 /*  21 - Negative Ack.      */ CharacterOther,
   9385 /*  22 - Synchronous Idle   */ CharacterOther,
   9386 /*  23 - End of Transmit    */ CharacterOther,
   9387 /*  24 - Cancel             */ CharacterOther,
   9388 /*  25 - End of Medium      */ CharacterOther,
   9389 /*  26 - Substitute         */ CharacterOther,
   9390 /*  27 - Escape             */ CharacterOther,
   9391 /*  28 - File Separator     */ CharacterOther,
   9392 /*  29 - Group Separator    */ CharacterOther,
   9393 /*  30 - Record Separator   */ CharacterOther,
   9394 /*  31 - Unit Separator     */ CharacterOther,
   9395 /*  32 - Space              */ CharacterWhiteSpace,
   9396 /*  33 - !                  */ CharacterExclamationMark,
   9397 /*  34 - "                  */ CharacterQuote,
   9398 /*  35 - #                  */ CharacterHashmark,
   9399 /*  36 - $                  */ CharacterDollar,
   9400 /*  37 - %                  */ CharacterOther,
   9401 /*  38 - &                  */ CharacterOther,
   9402 /*  39 - '                  */ CharacterQuote,
   9403 /*  40 - (                  */ CharacterOther,
   9404 /*  41 - )                  */ CharacterEndNthChild,
   9405 /*  42 - *                  */ CharacterAsterisk,
   9406 /*  43 - +                  */ CharacterPlus,
   9407 /*  44 - ,                  */ CharacterOther,
   9408 /*  45 - -                  */ CharacterDash,
   9409 /*  46 - .                  */ CharacterDot,
   9410 /*  47 - /                  */ CharacterSlash,
   9411 /*  48 - 0                  */ CharacterNumber,
   9412 /*  49 - 1                  */ CharacterNumber,
   9413 /*  50 - 2                  */ CharacterNumber,
   9414 /*  51 - 3                  */ CharacterNumber,
   9415 /*  52 - 4                  */ CharacterNumber,
   9416 /*  53 - 5                  */ CharacterNumber,
   9417 /*  54 - 6                  */ CharacterNumber,
   9418 /*  55 - 7                  */ CharacterNumber,
   9419 /*  56 - 8                  */ CharacterNumber,
   9420 /*  57 - 9                  */ CharacterNumber,
   9421 /*  58 - :                  */ CharacterOther,
   9422 /*  59 - ;                  */ CharacterEndMediaQueryOrSupports,
   9423 /*  60 - <                  */ CharacterLess,
   9424 /*  61 - =                  */ CharacterOther,
   9425 /*  62 - >                  */ CharacterOther,
   9426 /*  63 - ?                  */ CharacterOther,
   9427 /*  64 - @                  */ CharacterAt,
   9428 /*  65 - A                  */ CharacterIdentifierStart,
   9429 /*  66 - B                  */ CharacterIdentifierStart,
   9430 /*  67 - C                  */ CharacterIdentifierStart,
   9431 /*  68 - D                  */ CharacterIdentifierStart,
   9432 /*  69 - E                  */ CharacterIdentifierStart,
   9433 /*  70 - F                  */ CharacterIdentifierStart,
   9434 /*  71 - G                  */ CharacterIdentifierStart,
   9435 /*  72 - H                  */ CharacterIdentifierStart,
   9436 /*  73 - I                  */ CharacterIdentifierStart,
   9437 /*  74 - J                  */ CharacterIdentifierStart,
   9438 /*  75 - K                  */ CharacterIdentifierStart,
   9439 /*  76 - L                  */ CharacterIdentifierStart,
   9440 /*  77 - M                  */ CharacterIdentifierStart,
   9441 /*  78 - N                  */ CharacterIdentifierStart,
   9442 /*  79 - O                  */ CharacterIdentifierStart,
   9443 /*  80 - P                  */ CharacterIdentifierStart,
   9444 /*  81 - Q                  */ CharacterIdentifierStart,
   9445 /*  82 - R                  */ CharacterIdentifierStart,
   9446 /*  83 - S                  */ CharacterIdentifierStart,
   9447 /*  84 - T                  */ CharacterIdentifierStart,
   9448 /*  85 - U                  */ CharacterCaselessU,
   9449 /*  86 - V                  */ CharacterIdentifierStart,
   9450 /*  87 - W                  */ CharacterIdentifierStart,
   9451 /*  88 - X                  */ CharacterIdentifierStart,
   9452 /*  89 - Y                  */ CharacterIdentifierStart,
   9453 /*  90 - Z                  */ CharacterIdentifierStart,
   9454 /*  91 - [                  */ CharacterOther,
   9455 /*  92 - \                  */ CharacterBackSlash,
   9456 /*  93 - ]                  */ CharacterOther,
   9457 /*  94 - ^                  */ CharacterXor,
   9458 /*  95 - _                  */ CharacterIdentifierStart,
   9459 /*  96 - `                  */ CharacterOther,
   9460 /*  97 - a                  */ CharacterIdentifierStart,
   9461 /*  98 - b                  */ CharacterIdentifierStart,
   9462 /*  99 - c                  */ CharacterIdentifierStart,
   9463 /* 100 - d                  */ CharacterIdentifierStart,
   9464 /* 101 - e                  */ CharacterIdentifierStart,
   9465 /* 102 - f                  */ CharacterIdentifierStart,
   9466 /* 103 - g                  */ CharacterIdentifierStart,
   9467 /* 104 - h                  */ CharacterIdentifierStart,
   9468 /* 105 - i                  */ CharacterIdentifierStart,
   9469 /* 106 - j                  */ CharacterIdentifierStart,
   9470 /* 107 - k                  */ CharacterIdentifierStart,
   9471 /* 108 - l                  */ CharacterIdentifierStart,
   9472 /* 109 - m                  */ CharacterIdentifierStart,
   9473 /* 110 - n                  */ CharacterIdentifierStart,
   9474 /* 111 - o                  */ CharacterIdentifierStart,
   9475 /* 112 - p                  */ CharacterIdentifierStart,
   9476 /* 113 - q                  */ CharacterIdentifierStart,
   9477 /* 114 - r                  */ CharacterIdentifierStart,
   9478 /* 115 - s                  */ CharacterIdentifierStart,
   9479 /* 116 - t                  */ CharacterIdentifierStart,
   9480 /* 117 - u                  */ CharacterCaselessU,
   9481 /* 118 - v                  */ CharacterIdentifierStart,
   9482 /* 119 - w                  */ CharacterIdentifierStart,
   9483 /* 120 - x                  */ CharacterIdentifierStart,
   9484 /* 121 - y                  */ CharacterIdentifierStart,
   9485 /* 122 - z                  */ CharacterIdentifierStart,
   9486 /* 123 - {                  */ CharacterEndMediaQueryOrSupports,
   9487 /* 124 - |                  */ CharacterVerticalBar,
   9488 /* 125 - }                  */ CharacterOther,
   9489 /* 126 - ~                  */ CharacterTilde,
   9490 /* 127 - Delete             */ CharacterOther,
   9491 };
   9492 
   9493 // Utility functions for the CSS tokenizer.
   9494 
   9495 template <typename CharacterType>
   9496 static inline bool isCSSLetter(CharacterType character)
   9497 {
   9498     return character >= 128 || typesOfASCIICharacters[character] <= CharacterDash;
   9499 }
   9500 
   9501 template <typename CharacterType>
   9502 static inline bool isCSSEscape(CharacterType character)
   9503 {
   9504     return character >= ' ' && character != 127;
   9505 }
   9506 
   9507 template <typename CharacterType>
   9508 static inline bool isURILetter(CharacterType character)
   9509 {
   9510     return (character >= '*' && character != 127) || (character >= '#' && character <= '&') || character == '!';
   9511 }
   9512 
   9513 template <typename CharacterType>
   9514 static inline bool isIdentifierStartAfterDash(CharacterType* currentCharacter)
   9515 {
   9516     return isASCIIAlpha(currentCharacter[0]) || currentCharacter[0] == '_' || currentCharacter[0] >= 128
   9517         || (currentCharacter[0] == '\\' && isCSSEscape(currentCharacter[1]));
   9518 }
   9519 
   9520 template <typename CharacterType>
   9521 static inline bool isEqualToCSSIdentifier(CharacterType* cssString, const char* constantString)
   9522 {
   9523     // Compare an character memory data with a zero terminated string.
   9524     do {
   9525         // The input must be part of an identifier if constantChar or constString
   9526         // contains '-'. Otherwise toASCIILowerUnchecked('\r') would be equal to '-'.
   9527         ASSERT((*constantString >= 'a' && *constantString <= 'z') || *constantString == '-');
   9528         ASSERT(*constantString != '-' || isCSSLetter(*cssString));
   9529         if (toASCIILowerUnchecked(*cssString++) != (*constantString++))
   9530             return false;
   9531     } while (*constantString);
   9532     return true;
   9533 }
   9534 
   9535 template <typename CharacterType>
   9536 static inline bool isEqualToCSSCaseSensitiveIdentifier(CharacterType* string, const char* constantString)
   9537 {
   9538     ASSERT(*constantString);
   9539 
   9540     do {
   9541         if (*string++ != *constantString++)
   9542             return false;
   9543     } while (*constantString);
   9544     return true;
   9545 }
   9546 
   9547 template <typename CharacterType>
   9548 static CharacterType* checkAndSkipEscape(CharacterType* currentCharacter)
   9549 {
   9550     // Returns with 0, if escape check is failed. Otherwise
   9551     // it returns with the following character.
   9552     ASSERT(*currentCharacter == '\\');
   9553 
   9554     ++currentCharacter;
   9555     if (!isCSSEscape(*currentCharacter))
   9556         return 0;
   9557 
   9558     if (isASCIIHexDigit(*currentCharacter)) {
   9559         int length = 6;
   9560 
   9561         do {
   9562             ++currentCharacter;
   9563         } while (isASCIIHexDigit(*currentCharacter) && --length);
   9564 
   9565         // Optional space after the escape sequence.
   9566         if (isHTMLSpace(*currentCharacter))
   9567             ++currentCharacter;
   9568         return currentCharacter;
   9569     }
   9570     return currentCharacter + 1;
   9571 }
   9572 
   9573 template <typename CharacterType>
   9574 static inline CharacterType* skipWhiteSpace(CharacterType* currentCharacter)
   9575 {
   9576     while (isHTMLSpace(*currentCharacter))
   9577         ++currentCharacter;
   9578     return currentCharacter;
   9579 }
   9580 
   9581 // Main CSS tokenizer functions.
   9582 
   9583 template <>
   9584 const LChar* CSSParserString::characters<LChar>() const { return characters8(); }
   9585 
   9586 template <>
   9587 const UChar* CSSParserString::characters<UChar>() const { return characters16(); }
   9588 
   9589 template <>
   9590 inline LChar*& CSSParser::currentCharacter<LChar>()
   9591 {
   9592     return m_currentCharacter8;
   9593 }
   9594 
   9595 template <>
   9596 inline UChar*& CSSParser::currentCharacter<UChar>()
   9597 {
   9598     return m_currentCharacter16;
   9599 }
   9600 
   9601 UChar*& CSSParser::currentCharacter16()
   9602 {
   9603     if (!m_currentCharacter16) {
   9604         m_dataStart16 = adoptArrayPtr(new UChar[m_length]);
   9605         m_currentCharacter16 = m_dataStart16.get();
   9606     }
   9607 
   9608     return m_currentCharacter16;
   9609 }
   9610 
   9611 template <>
   9612 inline LChar* CSSParser::tokenStart<LChar>()
   9613 {
   9614     return m_tokenStart.ptr8;
   9615 }
   9616 
   9617 template <>
   9618 inline UChar* CSSParser::tokenStart<UChar>()
   9619 {
   9620     return m_tokenStart.ptr16;
   9621 }
   9622 
   9623 template <>
   9624 inline LChar* CSSParser::dataStart<LChar>()
   9625 {
   9626     return m_dataStart8.get();
   9627 }
   9628 
   9629 template <>
   9630 inline UChar* CSSParser::dataStart<UChar>()
   9631 {
   9632     return m_dataStart16.get();
   9633 }
   9634 
   9635 void CSSParser::ensureLineEndings()
   9636 {
   9637     if (!m_lineEndings)
   9638         m_lineEndings = lineEndings(*m_source);
   9639 }
   9640 
   9641 template <typename CharacterType>
   9642 inline CSSParserLocation CSSParser::tokenLocation()
   9643 {
   9644     CSSParserLocation location;
   9645     location.token.init(tokenStart<CharacterType>(), currentCharacter<CharacterType>() - tokenStart<CharacterType>());
   9646     location.lineNumber = m_tokenStartLineNumber;
   9647     location.offset = tokenStart<CharacterType>() - dataStart<CharacterType>();
   9648     return location;
   9649 }
   9650 
   9651 CSSParserLocation CSSParser::currentLocation()
   9652 {
   9653     if (is8BitSource())
   9654         return tokenLocation<LChar>();
   9655     else
   9656         return tokenLocation<UChar>();
   9657 }
   9658 
   9659 template <typename CharacterType>
   9660 inline bool CSSParser::isIdentifierStart()
   9661 {
   9662     // Check whether an identifier is started.
   9663     return isIdentifierStartAfterDash((*currentCharacter<CharacterType>() != '-') ? currentCharacter<CharacterType>() : currentCharacter<CharacterType>() + 1);
   9664 }
   9665 
   9666 template <typename CharacterType>
   9667 static inline CharacterType* checkAndSkipString(CharacterType* currentCharacter, int quote)
   9668 {
   9669     // Returns with 0, if string check is failed. Otherwise
   9670     // it returns with the following character. This is necessary
   9671     // since we cannot revert escape sequences, thus strings
   9672     // must be validated before parsing.
   9673     while (true) {
   9674         if (UNLIKELY(*currentCharacter == quote)) {
   9675             // String parsing is successful.
   9676             return currentCharacter + 1;
   9677         }
   9678         if (UNLIKELY(!*currentCharacter)) {
   9679             // String parsing is successful up to end of input.
   9680             return currentCharacter;
   9681         }
   9682         if (UNLIKELY(*currentCharacter <= '\r' && (*currentCharacter == '\n' || (*currentCharacter | 0x1) == '\r'))) {
   9683             // String parsing is failed for character '\n', '\f' or '\r'.
   9684             return 0;
   9685         }
   9686 
   9687         if (LIKELY(currentCharacter[0] != '\\'))
   9688             ++currentCharacter;
   9689         else if (currentCharacter[1] == '\n' || currentCharacter[1] == '\f')
   9690             currentCharacter += 2;
   9691         else if (currentCharacter[1] == '\r')
   9692             currentCharacter += currentCharacter[2] == '\n' ? 3 : 2;
   9693         else {
   9694             currentCharacter = checkAndSkipEscape(currentCharacter);
   9695             if (!currentCharacter)
   9696                 return 0;
   9697         }
   9698     }
   9699 }
   9700 
   9701 template <typename CharacterType>
   9702 unsigned CSSParser::parseEscape(CharacterType*& src)
   9703 {
   9704     ASSERT(*src == '\\' && isCSSEscape(src[1]));
   9705 
   9706     unsigned unicode = 0;
   9707 
   9708     ++src;
   9709     if (isASCIIHexDigit(*src)) {
   9710 
   9711         int length = 6;
   9712 
   9713         do {
   9714             unicode = (unicode << 4) + toASCIIHexValue(*src++);
   9715         } while (--length && isASCIIHexDigit(*src));
   9716 
   9717         // Characters above 0x10ffff are not handled.
   9718         if (unicode > 0x10ffff)
   9719             unicode = 0xfffd;
   9720 
   9721         // Optional space after the escape sequence.
   9722         if (isHTMLSpace(*src))
   9723             ++src;
   9724 
   9725         return unicode;
   9726     }
   9727 
   9728     return *currentCharacter<CharacterType>()++;
   9729 }
   9730 
   9731 template <>
   9732 inline void CSSParser::UnicodeToChars<LChar>(LChar*& result, unsigned unicode)
   9733 {
   9734     ASSERT(unicode <= 0xff);
   9735     *result = unicode;
   9736 
   9737     ++result;
   9738 }
   9739 
   9740 template <>
   9741 inline void CSSParser::UnicodeToChars<UChar>(UChar*& result, unsigned unicode)
   9742 {
   9743     // Replace unicode with a surrogate pairs when it is bigger than 0xffff
   9744     if (U16_LENGTH(unicode) == 2) {
   9745         *result++ = U16_LEAD(unicode);
   9746         *result = U16_TRAIL(unicode);
   9747     } else
   9748         *result = unicode;
   9749 
   9750     ++result;
   9751 }
   9752 
   9753 template <typename SrcCharacterType, typename DestCharacterType>
   9754 inline bool CSSParser::parseIdentifierInternal(SrcCharacterType*& src, DestCharacterType*& result, bool& hasEscape)
   9755 {
   9756     hasEscape = false;
   9757     do {
   9758         if (LIKELY(*src != '\\'))
   9759             *result++ = *src++;
   9760         else {
   9761             hasEscape = true;
   9762             SrcCharacterType* savedEscapeStart = src;
   9763             unsigned unicode = parseEscape<SrcCharacterType>(src);
   9764             if (unicode > 0xff && sizeof(DestCharacterType) == 1) {
   9765                 src = savedEscapeStart;
   9766                 return false;
   9767             }
   9768             UnicodeToChars(result, unicode);
   9769         }
   9770     } while (isCSSLetter(src[0]) || (src[0] == '\\' && isCSSEscape(src[1])));
   9771 
   9772     return true;
   9773 }
   9774 
   9775 template <typename CharacterType>
   9776 inline void CSSParser::parseIdentifier(CharacterType*& result, CSSParserString& resultString, bool& hasEscape)
   9777 {
   9778     // If a valid identifier start is found, we can safely
   9779     // parse the identifier until the next invalid character.
   9780     ASSERT(isIdentifierStart<CharacterType>());
   9781 
   9782     CharacterType* start = currentCharacter<CharacterType>();
   9783     if (UNLIKELY(!parseIdentifierInternal(currentCharacter<CharacterType>(), result, hasEscape))) {
   9784         // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue
   9785         ASSERT(is8BitSource());
   9786         UChar*& result16 = currentCharacter16();
   9787         UChar* start16 = result16;
   9788         int i = 0;
   9789         for (; i < result - start; i++)
   9790             result16[i] = start[i];
   9791 
   9792         result16 += i;
   9793 
   9794         parseIdentifierInternal(currentCharacter<CharacterType>(), result16, hasEscape);
   9795 
   9796         resultString.init(start16, result16 - start16);
   9797 
   9798         return;
   9799     }
   9800 
   9801     resultString.init(start, result - start);
   9802 }
   9803 
   9804 template <typename SrcCharacterType, typename DestCharacterType>
   9805 inline bool CSSParser::parseStringInternal(SrcCharacterType*& src, DestCharacterType*& result, UChar quote)
   9806 {
   9807     while (true) {
   9808         if (UNLIKELY(*src == quote)) {
   9809             // String parsing is done.
   9810             ++src;
   9811             return true;
   9812         }
   9813         if (UNLIKELY(!*src)) {
   9814             // String parsing is done, but don't advance pointer if at the end of input.
   9815             return true;
   9816         }
   9817         ASSERT(*src > '\r' || (*src < '\n' && *src) || *src == '\v');
   9818 
   9819         if (LIKELY(src[0] != '\\'))
   9820             *result++ = *src++;
   9821         else if (src[1] == '\n' || src[1] == '\f')
   9822             src += 2;
   9823         else if (src[1] == '\r')
   9824             src += src[2] == '\n' ? 3 : 2;
   9825         else {
   9826             SrcCharacterType* savedEscapeStart = src;
   9827             unsigned unicode = parseEscape<SrcCharacterType>(src);
   9828             if (unicode > 0xff && sizeof(DestCharacterType) == 1) {
   9829                 src = savedEscapeStart;
   9830                 return false;
   9831             }
   9832             UnicodeToChars(result, unicode);
   9833         }
   9834     }
   9835 
   9836     return true;
   9837 }
   9838 
   9839 template <typename CharacterType>
   9840 inline void CSSParser::parseString(CharacterType*& result, CSSParserString& resultString, UChar quote)
   9841 {
   9842     CharacterType* start = currentCharacter<CharacterType>();
   9843 
   9844     if (UNLIKELY(!parseStringInternal(currentCharacter<CharacterType>(), result, quote))) {
   9845         // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue
   9846         ASSERT(is8BitSource());
   9847         UChar*& result16 = currentCharacter16();
   9848         UChar* start16 = result16;
   9849         int i = 0;
   9850         for (; i < result - start; i++)
   9851             result16[i] = start[i];
   9852 
   9853         result16 += i;
   9854 
   9855         parseStringInternal(currentCharacter<CharacterType>(), result16, quote);
   9856 
   9857         resultString.init(start16, result16 - start16);
   9858         return;
   9859     }
   9860 
   9861     resultString.init(start, result - start);
   9862 }
   9863 
   9864 template <typename CharacterType>
   9865 inline bool CSSParser::findURI(CharacterType*& start, CharacterType*& end, UChar& quote)
   9866 {
   9867     start = skipWhiteSpace(currentCharacter<CharacterType>());
   9868 
   9869     if (*start == '"' || *start == '\'') {
   9870         quote = *start++;
   9871         end = checkAndSkipString(start, quote);
   9872         if (!end)
   9873             return false;
   9874     } else {
   9875         quote = 0;
   9876         end = start;
   9877         while (isURILetter(*end)) {
   9878             if (LIKELY(*end != '\\'))
   9879                 ++end;
   9880             else {
   9881                 end = checkAndSkipEscape(end);
   9882                 if (!end)
   9883                     return false;
   9884             }
   9885         }
   9886     }
   9887 
   9888     end = skipWhiteSpace(end);
   9889     if (*end != ')')
   9890         return false;
   9891 
   9892     return true;
   9893 }
   9894 
   9895 template <typename SrcCharacterType, typename DestCharacterType>
   9896 inline bool CSSParser::parseURIInternal(SrcCharacterType*& src, DestCharacterType*& dest, UChar quote)
   9897 {
   9898     if (quote) {
   9899         ASSERT(quote == '"' || quote == '\'');
   9900         return parseStringInternal(src, dest, quote);
   9901     }
   9902 
   9903     while (isURILetter(*src)) {
   9904         if (LIKELY(*src != '\\'))
   9905             *dest++ = *src++;
   9906         else {
   9907             unsigned unicode = parseEscape<SrcCharacterType>(src);
   9908             if (unicode > 0xff && sizeof(SrcCharacterType) == 1)
   9909                 return false;
   9910             UnicodeToChars(dest, unicode);
   9911         }
   9912     }
   9913 
   9914     return true;
   9915 }
   9916 
   9917 template <typename CharacterType>
   9918 inline void CSSParser::parseURI(CSSParserString& string)
   9919 {
   9920     CharacterType* uriStart;
   9921     CharacterType* uriEnd;
   9922     UChar quote;
   9923     if (!findURI(uriStart, uriEnd, quote))
   9924         return;
   9925 
   9926     CharacterType* dest = currentCharacter<CharacterType>() = uriStart;
   9927     if (LIKELY(parseURIInternal(currentCharacter<CharacterType>(), dest, quote)))
   9928         string.init(uriStart, dest - uriStart);
   9929     else {
   9930         // An escape sequence was encountered that can't be stored in 8 bits.
   9931         // Reset the current character to the start of the URI and re-parse with
   9932         // a 16-bit destination.
   9933         ASSERT(is8BitSource());
   9934         UChar* uriStart16 = currentCharacter16();
   9935         currentCharacter<CharacterType>() = uriStart;
   9936         bool result = parseURIInternal(currentCharacter<CharacterType>(), currentCharacter16(), quote);
   9937         ASSERT_UNUSED(result, result);
   9938         string.init(uriStart16, currentCharacter16() - uriStart16);
   9939     }
   9940 
   9941     currentCharacter<CharacterType>() = uriEnd + 1;
   9942     m_token = URI;
   9943 }
   9944 
   9945 template <typename CharacterType>
   9946 inline bool CSSParser::parseUnicodeRange()
   9947 {
   9948     CharacterType* character = currentCharacter<CharacterType>() + 1;
   9949     int length = 6;
   9950     ASSERT(*currentCharacter<CharacterType>() == '+');
   9951 
   9952     while (isASCIIHexDigit(*character) && length) {
   9953         ++character;
   9954         --length;
   9955     }
   9956 
   9957     if (length && *character == '?') {
   9958         // At most 5 hex digit followed by a question mark.
   9959         do {
   9960             ++character;
   9961             --length;
   9962         } while (*character == '?' && length);
   9963         currentCharacter<CharacterType>() = character;
   9964         return true;
   9965     }
   9966 
   9967     if (length < 6) {
   9968         // At least one hex digit.
   9969         if (character[0] == '-' && isASCIIHexDigit(character[1])) {
   9970             // Followed by a dash and a hex digit.
   9971             ++character;
   9972             length = 6;
   9973             do {
   9974                 ++character;
   9975             } while (--length && isASCIIHexDigit(*character));
   9976         }
   9977         currentCharacter<CharacterType>() = character;
   9978         return true;
   9979     }
   9980     return false;
   9981 }
   9982 
   9983 template <typename CharacterType>
   9984 bool CSSParser::parseNthChild()
   9985 {
   9986     CharacterType* character = currentCharacter<CharacterType>();
   9987 
   9988     while (isASCIIDigit(*character))
   9989         ++character;
   9990     if (isASCIIAlphaCaselessEqual(*character, 'n')) {
   9991         currentCharacter<CharacterType>() = character + 1;
   9992         return true;
   9993     }
   9994     return false;
   9995 }
   9996 
   9997 template <typename CharacterType>
   9998 bool CSSParser::parseNthChildExtra()
   9999 {
   10000     CharacterType* character = skipWhiteSpace(currentCharacter<CharacterType>());
   10001     if (*character != '+' && *character != '-')
   10002         return false;
   10003 
   10004     character = skipWhiteSpace(character + 1);
   10005     if (!isASCIIDigit(*character))
   10006         return false;
   10007 
   10008     do {
   10009         ++character;
   10010     } while (isASCIIDigit(*character));
   10011 
   10012     currentCharacter<CharacterType>() = character;
   10013     return true;
   10014 }
   10015 
   10016 template <typename CharacterType>
   10017 inline bool CSSParser::detectFunctionTypeToken(int length)
   10018 {
   10019     ASSERT(length > 0);
   10020     CharacterType* name = tokenStart<CharacterType>();
   10021     SWITCH(name, length) {
   10022         CASE("not") {
   10023             m_token = NOTFUNCTION;
   10024             return true;
   10025         }
   10026         CASE("url") {
   10027             m_token = URI;
   10028             return true;
   10029         }
   10030         CASE("cue") {
   10031             m_token = CUEFUNCTION;
   10032             return true;
   10033         }
   10034         CASE("var") {
   10035             if (!RuntimeEnabledFeatures::cssVariablesEnabled())
   10036                 return false;
   10037             m_token = VARFUNCTION;
   10038             return true;
   10039         }
   10040         CASE("calc") {
   10041             m_token = CALCFUNCTION;
   10042             return true;
   10043         }
   10044         CASE("host") {
   10045             m_token = HOSTFUNCTION;
   10046             return true;
   10047         }
   10048         CASE("nth-child") {
   10049             m_parsingMode = NthChildMode;
   10050             return true;
   10051         }
   10052         CASE("nth-of-type") {
   10053             m_parsingMode = NthChildMode;
   10054             return true;
   10055         }
   10056         CASE("nth-last-child") {
   10057             m_parsingMode = NthChildMode;
   10058             return true;
   10059         }
   10060         CASE("nth-last-of-type") {
   10061             m_parsingMode = NthChildMode;
   10062             return true;
   10063         }
   10064         CASE("part") {
   10065             m_token = PARTFUNCTION;
   10066             return true;
   10067         }
   10068     }
   10069     return false;
   10070 }
   10071 
   10072 template <typename CharacterType>
   10073 inline void CSSParser::detectMediaQueryToken(int length)
   10074 {
   10075     ASSERT(m_parsingMode == MediaQueryMode);
   10076     CharacterType* name = tokenStart<CharacterType>();
   10077 
   10078     SWITCH(name, length) {
   10079         CASE("and") {
   10080             m_token = MEDIA_AND;
   10081         }
   10082         CASE("not") {
   10083             m_token = MEDIA_NOT;
   10084         }
   10085         CASE("only") {
   10086             m_token = MEDIA_ONLY;
   10087         }
   10088     }
   10089 }
   10090 
   10091 template <typename CharacterType>
   10092 inline void CSSParser::detectNumberToken(CharacterType* type, int length)
   10093 {
   10094     ASSERT(length > 0);
   10095 
   10096     SWITCH(type, length) {
   10097         CASE("cm") {
   10098             m_token = CMS;
   10099         }
   10100         CASE("ch") {
   10101             m_token = CHS;
   10102         }
   10103         CASE("deg") {
   10104             m_token = DEGS;
   10105         }
   10106         CASE("dppx") {
   10107                 // There is a discussion about the name of this unit on www-style.
   10108                 // Keep this compile time guard in place until that is resolved.
   10109                 // http://lists.w3.org/Archives/Public/www-style/2012May/0915.html
   10110             m_token = DPPX;
   10111         }
   10112         CASE("dpcm") {
   10113             m_token = DPCM;
   10114         }
   10115         CASE("dpi") {
   10116             m_token = DPI;
   10117         }
   10118         CASE("em") {
   10119             m_token = EMS;
   10120         }
   10121         CASE("ex") {
   10122             m_token = EXS;
   10123         }
   10124         CASE("fr") {
   10125             m_token = FR;
   10126         }
   10127         CASE("grad") {
   10128             m_token = GRADS;
   10129         }
   10130         CASE("hz") {
   10131             m_token = HERTZ;
   10132         }
   10133         CASE("in") {
   10134             m_token = INS;
   10135         }
   10136         CASE("khz") {
   10137             m_token = KHERTZ;
   10138         }
   10139         CASE("mm") {
   10140             m_token = MMS;
   10141         }
   10142         CASE("ms") {
   10143             m_token = MSECS;
   10144         }
   10145         CASE("px") {
   10146             m_token = PXS;
   10147         }
   10148         CASE("pt") {
   10149             m_token = PTS;
   10150         }
   10151         CASE("pc") {
   10152             m_token = PCS;
   10153         }
   10154         CASE("rad") {
   10155             m_token = RADS;
   10156         }
   10157         CASE("rem") {
   10158             m_token = REMS;
   10159         }
   10160         CASE("s") {
   10161             m_token = SECS;
   10162         }
   10163         CASE("turn") {
   10164             m_token = TURNS;
   10165         }
   10166         CASE("vw") {
   10167             m_token = VW;
   10168         }
   10169         CASE("vh") {
   10170             m_token = VH;
   10171         }
   10172         CASE("vmin") {
   10173             m_token = VMIN;
   10174         }
   10175         CASE("vmax") {
   10176             m_token = VMAX;
   10177         }
   10178         CASE("__qem") {
   10179             m_token = QEMS;
   10180         }
   10181     }
   10182 }
   10183 
   10184 template <typename CharacterType>
   10185 inline void CSSParser::detectDashToken(int length)
   10186 {
   10187     CharacterType* name = tokenStart<CharacterType>();
   10188 
   10189     // Ignore leading dash.
   10190     ++name;
   10191     --length;
   10192 
   10193     SWITCH(name, length) {
   10194         CASE("webkit-any") {
   10195             m_token = ANYFUNCTION;
   10196         }
   10197         CASE("webkit-min") {
   10198             m_token = MINFUNCTION;
   10199         }
   10200         CASE("webkit-max") {
   10201             m_token = MAXFUNCTION;
   10202         }
   10203         CASE("webkit-calc") {
   10204             m_token = CALCFUNCTION;
   10205         }
   10206         CASE("webkit-distributed") {
   10207             m_token = DISTRIBUTEDFUNCTION;
   10208         }
   10209     }
   10210 }
   10211 
   10212 template <typename CharacterType>
   10213 inline void CSSParser::detectAtToken(int length, bool hasEscape)
   10214 {
   10215     CharacterType* name = tokenStart<CharacterType>();
   10216     ASSERT(name[0] == '@' && length >= 2);
   10217 
   10218     // Ignore leading @.
   10219     ++name;
   10220     --length;
   10221 
   10222     // charset, font-face, import, media, namespace, page, supports,
   10223     // -webkit-keyframes, and -webkit-mediaquery are not affected by hasEscape.
   10224     SWITCH(name, length) {
   10225         CASE("bottom-left") {
   10226             if (LIKELY(!hasEscape))
   10227                 m_token = BOTTOMLEFT_SYM;
   10228         }
   10229         CASE("bottom-right") {
   10230             if (LIKELY(!hasEscape))
   10231                 m_token = BOTTOMRIGHT_SYM;
   10232         }
   10233         CASE("bottom-center") {
   10234             if (LIKELY(!hasEscape))
   10235                 m_token = BOTTOMCENTER_SYM;
   10236         }
   10237         CASE("bottom-left-corner") {
   10238             if (LIKELY(!hasEscape))
   10239                 m_token = BOTTOMLEFTCORNER_SYM;
   10240         }
   10241         CASE("bottom-right-corner") {
   10242             if (LIKELY(!hasEscape))
   10243                 m_token = BOTTOMRIGHTCORNER_SYM;
   10244         }
   10245         CASE("charset") {
   10246             if (name - 1 == dataStart<CharacterType>())
   10247                 m_token = CHARSET_SYM;
   10248         }
   10249         CASE("font-face") {
   10250             m_token = FONT_FACE_SYM;
   10251         }
   10252         CASE("host") {
   10253             m_token = HOST_SYM;
   10254         }
   10255         CASE("import") {
   10256             m_parsingMode = MediaQueryMode;
   10257             m_token = IMPORT_SYM;
   10258         }
   10259         CASE("left-top") {
   10260             if (LIKELY(!hasEscape))
   10261                 m_token = LEFTTOP_SYM;
   10262         }
   10263         CASE("left-middle") {
   10264             if (LIKELY(!hasEscape))
   10265                 m_token = LEFTMIDDLE_SYM;
   10266         }
   10267         CASE("left-bottom") {
   10268             if (LIKELY(!hasEscape))
   10269                 m_token = LEFTBOTTOM_SYM;
   10270         }
   10271         CASE("media") {
   10272             m_parsingMode = MediaQueryMode;
   10273             m_token = MEDIA_SYM;
   10274         }
   10275         CASE("namespace") {
   10276             m_token = NAMESPACE_SYM;
   10277         }
   10278         CASE("page") {
   10279             m_token = PAGE_SYM;
   10280         }
   10281         CASE("right-top") {
   10282             if (LIKELY(!hasEscape))
   10283                 m_token = RIGHTTOP_SYM;
   10284         }
   10285         CASE("right-middle") {
   10286             if (LIKELY(!hasEscape))
   10287                 m_token = RIGHTMIDDLE_SYM;
   10288         }
   10289         CASE("right-bottom") {
   10290             if (LIKELY(!hasEscape))
   10291                 m_token = RIGHTBOTTOM_SYM;
   10292         }
   10293         CASE("supports") {
   10294             m_parsingMode = SupportsMode;
   10295             m_token = SUPPORTS_SYM;
   10296         }
   10297         CASE("top-left") {
   10298             if (LIKELY(!hasEscape))
   10299                 m_token = TOPLEFT_SYM;
   10300         }
   10301         CASE("top-right") {
   10302             if (LIKELY(!hasEscape))
   10303                 m_token = TOPRIGHT_SYM;
   10304         }
   10305         CASE("top-center") {
   10306             if (LIKELY(!hasEscape))
   10307                 m_token = TOPCENTER_SYM;
   10308         }
   10309         CASE("top-left-corner") {
   10310             if (LIKELY(!hasEscape))
   10311                 m_token = TOPLEFTCORNER_SYM;
   10312         }
   10313         CASE("top-right-corner") {
   10314             if (LIKELY(!hasEscape))
   10315                 m_token = TOPRIGHTCORNER_SYM;
   10316         }
   10317         CASE("viewport") {
   10318             m_token = VIEWPORT_RULE_SYM;
   10319         }
   10320         CASE("-internal-rule") {
   10321             if (LIKELY(!hasEscape))
   10322                 m_token = INTERNAL_RULE_SYM;
   10323         }
   10324         CASE("-webkit-region") {
   10325             if (LIKELY(!hasEscape))
   10326                 m_token = WEBKIT_REGION_RULE_SYM;
   10327         }
   10328         CASE("-webkit-filter") {
   10329             if (LIKELY(!hasEscape))
   10330                 m_token = WEBKIT_FILTER_RULE_SYM;
   10331         }
   10332         CASE("-internal-decls") {
   10333             if (LIKELY(!hasEscape))
   10334                 m_token = INTERNAL_DECLS_SYM;
   10335         }
   10336         CASE("-internal-value") {
   10337             if (LIKELY(!hasEscape))
   10338                 m_token = INTERNAL_VALUE_SYM;
   10339         }
   10340         CASE("-webkit-keyframes") {
   10341             m_token = WEBKIT_KEYFRAMES_SYM;
   10342         }
   10343         CASE("-internal-selector") {
   10344             if (LIKELY(!hasEscape))
   10345                 m_token = INTERNAL_SELECTOR_SYM;
   10346         }
   10347         CASE("-internal-medialist") {
   10348             m_parsingMode = MediaQueryMode;
   10349             m_token = INTERNAL_MEDIALIST_SYM;
   10350         }
   10351         CASE("-internal-keyframe-rule") {
   10352             if (LIKELY(!hasEscape))
   10353                 m_token = INTERNAL_KEYFRAME_RULE_SYM;
   10354         }
   10355         CASE("-internal-supports-condition") {
   10356             m_parsingMode = SupportsMode;
   10357             m_token = INTERNAL_SUPPORTS_CONDITION_SYM;
   10358         }
   10359     }
   10360 }
   10361 
   10362 template <typename CharacterType>
   10363 inline void CSSParser::detectSupportsToken(int length)
   10364 {
   10365     ASSERT(m_parsingMode == SupportsMode);
   10366     CharacterType* name = tokenStart<CharacterType>();
   10367 
   10368     SWITCH(name, length) {
   10369         CASE("or") {
   10370             m_token = SUPPORTS_OR;
   10371         }
   10372         CASE("and") {
   10373             m_token = SUPPORTS_AND;
   10374         }
   10375         CASE("not") {
   10376             m_token = SUPPORTS_NOT;
   10377         }
   10378     }
   10379 }
   10380 
   10381 template <typename CharacterType>
   10382 inline void CSSParser::detectCSSVariableDefinitionToken(int length)
   10383 {
   10384     static const unsigned prefixLength = sizeof("var-") - 1;
   10385     if (length <= prefixLength)
   10386         return;
   10387     CharacterType* name = tokenStart<CharacterType>();
   10388     COMPILE_ASSERT(prefixLength > 0, CSS_variable_prefix_must_be_nonempty);
   10389     if (name[prefixLength - 1] == '-' && isIdentifierStartAfterDash(name + prefixLength) && isEqualToCSSCaseSensitiveIdentifier(name, "var"))
   10390         m_token = VAR_DEFINITION;
   10391 }
   10392 
   10393 template <typename SrcCharacterType>
   10394 int CSSParser::realLex(void* yylvalWithoutType)
   10395 {
   10396     YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
   10397     // Write pointer for the next character.
   10398     SrcCharacterType* result;
   10399     CSSParserString resultString;
   10400     bool hasEscape;
   10401 
   10402     // The input buffer is terminated by a \0 character, so
   10403     // it is safe to read one character ahead of a known non-null.
   10404 #ifndef NDEBUG
   10405     // In debug we check with an ASSERT that the length is > 0 for string types.
   10406     yylval->string.clear();
   10407 #endif
   10408 
   10409 restartAfterComment:
   10410     result = currentCharacter<SrcCharacterType>();
   10411     setTokenStart(result);
   10412     m_tokenStartLineNumber = m_lineNumber;
   10413     m_token = *currentCharacter<SrcCharacterType>();
   10414     ++currentCharacter<SrcCharacterType>();
   10415 
   10416     switch ((m_token <= 127) ? typesOfASCIICharacters[m_token] : CharacterIdentifierStart) {
   10417     case CharacterCaselessU:
   10418         if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '+'))
   10419             if (parseUnicodeRange<SrcCharacterType>()) {
   10420                 m_token = UNICODERANGE;
   10421                 yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
   10422                 break;
   10423             }
   10424         // Fall through to CharacterIdentifierStart.
   10425 
   10426     case CharacterIdentifierStart:
   10427         --currentCharacter<SrcCharacterType>();
   10428         parseIdentifier(result, yylval->string, hasEscape);
   10429         m_token = IDENT;
   10430 
   10431         if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '(')) {
   10432             if (m_parsingMode == SupportsMode && !hasEscape) {
   10433                 detectSupportsToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
   10434                 if (m_token != IDENT)
   10435                     break;
   10436             }
   10437 
   10438             m_token = FUNCTION;
   10439             if (!hasEscape)
   10440                 detectFunctionTypeToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
   10441 
   10442             // Skip parenthesis
   10443             ++currentCharacter<SrcCharacterType>();
   10444             ++result;
   10445             ++yylval->string.m_length;
   10446 
   10447             if (token() == URI) {
   10448                 m_token = FUNCTION;
   10449                 // Check whether it is really an URI.
   10450                 if (yylval->string.is8Bit())
   10451                     parseURI<LChar>(yylval->string);
   10452                 else
   10453                     parseURI<UChar>(yylval->string);
   10454             }
   10455         } else if (UNLIKELY(m_parsingMode != NormalMode) && !hasEscape) {
   10456             if (m_parsingMode == MediaQueryMode)
   10457                 detectMediaQueryToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
   10458             else if (m_parsingMode == SupportsMode)
   10459                 detectSupportsToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
   10460             else if (m_parsingMode == NthChildMode && isASCIIAlphaCaselessEqual(tokenStart<SrcCharacterType>()[0], 'n')) {
   10461                 if (result - tokenStart<SrcCharacterType>() == 1) {
   10462                     // String "n" is IDENT but "n+1" is NTH.
   10463                     if (parseNthChildExtra<SrcCharacterType>()) {
   10464                         m_token = NTH;
   10465                         yylval->string.m_length = currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>();
   10466                     }
   10467                 } else if (result - tokenStart<SrcCharacterType>() >= 2 && tokenStart<SrcCharacterType>()[1] == '-') {
   10468                     // String "n-" is IDENT but "n-1" is NTH.
   10469                     // Set currentCharacter to '-' to continue parsing.
   10470                     SrcCharacterType* nextCharacter = result;
   10471                     currentCharacter<SrcCharacterType>() = tokenStart<SrcCharacterType>() + 1;
   10472                     if (parseNthChildExtra<SrcCharacterType>()) {
   10473                         m_token = NTH;
   10474                         yylval->string.setLength(currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
   10475                     } else {
   10476                         // Revert the change to currentCharacter if unsuccessful.
   10477                         currentCharacter<SrcCharacterType>() = nextCharacter;
   10478                     }
   10479                 }
   10480             }
   10481         } else if (UNLIKELY(RuntimeEnabledFeatures::cssVariablesEnabled())) {
   10482             detectCSSVariableDefinitionToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
   10483         }
   10484         break;
   10485 
   10486     case CharacterDot:
   10487         if (!isASCIIDigit(currentCharacter<SrcCharacterType>()[0]))
   10488             break;
   10489         // Fall through to CharacterNumber.
   10490 
   10491     case CharacterNumber: {
   10492         bool dotSeen = (m_token == '.');
   10493 
   10494         while (true) {
   10495             if (!isASCIIDigit(currentCharacter<SrcCharacterType>()[0])) {
   10496                 // Only one dot is allowed for a number,
   10497                 // and it must be followed by a digit.
   10498                 if (currentCharacter<SrcCharacterType>()[0] != '.' || dotSeen || !isASCIIDigit(currentCharacter<SrcCharacterType>()[1]))
   10499                     break;
   10500                 dotSeen = true;
   10501             }
   10502             ++currentCharacter<SrcCharacterType>();
   10503         }
   10504 
   10505         if (UNLIKELY(m_parsingMode == NthChildMode) && !dotSeen && isASCIIAlphaCaselessEqual(*currentCharacter<SrcCharacterType>(), 'n')) {
   10506             // "[0-9]+n" is always an NthChild.
   10507             ++currentCharacter<SrcCharacterType>();
   10508             parseNthChildExtra<SrcCharacterType>();
   10509             m_token = NTH;
   10510             yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
   10511             break;
   10512         }
   10513 
   10514         // Use SVG parser for numbers on SVG presentation attributes.
   10515         if (m_context.mode == SVGAttributeMode) {
   10516             // We need to take care of units like 'em' or 'ex'.
   10517             SrcCharacterType* character = currentCharacter<SrcCharacterType>();
   10518             if (isASCIIAlphaCaselessEqual(*character, 'e')) {
   10519                 ASSERT(character - tokenStart<SrcCharacterType>() > 0);
   10520                 ++character;
   10521                 if (*character == '-' || *character == '+' || isASCIIDigit(*character)) {
   10522                     ++character;
   10523                     while (isASCIIDigit(*character))
   10524                         ++character;
   10525                     // Use FLOATTOKEN if the string contains exponents.
   10526                     dotSeen = true;
   10527                     currentCharacter<SrcCharacterType>() = character;
   10528                 }
   10529             }
   10530             if (!parseSVGNumber(tokenStart<SrcCharacterType>(), character - tokenStart<SrcCharacterType>(), yylval->number))
   10531                 break;
   10532         } else {
   10533             yylval->number = charactersToDouble(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
   10534         }
   10535 
   10536         // Type of the function.
   10537         if (isIdentifierStart<SrcCharacterType>()) {
   10538             SrcCharacterType* type = currentCharacter<SrcCharacterType>();
   10539             result = currentCharacter<SrcCharacterType>();
   10540 
   10541             parseIdentifier(result, resultString, hasEscape);
   10542 
   10543             m_token = DIMEN;
   10544             if (!hasEscape)
   10545                 detectNumberToken(type, currentCharacter<SrcCharacterType>() - type);
   10546 
   10547             if (m_token == DIMEN) {
   10548                 // The decoded number is overwritten, but this is intentional.
   10549                 yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
   10550             }
   10551         } else if (*currentCharacter<SrcCharacterType>() == '%') {
   10552             // Although the CSS grammar says {num}% we follow
   10553             // webkit at the moment which uses {num}%+.
   10554             do {
   10555                 ++currentCharacter<SrcCharacterType>();
   10556             } while (*currentCharacter<SrcCharacterType>() == '%');
   10557             m_token = PERCENTAGE;
   10558         } else
   10559             m_token = dotSeen ? FLOATTOKEN : INTEGER;
   10560         break;
   10561     }
   10562 
   10563     case CharacterDash:
   10564         if (isIdentifierStartAfterDash(currentCharacter<SrcCharacterType>())) {
   10565             --currentCharacter<SrcCharacterType>();
   10566             parseIdentifier(result, resultString, hasEscape);
   10567             m_token = IDENT;
   10568 
   10569             if (*currentCharacter<SrcCharacterType>() == '(') {
   10570                 m_token = FUNCTION;
   10571                 if (!hasEscape)
   10572                     detectDashToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
   10573                 ++currentCharacter<SrcCharacterType>();
   10574                 ++result;
   10575             } else if (UNLIKELY(m_parsingMode == NthChildMode) && !hasEscape && isASCIIAlphaCaselessEqual(tokenStart<SrcCharacterType>()[1], 'n')) {
   10576                 if (result - tokenStart<SrcCharacterType>() == 2) {
   10577                     // String "-n" is IDENT but "-n+1" is NTH.
   10578                     if (parseNthChildExtra<SrcCharacterType>()) {
   10579                         m_token = NTH;
   10580                         result = currentCharacter<SrcCharacterType>();
   10581                     }
   10582                 } else if (result - tokenStart<SrcCharacterType>() >= 3 && tokenStart<SrcCharacterType>()[2] == '-') {
   10583                     // String "-n-" is IDENT but "-n-1" is NTH.
   10584                     // Set currentCharacter to second '-' of '-n-' to continue parsing.
   10585                     SrcCharacterType* nextCharacter = result;
   10586                     currentCharacter<SrcCharacterType>() = tokenStart<SrcCharacterType>() + 2;
   10587                     if (parseNthChildExtra<SrcCharacterType>()) {
   10588                         m_token = NTH;
   10589                         result = currentCharacter<SrcCharacterType>();
   10590                     } else {
   10591                         // Revert the change to currentCharacter if unsuccessful.
   10592                         currentCharacter<SrcCharacterType>() = nextCharacter;
   10593                     }
   10594                 }
   10595             }
   10596             resultString.setLength(result - tokenStart<SrcCharacterType>());
   10597             yylval->string = resultString;
   10598         } else if (currentCharacter<SrcCharacterType>()[0] == '-' && currentCharacter<SrcCharacterType>()[1] == '>') {
   10599             currentCharacter<SrcCharacterType>() += 2;
   10600             m_token = SGML_CD;
   10601         } else if (UNLIKELY(m_parsingMode == NthChildMode)) {
   10602             // "-[0-9]+n" is always an NthChild.
   10603             if (parseNthChild<SrcCharacterType>()) {
   10604                 parseNthChildExtra<SrcCharacterType>();
   10605                 m_token = NTH;
   10606                 yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
   10607             }
   10608         }
   10609         break;
   10610 
   10611     case CharacterOther:
   10612         // m_token is simply the current character.
   10613         break;
   10614 
   10615     case CharacterNull:
   10616         // Do not advance pointer at the end of input.
   10617         --currentCharacter<SrcCharacterType>();
   10618         break;
   10619 
   10620     case CharacterWhiteSpace:
   10621         m_token = WHITESPACE;
   10622         // Might start with a '\n'.
   10623         --currentCharacter<SrcCharacterType>();
   10624         do {
   10625             if (*currentCharacter<SrcCharacterType>() == '\n')
   10626                 ++m_lineNumber;
   10627             ++currentCharacter<SrcCharacterType>();
   10628         } while (*currentCharacter<SrcCharacterType>() <= ' ' && (typesOfASCIICharacters[*currentCharacter<SrcCharacterType>()] == CharacterWhiteSpace));
   10629         break;
   10630 
   10631     case CharacterEndMediaQueryOrSupports:
   10632         if (m_parsingMode == MediaQueryMode || m_parsingMode == SupportsMode)
   10633             m_parsingMode = NormalMode;
   10634         break;
   10635 
   10636     case CharacterEndNthChild:
   10637         if (m_parsingMode == NthChildMode)
   10638             m_parsingMode = NormalMode;
   10639         break;
   10640 
   10641     case CharacterQuote:
   10642         if (checkAndSkipString(currentCharacter<SrcCharacterType>(), m_token)) {
   10643             ++result;
   10644             parseString<SrcCharacterType>(result, yylval->string, m_token);
   10645             m_token = STRING;
   10646         }
   10647         break;
   10648 
   10649     case CharacterExclamationMark: {
   10650         SrcCharacterType* start = skipWhiteSpace(currentCharacter<SrcCharacterType>());
   10651         if (isEqualToCSSIdentifier(start, "important")) {
   10652             m_token = IMPORTANT_SYM;
   10653             currentCharacter<SrcCharacterType>() = start + 9;
   10654         }
   10655         break;
   10656     }
   10657 
   10658     case CharacterHashmark: {
   10659         SrcCharacterType* start = currentCharacter<SrcCharacterType>();
   10660         result = currentCharacter<SrcCharacterType>();
   10661 
   10662         if (isASCIIDigit(*currentCharacter<SrcCharacterType>())) {
   10663             // This must be a valid hex number token.
   10664             do {
   10665                 ++currentCharacter<SrcCharacterType>();
   10666             } while (isASCIIHexDigit(*currentCharacter<SrcCharacterType>()));
   10667             m_token = HEX;
   10668             yylval->string.init(start, currentCharacter<SrcCharacterType>() - start);
   10669         } else if (isIdentifierStart<SrcCharacterType>()) {
   10670             m_token = IDSEL;
   10671             parseIdentifier(result, yylval->string, hasEscape);
   10672             if (!hasEscape) {
   10673                 // Check whether the identifier is also a valid hex number.
   10674                 SrcCharacterType* current = start;
   10675                 m_token = HEX;
   10676                 do {
   10677                     if (!isASCIIHexDigit(*current)) {
   10678                         m_token = IDSEL;
   10679                         break;
   10680                     }
   10681                     ++current;
   10682                 } while (current < result);
   10683             }
   10684         }
   10685         break;
   10686     }
   10687 
   10688     case CharacterSlash:
   10689         // Ignore comments. They are not even considered as white spaces.
   10690         if (*currentCharacter<SrcCharacterType>() == '*') {
   10691             const CSSParserLocation startLocation = currentLocation();
   10692             if (m_sourceDataHandler) {
   10693                 unsigned startOffset = (is8BitSource() ? currentCharacter<LChar>() - m_dataStart8.get() : currentCharacter<UChar>() - m_dataStart16.get()) - 1; // Start with a slash.
   10694                 m_sourceDataHandler->startComment(startOffset - m_parsedTextPrefixLength);
   10695             }
   10696             ++currentCharacter<SrcCharacterType>();
   10697             while (currentCharacter<SrcCharacterType>()[0] != '*' || currentCharacter<SrcCharacterType>()[1] != '/') {
   10698                 if (*currentCharacter<SrcCharacterType>() == '\n')
   10699                     ++m_lineNumber;
   10700                 if (*currentCharacter<SrcCharacterType>() == '\0') {
   10701                     // Unterminated comments are simply ignored.
   10702                     currentCharacter<SrcCharacterType>() -= 2;
   10703                     reportError(startLocation, UnterminatedCommentError);
   10704                     break;
   10705                 }
   10706                 ++currentCharacter<SrcCharacterType>();
   10707             }
   10708             currentCharacter<SrcCharacterType>() += 2;
   10709             if (m_sourceDataHandler) {
   10710                 unsigned endOffset = is8BitSource() ? currentCharacter<LChar>() - m_dataStart8.get() : currentCharacter<UChar>() - m_dataStart16.get();
   10711                 unsigned userTextEndOffset = static_cast<unsigned>(m_length - 1 - m_parsedTextSuffixLength);
   10712                 m_sourceDataHandler->endComment(min(endOffset, userTextEndOffset) - m_parsedTextPrefixLength);
   10713             }
   10714             goto restartAfterComment;
   10715         }
   10716         break;
   10717 
   10718     case CharacterDollar:
   10719         if (*currentCharacter<SrcCharacterType>() == '=') {
   10720             ++currentCharacter<SrcCharacterType>();
   10721             m_token = ENDSWITH;
   10722         }
   10723         break;
   10724 
   10725     case CharacterAsterisk:
   10726         if (*currentCharacter<SrcCharacterType>() == '=') {
   10727             ++currentCharacter<SrcCharacterType>();
   10728             m_token = CONTAINS;
   10729         }
   10730         break;
   10731 
   10732     case CharacterPlus:
   10733         if (UNLIKELY(m_parsingMode == NthChildMode)) {
   10734             // Simplest case. "+[0-9]*n" is always NthChild.
   10735             if (parseNthChild<SrcCharacterType>()) {
   10736                 parseNthChildExtra<SrcCharacterType>();
   10737                 m_token = NTH;
   10738                 yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>());
   10739             }
   10740         }
   10741         break;
   10742 
   10743     case CharacterLess:
   10744         if (currentCharacter<SrcCharacterType>()[0] == '!' && currentCharacter<SrcCharacterType>()[1] == '-' && currentCharacter<SrcCharacterType>()[2] == '-') {
   10745             currentCharacter<SrcCharacterType>() += 3;
   10746             m_token = SGML_CD;
   10747         }
   10748         break;
   10749 
   10750     case CharacterAt:
   10751         if (isIdentifierStart<SrcCharacterType>()) {
   10752             m_token = ATKEYWORD;
   10753             ++result;
   10754             parseIdentifier(result, resultString, hasEscape);
   10755             detectAtToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>(), hasEscape);
   10756         }
   10757         break;
   10758 
   10759     case CharacterBackSlash:
   10760         if (isCSSEscape(*currentCharacter<SrcCharacterType>())) {
   10761             --currentCharacter<SrcCharacterType>();
   10762             parseIdentifier(result, yylval->string, hasEscape);
   10763             m_token = IDENT;
   10764         }
   10765         break;
   10766 
   10767     case CharacterXor:
   10768         if (*currentCharacter<SrcCharacterType>() == '=') {
   10769             ++currentCharacter<SrcCharacterType>();
   10770             m_token = BEGINSWITH;
   10771         }
   10772         break;
   10773 
   10774     case CharacterVerticalBar:
   10775         if (*currentCharacter<SrcCharacterType>() == '=') {
   10776             ++currentCharacter<SrcCharacterType>();
   10777             m_token = DASHMATCH;
   10778         }
   10779         break;
   10780 
   10781     case CharacterTilde:
   10782         if (*currentCharacter<SrcCharacterType>() == '=') {
   10783             ++currentCharacter<SrcCharacterType>();
   10784             m_token = INCLUDES;
   10785         }
   10786         break;
   10787 
   10788     default:
   10789         ASSERT_NOT_REACHED();
   10790         break;
   10791     }
   10792 
   10793     return token();
   10794 }
   10795 
   10796 CSSParserSelector* CSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName)
   10797 {
   10798     CSSParserSelector* selector = new CSSParserSelector(tagQName);
   10799     m_floatingSelectors.add(selector);
   10800     return selector;
   10801 }
   10802 
   10803 CSSParserSelector* CSSParser::createFloatingSelector()
   10804 {
   10805     CSSParserSelector* selector = new CSSParserSelector;
   10806     m_floatingSelectors.add(selector);
   10807     return selector;
   10808 }
   10809 
   10810 PassOwnPtr<CSSParserSelector> CSSParser::sinkFloatingSelector(CSSParserSelector* selector)
   10811 {
   10812     if (selector) {
   10813         ASSERT(m_floatingSelectors.contains(selector));
   10814         m_floatingSelectors.remove(selector);
   10815     }
   10816     return adoptPtr(selector);
   10817 }
   10818 
   10819 Vector<OwnPtr<CSSParserSelector> >* CSSParser::createFloatingSelectorVector()
   10820 {
   10821     Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
   10822     m_floatingSelectorVectors.add(selectorVector);
   10823     return selectorVector;
   10824 }
   10825 
   10826 PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > CSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
   10827 {
   10828     if (selectorVector) {
   10829         ASSERT(m_floatingSelectorVectors.contains(selectorVector));
   10830         m_floatingSelectorVectors.remove(selectorVector);
   10831     }
   10832     return adoptPtr(selectorVector);
   10833 }
   10834 
   10835 CSSParserValueList* CSSParser::createFloatingValueList()
   10836 {
   10837     CSSParserValueList* list = new CSSParserValueList;
   10838     m_floatingValueLists.add(list);
   10839     return list;
   10840 }
   10841 
   10842 PassOwnPtr<CSSParserValueList> CSSParser::sinkFloatingValueList(CSSParserValueList* list)
   10843 {
   10844     if (list) {
   10845         ASSERT(m_floatingValueLists.contains(list));
   10846         m_floatingValueLists.remove(list);
   10847     }
   10848     return adoptPtr(list);
   10849 }
   10850 
   10851 CSSParserFunction* CSSParser::createFloatingFunction()
   10852 {
   10853     CSSParserFunction* function = new CSSParserFunction;
   10854     m_floatingFunctions.add(function);
   10855     return function;
   10856 }
   10857 
   10858 CSSParserFunction* CSSParser::createFloatingFunction(const CSSParserString& name, PassOwnPtr<CSSParserValueList> args)
   10859 {
   10860     CSSParserFunction* function = createFloatingFunction();
   10861     function->name = name;
   10862     function->args = args;
   10863     return function;
   10864 }
   10865 
   10866 PassOwnPtr<CSSParserFunction> CSSParser::sinkFloatingFunction(CSSParserFunction* function)
   10867 {
   10868     if (function) {
   10869         ASSERT(m_floatingFunctions.contains(function));
   10870         m_floatingFunctions.remove(function);
   10871     }
   10872     return adoptPtr(function);
   10873 }
   10874 
   10875 CSSParserValue& CSSParser::sinkFloatingValue(CSSParserValue& value)
   10876 {
   10877     if (value.unit == CSSParserValue::Function) {
   10878         ASSERT(m_floatingFunctions.contains(value.function));
   10879         m_floatingFunctions.remove(value.function);
   10880     }
   10881     return value;
   10882 }
   10883 
   10884 MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values)
   10885 {
   10886     m_floatingMediaQueryExp = MediaQueryExp::create(mediaFeature, values);
   10887     return m_floatingMediaQueryExp.get();
   10888 }
   10889 
   10890 PassOwnPtr<MediaQueryExp> CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* expression)
   10891 {
   10892     ASSERT_UNUSED(expression, expression == m_floatingMediaQueryExp);
   10893     return m_floatingMediaQueryExp.release();
   10894 }
   10895 
   10896 Vector<OwnPtr<MediaQueryExp> >* CSSParser::createFloatingMediaQueryExpList()
   10897 {
   10898     m_floatingMediaQueryExpList = adoptPtr(new Vector<OwnPtr<MediaQueryExp> >);
   10899     return m_floatingMediaQueryExpList.get();
   10900 }
   10901 
   10902 PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > CSSParser::sinkFloatingMediaQueryExpList(Vector<OwnPtr<MediaQueryExp> >* list)
   10903 {
   10904     ASSERT_UNUSED(list, list == m_floatingMediaQueryExpList);
   10905     return m_floatingMediaQueryExpList.release();
   10906 }
   10907 
   10908 MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor restrictor, const String& mediaType, PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
   10909 {
   10910     m_floatingMediaQuery = adoptPtr(new MediaQuery(restrictor, mediaType, expressions));
   10911     return m_floatingMediaQuery.get();
   10912 }
   10913 
   10914 MediaQuery* CSSParser::createFloatingMediaQuery(PassOwnPtr<Vector<OwnPtr<MediaQueryExp> > > expressions)
   10915 {
   10916     return createFloatingMediaQuery(MediaQuery::None, "all", expressions);
   10917 }
   10918 
   10919 MediaQuery* CSSParser::createFloatingNotAllQuery()
   10920 {
   10921     return createFloatingMediaQuery(MediaQuery::Not, "all", sinkFloatingMediaQueryExpList(createFloatingMediaQueryExpList()));
   10922 }
   10923 
   10924 PassOwnPtr<MediaQuery> CSSParser::sinkFloatingMediaQuery(MediaQuery* query)
   10925 {
   10926     ASSERT_UNUSED(query, query == m_floatingMediaQuery);
   10927     return m_floatingMediaQuery.release();
   10928 }
   10929 
   10930 Vector<RefPtr<StyleKeyframe> >* CSSParser::createFloatingKeyframeVector()
   10931 {
   10932     m_floatingKeyframeVector = adoptPtr(new Vector<RefPtr<StyleKeyframe> >());
   10933     return m_floatingKeyframeVector.get();
   10934 }
   10935 
   10936 PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > CSSParser::sinkFloatingKeyframeVector(Vector<RefPtr<StyleKeyframe> >* keyframeVector)
   10937 {
   10938     ASSERT_UNUSED(keyframeVector, m_floatingKeyframeVector == keyframeVector);
   10939     return m_floatingKeyframeVector.release();
   10940 }
   10941 
   10942 MediaQuerySet* CSSParser::createMediaQuerySet()
   10943 {
   10944     RefPtr<MediaQuerySet> queries = MediaQuerySet::create();
   10945     MediaQuerySet* result = queries.get();
   10946     m_parsedMediaQuerySets.append(queries.release());
   10947     return result;
   10948 }
   10949 
   10950 StyleRuleBase* CSSParser::createImportRule(const CSSParserString& url, MediaQuerySet* media)
   10951 {
   10952     if (!media || !m_allowImportRules) {
   10953         endRuleBody(true);
   10954         return 0;
   10955     }
   10956     RefPtr<StyleRuleImport> rule = StyleRuleImport::create(url, media);
   10957     StyleRuleImport* result = rule.get();
   10958     m_parsedRules.append(rule.release());
   10959     endRuleBody();
   10960     return result;
   10961 }
   10962 
   10963 StyleRuleBase* CSSParser::createMediaRule(MediaQuerySet* media, RuleList* rules)
   10964 {
   10965     m_allowImportRules = m_allowNamespaceDeclarations = false;
   10966     RefPtr<StyleRuleMedia> rule;
   10967     if (rules)
   10968         rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), *rules);
   10969     else {
   10970         RuleList emptyRules;
   10971         rule = StyleRuleMedia::create(media ? media : MediaQuerySet::create(), emptyRules);
   10972     }
   10973     StyleRuleMedia* result = rule.get();
   10974     m_parsedRules.append(rule.release());
   10975     endRuleBody();
   10976     return result;
   10977 }
   10978 
   10979 StyleRuleBase* CSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules)
   10980 {
   10981     m_allowImportRules = m_allowNamespaceDeclarations = false;
   10982 
   10983     RefPtr<CSSRuleSourceData> data = popSupportsRuleData();
   10984     RefPtr<StyleRuleSupports> rule;
   10985     String conditionText;
   10986     unsigned conditionOffset = data->ruleHeaderRange.start + 9;
   10987     unsigned conditionLength = data->ruleHeaderRange.length() - 9;
   10988 
   10989     if (is8BitSource())
   10990         conditionText = String(m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace();
   10991     else
   10992         conditionText = String(m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace();
   10993 
   10994     if (rules)
   10995         rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules);
   10996     else {
   10997         RuleList emptyRules;
   10998         rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules);
   10999     }
   11000 
   11001     StyleRuleSupports* result = rule.get();
   11002     m_parsedRules.append(rule.release());
   11003     endRuleBody();
   11004 
   11005     return result;
   11006 }
   11007 
   11008 void CSSParser::markSupportsRuleHeaderStart()
   11009 {
   11010     if (!m_supportsRuleDataStack)
   11011         m_supportsRuleDataStack = adoptPtr(new RuleSourceDataList());
   11012 
   11013     RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE);
   11014     data->ruleHeaderRange.start = tokenStartOffset();
   11015     m_supportsRuleDataStack->append(data);
   11016 }
   11017 
   11018 void CSSParser::markSupportsRuleHeaderEnd()
   11019 {
   11020     ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
   11021 
   11022     if (is8BitSource())
   11023         m_supportsRuleDataStack->last()->ruleHeaderRange.end = tokenStart<LChar>() - m_dataStart8.get();
   11024     else
   11025         m_supportsRuleDataStack->last()->ruleHeaderRange.end = tokenStart<UChar>() - m_dataStart16.get();
   11026 }
   11027 
   11028 PassRefPtr<CSSRuleSourceData> CSSParser::popSupportsRuleData()
   11029 {
   11030     ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
   11031     RefPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last();
   11032     m_supportsRuleDataStack->removeLast();
   11033     return data.release();
   11034 }
   11035 
   11036 CSSParser::RuleList* CSSParser::createRuleList()
   11037 {
   11038     OwnPtr<RuleList> list = adoptPtr(new RuleList);
   11039     RuleList* listPtr = list.get();
   11040 
   11041     m_parsedRuleLists.append(list.release());
   11042     return listPtr;
   11043 }
   11044 
   11045 
   11046 template <typename CharacterType>
   11047 ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length)
   11048 {
   11049     // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
   11050     // that can potentially change the length of the string rather than the character
   11051     // by character kind. If we don't need Unicode lowercasing, it would be good to
   11052     // simplify this function.
   11053 
   11054     if (charactersAreAllASCII(input, length)) {
   11055         // Fast case for all-ASCII.
   11056         for (unsigned i = 0; i < length; i++)
   11057             output[i] = toASCIILower(input[i]);
   11058     } else {
   11059         for (unsigned i = 0; i < length; i++)
   11060             output[i] = Unicode::toLower(input[i]);
   11061     }
   11062 }
   11063 
   11064 void CSSParser::tokenToLowerCase(const CSSParserString& token)
   11065 {
   11066     size_t length = token.length();
   11067     if (is8BitSource()) {
   11068         size_t offset = token.characters8() - m_dataStart8.get();
   11069         makeLower(token.characters8(), m_dataStart8.get() + offset, length);
   11070     } else {
   11071         size_t offset = token.characters16() - m_dataStart16.get();
   11072         makeLower(token.characters16(), m_dataStart16.get() + offset, length);
   11073     }
   11074 }
   11075 
   11076 void CSSParser::endInvalidRuleHeader()
   11077 {
   11078     if (m_ruleHeaderType == CSSRuleSourceData::UNKNOWN_RULE)
   11079         return;
   11080 
   11081     CSSParserLocation location;
   11082     location.lineNumber = m_lineNumber;
   11083     location.offset = m_ruleHeaderStartOffset;
   11084     if (is8BitSource())
   11085         location.token.init(m_dataStart8.get() + m_ruleHeaderStartOffset, 0);
   11086     else
   11087         location.token.init(m_dataStart16.get() + m_ruleHeaderStartOffset, 0);
   11088 
   11089     reportError(location, m_ruleHeaderType == CSSRuleSourceData::STYLE_RULE ? InvalidSelectorError : InvalidRuleError);
   11090 
   11091     endRuleHeader();
   11092 }
   11093 
   11094 void CSSParser::reportError(const CSSParserLocation& location, ErrorType error)
   11095 {
   11096     if (!isLoggingErrors() || (m_ruleHeaderType == CSSRuleSourceData::SUPPORTS_RULE && error != InvalidSupportsConditionError))
   11097         return;
   11098 
   11099     m_ignoreErrors = true;
   11100     CSSParserString content = location.token;
   11101     if (error == InvalidPropertyValueError || error == InvalidSelectorError || error == InvalidMediaQueryError || error == InvalidKeyframeSelectorError) {
   11102         if (m_source) {
   11103             if (is8BitSource())
   11104                 content.init(*m_source, location.token.characters8() - m_dataStart8.get(), tokenStart<LChar>() - location.token.characters8());
   11105             else
   11106                 content.init(*m_source, location.token.characters16() - m_dataStart16.get(), tokenStart<UChar>() - location.token.characters16());
   11107             content.trimTrailingWhitespace();
   11108         }
   11109     }
   11110 
   11111     if (!InspectorInstrumentation::cssErrorFilter(content, m_id, error))
   11112         return;
   11113 
   11114     StringBuilder builder;
   11115     switch (error) {
   11116     case PropertyDeclarationError:
   11117         builder.appendLiteral("Invalid CSS property declaration at: ");
   11118         break;
   11119 
   11120     case InvalidPropertyValueError:
   11121         builder.appendLiteral("Invalid CSS property value: ");
   11122         break;
   11123 
   11124     case InvalidPropertyError:
   11125         builder.appendLiteral("Invalid CSS property name: ");
   11126         break;
   11127 
   11128     case InvalidSelectorError:
   11129         builder.appendLiteral("Invalid CSS selector: ");
   11130         break;
   11131 
   11132     case InvalidSupportsConditionError:
   11133         builder.appendLiteral("Invalid CSS @supports condition: ");
   11134         break;
   11135 
   11136     case InvalidRuleError:
   11137         builder.appendLiteral("Invalid CSS rule at: ");
   11138         break;
   11139 
   11140     case InvalidMediaQueryError:
   11141         builder.appendLiteral("Invalid CSS media query: ");
   11142         break;
   11143 
   11144     case InvalidSelectorPseudoError:
   11145         builder.appendLiteral("Invalid CSS selector pseudoclass: ");
   11146         break;
   11147 
   11148     case InvalidKeyframeSelectorError:
   11149         builder.appendLiteral("Invalid CSS keyframe selector: ");
   11150         break;
   11151 
   11152     case UnterminatedCommentError:
   11153         content.setLength(0);
   11154         builder.appendLiteral("Unterminated CSS comment");
   11155         break;
   11156 
   11157     default:
   11158         builder.appendLiteral("Unexpected CSS token: ");
   11159     }
   11160 
   11161     builder.append(content);
   11162 
   11163     logError(builder.toString(), location);
   11164 }
   11165 
   11166 bool CSSParser::isLoggingErrors()
   11167 {
   11168     return m_logErrors && !m_ignoreErrors;
   11169 }
   11170 
   11171 void CSSParser::logError(const String& message, const CSSParserLocation& location)
   11172 {
   11173     unsigned lineNumberInStyleSheet;
   11174     unsigned columnNumber = 0;
   11175     PageConsole* console = m_styleSheet->singleOwnerDocument()->page()->console();
   11176     if (InspectorInstrumentation::hasFrontends()) {
   11177         ensureLineEndings();
   11178         TextPosition tokenPosition = TextPosition::fromOffsetAndLineEndings(location.offset, *m_lineEndings);
   11179         lineNumberInStyleSheet = tokenPosition.m_line.zeroBasedInt();
   11180         columnNumber = (lineNumberInStyleSheet ? 0 : m_startPosition.m_column.zeroBasedInt()) + tokenPosition.m_column.zeroBasedInt();
   11181     } else {
   11182         lineNumberInStyleSheet = location.lineNumber;
   11183     }
   11184     console->addMessage(CSSMessageSource, WarningMessageLevel, message, m_styleSheet->baseURL().string(), lineNumberInStyleSheet + m_startPosition.m_line.zeroBasedInt() + 1, columnNumber + 1);
   11185 }
   11186 
   11187 StyleRuleKeyframes* CSSParser::createKeyframesRule(const String& name, PassOwnPtr<Vector<RefPtr<StyleKeyframe> > > popKeyframes)
   11188 {
   11189     OwnPtr<Vector<RefPtr<StyleKeyframe> > > keyframes = popKeyframes;
   11190     m_allowImportRules = m_allowNamespaceDeclarations = false;
   11191     RefPtr<StyleRuleKeyframes> rule = StyleRuleKeyframes::create();
   11192     for (size_t i = 0; i < keyframes->size(); ++i)
   11193         rule->parserAppendKeyframe(keyframes->at(i));
   11194     rule->setName(name);
   11195     StyleRuleKeyframes* rulePtr = rule.get();
   11196     m_parsedRules.append(rule.release());
   11197     endRuleBody();
   11198     return rulePtr;
   11199 }
   11200 
   11201 StyleRuleBase* CSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
   11202 {
   11203     StyleRule* result = 0;
   11204     if (selectors) {
   11205         m_allowImportRules = m_allowNamespaceDeclarations = false;
   11206         RefPtr<StyleRule> rule = StyleRule::create();
   11207         rule->parserAdoptSelectorVector(*selectors);
   11208         if (m_hasFontFaceOnlyValues)
   11209             deleteFontFaceOnlyValues();
   11210         rule->setProperties(createStylePropertySet());
   11211         result = rule.get();
   11212         m_parsedRules.append(rule.release());
   11213         endRuleBody();
   11214     } else
   11215         endRuleBody(true);
   11216     clearProperties();
   11217     return result;
   11218 }
   11219 
   11220 StyleRuleBase* CSSParser::createFontFaceRule()
   11221 {
   11222     m_allowImportRules = m_allowNamespaceDeclarations = false;
   11223     for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
   11224         CSSProperty& property = m_parsedProperties[i];
   11225         if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
   11226             property.wrapValueInCommaSeparatedList();
   11227         else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || toCSSValueList(property.value())->length() != 1)) {
   11228             // Unlike font-family property, font-family descriptor in @font-face rule
   11229             // has to be a value list with exactly one family name. It cannot have a
   11230             // have 'initial' value and cannot 'inherit' from parent.
   11231             // See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
   11232             clearProperties();
   11233             endRuleBody(true);
   11234             return 0;
   11235         }
   11236     }
   11237     RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
   11238     rule->setProperties(createStylePropertySet());
   11239     clearProperties();
   11240     StyleRuleFontFace* result = rule.get();
   11241     m_parsedRules.append(rule.release());
   11242     endRuleBody();
   11243     return result;
   11244 }
   11245 
   11246 StyleRuleBase* CSSParser::createHostRule(RuleList* rules)
   11247 {
   11248     m_allowImportRules = m_allowNamespaceDeclarations = false;
   11249     RefPtr<StyleRuleHost> rule;
   11250     if (rules)
   11251         rule = StyleRuleHost::create(*rules);
   11252     else {
   11253         RuleList emptyRules;
   11254         rule = StyleRuleHost::create(emptyRules);
   11255     }
   11256     StyleRuleHost* result = rule.get();
   11257     m_parsedRules.append(rule.release());
   11258     endRuleBody();
   11259     return result;
   11260 }
   11261 
   11262 void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri)
   11263 {
   11264     if (!m_styleSheet || !m_allowNamespaceDeclarations)
   11265         return;
   11266     m_allowImportRules = false;
   11267     m_styleSheet->parserAddNamespace(prefix, uri);
   11268     if (prefix.isEmpty() && !uri.isNull())
   11269         m_defaultNamespace = uri;
   11270 }
   11271 
   11272 QualifiedName CSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName)
   11273 {
   11274     if (!m_styleSheet)
   11275         return QualifiedName(prefix, localName, m_defaultNamespace);
   11276     return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix));
   11277 }
   11278 
   11279 CSSParserSelector* CSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers)
   11280 {
   11281     if (m_defaultNamespace != starAtom || specifiers->needsCrossingTreeScopeBoundary())
   11282         return rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
   11283     if (CSSParserSelector* distributedPseudoElementSelector = specifiers->findDistributedPseudoElementSelector()) {
   11284         specifiers->prependTagSelector(QualifiedName(nullAtom, starAtom, m_defaultNamespace), /*tagIsForNamespaceRule*/true);
   11285         return rewriteSpecifiersForShadowDistributed(specifiers, distributedPseudoElementSelector);
   11286     }
   11287     return specifiers;
   11288 }
   11289 
   11290 CSSParserSelector* CSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
   11291 {
   11292     AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
   11293     QualifiedName tag(namespacePrefix, elementName, determinedNamespace);
   11294 
   11295     if (CSSParserSelector* distributedPseudoElementSelector = specifiers->findDistributedPseudoElementSelector()) {
   11296         specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
   11297         return rewriteSpecifiersForShadowDistributed(specifiers, distributedPseudoElementSelector);
   11298     }
   11299 
   11300     if (specifiers->needsCrossingTreeScopeBoundary())
   11301         return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
   11302 
   11303     if (specifiers->isContentPseudoElement())
   11304         return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, elementName, specifiers, tagIsForNamespaceRule);
   11305 
   11306     if (tag == anyQName())
   11307         return specifiers;
   11308     if (!(specifiers->pseudoType() == CSSSelector::PseudoCue))
   11309         specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
   11310     return specifiers;
   11311 }
   11312 
   11313 CSSParserSelector* CSSParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
   11314 {
   11315     if (m_useCounter && specifiers->pseudoType() == CSSSelector::PseudoUserAgentCustomElement)
   11316         m_useCounter->count(UseCounter::CSSPseudoElementUserAgentCustomPseudo);
   11317 
   11318     CSSParserSelector* lastShadowPseudo = specifiers;
   11319     CSSParserSelector* history = specifiers;
   11320     while (history->tagHistory()) {
   11321         history = history->tagHistory();
   11322         if (history->needsCrossingTreeScopeBoundary() || history->hasShadowPseudo())
   11323             lastShadowPseudo = history;
   11324     }
   11325 
   11326     if (lastShadowPseudo->tagHistory()) {
   11327         if (tag != anyQName())
   11328             lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
   11329         return specifiers;
   11330     }
   11331 
   11332     // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
   11333     // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
   11334     OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
   11335     lastShadowPseudo->setTagHistory(elementNameSelector.release());
   11336     lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo);
   11337     return specifiers;
   11338 }
   11339 
   11340 CSSParserSelector* CSSParser::rewriteSpecifiersWithElementNameForContentPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
   11341 {
   11342     CSSParserSelector* last = specifiers;
   11343     CSSParserSelector* history = specifiers;
   11344     while (history->tagHistory()) {
   11345         history = history->tagHistory();
   11346         if (history->isContentPseudoElement() || history->relationIsAffectedByPseudoContent())
   11347             last = history;
   11348     }
   11349 
   11350     if (last->tagHistory()) {
   11351         if (tag != anyQName())
   11352             last->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
   11353         return specifiers;
   11354     }
   11355 
   11356     // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
   11357     // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
   11358     OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
   11359     last->setTagHistory(elementNameSelector.release());
   11360     last->setRelation(CSSSelector::SubSelector);
   11361     return specifiers;
   11362 }
   11363 
   11364 CSSParserSelector* CSSParser::rewriteSpecifiersForShadowDistributed(CSSParserSelector* specifiers, CSSParserSelector* distributedPseudoElementSelector)
   11365 {
   11366     if (m_useCounter)
   11367         m_useCounter->count(UseCounter::CSSPseudoElementPrefixedDistributed);
   11368     CSSParserSelector* argumentSelector = distributedPseudoElementSelector->functionArgumentSelector();
   11369     ASSERT(argumentSelector);
   11370     ASSERT(!specifiers->isDistributedPseudoElement());
   11371     for (CSSParserSelector* end = specifiers; end->tagHistory(); end = end->tagHistory()) {
   11372         if (end->tagHistory()->isDistributedPseudoElement()) {
   11373             end->clearTagHistory();
   11374             break;
   11375         }
   11376     }
   11377     CSSParserSelector* end = argumentSelector;
   11378     while (end->tagHistory())
   11379         end = end->tagHistory();
   11380 
   11381     switch (end->relation()) {
   11382     case CSSSelector::Child:
   11383     case CSSSelector::Descendant:
   11384         end->setTagHistory(sinkFloatingSelector(specifiers));
   11385         end->setRelationIsAffectedByPseudoContent();
   11386         return argumentSelector;
   11387     default:
   11388         return 0;
   11389     }
   11390 }
   11391 
   11392 CSSParserSelector* CSSParser::rewriteSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
   11393 {
   11394     if (newSpecifier->needsCrossingTreeScopeBoundary()) {
   11395         // Unknown pseudo element always goes at the top of selector chain.
   11396         newSpecifier->appendTagHistory(CSSSelector::ShadowPseudo, sinkFloatingSelector(specifiers));
   11397         return newSpecifier;
   11398     }
   11399     if (newSpecifier->isContentPseudoElement()) {
   11400         newSpecifier->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(specifiers));
   11401         return newSpecifier;
   11402     }
   11403     if (specifiers->needsCrossingTreeScopeBoundary()) {
   11404         // Specifiers for unknown pseudo element go right behind it in the chain.
   11405         specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowPseudo);
   11406         return specifiers;
   11407     }
   11408     if (specifiers->isContentPseudoElement()) {
   11409         specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::SubSelector);
   11410         return specifiers;
   11411     }
   11412     specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
   11413     return specifiers;
   11414 }
   11415 
   11416 StyleRuleBase* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
   11417 {
   11418     // FIXME: Margin at-rules are ignored.
   11419     m_allowImportRules = m_allowNamespaceDeclarations = false;
   11420     StyleRulePage* pageRule = 0;
   11421     if (pageSelector) {
   11422         RefPtr<StyleRulePage> rule = StyleRulePage::create();
   11423         Vector<OwnPtr<CSSParserSelector> > selectorVector;
   11424         selectorVector.append(pageSelector);
   11425         rule->parserAdoptSelectorVector(selectorVector);
   11426         rule->setProperties(createStylePropertySet());
   11427         pageRule = rule.get();
   11428         m_parsedRules.append(rule.release());
   11429         endRuleBody();
   11430     } else
   11431         endRuleBody(true);
   11432     clearProperties();
   11433     return pageRule;
   11434 }
   11435 
   11436 void CSSParser::setReusableRegionSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectors)
   11437 {
   11438     if (selectors)
   11439         m_reusableRegionSelectorVector.swap(*selectors);
   11440 }
   11441 
   11442 StyleRuleBase* CSSParser::createRegionRule(Vector<OwnPtr<CSSParserSelector> >* regionSelector, RuleList* rules)
   11443 {
   11444     if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !regionSelector || !rules) {
   11445         endRuleBody(true);
   11446         return 0;
   11447     }
   11448 
   11449     m_allowImportRules = m_allowNamespaceDeclarations = false;
   11450 
   11451     RefPtr<StyleRuleRegion> regionRule = StyleRuleRegion::create(regionSelector, *rules);
   11452 
   11453     StyleRuleRegion* result = regionRule.get();
   11454     m_parsedRules.append(regionRule.release());
   11455     if (m_sourceDataHandler)
   11456         m_sourceDataHandler->startEndUnknownRule();
   11457 
   11458     return result;
   11459 }
   11460 
   11461 StyleRuleBase* CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */)
   11462 {
   11463     // FIXME: Implement margin at-rule here, using:
   11464     //        - marginBox: margin box
   11465     //        - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule.
   11466     // Don't forget to also update the action for page symbol in CSSGrammar.y such that margin at-rule data is cleared if page_selector is invalid.
   11467 
   11468     endDeclarationsForMarginBox();
   11469     return 0; // until this method is implemented.
   11470 }
   11471 
   11472 void CSSParser::startDeclarationsForMarginBox()
   11473 {
   11474     m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
   11475 }
   11476 
   11477 void CSSParser::endDeclarationsForMarginBox()
   11478 {
   11479     rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
   11480     m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
   11481 }
   11482 
   11483 void CSSParser::deleteFontFaceOnlyValues()
   11484 {
   11485     ASSERT(m_hasFontFaceOnlyValues);
   11486     for (unsigned i = 0; i < m_parsedProperties.size();) {
   11487         CSSProperty& property = m_parsedProperties[i];
   11488         if (property.id() == CSSPropertyFontVariant && property.value()->isValueList()) {
   11489             m_parsedProperties.remove(i);
   11490             continue;
   11491         }
   11492         ++i;
   11493     }
   11494 }
   11495 
   11496 StyleKeyframe* CSSParser::createKeyframe(CSSParserValueList* keys)
   11497 {
   11498     // Create a key string from the passed keys
   11499     StringBuilder keyString;
   11500     for (unsigned i = 0; i < keys->size(); ++i) {
   11501         ASSERT(keys->valueAt(i)->unit == CSSPrimitiveValue::CSS_NUMBER);
   11502         float key = static_cast<float>(keys->valueAt(i)->fValue);
   11503         if (key < 0 || key > 100) {
   11504             // As per http://www.w3.org/TR/css3-animations/#keyframes,
   11505             // "If a keyframe selector specifies negative percentage values
   11506             // or values higher than 100%, then the keyframe will be ignored."
   11507             clearProperties();
   11508             return 0;
   11509         }
   11510         if (i != 0)
   11511             keyString.append(',');
   11512         keyString.append(String::number(key));
   11513         keyString.append('%');
   11514     }
   11515 
   11516     RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create();
   11517     keyframe->setKeyText(keyString.toString());
   11518     keyframe->setProperties(createStylePropertySet());
   11519 
   11520     clearProperties();
   11521 
   11522     StyleKeyframe* keyframePtr = keyframe.get();
   11523     m_parsedKeyframes.append(keyframe.release());
   11524     return keyframePtr;
   11525 }
   11526 
   11527 void CSSParser::invalidBlockHit()
   11528 {
   11529     if (m_styleSheet && !m_hadSyntacticallyValidCSSRule)
   11530         m_styleSheet->setHasSyntacticallyValidCSSHeader(false);
   11531 }
   11532 
   11533 void CSSParser::startRuleHeader(CSSRuleSourceData::Type ruleType)
   11534 {
   11535     resumeErrorLogging();
   11536     m_ruleHeaderType = ruleType;
   11537     m_ruleHeaderStartOffset = safeUserStringTokenOffset();
   11538     m_ruleHeaderStartLineNumber = m_tokenStartLineNumber;
   11539     if (m_sourceDataHandler)
   11540         m_sourceDataHandler->startRuleHeader(ruleType, m_ruleHeaderStartOffset);
   11541 }
   11542 
   11543 void CSSParser::endRuleHeader()
   11544 {
   11545     m_ruleHeaderType = CSSRuleSourceData::UNKNOWN_RULE;
   11546     if (m_sourceDataHandler)
   11547         m_sourceDataHandler->endRuleHeader(safeUserStringTokenOffset());
   11548 }
   11549 
   11550 void CSSParser::startSelector()
   11551 {
   11552     if (m_sourceDataHandler)
   11553         m_sourceDataHandler->startSelector(safeUserStringTokenOffset());
   11554 }
   11555 
   11556 void CSSParser::endSelector()
   11557 {
   11558     if (m_sourceDataHandler)
   11559         m_sourceDataHandler->endSelector(safeUserStringTokenOffset());
   11560 }
   11561 
   11562 void CSSParser::startRuleBody()
   11563 {
   11564     if (m_sourceDataHandler)
   11565         m_sourceDataHandler->startRuleBody(safeUserStringTokenOffset());
   11566 }
   11567 
   11568 void CSSParser::endRuleBody(bool discard)
   11569 {
   11570     if (m_sourceDataHandler)
   11571         m_sourceDataHandler->endRuleBody(safeUserStringTokenOffset(), discard);
   11572 }
   11573 
   11574 void CSSParser::startProperty()
   11575 {
   11576     resumeErrorLogging();
   11577     if (m_sourceDataHandler)
   11578         m_sourceDataHandler->startProperty(safeUserStringTokenOffset());
   11579 }
   11580 
   11581 void CSSParser::endProperty(bool isImportantFound, bool isPropertyParsed, ErrorType errorType)
   11582 {
   11583     m_id = CSSPropertyInvalid;
   11584     if (m_sourceDataHandler)
   11585         m_sourceDataHandler->endProperty(isImportantFound, isPropertyParsed, safeUserStringTokenOffset(), errorType);
   11586 }
   11587 
   11588 void CSSParser::startEndUnknownRule()
   11589 {
   11590     if (m_sourceDataHandler)
   11591         m_sourceDataHandler->startEndUnknownRule();
   11592 }
   11593 
   11594 unsigned CSSParser::safeUserStringTokenOffset()
   11595 {
   11596     return min(tokenStartOffset(), static_cast<unsigned>(m_length - 1 - m_parsedTextSuffixLength)) - m_parsedTextPrefixLength;
   11597 }
   11598 
   11599 StyleRuleBase* CSSParser::createViewportRule()
   11600 {
   11601     if (!RuntimeEnabledFeatures::cssViewportEnabled()) {
   11602         endRuleBody(true);
   11603         return 0;
   11604     }
   11605 
   11606     m_allowImportRules = m_allowNamespaceDeclarations = false;
   11607 
   11608     RefPtr<StyleRuleViewport> rule = StyleRuleViewport::create();
   11609 
   11610     rule->setProperties(createStylePropertySet());
   11611     clearProperties();
   11612 
   11613     StyleRuleViewport* result = rule.get();
   11614     m_parsedRules.append(rule.release());
   11615     endRuleBody();
   11616 
   11617     return result;
   11618 }
   11619 
   11620 bool CSSParser::parseViewportProperty(CSSPropertyID propId, bool important)
   11621 {
   11622     ASSERT(RuntimeEnabledFeatures::cssViewportEnabled());
   11623 
   11624     CSSParserValue* value = m_valueList->current();
   11625     if (!value)
   11626         return false;
   11627 
   11628     CSSValueID id = value->id;
   11629     bool validPrimitive = false;
   11630 
   11631     switch (propId) {
   11632     case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
   11633     case CSSPropertyMaxWidth:
   11634     case CSSPropertyMinHeight:
   11635     case CSSPropertyMaxHeight:
   11636         if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
   11637             validPrimitive = true;
   11638         else
   11639             validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
   11640         break;
   11641     case CSSPropertyWidth: // shorthand
   11642         return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
   11643     case CSSPropertyHeight:
   11644         return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
   11645     case CSSPropertyMinZoom: // auto | <number> | <percentage>
   11646     case CSSPropertyMaxZoom:
   11647     case CSSPropertyZoom:
   11648         if (id == CSSValueAuto)
   11649             validPrimitive = true;
   11650         else
   11651             validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
   11652         break;
   11653     case CSSPropertyUserZoom: // zoom | fixed
   11654         if (id == CSSValueZoom || id == CSSValueFixed)
   11655             validPrimitive = true;
   11656         break;
   11657     case CSSPropertyOrientation: // auto | portrait | landscape
   11658         if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
   11659             validPrimitive = true;
   11660     default:
   11661         break;
   11662     }
   11663 
   11664     RefPtr<CSSValue> parsedValue;
   11665     if (validPrimitive) {
   11666         parsedValue = parseValidPrimitive(id, value);
   11667         m_valueList->next();
   11668     }
   11669 
   11670     if (parsedValue) {
   11671         if (!m_valueList->current() || inShorthand()) {
   11672             addProperty(propId, parsedValue.release(), important);
   11673             return true;
   11674         }
   11675     }
   11676 
   11677     return false;
   11678 }
   11679 
   11680 bool CSSParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
   11681 {
   11682     ASSERT(RuntimeEnabledFeatures::cssViewportEnabled());
   11683     unsigned numValues = m_valueList->size();
   11684 
   11685     if (numValues > 2)
   11686         return false;
   11687 
   11688     ShorthandScope scope(this, propId);
   11689 
   11690     if (!parseViewportProperty(first, important))
   11691         return false;
   11692 
   11693     // If just one value is supplied, the second value
   11694     // is implicitly initialized with the first value.
   11695     if (numValues == 1)
   11696         m_valueList->previous();
   11697 
   11698     return parseViewportProperty(second, important);
   11699 }
   11700 
   11701 template <typename CharacterType>
   11702 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
   11703 {
   11704     char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
   11705 
   11706     for (unsigned i = 0; i != length; ++i) {
   11707         CharacterType c = propertyName[i];
   11708         if (c == 0 || c >= 0x7F)
   11709             return CSSPropertyInvalid; // illegal character
   11710         buffer[i] = toASCIILower(c);
   11711     }
   11712     buffer[length] = '\0';
   11713 
   11714     const char* name = buffer;
   11715     const Property* hashTableEntry = findProperty(name, length);
   11716     return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
   11717 }
   11718 
   11719 CSSPropertyID cssPropertyID(const String& string)
   11720 {
   11721     unsigned length = string.length();
   11722 
   11723     if (!length)
   11724         return CSSPropertyInvalid;
   11725     if (length > maxCSSPropertyNameLength)
   11726         return CSSPropertyInvalid;
   11727 
   11728     return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
   11729 }
   11730 
   11731 CSSPropertyID cssPropertyID(const CSSParserString& string)
   11732 {
   11733     unsigned length = string.length();
   11734 
   11735     if (!length)
   11736         return CSSPropertyInvalid;
   11737     if (length > maxCSSPropertyNameLength)
   11738         return CSSPropertyInvalid;
   11739 
   11740     return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
   11741 }
   11742 
   11743 template <typename CharacterType>
   11744 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
   11745 {
   11746     char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
   11747 
   11748     for (unsigned i = 0; i != length; ++i) {
   11749         CharacterType c = valueKeyword[i];
   11750         if (c == 0 || c >= 0x7F)
   11751             return CSSValueInvalid; // illegal character
   11752         buffer[i] = WTF::toASCIILower(c);
   11753     }
   11754     buffer[length] = '\0';
   11755 
   11756     if (buffer[0] == '-') {
   11757         // If the prefix is -apple- or -khtml-, change it to -webkit-.
   11758         // This makes the string one character longer.
   11759         if (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-")) {
   11760             memmove(buffer + 7, buffer + 6, length + 1 - 6);
   11761             memcpy(buffer, "-webkit", 7);
   11762             ++length;
   11763         }
   11764     }
   11765 
   11766     const Value* hashTableEntry = findValue(buffer, length);
   11767     return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
   11768 }
   11769 
   11770 CSSValueID cssValueKeywordID(const CSSParserString& string)
   11771 {
   11772     unsigned length = string.length();
   11773     if (!length)
   11774         return CSSValueInvalid;
   11775     if (length > maxCSSValueKeywordLength)
   11776         return CSSValueInvalid;
   11777 
   11778     return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
   11779 }
   11780 
   11781 template <typename CharacterType>
   11782 static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length)
   11783 {
   11784     const CharacterType* end = characters + length;
   11785 
   11786     // -?
   11787     if (characters != end && characters[0] == '-')
   11788         ++characters;
   11789 
   11790     // {nmstart}
   11791     if (characters == end || !(characters[0] == '_' || characters[0] >= 128 || isASCIIAlpha(characters[0])))
   11792         return false;
   11793     ++characters;
   11794 
   11795     // {nmchar}*
   11796     for (; characters != end; ++characters) {
   11797         if (!(characters[0] == '_' || characters[0] == '-' || characters[0] >= 128 || isASCIIAlphanumeric(characters[0])))
   11798             return false;
   11799     }
   11800 
   11801     return true;
   11802 }
   11803 
   11804 // "ident" from the CSS tokenizer, minus backslash-escape sequences
   11805 static bool isCSSTokenizerIdentifier(const String& string)
   11806 {
   11807     unsigned length = string.length();
   11808 
   11809     if (!length)
   11810         return false;
   11811 
   11812     if (string.is8Bit())
   11813         return isCSSTokenizerIdentifier(string.characters8(), length);
   11814     return isCSSTokenizerIdentifier(string.characters16(), length);
   11815 }
   11816 
   11817 template <typename CharacterType>
   11818 static inline bool isCSSTokenizerURL(const CharacterType* characters, unsigned length)
   11819 {
   11820     const CharacterType* end = characters + length;
   11821 
   11822     for (; characters != end; ++characters) {
   11823         CharacterType c = characters[0];
   11824         switch (c) {
   11825             case '!':
   11826             case '#':
   11827             case '$':
   11828             case '%':
   11829             case '&':
   11830                 break;
   11831             default:
   11832                 if (c < '*')
   11833                     return false;
   11834                 if (c <= '~')
   11835                     break;
   11836                 if (c < 128)
   11837                     return false;
   11838         }
   11839     }
   11840 
   11841     return true;
   11842 }
   11843 
   11844 // "url" from the CSS tokenizer, minus backslash-escape sequences
   11845 static bool isCSSTokenizerURL(const String& string)
   11846 {
   11847     unsigned length = string.length();
   11848 
   11849     if (!length)
   11850         return true;
   11851 
   11852     if (string.is8Bit())
   11853         return isCSSTokenizerURL(string.characters8(), length);
   11854     return isCSSTokenizerURL(string.characters16(), length);
   11855 }
   11856 
   11857 
   11858 template <typename CharacterType>
   11859 static inline String quoteCSSStringInternal(const CharacterType* characters, unsigned length)
   11860 {
   11861     // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one.
   11862     // Please see below for the actual logic.
   11863     unsigned quotedStringSize = 2; // Two quotes surrounding the entire string.
   11864     bool afterEscape = false;
   11865     for (unsigned i = 0; i < length; ++i) {
   11866         CharacterType ch = characters[i];
   11867         if (ch == '\\' || ch == '\'') {
   11868             quotedStringSize += 2;
   11869             afterEscape = false;
   11870         } else if (ch < 0x20 || ch == 0x7F) {
   11871             quotedStringSize += 2 + (ch >= 0x10);
   11872             afterEscape = true;
   11873         } else {
   11874             quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' '));
   11875             afterEscape = false;
   11876         }
   11877     }
   11878 
   11879     StringBuffer<CharacterType> buffer(quotedStringSize);
   11880     unsigned index = 0;
   11881     buffer[index++] = '\'';
   11882     afterEscape = false;
   11883     for (unsigned i = 0; i < length; ++i) {
   11884         CharacterType ch = characters[i];
   11885         if (ch == '\\' || ch == '\'') {
   11886             buffer[index++] = '\\';
   11887             buffer[index++] = ch;
   11888             afterEscape = false;
   11889         } else if (ch < 0x20 || ch == 0x7F) { // Control characters.
   11890             buffer[index++] = '\\';
   11891             placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase);
   11892             afterEscape = true;
   11893         } else {
   11894             // Space character may be required to separate backslash-escape sequence and normal characters.
   11895             if (afterEscape && (isASCIIHexDigit(ch) || ch == ' '))
   11896                 buffer[index++] = ' ';
   11897             buffer[index++] = ch;
   11898             afterEscape = false;
   11899         }
   11900     }
   11901     buffer[index++] = '\'';
   11902 
   11903     ASSERT(quotedStringSize == index);
   11904     return String::adopt(buffer);
   11905 }
   11906 
   11907 // We use single quotes for now because markup.cpp uses double quotes.
   11908 String quoteCSSString(const String& string)
   11909 {
   11910     // This function expands each character to at most 3 characters ('\u0010' -> '\' '1' '0') as well as adds
   11911     // 2 quote characters (before and after). Make sure the resulting size (3 * length + 2) will not overflow unsigned.
   11912 
   11913     unsigned length = string.length();
   11914 
   11915     if (!length)
   11916         return String("\'\'");
   11917 
   11918     if (length > std::numeric_limits<unsigned>::max() / 3 - 2)
   11919         return emptyString();
   11920 
   11921     if (string.is8Bit())
   11922         return quoteCSSStringInternal(string.characters8(), length);
   11923     return quoteCSSStringInternal(string.characters16(), length);
   11924 }
   11925 
   11926 String quoteCSSStringIfNeeded(const String& string)
   11927 {
   11928     return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
   11929 }
   11930 
   11931 String quoteCSSURLIfNeeded(const String& string)
   11932 {
   11933     return isCSSTokenizerURL(string) ? string : quoteCSSString(string);
   11934 }
   11935 
   11936 bool isValidNthToken(const CSSParserString& token)
   11937 {
   11938     // The tokenizer checks for the construct of an+b.
   11939     // However, since the {ident} rule precedes the {nth} rule, some of those
   11940     // tokens are identified as string literal. Furthermore we need to accept
   11941     // "odd" and "even" which does not match to an+b.
   11942     return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
   11943         || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
   11944 }
   11945 
   11946 }
   11947