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