Home | History | Annotate | Download | only in parser
      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/parser/CSSPropertyParser.h"
     29 
     30 // FIXME: Way too many!
     31 #include "core/CSSValueKeywords.h"
     32 #include "core/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/CSSGridTemplateAreasValue.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/CSSParserValues.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/CSSShadowValue.h"
     60 #include "core/css/CSSTimingFunctionValue.h"
     61 #include "core/css/CSSTransformValue.h"
     62 #include "core/css/CSSUnicodeRangeValue.h"
     63 #include "core/css/CSSValueList.h"
     64 #include "core/css/CSSValuePool.h"
     65 #include "core/css/Counter.h"
     66 #include "core/css/HashTools.h"
     67 #include "core/css/Pair.h"
     68 #include "core/css/Rect.h"
     69 #include "core/css/RuntimeCSSEnabled.h"
     70 #include "core/css/parser/CSSParserIdioms.h"
     71 #include "core/html/parser/HTMLParserIdioms.h"
     72 #include "core/inspector/InspectorInstrumentation.h"
     73 #include "core/rendering/RenderTheme.h"
     74 #include "core/svg/SVGPaint.h"
     75 #include "platform/FloatConversion.h"
     76 #include "platform/RuntimeEnabledFeatures.h"
     77 #include "wtf/BitArray.h"
     78 #include "wtf/HexNumber.h"
     79 #include "wtf/text/StringBuffer.h"
     80 #include "wtf/text/StringBuilder.h"
     81 #include "wtf/text/StringImpl.h"
     82 #include "wtf/text/TextEncoding.h"
     83 #include <limits.h>
     84 
     85 namespace WebCore {
     86 
     87 static const double MAX_SCALE = 1000000;
     88 static const unsigned minRepetitions = 10000;
     89 
     90 template <unsigned N>
     91 static bool equal(const CSSParserString& a, const char (&b)[N])
     92 {
     93     unsigned length = N - 1; // Ignore the trailing null character
     94     if (a.length() != length)
     95         return false;
     96 
     97     return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
     98 }
     99 
    100 template <unsigned N>
    101 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
    102 {
    103     unsigned length = N - 1; // Ignore the trailing null character
    104     if (a.length() != length)
    105         return false;
    106 
    107     return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
    108 }
    109 
    110 template <unsigned N>
    111 static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
    112 {
    113     ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
    114     return equalIgnoringCase(value->string, b);
    115 }
    116 
    117 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> first, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdenticalValues)
    118 {
    119     return cssValuePool().createValue(Pair::create(first, second, identicalValuesPolicy));
    120 }
    121 
    122 CSSPropertyParser::CSSPropertyParser(OwnPtr<CSSParserValueList>& valueList,
    123     const CSSParserContext& context, bool inViewport, bool savedImportant,
    124     WillBeHeapVector<CSSProperty, 256>& parsedProperties,
    125     CSSRuleSourceData::Type ruleType)
    126     : m_valueList(valueList)
    127     , m_context(context)
    128     , m_inViewport(inViewport)
    129     , m_important(savedImportant) // See comment in header, should be removed.
    130     , m_parsedProperties(parsedProperties)
    131     , m_ruleType(ruleType)
    132     , m_inParseShorthand(0)
    133     , m_currentShorthand(CSSPropertyInvalid)
    134     , m_implicitShorthand(false)
    135 {
    136 }
    137 
    138 CSSPropertyParser::~CSSPropertyParser()
    139 {
    140 }
    141 
    142 void CSSPropertyParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
    143 {
    144     RefPtrWillBeRawPtr<CSSValue> val = value.get();
    145     addProperty(propId, value, important, implicit);
    146 
    147     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
    148     if (prefixingVariant == propId)
    149         return;
    150 
    151     if (m_currentShorthand) {
    152         // We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
    153         m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
    154         addProperty(prefixingVariant, val.release(), important, implicit);
    155         m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
    156     } else {
    157         addProperty(prefixingVariant, val.release(), important, implicit);
    158     }
    159 }
    160 
    161 void CSSPropertyParser::addProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
    162 {
    163     // This property doesn't belong to a shorthand.
    164     if (!m_currentShorthand) {
    165         m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
    166         return;
    167     }
    168 
    169     Vector<StylePropertyShorthand, 4> shorthands;
    170     getMatchingShorthandsForLonghand(propId, &shorthands);
    171     // The longhand does not belong to multiple shorthands.
    172     if (shorthands.size() == 1)
    173         m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
    174     else
    175         m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
    176 }
    177 
    178 void CSSPropertyParser::rollbackLastProperties(int num)
    179 {
    180     ASSERT(num >= 0);
    181     ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
    182     m_parsedProperties.shrink(m_parsedProperties.size() - num);
    183 }
    184 
    185 KURL CSSPropertyParser::completeURL(const String& url) const
    186 {
    187     return m_context.completeURL(url);
    188 }
    189 
    190 bool CSSPropertyParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
    191 {
    192     bool mustBeNonNegative = unitflags & (FNonNeg | FPositiveInteger);
    193 
    194     if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : ValueRangeAll))
    195         return false;
    196 
    197     bool b = false;
    198     switch (m_parsedCalculation->category()) {
    199     case CalcLength:
    200         b = (unitflags & FLength);
    201         break;
    202     case CalcNumber:
    203         b = (unitflags & FNumber);
    204         if (!b && (unitflags & (FInteger | FPositiveInteger)) && m_parsedCalculation->isInt())
    205             b = true;
    206         if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
    207             b = false;
    208         // Always resolve calc() to a CSS_NUMBER in the CSSParserValue if there are no non-numbers specified in the unitflags.
    209         if (b && !(unitflags & ~(FInteger | FNumber | FPositiveInteger | FNonNeg))) {
    210             double number = m_parsedCalculation->doubleValue();
    211             if ((unitflags & FPositiveInteger) && number <= 0) {
    212                 b = false;
    213             } else {
    214                 delete value->function;
    215                 value->unit = CSSPrimitiveValue::CSS_NUMBER;
    216                 value->fValue = number;
    217                 value->isInt = m_parsedCalculation->isInt();
    218             }
    219             m_parsedCalculation.release();
    220             return b;
    221         }
    222         break;
    223     case CalcPercent:
    224         b = (unitflags & FPercent);
    225         if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
    226             b = false;
    227         break;
    228     case CalcPercentLength:
    229         b = (unitflags & FPercent) && (unitflags & FLength);
    230         break;
    231     case CalcPercentNumber:
    232         b = (unitflags & FPercent) && (unitflags & FNumber);
    233         break;
    234     case CalcOther:
    235         break;
    236     }
    237     if (!b || releaseCalc == ReleaseParsedCalcValue)
    238         m_parsedCalculation.release();
    239     return b;
    240 }
    241 
    242 inline bool CSSPropertyParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
    243 {
    244     // Quirks mode and presentation attributes accept unit less values.
    245     return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || isUnitLessLengthParsingEnabledForMode(cssParserMode));
    246 }
    247 
    248 bool CSSPropertyParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
    249 {
    250     if (isCalculation(value))
    251         return validCalculationUnit(value, unitflags, releaseCalc);
    252 
    253     bool b = false;
    254     switch (value->unit) {
    255     case CSSPrimitiveValue::CSS_NUMBER:
    256         b = (unitflags & FNumber);
    257         if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
    258             value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
    259                           ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
    260             b = true;
    261         }
    262         if (!b && (unitflags & FInteger) && value->isInt)
    263             b = true;
    264         if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
    265             b = true;
    266         break;
    267     case CSSPrimitiveValue::CSS_PERCENTAGE:
    268         b = (unitflags & FPercent);
    269         break;
    270     case CSSParserValue::Q_EMS:
    271     case CSSPrimitiveValue::CSS_EMS:
    272     case CSSPrimitiveValue::CSS_REMS:
    273     case CSSPrimitiveValue::CSS_CHS:
    274     case CSSPrimitiveValue::CSS_EXS:
    275     case CSSPrimitiveValue::CSS_PX:
    276     case CSSPrimitiveValue::CSS_CM:
    277     case CSSPrimitiveValue::CSS_MM:
    278     case CSSPrimitiveValue::CSS_IN:
    279     case CSSPrimitiveValue::CSS_PT:
    280     case CSSPrimitiveValue::CSS_PC:
    281     case CSSPrimitiveValue::CSS_VW:
    282     case CSSPrimitiveValue::CSS_VH:
    283     case CSSPrimitiveValue::CSS_VMIN:
    284     case CSSPrimitiveValue::CSS_VMAX:
    285         b = (unitflags & FLength);
    286         break;
    287     case CSSPrimitiveValue::CSS_MS:
    288     case CSSPrimitiveValue::CSS_S:
    289         b = (unitflags & FTime);
    290         break;
    291     case CSSPrimitiveValue::CSS_DEG:
    292     case CSSPrimitiveValue::CSS_RAD:
    293     case CSSPrimitiveValue::CSS_GRAD:
    294     case CSSPrimitiveValue::CSS_TURN:
    295         b = (unitflags & FAngle);
    296         break;
    297     case CSSPrimitiveValue::CSS_DPPX:
    298     case CSSPrimitiveValue::CSS_DPI:
    299     case CSSPrimitiveValue::CSS_DPCM:
    300         b = (unitflags & FResolution);
    301         break;
    302     case CSSPrimitiveValue::CSS_HZ:
    303     case CSSPrimitiveValue::CSS_KHZ:
    304     case CSSPrimitiveValue::CSS_DIMENSION:
    305     default:
    306         break;
    307     }
    308     if (b && unitflags & FNonNeg && value->fValue < 0)
    309         b = false;
    310     return b;
    311 }
    312 
    313 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveNumericValue(CSSParserValue* value)
    314 {
    315     if (m_parsedCalculation) {
    316         ASSERT(isCalculation(value));
    317         return CSSPrimitiveValue::create(m_parsedCalculation.release());
    318     }
    319 
    320     ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
    321         || (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
    322         || (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
    323         || (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
    324     return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitType>(value->unit));
    325 }
    326 
    327 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveStringValue(CSSParserValue* value)
    328 {
    329     ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
    330     return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
    331 }
    332 
    333 inline PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::createCSSImageValueWithReferrer(const String& rawValue, const KURL& url)
    334 {
    335     RefPtrWillBeRawPtr<CSSValue> imageValue = CSSImageValue::create(rawValue, url);
    336     toCSSImageValue(imageValue.get())->setReferrer(m_context.referrer());
    337     return imageValue;
    338 }
    339 
    340 static inline bool isComma(CSSParserValue* value)
    341 {
    342     return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
    343 }
    344 
    345 static inline bool isForwardSlashOperator(CSSParserValue* value)
    346 {
    347     ASSERT(value);
    348     return value->unit == CSSParserValue::Operator && value->iValue == '/';
    349 }
    350 
    351 static bool isGeneratedImageValue(CSSParserValue* val)
    352 {
    353     if (val->unit != CSSParserValue::Function)
    354         return false;
    355 
    356     return equalIgnoringCase(val->function->name, "-webkit-gradient(")
    357         || equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")
    358         || equalIgnoringCase(val->function->name, "linear-gradient(")
    359         || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")
    360         || equalIgnoringCase(val->function->name, "repeating-linear-gradient(")
    361         || equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")
    362         || equalIgnoringCase(val->function->name, "radial-gradient(")
    363         || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")
    364         || equalIgnoringCase(val->function->name, "repeating-radial-gradient(")
    365         || equalIgnoringCase(val->function->name, "-webkit-canvas(")
    366         || equalIgnoringCase(val->function->name, "-webkit-cross-fade(");
    367 }
    368 
    369 bool CSSPropertyParser::validWidthOrHeight(CSSParserValue* value)
    370 {
    371     int id = value->id;
    372     if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
    373         return true;
    374     return !id && validUnit(value, FLength | FPercent | FNonNeg);
    375 }
    376 
    377 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
    378 {
    379     if (identifier)
    380         return cssValuePool().createIdentifierValue(identifier);
    381     if (value->unit == CSSPrimitiveValue::CSS_STRING)
    382         return createPrimitiveStringValue(value);
    383     if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
    384         return createPrimitiveNumericValue(value);
    385     if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
    386         return createPrimitiveNumericValue(value);
    387     if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
    388         return createPrimitiveNumericValue(value);
    389     if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
    390         return createPrimitiveNumericValue(value);
    391     if (value->unit >= CSSParserValue::Q_EMS)
    392         return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
    393     if (isCalculation(value))
    394         return CSSPrimitiveValue::create(m_parsedCalculation.release());
    395 
    396     return nullptr;
    397 }
    398 
    399 void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> prpValue, bool important)
    400 {
    401     const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
    402     unsigned shorthandLength = shorthand.length();
    403     if (!shorthandLength) {
    404         addPropertyWithPrefixingVariant(propId, prpValue, important);
    405         return;
    406     }
    407 
    408     RefPtrWillBeRawPtr<CSSValue> value = prpValue;
    409     ShorthandScope scope(this, propId);
    410     const CSSPropertyID* longhands = shorthand.properties();
    411     for (unsigned i = 0; i < shorthandLength; ++i)
    412         addPropertyWithPrefixingVariant(longhands[i], value, important);
    413 }
    414 
    415 bool CSSPropertyParser::parseValue(CSSPropertyID propId, bool important)
    416 {
    417     if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode()) && isInternalProperty(propId))
    418         return false;
    419 
    420     // We don't count the UA style sheet in our statistics.
    421     if (m_context.useCounter())
    422         m_context.useCounter()->count(m_context, propId);
    423 
    424     if (!m_valueList)
    425         return false;
    426 
    427     CSSParserValue* value = m_valueList->current();
    428 
    429     if (!value)
    430         return false;
    431 
    432     if (inViewport()) {
    433         // Allow @viewport rules from UA stylesheets even if the feature is disabled.
    434         if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode()))
    435             return false;
    436 
    437         return parseViewportProperty(propId, important);
    438     }
    439 
    440     // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
    441     // FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
    442     ASSERT(!m_parsedCalculation);
    443 
    444     CSSValueID id = value->id;
    445 
    446     int num = inShorthand() ? 1 : m_valueList->size();
    447 
    448     if (id == CSSValueInherit) {
    449         if (num != 1)
    450             return false;
    451         addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
    452         return true;
    453     }
    454     else if (id == CSSValueInitial) {
    455         if (num != 1)
    456             return false;
    457         addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
    458         return true;
    459     }
    460 
    461     if (isKeywordPropertyID(propId)) {
    462         if (!isValidKeywordPropertyAndValue(propId, id, m_context))
    463             return false;
    464         if (m_valueList->next() && !inShorthand())
    465             return false;
    466         addProperty(propId, cssValuePool().createIdentifierValue(id), important);
    467         return true;
    468     }
    469 
    470     bool validPrimitive = false;
    471     RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
    472 
    473     switch (propId) {
    474     case CSSPropertySize:                 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
    475         return parseSize(propId, important);
    476 
    477     case CSSPropertyQuotes:               // [<string> <string>]+ | none | inherit
    478         if (id)
    479             validPrimitive = true;
    480         else
    481             return parseQuotes(propId, important);
    482         break;
    483     case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
    484         if (id == CSSValueNormal
    485             || id == CSSValueEmbed
    486             || id == CSSValueBidiOverride
    487             || id == CSSValueWebkitIsolate
    488             || id == CSSValueWebkitIsolateOverride
    489             || id == CSSValueWebkitPlaintext)
    490             validPrimitive = true;
    491         break;
    492 
    493     case CSSPropertyContent:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
    494         // close-quote | no-open-quote | no-close-quote ]+ | inherit
    495         return parseContent(propId, important);
    496 
    497     case CSSPropertyClip:                 // <shape> | auto | inherit
    498         if (id == CSSValueAuto)
    499             validPrimitive = true;
    500         else if (value->unit == CSSParserValue::Function)
    501             return parseClipShape(propId, important);
    502         break;
    503 
    504     /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
    505      * correctly and allows optimization in WebCore::applyRule(..)
    506      */
    507     case CSSPropertyOverflow: {
    508         ShorthandScope scope(this, propId);
    509         if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
    510             return false;
    511 
    512         RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr;
    513 
    514         // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
    515         // set using the shorthand, then for now overflow-x will default to auto, but once we implement
    516         // pagination controls, it should default to hidden. If the overflow-y value is anything but
    517         // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
    518         if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
    519             overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
    520         else
    521             overflowXValue = m_parsedProperties.last().value();
    522         addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
    523         return true;
    524     }
    525 
    526     case CSSPropertyTextAlign:
    527         // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
    528         // | start | end | <string> | inherit | -webkit-auto (converted to start)
    529         if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
    530             || value->unit == CSSPrimitiveValue::CSS_STRING)
    531             validPrimitive = true;
    532         break;
    533 
    534     case CSSPropertyFontWeight:  { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
    535         if (m_valueList->size() != 1)
    536             return false;
    537         return parseFontWeight(important);
    538     }
    539     case CSSPropertyBorderSpacing: {
    540         if (num == 1) {
    541             ShorthandScope scope(this, CSSPropertyBorderSpacing);
    542             if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
    543                 return false;
    544             CSSValue* value = m_parsedProperties.last().value();
    545             addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
    546             return true;
    547         }
    548         else if (num == 2) {
    549             ShorthandScope scope(this, CSSPropertyBorderSpacing);
    550             if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
    551                 return false;
    552             return true;
    553         }
    554         return false;
    555     }
    556     case CSSPropertyWebkitBorderHorizontalSpacing:
    557     case CSSPropertyWebkitBorderVerticalSpacing:
    558         validPrimitive = validUnit(value, FLength | FNonNeg);
    559         break;
    560     case CSSPropertyOutlineColor:        // <color> | invert | inherit
    561         // Outline color has "invert" as additional keyword.
    562         // Also, we want to allow the special focus color even in HTML Standard parsing mode.
    563         if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
    564             validPrimitive = true;
    565             break;
    566         }
    567         /* nobreak */
    568     case CSSPropertyBackgroundColor: // <color> | inherit
    569     case CSSPropertyBorderTopColor: // <color> | inherit
    570     case CSSPropertyBorderRightColor:
    571     case CSSPropertyBorderBottomColor:
    572     case CSSPropertyBorderLeftColor:
    573     case CSSPropertyWebkitBorderStartColor:
    574     case CSSPropertyWebkitBorderEndColor:
    575     case CSSPropertyWebkitBorderBeforeColor:
    576     case CSSPropertyWebkitBorderAfterColor:
    577     case CSSPropertyColor: // <color> | inherit
    578     case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
    579     case CSSPropertyTextLineThroughColor:
    580     case CSSPropertyTextUnderlineColor:
    581     case CSSPropertyTextOverlineColor:
    582     case CSSPropertyWebkitColumnRuleColor:
    583     case CSSPropertyWebkitTextEmphasisColor:
    584     case CSSPropertyWebkitTextFillColor:
    585     case CSSPropertyWebkitTextStrokeColor:
    586         if (propId == CSSPropertyTextDecorationColor
    587             && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
    588             return false;
    589 
    590         if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMenu) {
    591             validPrimitive = isValueAllowedInMode(id, m_context.mode());
    592         } else {
    593             parsedValue = parseColor();
    594             if (parsedValue)
    595                 m_valueList->next();
    596         }
    597         break;
    598 
    599     case CSSPropertyCursor: {
    600         // Grammar defined by CSS3 UI and modified by CSS4 images:
    601         // [ [<image> [<x> <y>]?,]*
    602         // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
    603         // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
    604         // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
    605         // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | all-scroll |
    606         // zoom-in | zoom-out | -webkit-grab | -webkit-grabbing | -webkit-zoom-in | -webkit-zoom-out ] ] | inherit
    607         RefPtrWillBeRawPtr<CSSValueList> list = nullptr;
    608         while (value) {
    609             RefPtrWillBeRawPtr<CSSValue> image = nullptr;
    610             if (value->unit == CSSPrimitiveValue::CSS_URI) {
    611                 String uri = value->string;
    612                 if (!uri.isNull())
    613                     image = createCSSImageValueWithReferrer(uri, completeURL(uri));
    614             } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
    615                 image = parseImageSet(m_valueList.get());
    616                 if (!image)
    617                     break;
    618             } else
    619                 break;
    620 
    621             Vector<int> coords;
    622             value = m_valueList->next();
    623             while (value && validUnit(value, FNumber)) {
    624                 coords.append(int(value->fValue));
    625                 value = m_valueList->next();
    626             }
    627             bool hasHotSpot = false;
    628             IntPoint hotSpot(-1, -1);
    629             int nrcoords = coords.size();
    630             if (nrcoords > 0 && nrcoords != 2)
    631                 return false;
    632             if (nrcoords == 2) {
    633                 hasHotSpot = true;
    634                 hotSpot = IntPoint(coords[0], coords[1]);
    635             }
    636 
    637             if (!list)
    638                 list = CSSValueList::createCommaSeparated();
    639 
    640             if (image)
    641                 list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
    642 
    643             if (!value || !(value->unit == CSSParserValue::Operator && value->iValue == ','))
    644                 return false;
    645             value = m_valueList->next(); // comma
    646         }
    647         if (value && m_context.useCounter()) {
    648             if (value->id == CSSValueWebkitZoomIn)
    649                 m_context.useCounter()->count(UseCounter::PrefixedCursorZoomIn);
    650             else if (value->id == CSSValueWebkitZoomOut)
    651                 m_context.useCounter()->count(UseCounter::PrefixedCursorZoomOut);
    652         }
    653         if (list) {
    654             if (!value)
    655                 return false;
    656             if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
    657                 list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
    658             else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitZoomOut) || value->id == CSSValueCopy || value->id == CSSValueNone)
    659                 list->append(cssValuePool().createIdentifierValue(value->id));
    660             m_valueList->next();
    661             parsedValue = list.release();
    662             break;
    663         } else if (value) {
    664             id = value->id;
    665             if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
    666                 id = CSSValuePointer;
    667                 validPrimitive = true;
    668             } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitZoomOut) || value->id == CSSValueCopy || value->id == CSSValueNone)
    669                 validPrimitive = true;
    670         } else {
    671             ASSERT_NOT_REACHED();
    672             return false;
    673         }
    674         break;
    675     }
    676 
    677     case CSSPropertyBackgroundBlendMode:
    678     case CSSPropertyBackgroundAttachment:
    679     case CSSPropertyBackgroundClip:
    680     case CSSPropertyWebkitBackgroundClip:
    681     case CSSPropertyWebkitBackgroundComposite:
    682     case CSSPropertyBackgroundImage:
    683     case CSSPropertyBackgroundOrigin:
    684     case CSSPropertyMaskSourceType:
    685     case CSSPropertyWebkitBackgroundOrigin:
    686     case CSSPropertyBackgroundPosition:
    687     case CSSPropertyBackgroundPositionX:
    688     case CSSPropertyBackgroundPositionY:
    689     case CSSPropertyBackgroundSize:
    690     case CSSPropertyWebkitBackgroundSize:
    691     case CSSPropertyBackgroundRepeat:
    692     case CSSPropertyBackgroundRepeatX:
    693     case CSSPropertyBackgroundRepeatY:
    694     case CSSPropertyWebkitMaskClip:
    695     case CSSPropertyWebkitMaskComposite:
    696     case CSSPropertyWebkitMaskImage:
    697     case CSSPropertyWebkitMaskOrigin:
    698     case CSSPropertyWebkitMaskPosition:
    699     case CSSPropertyWebkitMaskPositionX:
    700     case CSSPropertyWebkitMaskPositionY:
    701     case CSSPropertyWebkitMaskSize:
    702     case CSSPropertyWebkitMaskRepeat:
    703     case CSSPropertyWebkitMaskRepeatX:
    704     case CSSPropertyWebkitMaskRepeatY:
    705     {
    706         RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
    707         RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
    708         CSSPropertyID propId1, propId2;
    709         bool result = false;
    710         if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
    711             if (propId == CSSPropertyBackgroundPosition ||
    712                 propId == CSSPropertyBackgroundRepeat ||
    713                 propId == CSSPropertyWebkitMaskPosition ||
    714                 propId == CSSPropertyWebkitMaskRepeat) {
    715                 ShorthandScope scope(this, propId);
    716                 addProperty(propId1, val1.release(), important);
    717                 if (val2)
    718                     addProperty(propId2, val2.release(), important);
    719             } else {
    720                 addProperty(propId1, val1.release(), important);
    721                 if (val2)
    722                     addProperty(propId2, val2.release(), important);
    723             }
    724             result = true;
    725         }
    726         m_implicitShorthand = false;
    727         return result;
    728     }
    729     case CSSPropertyObjectPosition:
    730         return RuntimeEnabledFeatures::objectFitPositionEnabled() && parseObjectPosition(important);
    731     case CSSPropertyListStyleImage:     // <uri> | none | inherit
    732     case CSSPropertyBorderImageSource:
    733     case CSSPropertyWebkitMaskBoxImageSource:
    734         if (id == CSSValueNone) {
    735             parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
    736             m_valueList->next();
    737         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
    738             parsedValue = createCSSImageValueWithReferrer(value->string, completeURL(value->string));
    739             m_valueList->next();
    740         } else if (isGeneratedImageValue(value)) {
    741             if (parseGeneratedImage(m_valueList.get(), parsedValue))
    742                 m_valueList->next();
    743             else
    744                 return false;
    745         }
    746         else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
    747             parsedValue = parseImageSet(m_valueList.get());
    748             if (!parsedValue)
    749                 return false;
    750             m_valueList->next();
    751         }
    752         break;
    753 
    754     case CSSPropertyWebkitTextStrokeWidth:
    755     case CSSPropertyOutlineWidth:        // <border-width> | inherit
    756     case CSSPropertyBorderTopWidth:     //// <border-width> | inherit
    757     case CSSPropertyBorderRightWidth:   //   Which is defined as
    758     case CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
    759     case CSSPropertyBorderLeftWidth:
    760     case CSSPropertyWebkitBorderStartWidth:
    761     case CSSPropertyWebkitBorderEndWidth:
    762     case CSSPropertyWebkitBorderBeforeWidth:
    763     case CSSPropertyWebkitBorderAfterWidth:
    764     case CSSPropertyWebkitColumnRuleWidth:
    765         if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
    766             validPrimitive = true;
    767         else
    768             validPrimitive = validUnit(value, FLength | FNonNeg);
    769         break;
    770 
    771     case CSSPropertyLetterSpacing:       // normal | <length> | inherit
    772     case CSSPropertyWordSpacing:         // normal | <length> | inherit
    773         if (id == CSSValueNormal)
    774             validPrimitive = true;
    775         else
    776             validPrimitive = validUnit(value, FLength);
    777         break;
    778 
    779     case CSSPropertyTextIndent:
    780         parsedValue = parseTextIndent();
    781         break;
    782 
    783     case CSSPropertyPaddingTop:          //// <padding-width> | inherit
    784     case CSSPropertyPaddingRight:        //   Which is defined as
    785     case CSSPropertyPaddingBottom:       //   <length> | <percentage>
    786     case CSSPropertyPaddingLeft:         ////
    787     case CSSPropertyWebkitPaddingStart:
    788     case CSSPropertyWebkitPaddingEnd:
    789     case CSSPropertyWebkitPaddingBefore:
    790     case CSSPropertyWebkitPaddingAfter:
    791         validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
    792         break;
    793 
    794     case CSSPropertyMaxWidth:
    795     case CSSPropertyWebkitMaxLogicalWidth:
    796     case CSSPropertyMaxHeight:
    797     case CSSPropertyWebkitMaxLogicalHeight:
    798         validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
    799         break;
    800 
    801     case CSSPropertyMinWidth:
    802     case CSSPropertyWebkitMinLogicalWidth:
    803     case CSSPropertyMinHeight:
    804     case CSSPropertyWebkitMinLogicalHeight:
    805         validPrimitive = validWidthOrHeight(value);
    806         break;
    807 
    808     case CSSPropertyWidth:
    809     case CSSPropertyWebkitLogicalWidth:
    810     case CSSPropertyHeight:
    811     case CSSPropertyWebkitLogicalHeight:
    812         validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
    813         break;
    814 
    815     case CSSPropertyFontSize:
    816         return parseFontSize(important);
    817 
    818     case CSSPropertyFontVariant:         // normal | small-caps | inherit
    819         return parseFontVariant(important);
    820 
    821     case CSSPropertyVerticalAlign:
    822         // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
    823         // <percentage> | <length> | inherit
    824 
    825         if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
    826             validPrimitive = true;
    827         else
    828             validPrimitive = (!id && validUnit(value, FLength | FPercent));
    829         break;
    830 
    831     case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
    832     case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
    833     case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
    834     case CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
    835     case CSSPropertyMarginTop:           //// <margin-width> | inherit
    836     case CSSPropertyMarginRight:         //   Which is defined as
    837     case CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
    838     case CSSPropertyMarginLeft:          ////
    839     case CSSPropertyWebkitMarginStart:
    840     case CSSPropertyWebkitMarginEnd:
    841     case CSSPropertyWebkitMarginBefore:
    842     case CSSPropertyWebkitMarginAfter:
    843         if (id == CSSValueAuto)
    844             validPrimitive = true;
    845         else
    846             validPrimitive = (!id && validUnit(value, FLength | FPercent));
    847         break;
    848 
    849     case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
    850     case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
    851         if (id == CSSValueAuto)
    852             validPrimitive = true;
    853         else
    854             validPrimitive = (!id && validUnit(value, FPositiveInteger, HTMLQuirksMode));
    855         break;
    856 
    857     case CSSPropertyZIndex: // auto | <integer> | inherit
    858         if (id == CSSValueAuto)
    859             validPrimitive = true;
    860         else
    861             validPrimitive = (!id && validUnit(value, FInteger, HTMLQuirksMode));
    862         break;
    863 
    864     case CSSPropertyLineHeight:
    865         return parseLineHeight(important);
    866     case CSSPropertyCounterIncrement:    // [ <identifier> <integer>? ]+ | none | inherit
    867         if (id != CSSValueNone)
    868             return parseCounter(propId, 1, important);
    869         validPrimitive = true;
    870         break;
    871     case CSSPropertyCounterReset:        // [ <identifier> <integer>? ]+ | none | inherit
    872         if (id != CSSValueNone)
    873             return parseCounter(propId, 0, important);
    874         validPrimitive = true;
    875         break;
    876     case CSSPropertyFontFamily:
    877         // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
    878     {
    879         parsedValue = parseFontFamily();
    880         break;
    881     }
    882 
    883     case CSSPropertyTextDecoration:
    884         // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
    885         // is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
    886         if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
    887             // [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit
    888             return parseShorthand(CSSPropertyTextDecoration, textDecorationShorthand(), important);
    889         }
    890     case CSSPropertyWebkitTextDecorationsInEffect:
    891     case CSSPropertyTextDecorationLine:
    892         // none | [ underline || overline || line-through || blink ] | inherit
    893         return parseTextDecoration(propId, important);
    894 
    895     case CSSPropertyTextDecorationStyle:
    896         // solid | double | dotted | dashed | wavy
    897         if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
    898             && (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy))
    899             validPrimitive = true;
    900         break;
    901 
    902     case CSSPropertyTextUnderlinePosition:
    903         // auto | under | inherit
    904         if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
    905             return parseTextUnderlinePosition(important);
    906         return false;
    907 
    908     case CSSPropertyZoom:          // normal | reset | document | <number> | <percentage> | inherit
    909         if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
    910             validPrimitive = true;
    911         else
    912             validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode));
    913         break;
    914 
    915     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.
    916         return parseFontFaceSrc();
    917 
    918     case CSSPropertyUnicodeRange:
    919         return parseFontFaceUnicodeRange();
    920 
    921     /* CSS3 properties */
    922 
    923     case CSSPropertyBorderImage:
    924     case CSSPropertyWebkitMaskBoxImage:
    925         return parseBorderImageShorthand(propId, important);
    926     case CSSPropertyWebkitBorderImage: {
    927         if (RefPtrWillBeRawPtr<CSSValue> result = parseBorderImage(propId)) {
    928             addProperty(propId, result, important);
    929             return true;
    930         }
    931         return false;
    932     }
    933 
    934     case CSSPropertyBorderImageOutset:
    935     case CSSPropertyWebkitMaskBoxImageOutset: {
    936         RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
    937         if (parseBorderImageOutset(result)) {
    938             addProperty(propId, result, important);
    939             return true;
    940         }
    941         break;
    942     }
    943     case CSSPropertyBorderImageRepeat:
    944     case CSSPropertyWebkitMaskBoxImageRepeat: {
    945         RefPtrWillBeRawPtr<CSSValue> result = nullptr;
    946         if (parseBorderImageRepeat(result)) {
    947             addProperty(propId, result, important);
    948             return true;
    949         }
    950         break;
    951     }
    952     case CSSPropertyBorderImageSlice:
    953     case CSSPropertyWebkitMaskBoxImageSlice: {
    954         RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result = nullptr;
    955         if (parseBorderImageSlice(propId, result)) {
    956             addProperty(propId, result, important);
    957             return true;
    958         }
    959         break;
    960     }
    961     case CSSPropertyBorderImageWidth:
    962     case CSSPropertyWebkitMaskBoxImageWidth: {
    963         RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
    964         if (parseBorderImageWidth(result)) {
    965             addProperty(propId, result, important);
    966             return true;
    967         }
    968         break;
    969     }
    970     case CSSPropertyBorderTopRightRadius:
    971     case CSSPropertyBorderTopLeftRadius:
    972     case CSSPropertyBorderBottomLeftRadius:
    973     case CSSPropertyBorderBottomRightRadius: {
    974         if (num != 1 && num != 2)
    975             return false;
    976         validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
    977         if (!validPrimitive)
    978             return false;
    979         RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
    980         RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
    981         if (num == 2) {
    982             value = m_valueList->next();
    983             validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
    984             if (!validPrimitive)
    985                 return false;
    986             parsedValue2 = createPrimitiveNumericValue(value);
    987         } else
    988             parsedValue2 = parsedValue1;
    989 
    990         addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
    991         return true;
    992     }
    993     case CSSPropertyTabSize:
    994         validPrimitive = validUnit(value, FInteger | FNonNeg);
    995         break;
    996     case CSSPropertyWebkitAspectRatio:
    997         return parseAspectRatio(important);
    998     case CSSPropertyBorderRadius:
    999     case CSSPropertyWebkitBorderRadius:
   1000         return parseBorderRadius(propId, important);
   1001     case CSSPropertyOutlineOffset:
   1002         validPrimitive = validUnit(value, FLength);
   1003         break;
   1004     case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
   1005     case CSSPropertyBoxShadow:
   1006     case CSSPropertyWebkitBoxShadow:
   1007         if (id == CSSValueNone)
   1008             validPrimitive = true;
   1009         else {
   1010             RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
   1011             if (shadowValueList) {
   1012                 addProperty(propId, shadowValueList.release(), important);
   1013                 m_valueList->next();
   1014                 return true;
   1015             }
   1016             return false;
   1017         }
   1018         break;
   1019     case CSSPropertyWebkitBoxReflect:
   1020         if (id == CSSValueNone)
   1021             validPrimitive = true;
   1022         else
   1023             return parseReflect(propId, important);
   1024         break;
   1025     case CSSPropertyOpacity:
   1026         validPrimitive = validUnit(value, FNumber);
   1027         break;
   1028     case CSSPropertyWebkitBoxFlex:
   1029         validPrimitive = validUnit(value, FNumber);
   1030         break;
   1031     case CSSPropertyWebkitBoxFlexGroup:
   1032         validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode);
   1033         break;
   1034     case CSSPropertyWebkitBoxOrdinalGroup:
   1035         validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode) && value->fValue;
   1036         break;
   1037     case CSSPropertyWebkitFilter:
   1038         if (id == CSSValueNone)
   1039             validPrimitive = true;
   1040         else {
   1041             RefPtrWillBeRawPtr<CSSValue> val = parseFilter();
   1042             if (val) {
   1043                 addProperty(propId, val, important);
   1044                 return true;
   1045             }
   1046             return false;
   1047         }
   1048         break;
   1049     case CSSPropertyFlex: {
   1050         ShorthandScope scope(this, propId);
   1051         if (id == CSSValueNone) {
   1052             addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
   1053             addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
   1054             addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
   1055             return true;
   1056         }
   1057         return parseFlex(m_valueList.get(), important);
   1058     }
   1059     case CSSPropertyFlexBasis:
   1060         // FIXME: Support intrinsic dimensions too.
   1061         if (id == CSSValueAuto)
   1062             validPrimitive = true;
   1063         else
   1064             validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
   1065         break;
   1066     case CSSPropertyFlexGrow:
   1067     case CSSPropertyFlexShrink:
   1068         validPrimitive = validUnit(value, FNumber | FNonNeg);
   1069         break;
   1070     case CSSPropertyOrder:
   1071         validPrimitive = validUnit(value, FInteger, HTMLStandardMode);
   1072         break;
   1073     case CSSPropertyInternalMarqueeIncrement:
   1074         if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
   1075             validPrimitive = true;
   1076         else
   1077             validPrimitive = validUnit(value, FLength | FPercent);
   1078         break;
   1079     case CSSPropertyInternalMarqueeRepetition:
   1080         if (id == CSSValueInfinite)
   1081             validPrimitive = true;
   1082         else
   1083             validPrimitive = validUnit(value, FInteger | FNonNeg);
   1084         break;
   1085     case CSSPropertyInternalMarqueeSpeed:
   1086         if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
   1087             validPrimitive = true;
   1088         else
   1089             validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
   1090         break;
   1091     case CSSPropertyTransform:
   1092     case CSSPropertyWebkitTransform:
   1093         if (id == CSSValueNone)
   1094             validPrimitive = true;
   1095         else {
   1096             RefPtrWillBeRawPtr<CSSValue> transformValue = parseTransform(propId);
   1097             if (transformValue) {
   1098                 addProperty(propId, transformValue.release(), important);
   1099                 return true;
   1100             }
   1101             return false;
   1102         }
   1103         break;
   1104     case CSSPropertyTransformOrigin: {
   1105         RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
   1106         if (!list)
   1107             return false;
   1108         // These values are added to match gecko serialization.
   1109         if (list->length() == 1)
   1110             list->append(cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
   1111         if (list->length() == 2)
   1112             list->append(cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX));
   1113         addProperty(propId, list.release(), important);
   1114         return true;
   1115     }
   1116     case CSSPropertyWebkitTransformOrigin:
   1117     case CSSPropertyWebkitTransformOriginX:
   1118     case CSSPropertyWebkitTransformOriginY:
   1119     case CSSPropertyWebkitTransformOriginZ: {
   1120         RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
   1121         RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
   1122         RefPtrWillBeRawPtr<CSSValue> val3 = nullptr;
   1123         CSSPropertyID propId1, propId2, propId3;
   1124         if (parseWebkitTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
   1125             addProperty(propId1, val1.release(), important);
   1126             if (val2)
   1127                 addProperty(propId2, val2.release(), important);
   1128             if (val3)
   1129                 addProperty(propId3, val3.release(), important);
   1130             return true;
   1131         }
   1132         return false;
   1133     }
   1134     case CSSPropertyPerspective:
   1135         if (id == CSSValueNone) {
   1136             validPrimitive = true;
   1137         } else if (validUnit(value, FLength | FNonNeg)) {
   1138             addProperty(propId, createPrimitiveNumericValue(value), important);
   1139             return true;
   1140         }
   1141         break;
   1142     case CSSPropertyWebkitPerspective:
   1143         if (id == CSSValueNone) {
   1144             validPrimitive = true;
   1145         } else if (validUnit(value, FNumber | FLength | FNonNeg)) {
   1146             // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
   1147             addProperty(propId, createPrimitiveNumericValue(value), important);
   1148             return true;
   1149         }
   1150         break;
   1151     case CSSPropertyPerspectiveOrigin: {
   1152         RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
   1153         if (!list || list->length() == 3)
   1154             return false;
   1155         // This values are added to match gecko serialization.
   1156         if (list->length() == 1)
   1157             list->append(cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
   1158         addProperty(propId, list.release(), important);
   1159         return true;
   1160     }
   1161     case CSSPropertyWebkitPerspectiveOrigin:
   1162     case CSSPropertyWebkitPerspectiveOriginX:
   1163     case CSSPropertyWebkitPerspectiveOriginY: {
   1164         RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
   1165         RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
   1166         CSSPropertyID propId1, propId2;
   1167         if (parseWebkitPerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
   1168             addProperty(propId1, val1.release(), important);
   1169             if (val2)
   1170                 addProperty(propId2, val2.release(), important);
   1171             return true;
   1172         }
   1173         return false;
   1174     }
   1175     case CSSPropertyAnimationDelay:
   1176     case CSSPropertyAnimationDirection:
   1177     case CSSPropertyAnimationDuration:
   1178     case CSSPropertyAnimationFillMode:
   1179     case CSSPropertyAnimationName:
   1180     case CSSPropertyAnimationPlayState:
   1181     case CSSPropertyAnimationIterationCount:
   1182     case CSSPropertyAnimationTimingFunction:
   1183         if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
   1184             break;
   1185     case CSSPropertyWebkitAnimationDelay:
   1186     case CSSPropertyWebkitAnimationDirection:
   1187     case CSSPropertyWebkitAnimationDuration:
   1188     case CSSPropertyWebkitAnimationFillMode:
   1189     case CSSPropertyWebkitAnimationName:
   1190     case CSSPropertyWebkitAnimationPlayState:
   1191     case CSSPropertyWebkitAnimationIterationCount:
   1192     case CSSPropertyWebkitAnimationTimingFunction:
   1193     case CSSPropertyTransitionDelay:
   1194     case CSSPropertyTransitionDuration:
   1195     case CSSPropertyTransitionTimingFunction:
   1196     case CSSPropertyTransitionProperty:
   1197     case CSSPropertyWebkitTransitionDelay:
   1198     case CSSPropertyWebkitTransitionDuration:
   1199     case CSSPropertyWebkitTransitionTimingFunction:
   1200     case CSSPropertyWebkitTransitionProperty: {
   1201         if (RefPtrWillBeRawPtr<CSSValueList> val = parseAnimationPropertyList(propId)) {
   1202             addPropertyWithPrefixingVariant(propId, val.release(), important);
   1203             return true;
   1204         }
   1205         return false;
   1206     }
   1207 
   1208     case CSSPropertyJustifySelf:
   1209         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   1210             return false;
   1211 
   1212         return parseItemPositionOverflowPosition(propId, important);
   1213     case CSSPropertyGridAutoColumns:
   1214     case CSSPropertyGridAutoRows:
   1215         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   1216             return false;
   1217         parsedValue = parseGridTrackSize(*m_valueList);
   1218         break;
   1219 
   1220     case CSSPropertyGridTemplateColumns:
   1221     case CSSPropertyGridTemplateRows:
   1222         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   1223             return false;
   1224         parsedValue = parseGridTrackList(important);
   1225         break;
   1226 
   1227     case CSSPropertyGridColumnEnd:
   1228     case CSSPropertyGridColumnStart:
   1229     case CSSPropertyGridRowEnd:
   1230     case CSSPropertyGridRowStart:
   1231         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   1232             return false;
   1233         parsedValue = parseGridPosition();
   1234         break;
   1235 
   1236     case CSSPropertyGridColumn:
   1237     case CSSPropertyGridRow:
   1238         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   1239             return false;
   1240         return parseGridItemPositionShorthand(propId, important);
   1241 
   1242     case CSSPropertyGridArea:
   1243         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   1244             return false;
   1245         return parseGridAreaShorthand(important);
   1246 
   1247     case CSSPropertyGridTemplateAreas:
   1248         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   1249             return false;
   1250         parsedValue = parseGridTemplateAreas();
   1251         break;
   1252 
   1253     case CSSPropertyGridTemplate:
   1254         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   1255             return false;
   1256         return parseGridTemplateShorthand(important);
   1257 
   1258     case CSSPropertyGrid:
   1259         if (!RuntimeEnabledFeatures::cssGridLayoutEnabled())
   1260             return false;
   1261         return parseGridShorthand(important);
   1262 
   1263     case CSSPropertyWebkitMarginCollapse: {
   1264         if (num == 1) {
   1265             ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
   1266             if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important))
   1267                 return false;
   1268             CSSValue* value = m_parsedProperties.last().value();
   1269             addProperty(webkitMarginCollapseShorthand().properties()[1], value, important);
   1270             return true;
   1271         }
   1272         else if (num == 2) {
   1273             ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
   1274             if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important))
   1275                 return false;
   1276             return true;
   1277         }
   1278         return false;
   1279     }
   1280     case CSSPropertyTextLineThroughWidth:
   1281     case CSSPropertyTextOverlineWidth:
   1282     case CSSPropertyTextUnderlineWidth:
   1283         if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
   1284             id == CSSValueMedium || id == CSSValueThick)
   1285             validPrimitive = true;
   1286         else
   1287             validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent);
   1288         break;
   1289     case CSSPropertyWebkitColumnCount:
   1290         parsedValue = parseColumnCount();
   1291         break;
   1292     case CSSPropertyWebkitColumnGap:         // normal | <length>
   1293         if (id == CSSValueNormal)
   1294             validPrimitive = true;
   1295         else
   1296             validPrimitive = validUnit(value, FLength | FNonNeg);
   1297         break;
   1298     case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property)
   1299         validPrimitive = id == CSSValueAll || id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->fValue == 1);
   1300         break;
   1301     case CSSPropertyWebkitColumnWidth:         // auto | <length>
   1302         parsedValue = parseColumnWidth();
   1303         break;
   1304     case CSSPropertyWillChange:
   1305         if (!RuntimeEnabledFeatures::cssWillChangeEnabled())
   1306             return false;
   1307         return parseWillChange(important);
   1308     // End of CSS3 properties
   1309 
   1310     // Apple specific properties.  These will never be standardized and are purely to
   1311     // support custom WebKit-based Apple applications.
   1312     case CSSPropertyWebkitLineClamp:
   1313         // When specifying number of lines, don't allow 0 as a valid value
   1314         // When specifying either type of unit, require non-negative integers
   1315         validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, HTMLQuirksMode));
   1316         break;
   1317 
   1318     case CSSPropertyWebkitFontSizeDelta:           // <length>
   1319         validPrimitive = validUnit(value, FLength);
   1320         break;
   1321 
   1322     case CSSPropertyWebkitHighlight:
   1323         if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
   1324             validPrimitive = true;
   1325         break;
   1326 
   1327     case CSSPropertyWebkitHyphenateCharacter:
   1328         if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
   1329             validPrimitive = true;
   1330         break;
   1331 
   1332     case CSSPropertyWebkitLocale:
   1333         if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
   1334             validPrimitive = true;
   1335         break;
   1336 
   1337     // End Apple-specific properties
   1338 
   1339     case CSSPropertyWebkitAppRegion:
   1340         if (id >= CSSValueDrag && id <= CSSValueNoDrag)
   1341             validPrimitive = true;
   1342         break;
   1343 
   1344     case CSSPropertyWebkitTapHighlightColor:
   1345         if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu
   1346             || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) {
   1347             validPrimitive = true;
   1348         } else {
   1349             parsedValue = parseColor();
   1350             if (parsedValue)
   1351                 m_valueList->next();
   1352         }
   1353         break;
   1354 
   1355         /* shorthand properties */
   1356     case CSSPropertyBackground: {
   1357         // Position must come before color in this array because a plain old "0" is a legal color
   1358         // in quirks mode but it's usually the X coordinate of a position.
   1359         const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
   1360                                    CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
   1361                                    CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
   1362         return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
   1363     }
   1364     case CSSPropertyWebkitMask: {
   1365         const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
   1366             CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
   1367         return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important);
   1368     }
   1369     case CSSPropertyBorder:
   1370         // [ 'border-width' || 'border-style' || <color> ] | inherit
   1371     {
   1372         if (parseShorthand(propId, parsingShorthandForProperty(CSSPropertyBorder), important)) {
   1373             // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as
   1374             // though a value of none was specified for the image.
   1375             addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important);
   1376             return true;
   1377         }
   1378         return false;
   1379     }
   1380     case CSSPropertyBorderTop:
   1381         // [ 'border-top-width' || 'border-style' || <color> ] | inherit
   1382         return parseShorthand(propId, borderTopShorthand(), important);
   1383     case CSSPropertyBorderRight:
   1384         // [ 'border-right-width' || 'border-style' || <color> ] | inherit
   1385         return parseShorthand(propId, borderRightShorthand(), important);
   1386     case CSSPropertyBorderBottom:
   1387         // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
   1388         return parseShorthand(propId, borderBottomShorthand(), important);
   1389     case CSSPropertyBorderLeft:
   1390         // [ 'border-left-width' || 'border-style' || <color> ] | inherit
   1391         return parseShorthand(propId, borderLeftShorthand(), important);
   1392     case CSSPropertyWebkitBorderStart:
   1393         return parseShorthand(propId, webkitBorderStartShorthand(), important);
   1394     case CSSPropertyWebkitBorderEnd:
   1395         return parseShorthand(propId, webkitBorderEndShorthand(), important);
   1396     case CSSPropertyWebkitBorderBefore:
   1397         return parseShorthand(propId, webkitBorderBeforeShorthand(), important);
   1398     case CSSPropertyWebkitBorderAfter:
   1399         return parseShorthand(propId, webkitBorderAfterShorthand(), important);
   1400     case CSSPropertyOutline:
   1401         // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
   1402         return parseShorthand(propId, outlineShorthand(), important);
   1403     case CSSPropertyBorderColor:
   1404         // <color>{1,4} | inherit
   1405         return parse4Values(propId, borderColorShorthand().properties(), important);
   1406     case CSSPropertyBorderWidth:
   1407         // <border-width>{1,4} | inherit
   1408         return parse4Values(propId, borderWidthShorthand().properties(), important);
   1409     case CSSPropertyBorderStyle:
   1410         // <border-style>{1,4} | inherit
   1411         return parse4Values(propId, borderStyleShorthand().properties(), important);
   1412     case CSSPropertyMargin:
   1413         // <margin-width>{1,4} | inherit
   1414         return parse4Values(propId, marginShorthand().properties(), important);
   1415     case CSSPropertyPadding:
   1416         // <padding-width>{1,4} | inherit
   1417         return parse4Values(propId, paddingShorthand().properties(), important);
   1418     case CSSPropertyFlexFlow:
   1419         return parseShorthand(propId, flexFlowShorthand(), important);
   1420     case CSSPropertyFont:
   1421         // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
   1422         // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
   1423         if (id >= CSSValueCaption && id <= CSSValueStatusBar)
   1424             validPrimitive = true;
   1425         else
   1426             return parseFont(important);
   1427         break;
   1428     case CSSPropertyListStyle:
   1429         return parseShorthand(propId, listStyleShorthand(), important);
   1430     case CSSPropertyWebkitColumns:
   1431         return parseColumnsShorthand(important);
   1432     case CSSPropertyWebkitColumnRule:
   1433         return parseShorthand(propId, webkitColumnRuleShorthand(), important);
   1434     case CSSPropertyWebkitTextStroke:
   1435         return parseShorthand(propId, webkitTextStrokeShorthand(), important);
   1436     case CSSPropertyAnimation:
   1437         if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
   1438             break;
   1439     case CSSPropertyWebkitAnimation:
   1440         return parseAnimationShorthand(propId, important);
   1441     case CSSPropertyTransition:
   1442     case CSSPropertyWebkitTransition:
   1443         return parseTransitionShorthand(propId, important);
   1444     case CSSPropertyInvalid:
   1445         return false;
   1446     case CSSPropertyPage:
   1447         return parsePage(propId, important);
   1448     case CSSPropertyFontStretch:
   1449         return false;
   1450     // CSS Text Layout Module Level 3: Vertical writing support
   1451     case CSSPropertyWebkitTextEmphasis:
   1452         return parseShorthand(propId, webkitTextEmphasisShorthand(), important);
   1453 
   1454     case CSSPropertyWebkitTextEmphasisStyle:
   1455         return parseTextEmphasisStyle(important);
   1456 
   1457     case CSSPropertyWebkitTextOrientation:
   1458         // FIXME: For now just support sideways, sideways-right, upright and vertical-right.
   1459         if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSValueVerticalRight || id == CSSValueUpright)
   1460             validPrimitive = true;
   1461         break;
   1462 
   1463     case CSSPropertyWebkitLineBoxContain:
   1464         if (id == CSSValueNone)
   1465             validPrimitive = true;
   1466         else
   1467             return parseLineBoxContain(important);
   1468         break;
   1469     case CSSPropertyWebkitFontFeatureSettings:
   1470         if (id == CSSValueNormal)
   1471             validPrimitive = true;
   1472         else
   1473             return parseFontFeatureSettings(important);
   1474         break;
   1475 
   1476     case CSSPropertyFontVariantLigatures:
   1477         if (id == CSSValueNormal)
   1478             validPrimitive = true;
   1479         else
   1480             return parseFontVariantLigatures(important);
   1481         break;
   1482     case CSSPropertyWebkitClipPath:
   1483         if (id == CSSValueNone) {
   1484             validPrimitive = true;
   1485         } else if (value->unit == CSSParserValue::Function) {
   1486             parsedValue = parseBasicShape();
   1487         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
   1488             parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
   1489             addProperty(propId, parsedValue.release(), important);
   1490             return true;
   1491         }
   1492         break;
   1493     case CSSPropertyShapeOutside:
   1494         parsedValue = parseShapeProperty(propId);
   1495         break;
   1496     case CSSPropertyShapeMargin:
   1497         validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FLength | FPercent | FNonNeg));
   1498         break;
   1499     case CSSPropertyShapeImageThreshold:
   1500         validPrimitive = (RuntimeEnabledFeatures::cssShapesEnabled() && !id && validUnit(value, FNumber));
   1501         break;
   1502 
   1503     case CSSPropertyTouchAction:
   1504         // auto | none | [pan-x || pan-y] | manipulation
   1505         return parseTouchAction(important);
   1506 
   1507     case CSSPropertyAlignSelf:
   1508         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   1509         return parseItemPositionOverflowPosition(propId, important);
   1510 
   1511     case CSSPropertyAlignItems:
   1512         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   1513         return parseItemPositionOverflowPosition(propId, important);
   1514 
   1515     case CSSPropertyBorderBottomStyle:
   1516     case CSSPropertyBorderCollapse:
   1517     case CSSPropertyBorderLeftStyle:
   1518     case CSSPropertyBorderRightStyle:
   1519     case CSSPropertyBorderTopStyle:
   1520     case CSSPropertyBoxSizing:
   1521     case CSSPropertyCaptionSide:
   1522     case CSSPropertyClear:
   1523     case CSSPropertyDirection:
   1524     case CSSPropertyDisplay:
   1525     case CSSPropertyEmptyCells:
   1526     case CSSPropertyFloat:
   1527     case CSSPropertyFontStyle:
   1528     case CSSPropertyImageRendering:
   1529     case CSSPropertyListStylePosition:
   1530     case CSSPropertyListStyleType:
   1531     case CSSPropertyObjectFit:
   1532     case CSSPropertyOutlineStyle:
   1533     case CSSPropertyOverflowWrap:
   1534     case CSSPropertyOverflowX:
   1535     case CSSPropertyOverflowY:
   1536     case CSSPropertyPageBreakAfter:
   1537     case CSSPropertyPageBreakBefore:
   1538     case CSSPropertyPageBreakInside:
   1539     case CSSPropertyPointerEvents:
   1540     case CSSPropertyPosition:
   1541     case CSSPropertyResize:
   1542     case CSSPropertySpeak:
   1543     case CSSPropertyTableLayout:
   1544     case CSSPropertyTextAlignLast:
   1545     case CSSPropertyTextJustify:
   1546     case CSSPropertyTextLineThroughMode:
   1547     case CSSPropertyTextLineThroughStyle:
   1548     case CSSPropertyTextOverflow:
   1549     case CSSPropertyTextOverlineMode:
   1550     case CSSPropertyTextOverlineStyle:
   1551     case CSSPropertyTextRendering:
   1552     case CSSPropertyTextTransform:
   1553     case CSSPropertyTextUnderlineMode:
   1554     case CSSPropertyTextUnderlineStyle:
   1555     case CSSPropertyTouchActionDelay:
   1556     case CSSPropertyVisibility:
   1557     case CSSPropertyWebkitAppearance:
   1558     case CSSPropertyBackfaceVisibility:
   1559     case CSSPropertyWebkitBackfaceVisibility:
   1560     case CSSPropertyWebkitBorderAfterStyle:
   1561     case CSSPropertyWebkitBorderBeforeStyle:
   1562     case CSSPropertyWebkitBorderEndStyle:
   1563     case CSSPropertyWebkitBorderFit:
   1564     case CSSPropertyWebkitBorderStartStyle:
   1565     case CSSPropertyWebkitBoxAlign:
   1566     case CSSPropertyWebkitBoxDecorationBreak:
   1567     case CSSPropertyWebkitBoxDirection:
   1568     case CSSPropertyWebkitBoxLines:
   1569     case CSSPropertyWebkitBoxOrient:
   1570     case CSSPropertyWebkitBoxPack:
   1571     case CSSPropertyInternalCallback:
   1572     case CSSPropertyWebkitColumnBreakAfter:
   1573     case CSSPropertyWebkitColumnBreakBefore:
   1574     case CSSPropertyWebkitColumnBreakInside:
   1575     case CSSPropertyColumnFill:
   1576     case CSSPropertyWebkitColumnRuleStyle:
   1577     case CSSPropertyAlignContent:
   1578     case CSSPropertyFlexDirection:
   1579     case CSSPropertyFlexWrap:
   1580     case CSSPropertyJustifyContent:
   1581     case CSSPropertyFontKerning:
   1582     case CSSPropertyWebkitFontSmoothing:
   1583     case CSSPropertyGridAutoFlow:
   1584     case CSSPropertyWebkitLineBreak:
   1585     case CSSPropertyWebkitMarginAfterCollapse:
   1586     case CSSPropertyWebkitMarginBeforeCollapse:
   1587     case CSSPropertyWebkitMarginBottomCollapse:
   1588     case CSSPropertyWebkitMarginTopCollapse:
   1589     case CSSPropertyInternalMarqueeDirection:
   1590     case CSSPropertyInternalMarqueeStyle:
   1591     case CSSPropertyWebkitPrintColorAdjust:
   1592     case CSSPropertyWebkitRtlOrdering:
   1593     case CSSPropertyWebkitRubyPosition:
   1594     case CSSPropertyWebkitTextCombine:
   1595     case CSSPropertyWebkitTextEmphasisPosition:
   1596     case CSSPropertyWebkitTextSecurity:
   1597     case CSSPropertyTransformStyle:
   1598     case CSSPropertyWebkitTransformStyle:
   1599     case CSSPropertyWebkitUserDrag:
   1600     case CSSPropertyWebkitUserModify:
   1601     case CSSPropertyWebkitUserSelect:
   1602     case CSSPropertyWebkitWrapFlow:
   1603     case CSSPropertyWebkitWrapThrough:
   1604     case CSSPropertyWebkitWritingMode:
   1605     case CSSPropertyWhiteSpace:
   1606     case CSSPropertyWordBreak:
   1607     case CSSPropertyWordWrap:
   1608     case CSSPropertyMixBlendMode:
   1609     case CSSPropertyIsolation:
   1610         // These properties should be handled before in isValidKeywordPropertyAndValue().
   1611         ASSERT_NOT_REACHED();
   1612         return false;
   1613     // Properties below are validated inside parseViewportProperty, because we
   1614     // check for parser state. We need to invalidate if someone adds them outside
   1615     // a @viewport rule.
   1616     case CSSPropertyMaxZoom:
   1617     case CSSPropertyMinZoom:
   1618     case CSSPropertyOrientation:
   1619     case CSSPropertyUserZoom:
   1620         validPrimitive = false;
   1621         break;
   1622 
   1623     case CSSPropertyAll:
   1624         if (id == CSSValueInitial || id == CSSValueInherit || id == CSSValueUnset) {
   1625             validPrimitive = true;
   1626             break;
   1627         }
   1628         return false;
   1629 
   1630     default:
   1631         return parseSVGValue(propId, important);
   1632     }
   1633 
   1634     if (validPrimitive) {
   1635         parsedValue = parseValidPrimitive(id, value);
   1636         m_valueList->next();
   1637     }
   1638     ASSERT(!m_parsedCalculation);
   1639     if (parsedValue) {
   1640         if (!m_valueList->current() || inShorthand()) {
   1641             addProperty(propId, parsedValue.release(), important);
   1642             return true;
   1643         }
   1644     }
   1645     return false;
   1646 }
   1647 
   1648 void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRefPtrWillBeRawPtr<CSSValue> rval)
   1649 {
   1650     if (lval) {
   1651         if (lval->isBaseValueList())
   1652             toCSSValueList(lval.get())->append(rval);
   1653         else {
   1654             PassRefPtrWillBeRawPtr<CSSValue> oldlVal(lval.release());
   1655             PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   1656             list->append(oldlVal);
   1657             list->append(rval);
   1658             lval = list;
   1659         }
   1660     }
   1661     else
   1662         lval = rval;
   1663 }
   1664 
   1665 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtrWillBeRawPtr<CSSValue>& cssValue)
   1666 {
   1667     if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox
   1668         || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) {
   1669         cssValue = cssValuePool().createIdentifierValue(parserValue->id);
   1670         return true;
   1671     }
   1672     return false;
   1673 }
   1674 
   1675 const int cMaxFillProperties = 9;
   1676 
   1677 bool CSSPropertyParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important)
   1678 {
   1679     ASSERT(numProperties <= cMaxFillProperties);
   1680     if (numProperties > cMaxFillProperties)
   1681         return false;
   1682 
   1683     ShorthandScope scope(this, propId);
   1684 
   1685     bool parsedProperty[cMaxFillProperties] = { false };
   1686     RefPtrWillBeRawPtr<CSSValue> values[cMaxFillProperties];
   1687 #if ENABLE(OILPAN)
   1688     // Zero initialize the array of raw pointers.
   1689     memset(&values, 0, sizeof(values));
   1690 #endif
   1691     RefPtrWillBeRawPtr<CSSValue> clipValue = nullptr;
   1692     RefPtrWillBeRawPtr<CSSValue> positionYValue = nullptr;
   1693     RefPtrWillBeRawPtr<CSSValue> repeatYValue = nullptr;
   1694     bool foundClip = false;
   1695     int i;
   1696     bool foundPositionCSSProperty = false;
   1697 
   1698     while (m_valueList->current()) {
   1699         CSSParserValue* val = m_valueList->current();
   1700         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   1701             // We hit the end.  Fill in all remaining values with the initial value.
   1702             m_valueList->next();
   1703             for (i = 0; i < numProperties; ++i) {
   1704                 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
   1705                     // Color is not allowed except as the last item in a list for backgrounds.
   1706                     // Reject the entire property.
   1707                     return false;
   1708 
   1709                 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
   1710                     addFillValue(values[i], cssValuePool().createImplicitInitialValue());
   1711                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   1712                         addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
   1713                     if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
   1714                         addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
   1715                     if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
   1716                         // If background-origin wasn't present, then reset background-clip also.
   1717                         addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
   1718                     }
   1719                 }
   1720                 parsedProperty[i] = false;
   1721             }
   1722             if (!m_valueList->current())
   1723                 break;
   1724         }
   1725 
   1726         bool sizeCSSPropertyExpected = false;
   1727         if (isForwardSlashOperator(val) && foundPositionCSSProperty) {
   1728             sizeCSSPropertyExpected = true;
   1729             m_valueList->next();
   1730         }
   1731 
   1732         foundPositionCSSProperty = false;
   1733         bool found = false;
   1734         for (i = 0; !found && i < numProperties; ++i) {
   1735 
   1736             if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize))
   1737                 continue;
   1738             if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize))
   1739                 continue;
   1740 
   1741             if (!parsedProperty[i]) {
   1742                 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr;
   1743                 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr;
   1744                 CSSPropertyID propId1, propId2;
   1745                 CSSParserValue* parserValue = m_valueList->current();
   1746                 // parseFillProperty() may modify m_implicitShorthand, so we MUST reset it
   1747                 // before EACH return below.
   1748                 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
   1749                     parsedProperty[i] = found = true;
   1750                     addFillValue(values[i], val1.release());
   1751                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   1752                         addFillValue(positionYValue, val2.release());
   1753                     if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
   1754                         addFillValue(repeatYValue, val2.release());
   1755                     if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
   1756                         // Reparse the value as a clip, and see if we succeed.
   1757                         if (parseBackgroundClip(parserValue, val1))
   1758                             addFillValue(clipValue, val1.release()); // The property parsed successfully.
   1759                         else
   1760                             addFillValue(clipValue, cssValuePool().createImplicitInitialValue()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
   1761                     }
   1762                     if (properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) {
   1763                         // Update clipValue
   1764                         addFillValue(clipValue, val1.release());
   1765                         foundClip = true;
   1766                     }
   1767                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   1768                         foundPositionCSSProperty = true;
   1769                 }
   1770             }
   1771         }
   1772 
   1773         // if we didn't find at least one match, this is an
   1774         // invalid shorthand and we have to ignore it
   1775         if (!found) {
   1776             m_implicitShorthand = false;
   1777             return false;
   1778         }
   1779     }
   1780 
   1781     // Now add all of the properties we found.
   1782     for (i = 0; i < numProperties; i++) {
   1783         // Fill in any remaining properties with the initial value.
   1784         if (!parsedProperty[i]) {
   1785             addFillValue(values[i], cssValuePool().createImplicitInitialValue());
   1786             if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
   1787                 addFillValue(positionYValue, cssValuePool().createImplicitInitialValue());
   1788             if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
   1789                 addFillValue(repeatYValue, cssValuePool().createImplicitInitialValue());
   1790             if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
   1791                 // If background-origin wasn't present, then reset background-clip also.
   1792                 addFillValue(clipValue, cssValuePool().createImplicitInitialValue());
   1793             }
   1794         }
   1795         if (properties[i] == CSSPropertyBackgroundPosition) {
   1796             addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
   1797             // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
   1798             addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
   1799         } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
   1800             addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
   1801             // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
   1802             addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
   1803         } else if (properties[i] == CSSPropertyBackgroundRepeat) {
   1804             addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
   1805             // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
   1806             addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
   1807         } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
   1808             addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
   1809             // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
   1810             addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
   1811         } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip)
   1812             // Value is already set while updating origin
   1813             continue;
   1814         else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && m_context.useLegacyBackgroundSizeShorthandBehavior())
   1815             continue;
   1816         else
   1817             addProperty(properties[i], values[i].release(), important);
   1818 
   1819         // Add in clip values when we hit the corresponding origin property.
   1820         if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip)
   1821             addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
   1822         else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip)
   1823             addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
   1824     }
   1825 
   1826     m_implicitShorthand = false;
   1827     return true;
   1828 }
   1829 
   1830 static bool isValidTransitionPropertyList(CSSValueList* value)
   1831 {
   1832     if (value->length() < 2)
   1833         return true;
   1834     for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
   1835         // FIXME: Shorthand parsing shouldn't add initial to the list since it won't round-trip
   1836         if (i.value()->isInitialValue())
   1837             continue;
   1838         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(i.value());
   1839         if (primitiveValue->isValueID() && primitiveValue->getValueID() == CSSValueNone)
   1840             return false;
   1841     }
   1842     return true;
   1843 }
   1844 
   1845 bool CSSPropertyParser::parseAnimationShorthand(CSSPropertyID propId, bool important)
   1846 {
   1847     const StylePropertyShorthand& animationProperties = parsingShorthandForProperty(propId);
   1848     const unsigned numProperties = 8;
   1849 
   1850     // The list of properties in the shorthand should be the same
   1851     // length as the list with animation name in last position, even though they are
   1852     // in a different order.
   1853     ASSERT(numProperties == animationProperties.length());
   1854     ASSERT(numProperties == shorthandForProperty(propId).length());
   1855 
   1856     ShorthandScope scope(this, propId);
   1857 
   1858     bool parsedProperty[numProperties] = { false };
   1859     RefPtrWillBeRawPtr<CSSValueList> values[numProperties];
   1860     for (size_t i = 0; i < numProperties; ++i)
   1861         values[i] = CSSValueList::createCommaSeparated();
   1862 
   1863     while (m_valueList->current()) {
   1864         CSSParserValue* val = m_valueList->current();
   1865         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   1866             // We hit the end. Fill in all remaining values with the initial value.
   1867             m_valueList->next();
   1868             for (size_t i = 0; i < numProperties; ++i) {
   1869                 if (!parsedProperty[i])
   1870                     values[i]->append(cssValuePool().createImplicitInitialValue());
   1871                 parsedProperty[i] = false;
   1872             }
   1873             if (!m_valueList->current())
   1874                 break;
   1875         }
   1876 
   1877         bool found = false;
   1878         for (size_t i = 0; i < numProperties; ++i) {
   1879             if (parsedProperty[i])
   1880                 continue;
   1881             if (RefPtrWillBeRawPtr<CSSValue> val = parseAnimationProperty(animationProperties.properties()[i])) {
   1882                 parsedProperty[i] = found = true;
   1883                 values[i]->append(val.release());
   1884                 break;
   1885             }
   1886         }
   1887 
   1888         // if we didn't find at least one match, this is an
   1889         // invalid shorthand and we have to ignore it
   1890         if (!found)
   1891             return false;
   1892     }
   1893 
   1894     for (size_t i = 0; i < numProperties; ++i) {
   1895         // If we didn't find the property, set an intial value.
   1896         if (!parsedProperty[i])
   1897             values[i]->append(cssValuePool().createImplicitInitialValue());
   1898 
   1899         if (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled())
   1900             addPropertyWithPrefixingVariant(animationProperties.properties()[i], values[i].release(), important);
   1901         else
   1902             addProperty(animationProperties.properties()[i], values[i].release(), important);
   1903     }
   1904 
   1905     return true;
   1906 }
   1907 
   1908 bool CSSPropertyParser::parseTransitionShorthand(CSSPropertyID propId, bool important)
   1909 {
   1910     const unsigned numProperties = 4;
   1911     const StylePropertyShorthand& shorthand = parsingShorthandForProperty(propId);
   1912     ASSERT(numProperties == shorthand.length());
   1913 
   1914     ShorthandScope scope(this, propId);
   1915 
   1916     bool parsedProperty[numProperties] = { false };
   1917     RefPtrWillBeRawPtr<CSSValueList> values[numProperties];
   1918     for (size_t i = 0; i < numProperties; ++i)
   1919         values[i] = CSSValueList::createCommaSeparated();
   1920 
   1921     while (m_valueList->current()) {
   1922         CSSParserValue* val = m_valueList->current();
   1923         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   1924             // We hit the end. Fill in all remaining values with the initial value.
   1925             m_valueList->next();
   1926             for (size_t i = 0; i < numProperties; ++i) {
   1927                 if (!parsedProperty[i])
   1928                     values[i]->append(cssValuePool().createImplicitInitialValue());
   1929                 parsedProperty[i] = false;
   1930             }
   1931             if (!m_valueList->current())
   1932                 break;
   1933         }
   1934 
   1935         bool found = false;
   1936         for (size_t i = 0; i < numProperties; ++i) {
   1937             if (parsedProperty[i])
   1938                 continue;
   1939             if (RefPtrWillBeRawPtr<CSSValue> val = parseAnimationProperty(shorthand.properties()[i])) {
   1940                 parsedProperty[i] = found = true;
   1941                 values[i]->append(val.release());
   1942                 break;
   1943             }
   1944         }
   1945 
   1946         // if we didn't find at least one match, this is an
   1947         // invalid shorthand and we have to ignore it
   1948         if (!found)
   1949             return false;
   1950     }
   1951 
   1952     ASSERT(shorthand.properties()[3] == CSSPropertyTransitionProperty || shorthand.properties()[3] == CSSPropertyWebkitTransitionProperty);
   1953     if (!isValidTransitionPropertyList(values[3].get()))
   1954         return false;
   1955 
   1956     // Fill in any remaining properties with the initial value and add
   1957     for (size_t i = 0; i < numProperties; ++i) {
   1958         if (!parsedProperty[i])
   1959             values[i]->append(cssValuePool().createImplicitInitialValue());
   1960         addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important);
   1961     }
   1962 
   1963     return true;
   1964 }
   1965 
   1966 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnWidth()
   1967 {
   1968     CSSParserValue* value = m_valueList->current();
   1969     // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
   1970     // the 'columns' shorthand property.
   1971     if (value->id == CSSValueAuto || (validUnit(value, FLength | FNonNeg, HTMLStandardMode) && (m_parsedCalculation || value->fValue != 0))) {
   1972         RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
   1973         m_valueList->next();
   1974         return parsedValue;
   1975     }
   1976     return nullptr;
   1977 }
   1978 
   1979 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnCount()
   1980 {
   1981     CSSParserValue* value = m_valueList->current();
   1982     if (value->id == CSSValueAuto
   1983         || (!value->id && validUnit(value, FPositiveInteger, HTMLQuirksMode))) {
   1984         RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id, value);
   1985         m_valueList->next();
   1986         return parsedValue;
   1987     }
   1988     return nullptr;
   1989 }
   1990 
   1991 bool CSSPropertyParser::parseColumnsShorthand(bool important)
   1992 {
   1993     RefPtrWillBeRawPtr<CSSValue> columnWidth = nullptr;
   1994     RefPtrWillBeRawPtr<CSSValue> columnCount = nullptr;
   1995     bool hasPendingExplicitAuto = false;
   1996 
   1997     for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->current(); propertiesParsed++) {
   1998         if (propertiesParsed >= 2)
   1999             return false; // Too many values for this shorthand. Invalid declaration.
   2000         if (!propertiesParsed && value->id == CSSValueAuto) {
   2001             // 'auto' is a valid value for any of the two longhands, and at this point we
   2002             // don't know which one(s) it is meant for. We need to see if there are other
   2003             // values first.
   2004             m_valueList->next();
   2005             hasPendingExplicitAuto = true;
   2006         } else {
   2007             if (!columnWidth) {
   2008                 if ((columnWidth = parseColumnWidth()))
   2009                     continue;
   2010             }
   2011             if (!columnCount) {
   2012                 if ((columnCount = parseColumnCount()))
   2013                     continue;
   2014             }
   2015             // If we didn't find at least one match, this is an
   2016             // invalid shorthand and we have to ignore it.
   2017             return false;
   2018         }
   2019     }
   2020     if (hasPendingExplicitAuto) {
   2021         // Time to assign the previously skipped 'auto' value to a property. If both properties are
   2022         // unassigned at this point (i.e. 'columns:auto'), it doesn't matter that much which one we
   2023         // set (although it does make a slight difference to web-inspector). The one we don't set
   2024         // here will get an implicit 'auto' value further down.
   2025         if (!columnWidth) {
   2026             columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto);
   2027         } else {
   2028             ASSERT(!columnCount);
   2029             columnCount = cssValuePool().createIdentifierValue(CSSValueAuto);
   2030         }
   2031     }
   2032     ASSERT(columnCount || columnWidth);
   2033 
   2034     // Any unassigned property at this point will become implicit 'auto'.
   2035     if (columnWidth)
   2036         addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important);
   2037     else
   2038         addProperty(CSSPropertyWebkitColumnWidth, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
   2039     if (columnCount)
   2040         addProperty(CSSPropertyWebkitColumnCount, columnCount, important);
   2041     else
   2042         addProperty(CSSPropertyWebkitColumnCount, cssValuePool().createIdentifierValue(CSSValueAuto), important, true /* implicit */);
   2043     return true;
   2044 }
   2045 
   2046 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important)
   2047 {
   2048     // We try to match as many properties as possible
   2049     // We set up an array of booleans to mark which property has been found,
   2050     // and we try to search for properties until it makes no longer any sense.
   2051     ShorthandScope scope(this, propId);
   2052 
   2053     bool found = false;
   2054     unsigned propertiesParsed = 0;
   2055     bool propertyFound[6] = { false, false, false, false, false, false }; // 6 is enough size.
   2056 
   2057     while (m_valueList->current()) {
   2058         found = false;
   2059         for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) {
   2060             if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) {
   2061                 propertyFound[propIndex] = found = true;
   2062                 propertiesParsed++;
   2063             }
   2064         }
   2065 
   2066         // if we didn't find at least one match, this is an
   2067         // invalid shorthand and we have to ignore it
   2068         if (!found)
   2069             return false;
   2070     }
   2071 
   2072     if (propertiesParsed == shorthand.length())
   2073         return true;
   2074 
   2075     // Fill in any remaining properties with the initial value.
   2076     ImplicitScope implicitScope(this, PropertyImplicit);
   2077     const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization();
   2078     for (unsigned i = 0; i < shorthand.length(); ++i) {
   2079         if (propertyFound[i])
   2080             continue;
   2081 
   2082         if (propertiesForInitialization) {
   2083             const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]);
   2084             for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex)
   2085                 addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important);
   2086         } else
   2087             addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important);
   2088     }
   2089 
   2090     return true;
   2091 }
   2092 
   2093 bool CSSPropertyParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties,  bool important)
   2094 {
   2095     /* From the CSS 2 specs, 8.3
   2096      * If there is only one value, it applies to all sides. If there are two values, the top and
   2097      * bottom margins are set to the first value and the right and left margins are set to the second.
   2098      * If there are three values, the top is set to the first value, the left and right are set to the
   2099      * second, and the bottom is set to the third. If there are four values, they apply to the top,
   2100      * right, bottom, and left, respectively.
   2101      */
   2102 
   2103     int num = inShorthand() ? 1 : m_valueList->size();
   2104 
   2105     ShorthandScope scope(this, propId);
   2106 
   2107     // the order is top, right, bottom, left
   2108     switch (num) {
   2109         case 1: {
   2110             if (!parseValue(properties[0], important))
   2111                 return false;
   2112             CSSValue* value = m_parsedProperties.last().value();
   2113             ImplicitScope implicitScope(this, PropertyImplicit);
   2114             addProperty(properties[1], value, important);
   2115             addProperty(properties[2], value, important);
   2116             addProperty(properties[3], value, important);
   2117             break;
   2118         }
   2119         case 2: {
   2120             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
   2121                 return false;
   2122             CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
   2123             ImplicitScope implicitScope(this, PropertyImplicit);
   2124             addProperty(properties[2], value, important);
   2125             value = m_parsedProperties[m_parsedProperties.size() - 2].value();
   2126             addProperty(properties[3], value, important);
   2127             break;
   2128         }
   2129         case 3: {
   2130             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
   2131                 return false;
   2132             CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value();
   2133             ImplicitScope implicitScope(this, PropertyImplicit);
   2134             addProperty(properties[3], value, important);
   2135             break;
   2136         }
   2137         case 4: {
   2138             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
   2139                 !parseValue(properties[2], important) || !parseValue(properties[3], important))
   2140                 return false;
   2141             break;
   2142         }
   2143         default: {
   2144             return false;
   2145         }
   2146     }
   2147 
   2148     return true;
   2149 }
   2150 
   2151 // auto | <identifier>
   2152 bool CSSPropertyParser::parsePage(CSSPropertyID propId, bool important)
   2153 {
   2154     ASSERT(propId == CSSPropertyPage);
   2155 
   2156     if (m_valueList->size() != 1)
   2157         return false;
   2158 
   2159     CSSParserValue* value = m_valueList->current();
   2160     if (!value)
   2161         return false;
   2162 
   2163     if (value->id == CSSValueAuto) {
   2164         addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
   2165         return true;
   2166     } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
   2167         addProperty(propId, createPrimitiveStringValue(value), important);
   2168         return true;
   2169     }
   2170     return false;
   2171 }
   2172 
   2173 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
   2174 bool CSSPropertyParser::parseSize(CSSPropertyID propId, bool important)
   2175 {
   2176     ASSERT(propId == CSSPropertySize);
   2177 
   2178     if (m_valueList->size() > 2)
   2179         return false;
   2180 
   2181     CSSParserValue* value = m_valueList->current();
   2182     if (!value)
   2183         return false;
   2184 
   2185     RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
   2186 
   2187     // First parameter.
   2188     SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
   2189     if (paramType == None)
   2190         return false;
   2191 
   2192     // Second parameter, if any.
   2193     value = m_valueList->next();
   2194     if (value) {
   2195         paramType = parseSizeParameter(parsedValues.get(), value, paramType);
   2196         if (paramType == None)
   2197             return false;
   2198     }
   2199 
   2200     addProperty(propId, parsedValues.release(), important);
   2201     return true;
   2202 }
   2203 
   2204 CSSPropertyParser::SizeParameterType CSSPropertyParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
   2205 {
   2206     switch (value->id) {
   2207     case CSSValueAuto:
   2208         if (prevParamType == None) {
   2209             parsedValues->append(cssValuePool().createIdentifierValue(value->id));
   2210             return Auto;
   2211         }
   2212         return None;
   2213     case CSSValueLandscape:
   2214     case CSSValuePortrait:
   2215         if (prevParamType == None || prevParamType == PageSize) {
   2216             parsedValues->append(cssValuePool().createIdentifierValue(value->id));
   2217             return Orientation;
   2218         }
   2219         return None;
   2220     case CSSValueA3:
   2221     case CSSValueA4:
   2222     case CSSValueA5:
   2223     case CSSValueB4:
   2224     case CSSValueB5:
   2225     case CSSValueLedger:
   2226     case CSSValueLegal:
   2227     case CSSValueLetter:
   2228         if (prevParamType == None || prevParamType == Orientation) {
   2229             // Normalize to Page Size then Orientation order by prepending.
   2230             // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (StyleResolver::applyPageSizeProperty).
   2231             parsedValues->prepend(cssValuePool().createIdentifierValue(value->id));
   2232             return PageSize;
   2233         }
   2234         return None;
   2235     case 0:
   2236         if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) {
   2237             parsedValues->append(createPrimitiveNumericValue(value));
   2238             return Length;
   2239         }
   2240         return None;
   2241     default:
   2242         return None;
   2243     }
   2244 }
   2245 
   2246 // [ <string> <string> ]+ | inherit | none
   2247 // inherit and none are handled in parseValue.
   2248 bool CSSPropertyParser::parseQuotes(CSSPropertyID propId, bool important)
   2249 {
   2250     RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   2251     while (CSSParserValue* val = m_valueList->current()) {
   2252         RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
   2253         if (val->unit == CSSPrimitiveValue::CSS_STRING)
   2254             parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
   2255         else
   2256             break;
   2257         values->append(parsedValue.release());
   2258         m_valueList->next();
   2259     }
   2260     if (values->length()) {
   2261         addProperty(propId, values.release(), important);
   2262         m_valueList->next();
   2263         return true;
   2264     }
   2265     return false;
   2266 }
   2267 
   2268 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
   2269 // in CSS 2.1 this got somewhat reduced:
   2270 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
   2271 bool CSSPropertyParser::parseContent(CSSPropertyID propId, bool important)
   2272 {
   2273     RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   2274 
   2275     while (CSSParserValue* val = m_valueList->current()) {
   2276         RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
   2277         if (val->unit == CSSPrimitiveValue::CSS_URI) {
   2278             // url
   2279             parsedValue = createCSSImageValueWithReferrer(val->string, completeURL(val->string));
   2280         } else if (val->unit == CSSParserValue::Function) {
   2281             // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
   2282             CSSParserValueList* args = val->function->args.get();
   2283             if (!args)
   2284                 return false;
   2285             if (equalIgnoringCase(val->function->name, "attr(")) {
   2286                 parsedValue = parseAttr(args);
   2287                 if (!parsedValue)
   2288                     return false;
   2289             } else if (equalIgnoringCase(val->function->name, "counter(")) {
   2290                 parsedValue = parseCounterContent(args, false);
   2291                 if (!parsedValue)
   2292                     return false;
   2293             } else if (equalIgnoringCase(val->function->name, "counters(")) {
   2294                 parsedValue = parseCounterContent(args, true);
   2295                 if (!parsedValue)
   2296                     return false;
   2297             } else if (equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
   2298                 parsedValue = parseImageSet(m_valueList.get());
   2299                 if (!parsedValue)
   2300                     return false;
   2301             } else if (isGeneratedImageValue(val)) {
   2302                 if (!parseGeneratedImage(m_valueList.get(), parsedValue))
   2303                     return false;
   2304             } else
   2305                 return false;
   2306         } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
   2307             // open-quote
   2308             // close-quote
   2309             // no-open-quote
   2310             // no-close-quote
   2311             // inherit
   2312             // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
   2313             // none
   2314             // normal
   2315             switch (val->id) {
   2316             case CSSValueOpenQuote:
   2317             case CSSValueCloseQuote:
   2318             case CSSValueNoOpenQuote:
   2319             case CSSValueNoCloseQuote:
   2320             case CSSValueNone:
   2321             case CSSValueNormal:
   2322                 parsedValue = cssValuePool().createIdentifierValue(val->id);
   2323             default:
   2324                 break;
   2325             }
   2326         } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
   2327             parsedValue = createPrimitiveStringValue(val);
   2328         }
   2329         if (!parsedValue)
   2330             break;
   2331         values->append(parsedValue.release());
   2332         m_valueList->next();
   2333     }
   2334 
   2335     if (values->length()) {
   2336         addProperty(propId, values.release(), important);
   2337         m_valueList->next();
   2338         return true;
   2339     }
   2340 
   2341     return false;
   2342 }
   2343 
   2344 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAttr(CSSParserValueList* args)
   2345 {
   2346     if (args->size() != 1)
   2347         return nullptr;
   2348 
   2349     CSSParserValue* a = args->current();
   2350 
   2351     if (a->unit != CSSPrimitiveValue::CSS_IDENT)
   2352         return nullptr;
   2353 
   2354     String attrName = a->string;
   2355     // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
   2356     // But HTML attribute names can't have those characters, and we should not
   2357     // even parse them inside attr().
   2358     if (attrName[0] == '-')
   2359         return nullptr;
   2360 
   2361     if (m_context.isHTMLDocument())
   2362         attrName = attrName.lower();
   2363 
   2364     return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
   2365 }
   2366 
   2367 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBackgroundColor()
   2368 {
   2369     CSSValueID id = m_valueList->current()->id;
   2370     if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
   2371         (id >= CSSValueGrey && id < CSSValueWebkitText && inQuirksMode()))
   2372         return cssValuePool().createIdentifierValue(id);
   2373     return parseColor();
   2374 }
   2375 
   2376 bool CSSPropertyParser::parseFillImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
   2377 {
   2378     if (valueList->current()->id == CSSValueNone) {
   2379         value = cssValuePool().createIdentifierValue(CSSValueNone);
   2380         return true;
   2381     }
   2382     if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
   2383         value = createCSSImageValueWithReferrer(valueList->current()->string, completeURL(valueList->current()->string));
   2384         return true;
   2385     }
   2386 
   2387     if (isGeneratedImageValue(valueList->current()))
   2388         return parseGeneratedImage(valueList, value);
   2389 
   2390     if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set(")) {
   2391         value = parseImageSet(m_valueList.get());
   2392         if (value)
   2393             return true;
   2394     }
   2395 
   2396     return false;
   2397 }
   2398 
   2399 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionX(CSSParserValueList* valueList)
   2400 {
   2401     int id = valueList->current()->id;
   2402     if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) {
   2403         int percent = 0;
   2404         if (id == CSSValueRight)
   2405             percent = 100;
   2406         else if (id == CSSValueCenter)
   2407             percent = 50;
   2408         return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
   2409     }
   2410     if (validUnit(valueList->current(), FPercent | FLength))
   2411         return createPrimitiveNumericValue(valueList->current());
   2412     return nullptr;
   2413 }
   2414 
   2415 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionY(CSSParserValueList* valueList)
   2416 {
   2417     int id = valueList->current()->id;
   2418     if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) {
   2419         int percent = 0;
   2420         if (id == CSSValueBottom)
   2421             percent = 100;
   2422         else if (id == CSSValueCenter)
   2423             percent = 50;
   2424         return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
   2425     }
   2426     if (validUnit(valueList->current(), FPercent | FLength))
   2427         return createPrimitiveNumericValue(valueList->current());
   2428     return nullptr;
   2429 }
   2430 
   2431 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode)
   2432 {
   2433     CSSValueID id = valueList->current()->id;
   2434     if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
   2435         int percent = 0;
   2436         if (id == CSSValueLeft || id == CSSValueRight) {
   2437             if (cumulativeFlags & XFillPosition)
   2438                 return nullptr;
   2439             cumulativeFlags |= XFillPosition;
   2440             individualFlag = XFillPosition;
   2441             if (id == CSSValueRight)
   2442                 percent = 100;
   2443         }
   2444         else if (id == CSSValueTop || id == CSSValueBottom) {
   2445             if (cumulativeFlags & YFillPosition)
   2446                 return nullptr;
   2447             cumulativeFlags |= YFillPosition;
   2448             individualFlag = YFillPosition;
   2449             if (id == CSSValueBottom)
   2450                 percent = 100;
   2451         } else if (id == CSSValueCenter) {
   2452             // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
   2453             percent = 50;
   2454             cumulativeFlags |= AmbiguousFillPosition;
   2455             individualFlag = AmbiguousFillPosition;
   2456         }
   2457 
   2458         if (parsingMode == ResolveValuesAsKeyword)
   2459             return cssValuePool().createIdentifierValue(id);
   2460 
   2461         return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
   2462     }
   2463     if (validUnit(valueList->current(), FPercent | FLength)) {
   2464         if (!cumulativeFlags) {
   2465             cumulativeFlags |= XFillPosition;
   2466             individualFlag = XFillPosition;
   2467         } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) {
   2468             cumulativeFlags |= YFillPosition;
   2469             individualFlag = YFillPosition;
   2470         } else {
   2471             if (m_parsedCalculation)
   2472                 m_parsedCalculation.release();
   2473             return nullptr;
   2474         }
   2475         return createPrimitiveNumericValue(valueList->current());
   2476     }
   2477     return nullptr;
   2478 }
   2479 
   2480 static bool isValueConflictingWithCurrentEdge(int value1, int value2)
   2481 {
   2482     if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight))
   2483         return true;
   2484 
   2485     if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom))
   2486         return true;
   2487 
   2488     return false;
   2489 }
   2490 
   2491 static bool isFillPositionKeyword(CSSValueID value)
   2492 {
   2493     return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
   2494 }
   2495 
   2496 void CSSPropertyParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
   2497 {
   2498     // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <percentage> | <length> ]
   2499     // In the case of 4 values <position> requires the second value to be a length or a percentage.
   2500     if (isFillPositionKeyword(parsedValue2->getValueID()))
   2501         return;
   2502 
   2503     unsigned cumulativeFlags = 0;
   2504     FillPositionFlag value3Flag = InvalidFillPosition;
   2505     RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
   2506     if (!value3)
   2507         return;
   2508 
   2509     CSSValueID ident1 = parsedValue1->getValueID();
   2510     CSSValueID ident3 = value3->getValueID();
   2511 
   2512     if (ident1 == CSSValueCenter)
   2513         return;
   2514 
   2515     if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter)
   2516         return;
   2517 
   2518     // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is
   2519     // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the
   2520     // case of two values top 20px is invalid but in the case of 4 values it becomes valid.
   2521     if (isValueConflictingWithCurrentEdge(ident1, ident3))
   2522         return;
   2523 
   2524     valueList->next();
   2525 
   2526     cumulativeFlags = 0;
   2527     FillPositionFlag value4Flag = InvalidFillPosition;
   2528     RefPtrWillBeRawPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword);
   2529     if (!value4)
   2530         return;
   2531 
   2532     // 4th value must be a length or a percentage.
   2533     if (isFillPositionKeyword(value4->getValueID()))
   2534         return;
   2535 
   2536     value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
   2537     value2 = createPrimitiveValuePair(value3, value4);
   2538 
   2539     if (ident1 == CSSValueTop || ident1 == CSSValueBottom)
   2540         value1.swap(value2);
   2541 
   2542     valueList->next();
   2543 }
   2544 void CSSPropertyParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2)
   2545 {
   2546     unsigned cumulativeFlags = 0;
   2547     FillPositionFlag value3Flag = InvalidFillPosition;
   2548     RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword);
   2549 
   2550     // value3 is not an expected value, we return.
   2551     if (!value3)
   2552         return;
   2553 
   2554     valueList->next();
   2555 
   2556     bool swapNeeded = false;
   2557     CSSValueID ident1 = parsedValue1->getValueID();
   2558     CSSValueID ident2 = parsedValue2->getValueID();
   2559     CSSValueID ident3 = value3->getValueID();
   2560 
   2561     CSSValueID firstPositionKeyword;
   2562     CSSValueID secondPositionKeyword;
   2563 
   2564     if (ident1 == CSSValueCenter) {
   2565         // <position> requires the first 'center' to be followed by a keyword.
   2566         if (!isFillPositionKeyword(ident2))
   2567             return;
   2568 
   2569         // If 'center' is the first keyword then the last one needs to be a length.
   2570         if (isFillPositionKeyword(ident3))
   2571             return;
   2572 
   2573         firstPositionKeyword = CSSValueLeft;
   2574         if (ident2 == CSSValueLeft || ident2 == CSSValueRight) {
   2575             firstPositionKeyword = CSSValueTop;
   2576             swapNeeded = true;
   2577         }
   2578         value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
   2579         value2 = createPrimitiveValuePair(parsedValue2, value3);
   2580     } else if (ident3 == CSSValueCenter) {
   2581         if (isFillPositionKeyword(ident2))
   2582             return;
   2583 
   2584         secondPositionKeyword = CSSValueTop;
   2585         if (ident1 == CSSValueTop || ident1 == CSSValueBottom) {
   2586             secondPositionKeyword = CSSValueLeft;
   2587             swapNeeded = true;
   2588         }
   2589         value1 = createPrimitiveValuePair(parsedValue1, parsedValue2);
   2590         value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE));
   2591     } else {
   2592         RefPtrWillBeRawPtr<CSSPrimitiveValue> firstPositionValue = nullptr;
   2593         RefPtrWillBeRawPtr<CSSPrimitiveValue> secondPositionValue = nullptr;
   2594 
   2595         if (isFillPositionKeyword(ident2)) {
   2596             // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ].
   2597             ASSERT(ident2 != CSSValueCenter);
   2598 
   2599             if (isFillPositionKeyword(ident3))
   2600                 return;
   2601 
   2602             secondPositionValue = value3;
   2603             secondPositionKeyword = ident2;
   2604             firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
   2605         } else {
   2606             // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ].
   2607             if (!isFillPositionKeyword(ident3))
   2608                 return;
   2609 
   2610             firstPositionValue = parsedValue2;
   2611             secondPositionKeyword = ident3;
   2612             secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
   2613         }
   2614 
   2615         if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword))
   2616             return;
   2617 
   2618         value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue);
   2619         value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue);
   2620     }
   2621 
   2622     if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded)
   2623         value1.swap(value2);
   2624 
   2625 #ifndef NDEBUG
   2626     CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get());
   2627     CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get());
   2628     ident1 = first->getPairValue()->first()->getValueID();
   2629     ident2 = second->getPairValue()->first()->getValueID();
   2630     ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight);
   2631     ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop);
   2632 #endif
   2633 }
   2634 
   2635 inline bool CSSPropertyParser::isPotentialPositionValue(CSSParserValue* value)
   2636 {
   2637     return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
   2638 }
   2639 
   2640 void CSSPropertyParser::parseFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
   2641 {
   2642     unsigned numberOfValues = 0;
   2643     for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++numberOfValues) {
   2644         CSSParserValue* current = valueList->valueAt(i);
   2645         if (isComma(current) || !current || isForwardSlashOperator(current) || !isPotentialPositionValue(current))
   2646             break;
   2647     }
   2648 
   2649     if (numberOfValues > 4)
   2650         return;
   2651 
   2652     // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return.
   2653     if (numberOfValues <= 2) {
   2654         parse2ValuesFillPosition(valueList, value1, value2);
   2655         return;
   2656     }
   2657 
   2658     ASSERT(numberOfValues > 2 && numberOfValues <= 4);
   2659 
   2660     CSSParserValue* value = valueList->current();
   2661 
   2662     // <position> requires the first value to be a background keyword.
   2663     if (!isFillPositionKeyword(value->id))
   2664         return;
   2665 
   2666     // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
   2667     unsigned cumulativeFlags = 0;
   2668     FillPositionFlag value1Flag = InvalidFillPosition;
   2669     FillPositionFlag value2Flag = InvalidFillPosition;
   2670     value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword);
   2671     if (!value1)
   2672         return;
   2673 
   2674     valueList->next();
   2675 
   2676     // In case we are parsing more than two values, relax the check inside of parseFillPositionComponent. top 20px is
   2677     // a valid start for <position>.
   2678     cumulativeFlags = AmbiguousFillPosition;
   2679     value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword);
   2680     if (value2)
   2681         valueList->next();
   2682     else {
   2683         value1.clear();
   2684         return;
   2685     }
   2686 
   2687     RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(value1.get());
   2688     RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(value2.get());
   2689 
   2690     value1.clear();
   2691     value2.clear();
   2692 
   2693     // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow.
   2694     if (parsedValue2->getValueID() == CSSValueCenter)
   2695         return;
   2696 
   2697     if (numberOfValues == 3)
   2698         parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
   2699     else
   2700         parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release());
   2701 }
   2702 
   2703 void CSSPropertyParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
   2704 {
   2705     // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
   2706     unsigned cumulativeFlags = 0;
   2707     FillPositionFlag value1Flag = InvalidFillPosition;
   2708     FillPositionFlag value2Flag = InvalidFillPosition;
   2709     value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag);
   2710     if (!value1)
   2711         return;
   2712 
   2713     // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
   2714     // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
   2715     // value was explicitly specified for our property.
   2716     CSSParserValue* value = valueList->next();
   2717 
   2718     // First check for the comma.  If so, we are finished parsing this value or value pair.
   2719     if (isComma(value))
   2720         value = 0;
   2721 
   2722     if (value) {
   2723         value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag);
   2724         if (value2)
   2725             valueList->next();
   2726         else {
   2727             if (!inShorthand()) {
   2728                 value1.clear();
   2729                 return;
   2730             }
   2731         }
   2732     }
   2733 
   2734     if (!value2)
   2735         // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
   2736         // is simply 50%. This is our default.
   2737         // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
   2738         // For left/right/center, the default of 50% in the y is still correct.
   2739         value2 = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
   2740 
   2741     if (value1Flag == YFillPosition || value2Flag == XFillPosition)
   2742         value1.swap(value2);
   2743 }
   2744 
   2745 void CSSPropertyParser::parseFillRepeat(RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2)
   2746 {
   2747     CSSValueID id = m_valueList->current()->id;
   2748     if (id == CSSValueRepeatX) {
   2749         m_implicitShorthand = true;
   2750         value1 = cssValuePool().createIdentifierValue(CSSValueRepeat);
   2751         value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
   2752         m_valueList->next();
   2753         return;
   2754     }
   2755     if (id == CSSValueRepeatY) {
   2756         m_implicitShorthand = true;
   2757         value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat);
   2758         value2 = cssValuePool().createIdentifierValue(CSSValueRepeat);
   2759         m_valueList->next();
   2760         return;
   2761     }
   2762     if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
   2763         value1 = cssValuePool().createIdentifierValue(id);
   2764     else {
   2765         value1 = nullptr;
   2766         return;
   2767     }
   2768 
   2769     CSSParserValue* value = m_valueList->next();
   2770 
   2771     // Parse the second value if one is available
   2772     if (value && !isComma(value)) {
   2773         id = value->id;
   2774         if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) {
   2775             value2 = cssValuePool().createIdentifierValue(id);
   2776             m_valueList->next();
   2777             return;
   2778         }
   2779     }
   2780 
   2781     // If only one value was specified, value2 is the same as value1.
   2782     m_implicitShorthand = true;
   2783     value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID());
   2784 }
   2785 
   2786 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillSize(CSSPropertyID propId, bool& allowComma)
   2787 {
   2788     allowComma = true;
   2789     CSSParserValue* value = m_valueList->current();
   2790 
   2791     if (value->id == CSSValueContain || value->id == CSSValueCover)
   2792         return cssValuePool().createIdentifierValue(value->id);
   2793 
   2794     RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = nullptr;
   2795 
   2796     if (value->id == CSSValueAuto)
   2797         parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto);
   2798     else {
   2799         if (!validUnit(value, FLength | FPercent))
   2800             return nullptr;
   2801         parsedValue1 = createPrimitiveNumericValue(value);
   2802     }
   2803 
   2804     RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr;
   2805     if ((value = m_valueList->next())) {
   2806         if (value->unit == CSSParserValue::Operator && value->iValue == ',')
   2807             allowComma = false;
   2808         else if (value->id != CSSValueAuto) {
   2809             if (!validUnit(value, FLength | FPercent)) {
   2810                 if (!inShorthand())
   2811                     return nullptr;
   2812                 // We need to rewind the value list, so that when it is advanced we'll end up back at this value.
   2813                 m_valueList->previous();
   2814             } else
   2815                 parsedValue2 = createPrimitiveNumericValue(value);
   2816         }
   2817     } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) {
   2818         // For backwards compatibility we set the second value to the first if it is omitted.
   2819         // We only need to do this for -webkit-background-size. It should be safe to let masks match
   2820         // the real property.
   2821         parsedValue2 = parsedValue1;
   2822     }
   2823 
   2824     if (!parsedValue2)
   2825         return parsedValue1;
   2826 
   2827     Pair::IdenticalValuesPolicy policy = propId == CSSPropertyWebkitBackgroundSize ?
   2828         Pair::DropIdenticalValues : Pair::KeepIdenticalValues;
   2829 
   2830     return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release(), policy);
   2831 }
   2832 
   2833 bool CSSPropertyParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2,
   2834     RefPtrWillBeRawPtr<CSSValue>& retValue1, RefPtrWillBeRawPtr<CSSValue>& retValue2)
   2835 {
   2836     RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
   2837     RefPtrWillBeRawPtr<CSSValueList> values2 = nullptr;
   2838     CSSParserValue* val;
   2839     RefPtrWillBeRawPtr<CSSValue> value = nullptr;
   2840     RefPtrWillBeRawPtr<CSSValue> value2 = nullptr;
   2841 
   2842     bool allowComma = false;
   2843 
   2844     retValue1 = retValue2 = nullptr;
   2845     propId1 = propId;
   2846     propId2 = propId;
   2847     if (propId == CSSPropertyBackgroundPosition) {
   2848         propId1 = CSSPropertyBackgroundPositionX;
   2849         propId2 = CSSPropertyBackgroundPositionY;
   2850     } else if (propId == CSSPropertyWebkitMaskPosition) {
   2851         propId1 = CSSPropertyWebkitMaskPositionX;
   2852         propId2 = CSSPropertyWebkitMaskPositionY;
   2853     } else if (propId == CSSPropertyBackgroundRepeat) {
   2854         propId1 = CSSPropertyBackgroundRepeatX;
   2855         propId2 = CSSPropertyBackgroundRepeatY;
   2856     } else if (propId == CSSPropertyWebkitMaskRepeat) {
   2857         propId1 = CSSPropertyWebkitMaskRepeatX;
   2858         propId2 = CSSPropertyWebkitMaskRepeatY;
   2859     }
   2860 
   2861     while ((val = m_valueList->current())) {
   2862         RefPtrWillBeRawPtr<CSSValue> currValue = nullptr;
   2863         RefPtrWillBeRawPtr<CSSValue> currValue2 = nullptr;
   2864 
   2865         if (allowComma) {
   2866             if (!isComma(val))
   2867                 return false;
   2868             m_valueList->next();
   2869             allowComma = false;
   2870         } else {
   2871             allowComma = true;
   2872             switch (propId) {
   2873                 case CSSPropertyBackgroundColor:
   2874                     currValue = parseBackgroundColor();
   2875                     if (currValue)
   2876                         m_valueList->next();
   2877                     break;
   2878                 case CSSPropertyBackgroundAttachment:
   2879                     if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
   2880                         currValue = cssValuePool().createIdentifierValue(val->id);
   2881                         m_valueList->next();
   2882                     }
   2883                     break;
   2884                 case CSSPropertyBackgroundImage:
   2885                 case CSSPropertyWebkitMaskImage:
   2886                     if (parseFillImage(m_valueList.get(), currValue))
   2887                         m_valueList->next();
   2888                     break;
   2889                 case CSSPropertyWebkitBackgroundClip:
   2890                 case CSSPropertyWebkitBackgroundOrigin:
   2891                 case CSSPropertyWebkitMaskClip:
   2892                 case CSSPropertyWebkitMaskOrigin:
   2893                     // The first three values here are deprecated and do not apply to the version of the property that has
   2894                     // the -webkit- prefix removed.
   2895                     if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
   2896                         val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
   2897                         ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
   2898                          (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
   2899                         currValue = cssValuePool().createIdentifierValue(val->id);
   2900                         m_valueList->next();
   2901                     }
   2902                     break;
   2903                 case CSSPropertyBackgroundClip:
   2904                     if (parseBackgroundClip(val, currValue))
   2905                         m_valueList->next();
   2906                     break;
   2907                 case CSSPropertyBackgroundOrigin:
   2908                     if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
   2909                         currValue = cssValuePool().createIdentifierValue(val->id);
   2910                         m_valueList->next();
   2911                     }
   2912                     break;
   2913                 case CSSPropertyBackgroundPosition:
   2914                 case CSSPropertyWebkitMaskPosition:
   2915                     parseFillPosition(m_valueList.get(), currValue, currValue2);
   2916                     // parseFillPosition advances the m_valueList pointer.
   2917                     break;
   2918                 case CSSPropertyBackgroundPositionX:
   2919                 case CSSPropertyWebkitMaskPositionX: {
   2920                     currValue = parseFillPositionX(m_valueList.get());
   2921                     if (currValue)
   2922                         m_valueList->next();
   2923                     break;
   2924                 }
   2925                 case CSSPropertyBackgroundPositionY:
   2926                 case CSSPropertyWebkitMaskPositionY: {
   2927                     currValue = parseFillPositionY(m_valueList.get());
   2928                     if (currValue)
   2929                         m_valueList->next();
   2930                     break;
   2931                 }
   2932                 case CSSPropertyWebkitBackgroundComposite:
   2933                 case CSSPropertyWebkitMaskComposite:
   2934                     if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) {
   2935                         currValue = cssValuePool().createIdentifierValue(val->id);
   2936                         m_valueList->next();
   2937                     }
   2938                     break;
   2939                 case CSSPropertyBackgroundBlendMode:
   2940                     if (val->id == CSSValueNormal || val->id == CSSValueMultiply
   2941                         || val->id == CSSValueScreen || val->id == CSSValueOverlay || val->id == CSSValueDarken
   2942                         || val->id == CSSValueLighten ||  val->id == CSSValueColorDodge || val->id == CSSValueColorBurn
   2943                         || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference
   2944                         || val->id == CSSValueExclusion || val->id == CSSValueHue || val->id == CSSValueSaturation
   2945                         || val->id == CSSValueColor || val->id == CSSValueLuminosity) {
   2946                         currValue = cssValuePool().createIdentifierValue(val->id);
   2947                         m_valueList->next();
   2948                     }
   2949                     break;
   2950                 case CSSPropertyBackgroundRepeat:
   2951                 case CSSPropertyWebkitMaskRepeat:
   2952                     parseFillRepeat(currValue, currValue2);
   2953                     // parseFillRepeat advances the m_valueList pointer
   2954                     break;
   2955                 case CSSPropertyBackgroundSize:
   2956                 case CSSPropertyWebkitBackgroundSize:
   2957                 case CSSPropertyWebkitMaskSize: {
   2958                     currValue = parseFillSize(propId, allowComma);
   2959                     if (currValue)
   2960                         m_valueList->next();
   2961                     break;
   2962                 }
   2963                 case CSSPropertyMaskSourceType: {
   2964                     if (RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()) {
   2965                         if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) {
   2966                             currValue = cssValuePool().createIdentifierValue(val->id);
   2967                             m_valueList->next();
   2968                         } else {
   2969                             currValue = nullptr;
   2970                         }
   2971                     }
   2972                     break;
   2973                 }
   2974                 default:
   2975                     break;
   2976             }
   2977             if (!currValue)
   2978                 return false;
   2979 
   2980             if (value && !values) {
   2981                 values = CSSValueList::createCommaSeparated();
   2982                 values->append(value.release());
   2983             }
   2984 
   2985             if (value2 && !values2) {
   2986                 values2 = CSSValueList::createCommaSeparated();
   2987                 values2->append(value2.release());
   2988             }
   2989 
   2990             if (values)
   2991                 values->append(currValue.release());
   2992             else
   2993                 value = currValue.release();
   2994             if (currValue2) {
   2995                 if (values2)
   2996                     values2->append(currValue2.release());
   2997                 else
   2998                     value2 = currValue2.release();
   2999             }
   3000         }
   3001 
   3002         // When parsing any fill shorthand property, we let it handle building up the lists for all
   3003         // properties.
   3004         if (inShorthand())
   3005             break;
   3006     }
   3007 
   3008     if (values && values->length()) {
   3009         retValue1 = values.release();
   3010         if (values2 && values2->length())
   3011             retValue2 = values2.release();
   3012         return true;
   3013     }
   3014     if (value) {
   3015         retValue1 = value.release();
   3016         retValue2 = value2.release();
   3017         return true;
   3018     }
   3019     return false;
   3020 }
   3021 
   3022 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDelay()
   3023 {
   3024     CSSParserValue* value = m_valueList->current();
   3025     if (validUnit(value, FTime))
   3026         return createPrimitiveNumericValue(value);
   3027     return nullptr;
   3028 }
   3029 
   3030 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDirection()
   3031 {
   3032     CSSParserValue* value = m_valueList->current();
   3033     if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value->id == CSSValueReverse || value->id == CSSValueAlternateReverse)
   3034         return cssValuePool().createIdentifierValue(value->id);
   3035     return nullptr;
   3036 }
   3037 
   3038 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDuration()
   3039 {
   3040     CSSParserValue* value = m_valueList->current();
   3041     if (validUnit(value, FTime | FNonNeg))
   3042         return createPrimitiveNumericValue(value);
   3043     return nullptr;
   3044 }
   3045 
   3046 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationFillMode()
   3047 {
   3048     CSSParserValue* value = m_valueList->current();
   3049     if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
   3050         return cssValuePool().createIdentifierValue(value->id);
   3051     return nullptr;
   3052 }
   3053 
   3054 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationIterationCount()
   3055 {
   3056     CSSParserValue* value = m_valueList->current();
   3057     if (value->id == CSSValueInfinite)
   3058         return cssValuePool().createIdentifierValue(value->id);
   3059     if (validUnit(value, FNumber | FNonNeg))
   3060         return createPrimitiveNumericValue(value);
   3061     return nullptr;
   3062 }
   3063 
   3064 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationName()
   3065 {
   3066     CSSParserValue* value = m_valueList->current();
   3067     if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
   3068         if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
   3069             return cssValuePool().createIdentifierValue(CSSValueNone);
   3070         } else {
   3071             return createPrimitiveStringValue(value);
   3072         }
   3073     }
   3074     return nullptr;
   3075 }
   3076 
   3077 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationPlayState()
   3078 {
   3079     CSSParserValue* value = m_valueList->current();
   3080     if (value->id == CSSValueRunning || value->id == CSSValuePaused)
   3081         return cssValuePool().createIdentifierValue(value->id);
   3082     return nullptr;
   3083 }
   3084 
   3085 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty()
   3086 {
   3087     CSSParserValue* value = m_valueList->current();
   3088     if (value->unit != CSSPrimitiveValue::CSS_IDENT)
   3089         return nullptr;
   3090     // Since all is valid css property keyword, cssPropertyID for all
   3091     // returns non-null value. We need to check "all" before
   3092     // cssPropertyID check.
   3093     if (equalIgnoringCase(value, "all"))
   3094         return cssValuePool().createIdentifierValue(CSSValueAll);
   3095     CSSPropertyID result = cssPropertyID(value->string);
   3096     if (result && RuntimeCSSEnabled::isCSSPropertyEnabled(result))
   3097         return cssValuePool().createIdentifierValue(result);
   3098     if (equalIgnoringCase(value, "none"))
   3099         return cssValuePool().createIdentifierValue(CSSValueNone);
   3100     if (equalIgnoringCase(value, "inherit") || equalIgnoringCase(value, "initial"))
   3101         return nullptr;
   3102     return createPrimitiveStringValue(value);
   3103 }
   3104 
   3105 bool CSSPropertyParser::parseWebkitTransformOriginShorthand(RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValue>& value3)
   3106 {
   3107     parse2ValuesFillPosition(m_valueList.get(), value1, value2);
   3108 
   3109     // now get z
   3110     if (m_valueList->current()) {
   3111         if (validUnit(m_valueList->current(), FLength)) {
   3112             value3 = createPrimitiveNumericValue(m_valueList->current());
   3113             m_valueList->next();
   3114             return true;
   3115         }
   3116         return false;
   3117     }
   3118     value3 = cssValuePool().createImplicitInitialValue();
   3119     return true;
   3120 }
   3121 
   3122 bool CSSPropertyParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
   3123 {
   3124     CSSParserValue* v = args->current();
   3125     if (!validUnit(v, FNumber))
   3126         return false;
   3127     result = v->fValue;
   3128     v = args->next();
   3129     if (!v)
   3130         // The last number in the function has no comma after it, so we're done.
   3131         return true;
   3132     if (!isComma(v))
   3133         return false;
   3134     args->next();
   3135     return true;
   3136 }
   3137 
   3138 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationTimingFunction()
   3139 {
   3140     CSSParserValue* value = m_valueList->current();
   3141     if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut
   3142         || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || value->id == CSSValueStepEnd
   3143         || (value->id == CSSValueStepMiddle && RuntimeEnabledFeatures::webAnimationsElementAnimateEnabled()))
   3144         return cssValuePool().createIdentifierValue(value->id);
   3145 
   3146     // We must be a function.
   3147     if (value->unit != CSSParserValue::Function)
   3148         return nullptr;
   3149 
   3150     CSSParserValueList* args = value->function->args.get();
   3151 
   3152     if (equalIgnoringCase(value->function->name, "steps(")) {
   3153         // For steps, 1 or 2 params must be specified (comma-separated)
   3154         if (!args || (args->size() != 1 && args->size() != 3))
   3155             return nullptr;
   3156 
   3157         // There are two values.
   3158         int numSteps;
   3159         StepsTimingFunction::StepAtPosition stepAtPosition = StepsTimingFunction::StepAtEnd;
   3160 
   3161         CSSParserValue* v = args->current();
   3162         if (!validUnit(v, FInteger))
   3163             return nullptr;
   3164         numSteps = clampToInteger(v->fValue);
   3165         if (numSteps < 1)
   3166             return nullptr;
   3167         v = args->next();
   3168 
   3169         if (v) {
   3170             // There is a comma so we need to parse the second value
   3171             if (!isComma(v))
   3172                 return nullptr;
   3173             v = args->next();
   3174             switch (v->id) {
   3175             case CSSValueMiddle:
   3176                 if (!RuntimeEnabledFeatures::webAnimationsAPIEnabled())
   3177                     return nullptr;
   3178                 stepAtPosition = StepsTimingFunction::StepAtMiddle;
   3179                 break;
   3180             case CSSValueStart:
   3181                 stepAtPosition = StepsTimingFunction::StepAtStart;
   3182                 break;
   3183             case CSSValueEnd:
   3184                 stepAtPosition = StepsTimingFunction::StepAtEnd;
   3185                 break;
   3186             default:
   3187                 return nullptr;
   3188             }
   3189         }
   3190 
   3191         return CSSStepsTimingFunctionValue::create(numSteps, stepAtPosition);
   3192     }
   3193 
   3194     if (equalIgnoringCase(value->function->name, "cubic-bezier(")) {
   3195         // For cubic bezier, 4 values must be specified.
   3196         if (!args || args->size() != 7)
   3197             return nullptr;
   3198 
   3199         // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range.
   3200         double x1, y1, x2, y2;
   3201 
   3202         if (!parseCubicBezierTimingFunctionValue(args, x1))
   3203             return nullptr;
   3204         if (x1 < 0 || x1 > 1)
   3205             return nullptr;
   3206         if (!parseCubicBezierTimingFunctionValue(args, y1))
   3207             return nullptr;
   3208         if (!parseCubicBezierTimingFunctionValue(args, x2))
   3209             return nullptr;
   3210         if (x2 < 0 || x2 > 1)
   3211             return nullptr;
   3212         if (!parseCubicBezierTimingFunctionValue(args, y2))
   3213             return nullptr;
   3214 
   3215         return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
   3216     }
   3217 
   3218     return nullptr;
   3219 }
   3220 
   3221 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty(CSSPropertyID propId)
   3222 {
   3223     RefPtrWillBeRawPtr<CSSValue> value = nullptr;
   3224     switch (propId) {
   3225     case CSSPropertyAnimationDelay:
   3226     case CSSPropertyWebkitAnimationDelay:
   3227     case CSSPropertyTransitionDelay:
   3228     case CSSPropertyWebkitTransitionDelay:
   3229         value = parseAnimationDelay();
   3230         break;
   3231     case CSSPropertyAnimationDirection:
   3232     case CSSPropertyWebkitAnimationDirection:
   3233         value = parseAnimationDirection();
   3234         break;
   3235     case CSSPropertyAnimationDuration:
   3236     case CSSPropertyWebkitAnimationDuration:
   3237     case CSSPropertyTransitionDuration:
   3238     case CSSPropertyWebkitTransitionDuration:
   3239         value = parseAnimationDuration();
   3240         break;
   3241     case CSSPropertyAnimationFillMode:
   3242     case CSSPropertyWebkitAnimationFillMode:
   3243         value = parseAnimationFillMode();
   3244         break;
   3245     case CSSPropertyAnimationIterationCount:
   3246     case CSSPropertyWebkitAnimationIterationCount:
   3247         value = parseAnimationIterationCount();
   3248         break;
   3249     case CSSPropertyAnimationName:
   3250     case CSSPropertyWebkitAnimationName:
   3251         value = parseAnimationName();
   3252         break;
   3253     case CSSPropertyAnimationPlayState:
   3254     case CSSPropertyWebkitAnimationPlayState:
   3255         value = parseAnimationPlayState();
   3256         break;
   3257     case CSSPropertyTransitionProperty:
   3258     case CSSPropertyWebkitTransitionProperty:
   3259         value = parseAnimationProperty();
   3260         break;
   3261     case CSSPropertyAnimationTimingFunction:
   3262     case CSSPropertyWebkitAnimationTimingFunction:
   3263     case CSSPropertyTransitionTimingFunction:
   3264     case CSSPropertyWebkitTransitionTimingFunction:
   3265         value = parseAnimationTimingFunction();
   3266         break;
   3267     default:
   3268         ASSERT_NOT_REACHED();
   3269         return nullptr;
   3270     }
   3271 
   3272     if (value)
   3273         m_valueList->next();
   3274     return value.release();
   3275 }
   3276 
   3277 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseAnimationPropertyList(CSSPropertyID propId)
   3278 {
   3279     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   3280     while (m_valueList->current()) {
   3281         RefPtrWillBeRawPtr<CSSValue> value = parseAnimationProperty(propId);
   3282         if (!value)
   3283             return nullptr;
   3284         list->append(value.release());
   3285         if (CSSParserValue* parserValue = m_valueList->current()) {
   3286             if (!isComma(parserValue))
   3287                 return nullptr;
   3288             m_valueList->next();
   3289             ASSERT(m_valueList->current());
   3290         }
   3291     }
   3292     if ((propId == CSSPropertyTransitionProperty || propId == CSSPropertyWebkitTransitionProperty) && !isValidTransitionPropertyList(list.get()))
   3293         return nullptr;
   3294     ASSERT(list->length());
   3295     return list.release();
   3296 }
   3297 
   3298 static inline bool isCSSWideKeyword(CSSParserValue& value)
   3299 {
   3300     return value.id == CSSValueInitial || value.id == CSSValueInherit || value.id == CSSValueDefault;
   3301 }
   3302 
   3303 static inline bool isValidCustomIdentForGridPositions(CSSParserValue& value)
   3304 {
   3305     // FIXME: we need a more general solution for <custom-ident> in all properties.
   3306     return value.unit == CSSPrimitiveValue::CSS_IDENT && value.id != CSSValueSpan && value.id != CSSValueAuto && !isCSSWideKeyword(value);
   3307 }
   3308 
   3309 // The function parses [ <integer> || <custom-ident> ] in <grid-line> (which can be stand alone or with 'span').
   3310 bool CSSPropertyParser::parseIntegerOrCustomIdentFromGridPosition(RefPtrWillBeRawPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSPrimitiveValue>& gridLineName)
   3311 {
   3312     CSSParserValue* value = m_valueList->current();
   3313     if (validUnit(value, FInteger) && value->fValue) {
   3314         numericValue = createPrimitiveNumericValue(value);
   3315         value = m_valueList->next();
   3316         if (value && isValidCustomIdentForGridPositions(*value)) {
   3317             gridLineName = createPrimitiveStringValue(m_valueList->current());
   3318             m_valueList->next();
   3319         }
   3320         return true;
   3321     }
   3322 
   3323     if (isValidCustomIdentForGridPositions(*value)) {
   3324         gridLineName = createPrimitiveStringValue(m_valueList->current());
   3325         value = m_valueList->next();
   3326         if (value && validUnit(value, FInteger) && value->fValue) {
   3327             numericValue = createPrimitiveNumericValue(value);
   3328             m_valueList->next();
   3329         }
   3330         return true;
   3331     }
   3332 
   3333     return false;
   3334 }
   3335 
   3336 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridPosition()
   3337 {
   3338     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   3339 
   3340     CSSParserValue* value = m_valueList->current();
   3341     if (value->id == CSSValueAuto) {
   3342         m_valueList->next();
   3343         return cssValuePool().createIdentifierValue(CSSValueAuto);
   3344     }
   3345 
   3346     RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue = nullptr;
   3347     RefPtrWillBeRawPtr<CSSPrimitiveValue> gridLineName = nullptr;
   3348     bool hasSeenSpanKeyword = false;
   3349 
   3350     if (parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName)) {
   3351         value = m_valueList->current();
   3352         if (value && value->id == CSSValueSpan) {
   3353             hasSeenSpanKeyword = true;
   3354             m_valueList->next();
   3355         }
   3356     } else if (value->id == CSSValueSpan) {
   3357         hasSeenSpanKeyword = true;
   3358         if (CSSParserValue* nextValue = m_valueList->next()) {
   3359             if (!isForwardSlashOperator(nextValue) && !parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName))
   3360                 return nullptr;
   3361         }
   3362     }
   3363 
   3364     // Check that we have consumed all the value list. For shorthands, the parser will pass
   3365     // the whole value list (including the opposite position).
   3366     if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current()))
   3367         return nullptr;
   3368 
   3369     // If we didn't parse anything, this is not a valid grid position.
   3370     if (!hasSeenSpanKeyword && !gridLineName && !numericValue)
   3371         return nullptr;
   3372 
   3373     // Negative numbers are not allowed for span (but are for <integer>).
   3374     if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0)
   3375         return nullptr;
   3376 
   3377     // For the <custom-ident> case.
   3378     if (gridLineName && !numericValue && !hasSeenSpanKeyword)
   3379         return cssValuePool().createValue(gridLineName->getStringValue(), CSSPrimitiveValue::CSS_STRING);
   3380 
   3381     RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
   3382     if (hasSeenSpanKeyword)
   3383         values->append(cssValuePool().createIdentifierValue(CSSValueSpan));
   3384     if (numericValue)
   3385         values->append(numericValue.release());
   3386     if (gridLineName)
   3387         values->append(gridLineName.release());
   3388     ASSERT(values->length());
   3389     return values.release();
   3390 }
   3391 
   3392 static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
   3393 {
   3394     if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
   3395         return value;
   3396 
   3397     return cssValuePool().createIdentifierValue(CSSValueAuto);
   3398 }
   3399 
   3400 bool CSSPropertyParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
   3401 {
   3402     ShorthandScope scope(this, shorthandId);
   3403     const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId);
   3404     ASSERT(shorthand.length() == 2);
   3405 
   3406     RefPtrWillBeRawPtr<CSSValue> startValue = parseGridPosition();
   3407     if (!startValue)
   3408         return false;
   3409 
   3410     RefPtrWillBeRawPtr<CSSValue> endValue = nullptr;
   3411     if (m_valueList->current()) {
   3412         if (!isForwardSlashOperator(m_valueList->current()))
   3413             return false;
   3414 
   3415         if (!m_valueList->next())
   3416             return false;
   3417 
   3418         endValue = parseGridPosition();
   3419         if (!endValue || m_valueList->current())
   3420             return false;
   3421     } else {
   3422         endValue = gridMissingGridPositionValue(startValue.get());
   3423     }
   3424 
   3425     addProperty(shorthand.properties()[0], startValue, important);
   3426     addProperty(shorthand.properties()[1], endValue, important);
   3427     return true;
   3428 }
   3429 
   3430 bool CSSPropertyParser::parseGridTemplateRowsAndAreas(PassRefPtrWillBeRawPtr<CSSValue> templateColumns, bool important)
   3431 {
   3432     NamedGridAreaMap gridAreaMap;
   3433     size_t rowCount = 0;
   3434     size_t columnCount = 0;
   3435     bool trailingIdentWasAdded = false;
   3436     RefPtrWillBeRawPtr<CSSValueList> templateRows = CSSValueList::createSpaceSeparated();
   3437 
   3438     // At least template-areas strings must be defined.
   3439     if (!m_valueList->current())
   3440         return false;
   3441 
   3442     while (m_valueList->current()) {
   3443         // Handle leading <custom-ident>*.
   3444         if (m_valueList->current()->unit == CSSParserValue::ValueList) {
   3445             if (trailingIdentWasAdded) {
   3446                 // A row's trailing ident must be concatenated with the next row's leading one.
   3447                 parseGridLineNames(*m_valueList, *templateRows, static_cast<CSSGridLineNamesValue*>(templateRows->item(templateRows->length() - 1)));
   3448             } else {
   3449                 parseGridLineNames(*m_valueList, *templateRows);
   3450             }
   3451         }
   3452 
   3453         // Handle a template-area's row.
   3454         if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
   3455             return false;
   3456         ++rowCount;
   3457 
   3458         // Handle template-rows's track-size.
   3459         if (m_valueList->current() && m_valueList->current()->unit != CSSParserValue::ValueList && m_valueList->current()->unit != CSSPrimitiveValue::CSS_STRING) {
   3460             RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
   3461             if (!value)
   3462                 return false;
   3463             templateRows->append(value);
   3464         } else {
   3465             templateRows->append(cssValuePool().createIdentifierValue(CSSValueAuto));
   3466         }
   3467 
   3468         // This will handle the trailing/leading <custom-ident>* in the grammar.
   3469         trailingIdentWasAdded = false;
   3470         if (m_valueList->current() && m_valueList->current()->unit == CSSParserValue::ValueList) {
   3471             parseGridLineNames(*m_valueList, *templateRows);
   3472             trailingIdentWasAdded = true;
   3473         }
   3474     }
   3475 
   3476     // [<track-list> /]?
   3477     if (templateColumns)
   3478         addProperty(CSSPropertyGridTemplateColumns, templateColumns, important);
   3479     else
   3480         addProperty(CSSPropertyGridTemplateColumns,  cssValuePool().createIdentifierValue(CSSValueNone), important);
   3481 
   3482     // [<line-names>? <string> [<track-size> <line-names>]? ]+
   3483     RefPtrWillBeRawPtr<CSSValue> templateAreas = CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
   3484     addProperty(CSSPropertyGridTemplateAreas, templateAreas.release(), important);
   3485     addProperty(CSSPropertyGridTemplateRows, templateRows.release(), important);
   3486 
   3487 
   3488     return true;
   3489 }
   3490 
   3491 
   3492 bool CSSPropertyParser::parseGridTemplateShorthand(bool important)
   3493 {
   3494     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   3495 
   3496     ShorthandScope scope(this, CSSPropertyGridTemplate);
   3497     ASSERT(gridTemplateShorthand().length() == 3);
   3498 
   3499     // At least "none" must be defined.
   3500     if (!m_valueList->current())
   3501         return false;
   3502 
   3503     bool firstValueIsNone = m_valueList->current()->id == CSSValueNone;
   3504 
   3505     // 1- 'none' case.
   3506     if (firstValueIsNone && !m_valueList->next()) {
   3507         addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentifierValue(CSSValueNone), important);
   3508         addProperty(CSSPropertyGridTemplateRows, cssValuePool().createIdentifierValue(CSSValueNone), important);
   3509         addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
   3510         return true;
   3511     }
   3512 
   3513     unsigned index = 0;
   3514     RefPtrWillBeRawPtr<CSSValue> columnsValue = nullptr;
   3515     if (firstValueIsNone) {
   3516         columnsValue = cssValuePool().createIdentifierValue(CSSValueNone);
   3517     } else {
   3518         columnsValue = parseGridTrackList(important);
   3519     }
   3520 
   3521     // 2- <grid-template-columns> / <grid-template-columns> syntax.
   3522     if (columnsValue) {
   3523         if (!(m_valueList->current() && isForwardSlashOperator(m_valueList->current()) && m_valueList->next()))
   3524             return false;
   3525         index = m_valueList->currentIndex();
   3526         if (RefPtrWillBeRawPtr<CSSValue> rowsValue = parseGridTrackList(important)) {
   3527             if (m_valueList->current())
   3528                 return false;
   3529             addProperty(CSSPropertyGridTemplateColumns, columnsValue, important);
   3530             addProperty(CSSPropertyGridTemplateRows, rowsValue, important);
   3531             addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifierValue(CSSValueNone), important);
   3532             return true;
   3533         }
   3534     }
   3535 
   3536 
   3537     // 3- [<track-list> /]? [<line-names>? <string> [<track-size> <line-names>]? ]+ syntax.
   3538     // The template-columns <track-list> can't be 'none'.
   3539     if (firstValueIsNone)
   3540         return false;
   3541     // It requires to rewind parsing due to previous syntax failures.
   3542     m_valueList->setCurrentIndex(index);
   3543     return parseGridTemplateRowsAndAreas(columnsValue, important);
   3544 }
   3545 
   3546 bool CSSPropertyParser::parseGridShorthand(bool important)
   3547 {
   3548     ShorthandScope scope(this, CSSPropertyGrid);
   3549     ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 4);
   3550 
   3551     // 1- <grid-template>
   3552     if (parseGridTemplateShorthand(important)) {
   3553         // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
   3554         // The sub-properties not specified are set to their initial value, as normal for shorthands.
   3555         addProperty(CSSPropertyGridAutoFlow, cssValuePool().createImplicitInitialValue(), important);
   3556         addProperty(CSSPropertyGridAutoColumns, cssValuePool().createImplicitInitialValue(), important);
   3557         addProperty(CSSPropertyGridAutoRows, cssValuePool().createImplicitInitialValue(), important);
   3558         return true;
   3559     }
   3560 
   3561     // Need to rewind parsing to explore the alternative syntax of this shorthand.
   3562     m_valueList->setCurrentIndex(0);
   3563 
   3564     // 2- <grid-auto-flow> [ <grid-auto-columns> [ / <grid-auto-rows> ]? ]
   3565     CSSValueID id = m_valueList->current()->id;
   3566     if (id != CSSValueRow && id != CSSValueColumn && id != CSSValueNone)
   3567         return false;
   3568 
   3569     RefPtrWillBeRawPtr<CSSValue> autoFlowValue = cssValuePool().createIdentifierValue(id);
   3570     RefPtrWillBeRawPtr<CSSValue> autoColumnsValue = nullptr;
   3571     RefPtrWillBeRawPtr<CSSValue> autoRowsValue = nullptr;
   3572 
   3573     if (m_valueList->next()) {
   3574         autoColumnsValue = parseGridTrackSize(*m_valueList);
   3575         if (!autoColumnsValue)
   3576             return false;
   3577         if (m_valueList->current()) {
   3578             if (!isForwardSlashOperator(m_valueList->current()) || !m_valueList->next())
   3579                 return false;
   3580             autoRowsValue = parseGridTrackSize(*m_valueList);
   3581             if (!autoRowsValue)
   3582                 return false;
   3583         }
   3584         if (m_valueList->current())
   3585             return false;
   3586     } else {
   3587         // Other omitted values are set to their initial values.
   3588         autoColumnsValue = cssValuePool().createImplicitInitialValue();
   3589         autoRowsValue = cssValuePool().createImplicitInitialValue();
   3590     }
   3591 
   3592     // if <grid-auto-rows> value is omitted, it is set to the value specified for grid-auto-columns.
   3593     if (!autoRowsValue)
   3594         autoRowsValue = autoColumnsValue;
   3595 
   3596     addProperty(CSSPropertyGridAutoFlow, autoFlowValue, important);
   3597     addProperty(CSSPropertyGridAutoColumns, autoColumnsValue, important);
   3598     addProperty(CSSPropertyGridAutoRows, autoRowsValue, important);
   3599 
   3600     // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
   3601     // The sub-properties not specified are set to their initial value, as normal for shorthands.
   3602     addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createImplicitInitialValue(), important);
   3603     addProperty(CSSPropertyGridTemplateRows, cssValuePool().createImplicitInitialValue(), important);
   3604     addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createImplicitInitialValue(), important);
   3605 
   3606     return true;
   3607 }
   3608 
   3609 bool CSSPropertyParser::parseGridAreaShorthand(bool important)
   3610 {
   3611     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   3612 
   3613     ShorthandScope scope(this, CSSPropertyGridArea);
   3614     const StylePropertyShorthand& shorthand = gridAreaShorthand();
   3615     ASSERT_UNUSED(shorthand, shorthand.length() == 4);
   3616 
   3617     RefPtrWillBeRawPtr<CSSValue> rowStartValue = parseGridPosition();
   3618     if (!rowStartValue)
   3619         return false;
   3620 
   3621     RefPtrWillBeRawPtr<CSSValue> columnStartValue = nullptr;
   3622     if (!parseSingleGridAreaLonghand(columnStartValue))
   3623         return false;
   3624 
   3625     RefPtrWillBeRawPtr<CSSValue> rowEndValue = nullptr;
   3626     if (!parseSingleGridAreaLonghand(rowEndValue))
   3627         return false;
   3628 
   3629     RefPtrWillBeRawPtr<CSSValue> columnEndValue = nullptr;
   3630     if (!parseSingleGridAreaLonghand(columnEndValue))
   3631         return false;
   3632 
   3633     if (!columnStartValue)
   3634         columnStartValue = gridMissingGridPositionValue(rowStartValue.get());
   3635 
   3636     if (!rowEndValue)
   3637         rowEndValue = gridMissingGridPositionValue(rowStartValue.get());
   3638 
   3639     if (!columnEndValue)
   3640         columnEndValue = gridMissingGridPositionValue(columnStartValue.get());
   3641 
   3642     addProperty(CSSPropertyGridRowStart, rowStartValue, important);
   3643     addProperty(CSSPropertyGridColumnStart, columnStartValue, important);
   3644     addProperty(CSSPropertyGridRowEnd, rowEndValue, important);
   3645     addProperty(CSSPropertyGridColumnEnd, columnEndValue, important);
   3646     return true;
   3647 }
   3648 
   3649 bool CSSPropertyParser::parseSingleGridAreaLonghand(RefPtrWillBeRawPtr<CSSValue>& property)
   3650 {
   3651     if (!m_valueList->current())
   3652         return true;
   3653 
   3654     if (!isForwardSlashOperator(m_valueList->current()))
   3655         return false;
   3656 
   3657     if (!m_valueList->next())
   3658         return false;
   3659 
   3660     property = parseGridPosition();
   3661     return true;
   3662 }
   3663 
   3664 void CSSPropertyParser::parseGridLineNames(CSSParserValueList& inputList, CSSValueList& valueList, CSSGridLineNamesValue* previousNamedAreaTrailingLineNames)
   3665 {
   3666     ASSERT(inputList.current() && inputList.current()->unit == CSSParserValue::ValueList);
   3667 
   3668     CSSParserValueList* identList = inputList.current()->valueList;
   3669     if (!identList->size()) {
   3670         inputList.next();
   3671         return;
   3672     }
   3673 
   3674     // Need to ensure the identList is at the heading index, since the parserList might have been rewound.
   3675     identList->setCurrentIndex(0);
   3676 
   3677     RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = previousNamedAreaTrailingLineNames;
   3678     if (!lineNames)
   3679         lineNames = CSSGridLineNamesValue::create();
   3680     while (CSSParserValue* identValue = identList->current()) {
   3681         ASSERT(identValue->unit == CSSPrimitiveValue::CSS_IDENT);
   3682         RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveStringValue(identValue);
   3683         lineNames->append(lineName.release());
   3684         identList->next();
   3685     }
   3686     if (!previousNamedAreaTrailingLineNames)
   3687         valueList.append(lineNames.release());
   3688 
   3689     inputList.next();
   3690 }
   3691 
   3692 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackList(bool important)
   3693 {
   3694     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   3695 
   3696     CSSParserValue* value = m_valueList->current();
   3697     if (value->id == CSSValueNone) {
   3698         m_valueList->next();
   3699         return cssValuePool().createIdentifierValue(CSSValueNone);
   3700     }
   3701 
   3702     RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
   3703     // Handle leading  <ident>*.
   3704     value = m_valueList->current();
   3705     if (value && value->unit == CSSParserValue::ValueList)
   3706         parseGridLineNames(*m_valueList, *values);
   3707 
   3708     bool seenTrackSizeOrRepeatFunction = false;
   3709     while (CSSParserValue* currentValue = m_valueList->current()) {
   3710         if (isForwardSlashOperator(currentValue))
   3711             break;
   3712         if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) {
   3713             if (!parseGridTrackRepeatFunction(*values))
   3714                 return nullptr;
   3715             seenTrackSizeOrRepeatFunction = true;
   3716         } else {
   3717             RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList);
   3718             if (!value)
   3719                 return nullptr;
   3720             values->append(value);
   3721             seenTrackSizeOrRepeatFunction = true;
   3722         }
   3723         // This will handle the trailing <ident>* in the grammar.
   3724         value = m_valueList->current();
   3725         if (value && value->unit == CSSParserValue::ValueList)
   3726             parseGridLineNames(*m_valueList, *values);
   3727     }
   3728 
   3729     // We should have found a <track-size> or else it is not a valid <track-list>
   3730     if (!seenTrackSizeOrRepeatFunction)
   3731         return nullptr;
   3732 
   3733     return values;
   3734 }
   3735 
   3736 bool CSSPropertyParser::parseGridTrackRepeatFunction(CSSValueList& list)
   3737 {
   3738     CSSParserValueList* arguments = m_valueList->current()->function->args.get();
   3739     if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
   3740         return false;
   3741 
   3742     ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
   3743     size_t repetitions = arguments->valueAt(0)->fValue;
   3744     // Clamp repetitions at minRepetitions.
   3745     // http://www.w3.org/TR/css-grid-1/#repeat-notation
   3746     if (repetitions > minRepetitions)
   3747         repetitions = minRepetitions;
   3748     RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
   3749     arguments->next(); // Skip the repetition count.
   3750     arguments->next(); // Skip the comma.
   3751 
   3752     // Handle leading <ident>*.
   3753     CSSParserValue* currentValue = arguments->current();
   3754     if (currentValue && currentValue->unit == CSSParserValue::ValueList)
   3755         parseGridLineNames(*arguments, *repeatedValues);
   3756 
   3757     while (arguments->current()) {
   3758         RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
   3759         if (!trackSize)
   3760             return false;
   3761 
   3762         repeatedValues->append(trackSize);
   3763 
   3764         // This takes care of any trailing <ident>* in the grammar.
   3765         currentValue = arguments->current();
   3766         if (currentValue && currentValue->unit == CSSParserValue::ValueList)
   3767             parseGridLineNames(*arguments, *repeatedValues);
   3768     }
   3769 
   3770     for (size_t i = 0; i < repetitions; ++i) {
   3771         for (size_t j = 0; j < repeatedValues->length(); ++j)
   3772             list.append(repeatedValues->itemWithoutBoundsCheck(j));
   3773     }
   3774 
   3775     // parseGridTrackSize iterated over the repeat arguments, move to the next value.
   3776     m_valueList->next();
   3777     return true;
   3778 }
   3779 
   3780 
   3781 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackSize(CSSParserValueList& inputList)
   3782 {
   3783     ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   3784 
   3785     CSSParserValue* currentValue = inputList.current();
   3786     inputList.next();
   3787 
   3788     if (currentValue->id == CSSValueAuto)
   3789         return cssValuePool().createIdentifierValue(CSSValueAuto);
   3790 
   3791     if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) {
   3792         // The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
   3793         CSSParserValueList* arguments = currentValue->function->args.get();
   3794         if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
   3795             return nullptr;
   3796 
   3797         RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth(arguments->valueAt(0));
   3798         if (!minTrackBreadth)
   3799             return nullptr;
   3800 
   3801         RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth(arguments->valueAt(2));
   3802         if (!maxTrackBreadth)
   3803             return nullptr;
   3804 
   3805         RefPtrWillBeRawPtr<CSSValueList> parsedArguments = CSSValueList::createCommaSeparated();
   3806         parsedArguments->append(minTrackBreadth);
   3807         parsedArguments->append(maxTrackBreadth);
   3808         return CSSFunctionValue::create("minmax(", parsedArguments);
   3809     }
   3810 
   3811     return parseGridBreadth(currentValue);
   3812 }
   3813 
   3814 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseGridBreadth(CSSParserValue* currentValue)
   3815 {
   3816     if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMaxContent)
   3817         return cssValuePool().createIdentifierValue(currentValue->id);
   3818 
   3819     if (currentValue->unit == CSSPrimitiveValue::CSS_FR) {
   3820         double flexValue = currentValue->fValue;
   3821 
   3822         // Fractional unit is a non-negative dimension.
   3823         if (flexValue <= 0)
   3824             return nullptr;
   3825 
   3826         return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR);
   3827     }
   3828 
   3829     if (!validUnit(currentValue, FNonNeg | FLength | FPercent))
   3830         return nullptr;
   3831 
   3832     return createPrimitiveNumericValue(currentValue);
   3833 }
   3834 
   3835 bool CSSPropertyParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
   3836 {
   3837     CSSParserValue* currentValue = m_valueList->current();
   3838     if (!currentValue || currentValue->unit != CSSPrimitiveValue::CSS_STRING)
   3839         return false;
   3840 
   3841     String gridRowNames = currentValue->string;
   3842     if (!gridRowNames.length())
   3843         return false;
   3844 
   3845     Vector<String> columnNames;
   3846     gridRowNames.split(' ', columnNames);
   3847 
   3848     if (!columnCount) {
   3849         columnCount = columnNames.size();
   3850         ASSERT(columnCount);
   3851     } else if (columnCount != columnNames.size()) {
   3852         // The declaration is invalid is all the rows don't have the number of columns.
   3853         return false;
   3854     }
   3855 
   3856     for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) {
   3857         const String& gridAreaName = columnNames[currentCol];
   3858 
   3859         // Unamed areas are always valid (we consider them to be 1x1).
   3860         if (gridAreaName == ".")
   3861             continue;
   3862 
   3863         // We handle several grid areas with the same name at once to simplify the validation code.
   3864         size_t lookAheadCol;
   3865         for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++lookAheadCol) {
   3866             if (columnNames[lookAheadCol + 1] != gridAreaName)
   3867                 break;
   3868         }
   3869 
   3870         NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
   3871         if (gridAreaIt == gridAreaMap.end()) {
   3872             gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(currentCol, lookAheadCol)));
   3873         } else {
   3874             GridCoordinate& gridCoordinate = gridAreaIt->value;
   3875 
   3876             // The following checks test that the grid area is a single filled-in rectangle.
   3877             // 1. The new row is adjacent to the previously parsed row.
   3878             if (rowCount != gridCoordinate.rows.resolvedFinalPosition.next().toInt())
   3879                 return false;
   3880 
   3881             // 2. The new area starts at the same position as the previously parsed area.
   3882             if (currentCol != gridCoordinate.columns.resolvedInitialPosition.toInt())
   3883                 return false;
   3884 
   3885             // 3. The new area ends at the same position as the previously parsed area.
   3886             if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition.toInt())
   3887                 return false;
   3888 
   3889             ++gridCoordinate.rows.resolvedFinalPosition;
   3890         }
   3891         currentCol = lookAheadCol;
   3892     }
   3893 
   3894     m_valueList->next();
   3895     return true;
   3896 }
   3897 
   3898 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateAreas()
   3899 {
   3900     NamedGridAreaMap gridAreaMap;
   3901     size_t rowCount = 0;
   3902     size_t columnCount = 0;
   3903 
   3904     while (m_valueList->current()) {
   3905         if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount))
   3906             return nullptr;
   3907         ++rowCount;
   3908     }
   3909 
   3910     if (!rowCount || !columnCount)
   3911         return nullptr;
   3912 
   3913     return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
   3914 }
   3915 
   3916 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounterContent(CSSParserValueList* args, bool counters)
   3917 {
   3918     unsigned numArgs = args->size();
   3919     if (counters && numArgs != 3 && numArgs != 5)
   3920         return nullptr;
   3921     if (!counters && numArgs != 1 && numArgs != 3)
   3922         return nullptr;
   3923 
   3924     CSSParserValue* i = args->current();
   3925     if (i->unit != CSSPrimitiveValue::CSS_IDENT)
   3926         return nullptr;
   3927     RefPtrWillBeRawPtr<CSSPrimitiveValue> identifier = createPrimitiveStringValue(i);
   3928 
   3929     RefPtrWillBeRawPtr<CSSPrimitiveValue> separator = nullptr;
   3930     if (!counters)
   3931         separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING);
   3932     else {
   3933         i = args->next();
   3934         if (i->unit != CSSParserValue::Operator || i->iValue != ',')
   3935             return nullptr;
   3936 
   3937         i = args->next();
   3938         if (i->unit != CSSPrimitiveValue::CSS_STRING)
   3939             return nullptr;
   3940 
   3941         separator = createPrimitiveStringValue(i);
   3942     }
   3943 
   3944     RefPtrWillBeRawPtr<CSSPrimitiveValue> listStyle = nullptr;
   3945     i = args->next();
   3946     if (!i) // Make the list style default decimal
   3947         listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal);
   3948     else {
   3949         if (i->unit != CSSParserValue::Operator || i->iValue != ',')
   3950             return nullptr;
   3951 
   3952         i = args->next();
   3953         if (i->unit != CSSPrimitiveValue::CSS_IDENT)
   3954             return nullptr;
   3955 
   3956         CSSValueID listStyleID = CSSValueInvalid;
   3957         if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha))
   3958             listStyleID = i->id;
   3959         else
   3960             return nullptr;
   3961 
   3962         listStyle = cssValuePool().createIdentifierValue(listStyleID);
   3963     }
   3964 
   3965     return cssValuePool().createValue(Counter::create(identifier.release(), listStyle.release(), separator.release()));
   3966 }
   3967 
   3968 bool CSSPropertyParser::parseClipShape(CSSPropertyID propId, bool important)
   3969 {
   3970     CSSParserValue* value = m_valueList->current();
   3971     CSSParserValueList* args = value->function->args.get();
   3972 
   3973     if (!equalIgnoringCase(value->function->name, "rect(") || !args)
   3974         return false;
   3975 
   3976     // rect(t, r, b, l) || rect(t r b l)
   3977     if (args->size() != 4 && args->size() != 7)
   3978         return false;
   3979     RefPtrWillBeRawPtr<Rect> rect = Rect::create();
   3980     bool valid = true;
   3981     int i = 0;
   3982     CSSParserValue* a = args->current();
   3983     while (a) {
   3984         valid = a->id == CSSValueAuto || validUnit(a, FLength);
   3985         if (!valid)
   3986             break;
   3987         RefPtrWillBeRawPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
   3988             cssValuePool().createIdentifierValue(CSSValueAuto) :
   3989             createPrimitiveNumericValue(a);
   3990         if (i == 0)
   3991             rect->setTop(length);
   3992         else if (i == 1)
   3993             rect->setRight(length);
   3994         else if (i == 2)
   3995             rect->setBottom(length);
   3996         else
   3997             rect->setLeft(length);
   3998         a = args->next();
   3999         if (a && args->size() == 7) {
   4000             if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
   4001                 a = args->next();
   4002             } else {
   4003                 valid = false;
   4004                 break;
   4005             }
   4006         }
   4007         i++;
   4008     }
   4009     if (valid) {
   4010         addProperty(propId, cssValuePool().createValue(rect.release()), important);
   4011         m_valueList->next();
   4012         return true;
   4013     }
   4014     return false;
   4015 }
   4016 
   4017 static void completeBorderRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[4])
   4018 {
   4019     if (radii[3])
   4020         return;
   4021     if (!radii[2]) {
   4022         if (!radii[1])
   4023             radii[1] = radii[0];
   4024         radii[2] = radii[0];
   4025     }
   4026     radii[3] = radii[1];
   4027 }
   4028 
   4029 // FIXME: This should be refactored with CSSParser::parseBorderRadius.
   4030 // CSSParser::parseBorderRadius contains support for some legacy radius construction.
   4031 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseInsetRoundedCorners(PassRefPtrWillBeRawPtr<CSSBasicShapeInset> shape, CSSParserValueList* args)
   4032 {
   4033     CSSParserValue* argument = args->next();
   4034 
   4035     if (!argument)
   4036         return nullptr;
   4037 
   4038     Vector<CSSParserValue*> radiusArguments;
   4039     while (argument) {
   4040         radiusArguments.append(argument);
   4041         argument = args->next();
   4042     }
   4043 
   4044     unsigned num = radiusArguments.size();
   4045     if (!num || num > 9)
   4046         return nullptr;
   4047 
   4048     // FIXME: Refactor completeBorderRadii and the array
   4049     RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
   4050 #if ENABLE(OILPAN)
   4051     // Zero initialize the array of raw pointers.
   4052     memset(&radii, 0, sizeof(radii));
   4053 #endif
   4054 
   4055     unsigned indexAfterSlash = 0;
   4056     for (unsigned i = 0; i < num; ++i) {
   4057         CSSParserValue* value = radiusArguments.at(i);
   4058         if (value->unit == CSSParserValue::Operator) {
   4059             if (value->iValue != '/')
   4060                 return nullptr;
   4061 
   4062             if (!i || indexAfterSlash || i + 1 == num)
   4063                 return nullptr;
   4064 
   4065             indexAfterSlash = i + 1;
   4066             completeBorderRadii(radii[0]);
   4067             continue;
   4068         }
   4069 
   4070         if (i - indexAfterSlash >= 4)
   4071             return nullptr;
   4072 
   4073         if (!validUnit(value, FLength | FPercent | FNonNeg))
   4074             return nullptr;
   4075 
   4076         RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
   4077 
   4078         if (!indexAfterSlash)
   4079             radii[0][i] = radius;
   4080         else
   4081             radii[1][i - indexAfterSlash] = radius.release();
   4082     }
   4083 
   4084     if (!indexAfterSlash) {
   4085         completeBorderRadii(radii[0]);
   4086         for (unsigned i = 0; i < 4; ++i)
   4087             radii[1][i] = radii[0][i];
   4088     } else {
   4089         completeBorderRadii(radii[1]);
   4090     }
   4091     shape->setTopLeftRadius(createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()));
   4092     shape->setTopRightRadius(createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()));
   4093     shape->setBottomRightRadius(createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()));
   4094     shape->setBottomLeftRadius(createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()));
   4095 
   4096     return shape;
   4097 }
   4098 
   4099 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeInset(CSSParserValueList* args)
   4100 {
   4101     ASSERT(args);
   4102 
   4103     RefPtrWillBeRawPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
   4104 
   4105     CSSParserValue* argument = args->current();
   4106     WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue> > widthArguments;
   4107     bool hasRoundedInset = false;
   4108 
   4109     while (argument) {
   4110         if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(argument->string, "round")) {
   4111             hasRoundedInset = true;
   4112             break;
   4113         }
   4114 
   4115         Units unitFlags = FLength | FPercent;
   4116         if (!validUnit(argument, unitFlags) || widthArguments.size() > 4)
   4117             return nullptr;
   4118 
   4119         widthArguments.append(createPrimitiveNumericValue(argument));
   4120         argument = args->next();
   4121     }
   4122 
   4123     switch (widthArguments.size()) {
   4124     case 1: {
   4125         shape->updateShapeSize1Value(widthArguments[0].get());
   4126         break;
   4127     }
   4128     case 2: {
   4129         shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1].get());
   4130         break;
   4131         }
   4132     case 3: {
   4133         shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get());
   4134         break;
   4135     }
   4136     case 4: {
   4137         shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1].get(), widthArguments[2].get(), widthArguments[3].get());
   4138         break;
   4139     }
   4140     default:
   4141         return nullptr;
   4142     }
   4143 
   4144     if (hasRoundedInset)
   4145         return parseInsetRoundedCorners(shape, args);
   4146     return shape;
   4147 }
   4148 
   4149 static bool isItemPositionKeyword(CSSValueID id)
   4150 {
   4151     return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
   4152         || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
   4153         || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight;
   4154 }
   4155 
   4156 bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
   4157 {
   4158     // auto | baseline | stretch | [<item-position> && <overflow-position>? ]
   4159     // <item-position> = center | start | end | self-start | self-end | flex-start | flex-end | left | right;
   4160     // <overflow-position> = true | safe
   4161 
   4162     CSSParserValue* value = m_valueList->current();
   4163 
   4164     if (value->id == CSSValueAuto || value->id == CSSValueBaseline || value->id == CSSValueStretch) {
   4165         if (m_valueList->next())
   4166             return false;
   4167 
   4168         addProperty(propId, cssValuePool().createIdentifierValue(value->id), important);
   4169         return true;
   4170     }
   4171 
   4172     RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr;
   4173     RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = nullptr;
   4174     if (isItemPositionKeyword(value->id)) {
   4175         position = cssValuePool().createIdentifierValue(value->id);
   4176         value = m_valueList->next();
   4177         if (value) {
   4178             if (value->id == CSSValueTrue || value->id == CSSValueSafe)
   4179                 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
   4180             else
   4181                 return false;
   4182         }
   4183     } else if (value->id == CSSValueTrue || value->id == CSSValueSafe) {
   4184         overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
   4185         value = m_valueList->next();
   4186         if (value && isItemPositionKeyword(value->id))
   4187             position = cssValuePool().createIdentifierValue(value->id);
   4188         else
   4189             return false;
   4190     } else {
   4191         return false;
   4192     }
   4193 
   4194     if (m_valueList->next())
   4195         return false;
   4196 
   4197     ASSERT(position);
   4198     if (overflowAlignmentKeyword)
   4199         addProperty(propId, createPrimitiveValuePair(position, overflowAlignmentKeyword), important);
   4200     else
   4201         addProperty(propId, position.release(), important);
   4202 
   4203     return true;
   4204 }
   4205 
   4206 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseShapeRadius(CSSParserValue* value)
   4207 {
   4208     if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide)
   4209         return cssValuePool().createIdentifierValue(value->id);
   4210 
   4211     if (!validUnit(value, FLength | FPercent | FNonNeg))
   4212         return nullptr;
   4213 
   4214     return createPrimitiveNumericValue(value);
   4215 }
   4216 
   4217 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeCircle(CSSParserValueList* args)
   4218 {
   4219     ASSERT(args);
   4220 
   4221     // circle(radius)
   4222     // circle(radius at <position>)
   4223     // circle(at <position>)
   4224     // where position defines centerX and centerY using a CSS <position> data type.
   4225     RefPtrWillBeRawPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
   4226 
   4227     for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
   4228         // The call to parseFillPosition below should consume all of the
   4229         // arguments except the first two. Thus, and index greater than one
   4230         // indicates an invalid production.
   4231         if (args->currentIndex() > 1)
   4232             return nullptr;
   4233 
   4234         if (!args->currentIndex() && argument->id != CSSValueAt) {
   4235             if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
   4236                 shape->setRadius(radius);
   4237                 continue;
   4238             }
   4239 
   4240             return nullptr;
   4241         }
   4242 
   4243         if (argument->id == CSSValueAt && args->next()) {
   4244             RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
   4245             RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
   4246             parseFillPosition(args, centerX, centerY);
   4247             if (centerX && centerY && !args->current()) {
   4248                 ASSERT(centerX->isPrimitiveValue());
   4249                 ASSERT(centerY->isPrimitiveValue());
   4250                 shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
   4251                 shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
   4252             } else {
   4253                 return nullptr;
   4254             }
   4255         } else {
   4256             return nullptr;
   4257         }
   4258     }
   4259 
   4260     return shape;
   4261 }
   4262 
   4263 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeEllipse(CSSParserValueList* args)
   4264 {
   4265     ASSERT(args);
   4266 
   4267     // ellipse(radiusX)
   4268     // ellipse(radiusX at <position>)
   4269     // ellipse(radiusX radiusY)
   4270     // ellipse(radiusX radiusY at <position>)
   4271     // ellipse(at <position>)
   4272     // where position defines centerX and centerY using a CSS <position> data type.
   4273     RefPtrWillBeRawPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
   4274 
   4275     for (CSSParserValue* argument = args->current(); argument; argument = args->next()) {
   4276         // The call to parseFillPosition below should consume all of the
   4277         // arguments except the first three. Thus, an index greater than two
   4278         // indicates an invalid production.
   4279         if (args->currentIndex() > 2)
   4280             return nullptr;
   4281 
   4282         if (args->currentIndex() < 2 && argument->id != CSSValueAt) {
   4283             if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius(argument)) {
   4284                 if (!shape->radiusX())
   4285                     shape->setRadiusX(radius);
   4286                 else
   4287                     shape->setRadiusY(radius);
   4288                 continue;
   4289             }
   4290 
   4291             return nullptr;
   4292         }
   4293 
   4294         if (argument->id != CSSValueAt || !args->next()) // expecting ellipse(.. at <position>)
   4295             return nullptr;
   4296         RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
   4297         RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
   4298         parseFillPosition(args, centerX, centerY);
   4299         if (!centerX || !centerY || args->current())
   4300             return nullptr;
   4301 
   4302         ASSERT(centerX->isPrimitiveValue());
   4303         ASSERT(centerY->isPrimitiveValue());
   4304         shape->setCenterX(toCSSPrimitiveValue(centerX.get()));
   4305         shape->setCenterY(toCSSPrimitiveValue(centerY.get()));
   4306     }
   4307 
   4308     return shape;
   4309 }
   4310 
   4311 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapePolygon(CSSParserValueList* args)
   4312 {
   4313     ASSERT(args);
   4314 
   4315     unsigned size = args->size();
   4316     if (!size)
   4317         return nullptr;
   4318 
   4319     RefPtrWillBeRawPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
   4320 
   4321     CSSParserValue* argument = args->current();
   4322     if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) {
   4323         shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
   4324 
   4325         if (!isComma(args->next()))
   4326             return nullptr;
   4327 
   4328         argument = args->next();
   4329         size -= 2;
   4330     }
   4331 
   4332     // <length> <length>, ... <length> <length> -> each pair has 3 elements except the last one
   4333     if (!size || (size % 3) - 2)
   4334         return nullptr;
   4335 
   4336     CSSParserValue* argumentX = argument;
   4337     while (argumentX) {
   4338 
   4339         if (!validUnit(argumentX, FLength | FPercent))
   4340             return nullptr;
   4341         RefPtrWillBeRawPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericValue(argumentX);
   4342 
   4343         CSSParserValue* argumentY = args->next();
   4344         if (!argumentY || !validUnit(argumentY, FLength | FPercent))
   4345             return nullptr;
   4346 
   4347         RefPtrWillBeRawPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericValue(argumentY);
   4348 
   4349         shape->appendPoint(xLength.release(), yLength.release());
   4350 
   4351         CSSParserValue* commaOrNull = args->next();
   4352         if (!commaOrNull)
   4353             argumentX = 0;
   4354         else if (!isComma(commaOrNull))
   4355             return nullptr;
   4356         else
   4357             argumentX = args->next();
   4358     }
   4359 
   4360     return shape;
   4361 }
   4362 
   4363 static bool isBoxValue(CSSValueID valueId)
   4364 {
   4365     switch (valueId) {
   4366     case CSSValueContentBox:
   4367     case CSSValuePaddingBox:
   4368     case CSSValueBorderBox:
   4369     case CSSValueMarginBox:
   4370         return true;
   4371     default:
   4372         break;
   4373     }
   4374 
   4375     return false;
   4376 }
   4377 
   4378 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseShapeProperty(CSSPropertyID propId)
   4379 {
   4380     if (!RuntimeEnabledFeatures::cssShapesEnabled())
   4381         return nullptr;
   4382 
   4383     CSSParserValue* value = m_valueList->current();
   4384     CSSValueID valueId = value->id;
   4385 
   4386     if (valueId == CSSValueNone) {
   4387         RefPtrWillBeRawPtr<CSSPrimitiveValue> keywordValue = parseValidPrimitive(valueId, value);
   4388         m_valueList->next();
   4389         return keywordValue.release();
   4390     }
   4391 
   4392     RefPtrWillBeRawPtr<CSSValue> imageValue = nullptr;
   4393     if (valueId != CSSValueNone && parseFillImage(m_valueList.get(), imageValue)) {
   4394         m_valueList->next();
   4395         return imageValue.release();
   4396     }
   4397 
   4398     return parseBasicShapeAndOrBox();
   4399 }
   4400 
   4401 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBasicShapeAndOrBox()
   4402 {
   4403     CSSParserValue* value = m_valueList->current();
   4404 
   4405     bool shapeFound = false;
   4406     bool boxFound = false;
   4407     CSSValueID valueId;
   4408 
   4409     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   4410     for (unsigned i = 0; i < 2; ++i) {
   4411         if (!value)
   4412             break;
   4413         valueId = value->id;
   4414         if (value->unit == CSSParserValue::Function && !shapeFound) {
   4415             // parseBasicShape already asks for the next value list item.
   4416             RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = parseBasicShape();
   4417             if (!shapeValue)
   4418                 return nullptr;
   4419             list->append(shapeValue.release());
   4420             shapeFound = true;
   4421         } else if (isBoxValue(valueId) && !boxFound) {
   4422             list->append(parseValidPrimitive(valueId, value));
   4423             boxFound = true;
   4424             m_valueList->next();
   4425         } else {
   4426             return nullptr;
   4427         }
   4428 
   4429         value = m_valueList->current();
   4430     }
   4431 
   4432     if (m_valueList->current())
   4433         return nullptr;
   4434     return list.release();
   4435 }
   4436 
   4437 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseBasicShape()
   4438 {
   4439     CSSParserValue* value = m_valueList->current();
   4440     ASSERT(value->unit == CSSParserValue::Function);
   4441     CSSParserValueList* args = value->function->args.get();
   4442 
   4443     if (!args)
   4444         return nullptr;
   4445 
   4446     RefPtrWillBeRawPtr<CSSBasicShape> shape = nullptr;
   4447     if (equalIgnoringCase(value->function->name, "circle("))
   4448         shape = parseBasicShapeCircle(args);
   4449     else if (equalIgnoringCase(value->function->name, "ellipse("))
   4450         shape = parseBasicShapeEllipse(args);
   4451     else if (equalIgnoringCase(value->function->name, "polygon("))
   4452         shape = parseBasicShapePolygon(args);
   4453     else if (equalIgnoringCase(value->function->name, "inset("))
   4454         shape = parseBasicShapeInset(args);
   4455 
   4456     if (!shape)
   4457         return nullptr;
   4458 
   4459     m_valueList->next();
   4460 
   4461     return cssValuePool().createValue(shape.release());
   4462 }
   4463 
   4464 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
   4465 bool CSSPropertyParser::parseFont(bool important)
   4466 {
   4467     // Let's check if there is an inherit or initial somewhere in the shorthand.
   4468     for (unsigned i = 0; i < m_valueList->size(); ++i) {
   4469         if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial)
   4470             return false;
   4471     }
   4472 
   4473     ShorthandScope scope(this, CSSPropertyFont);
   4474     // Optional font-style, font-variant and font-weight.
   4475     bool fontStyleParsed = false;
   4476     bool fontVariantParsed = false;
   4477     bool fontWeightParsed = false;
   4478     CSSParserValue* value;
   4479     while ((value = m_valueList->current())) {
   4480         if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
   4481             addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
   4482             fontStyleParsed = true;
   4483         } else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
   4484             // Font variant in the shorthand is particular, it only accepts normal or small-caps.
   4485             addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(value->id), important);
   4486             fontVariantParsed = true;
   4487         } else if (!fontWeightParsed && parseFontWeight(important))
   4488             fontWeightParsed = true;
   4489         else
   4490             break;
   4491         m_valueList->next();
   4492     }
   4493 
   4494     if (!value)
   4495         return false;
   4496 
   4497     if (!fontStyleParsed)
   4498         addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
   4499     if (!fontVariantParsed)
   4500         addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
   4501     if (!fontWeightParsed)
   4502         addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
   4503 
   4504     // Now a font size _must_ come.
   4505     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
   4506     if (!parseFontSize(important))
   4507         return false;
   4508 
   4509     value = m_valueList->current();
   4510     if (!value)
   4511         return false;
   4512 
   4513     if (isForwardSlashOperator(value)) {
   4514         // The line-height property.
   4515         value = m_valueList->next();
   4516         if (!value)
   4517             return false;
   4518         if (!parseLineHeight(important))
   4519             return false;
   4520     } else
   4521         addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true);
   4522 
   4523     // Font family must come now.
   4524     RefPtrWillBeRawPtr<CSSValue> parsedFamilyValue = parseFontFamily();
   4525     if (!parsedFamilyValue)
   4526         return false;
   4527 
   4528     addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important);
   4529 
   4530     // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
   4531     // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
   4532     // but we don't seem to support them at the moment. They should also be added here once implemented.
   4533     if (m_valueList->current())
   4534         return false;
   4535 
   4536     return true;
   4537 }
   4538 
   4539 class FontFamilyValueBuilder {
   4540     DISALLOW_ALLOCATION();
   4541 public:
   4542     FontFamilyValueBuilder(CSSValueList* list)
   4543         : m_list(list)
   4544     {
   4545     }
   4546 
   4547     void add(const CSSParserString& string)
   4548     {
   4549         if (!m_builder.isEmpty())
   4550             m_builder.append(' ');
   4551 
   4552         if (string.is8Bit()) {
   4553             m_builder.append(string.characters8(), string.length());
   4554             return;
   4555         }
   4556 
   4557         m_builder.append(string.characters16(), string.length());
   4558     }
   4559 
   4560     void commit()
   4561     {
   4562         if (m_builder.isEmpty())
   4563             return;
   4564         m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString()));
   4565         m_builder.clear();
   4566     }
   4567 
   4568 private:
   4569     StringBuilder m_builder;
   4570     CSSValueList* m_list;
   4571 };
   4572 
   4573 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFamily()
   4574 {
   4575     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   4576     CSSParserValue* value = m_valueList->current();
   4577 
   4578     FontFamilyValueBuilder familyBuilder(list.get());
   4579     bool inFamily = false;
   4580 
   4581     while (value) {
   4582         CSSParserValue* nextValue = m_valueList->next();
   4583         bool nextValBreaksFont = !nextValue ||
   4584                                  (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
   4585         bool nextValIsFontName = nextValue &&
   4586             ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
   4587             (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
   4588 
   4589         if (isCSSWideKeyword(*value) && !inFamily) {
   4590             if (nextValBreaksFont)
   4591                 value = m_valueList->next();
   4592             else if (nextValIsFontName)
   4593                 value = nextValue;
   4594             continue;
   4595         }
   4596 
   4597         if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
   4598             if (inFamily)
   4599                 familyBuilder.add(value->string);
   4600             else if (nextValBreaksFont || !nextValIsFontName)
   4601                 list->append(cssValuePool().createIdentifierValue(value->id));
   4602             else {
   4603                 familyBuilder.commit();
   4604                 familyBuilder.add(value->string);
   4605                 inFamily = true;
   4606             }
   4607         } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
   4608             // Strings never share in a family name.
   4609             inFamily = false;
   4610             familyBuilder.commit();
   4611             list->append(cssValuePool().createFontFamilyValue(value->string));
   4612         } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
   4613             if (inFamily)
   4614                 familyBuilder.add(value->string);
   4615             else if (nextValBreaksFont || !nextValIsFontName)
   4616                 list->append(cssValuePool().createFontFamilyValue(value->string));
   4617             else {
   4618                 familyBuilder.commit();
   4619                 familyBuilder.add(value->string);
   4620                 inFamily = true;
   4621             }
   4622         } else {
   4623             break;
   4624         }
   4625 
   4626         if (!nextValue)
   4627             break;
   4628 
   4629         if (nextValBreaksFont) {
   4630             value = m_valueList->next();
   4631             familyBuilder.commit();
   4632             inFamily = false;
   4633         }
   4634         else if (nextValIsFontName)
   4635             value = nextValue;
   4636         else
   4637             break;
   4638     }
   4639     familyBuilder.commit();
   4640 
   4641     if (!list->length())
   4642         list = nullptr;
   4643     return list.release();
   4644 }
   4645 
   4646 bool CSSPropertyParser::parseLineHeight(bool important)
   4647 {
   4648     CSSParserValue* value = m_valueList->current();
   4649     CSSValueID id = value->id;
   4650     bool validPrimitive = false;
   4651     // normal | <number> | <length> | <percentage> | inherit
   4652     if (id == CSSValueNormal)
   4653         validPrimitive = true;
   4654     else
   4655         validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg));
   4656     if (validPrimitive && (!m_valueList->next() || inShorthand()))
   4657         addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important);
   4658     return validPrimitive;
   4659 }
   4660 
   4661 bool CSSPropertyParser::parseFontSize(bool important)
   4662 {
   4663     CSSParserValue* value = m_valueList->current();
   4664     CSSValueID id = value->id;
   4665     bool validPrimitive = false;
   4666     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
   4667     if (id >= CSSValueXxSmall && id <= CSSValueLarger)
   4668         validPrimitive = true;
   4669     else
   4670         validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
   4671     if (validPrimitive && (!m_valueList->next() || inShorthand()))
   4672         addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important);
   4673     return validPrimitive;
   4674 }
   4675 
   4676 bool CSSPropertyParser::parseFontVariant(bool important)
   4677 {
   4678     RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
   4679     if (m_valueList->size() > 1)
   4680         values = CSSValueList::createCommaSeparated();
   4681     CSSParserValue* val;
   4682     bool expectComma = false;
   4683     while ((val = m_valueList->current())) {
   4684         RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = nullptr;
   4685         if (!expectComma) {
   4686             expectComma = true;
   4687             if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
   4688                 parsedValue = cssValuePool().createIdentifierValue(val->id);
   4689             else if (val->id == CSSValueAll && !values) {
   4690                 // FIXME: CSSPropertyParser::parseFontVariant() implements
   4691                 // the old css3 draft:
   4692                 // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#font-variant
   4693                 // 'all' is only allowed in @font-face and with no other values. Make a value list to
   4694                 // indicate that we are in the @font-face case.
   4695                 values = CSSValueList::createCommaSeparated();
   4696                 parsedValue = cssValuePool().createIdentifierValue(val->id);
   4697             }
   4698         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
   4699             expectComma = false;
   4700             m_valueList->next();
   4701             continue;
   4702         }
   4703 
   4704         if (!parsedValue)
   4705             return false;
   4706 
   4707         m_valueList->next();
   4708 
   4709         if (values)
   4710             values->append(parsedValue.release());
   4711         else {
   4712             addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
   4713             return true;
   4714         }
   4715     }
   4716 
   4717     if (values && values->length()) {
   4718         if (m_ruleType != CSSRuleSourceData::FONT_FACE_RULE)
   4719             return false;
   4720         addProperty(CSSPropertyFontVariant, values.release(), important);
   4721         return true;
   4722     }
   4723 
   4724     return false;
   4725 }
   4726 
   4727 bool CSSPropertyParser::parseFontWeight(bool important)
   4728 {
   4729     CSSParserValue* value = m_valueList->current();
   4730     if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) {
   4731         addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important);
   4732         return true;
   4733     }
   4734     if (value->unit == CSSPrimitiveValue::CSS_NUMBER) {
   4735         int weight = static_cast<int>(value->fValue);
   4736         if (!(weight % 100) && weight >= 100 && weight <= 900) {
   4737             addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important);
   4738             return true;
   4739         }
   4740     }
   4741     return false;
   4742 }
   4743 
   4744 bool CSSPropertyParser::parseFontFaceSrcURI(CSSValueList* valueList)
   4745 {
   4746     RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string)));
   4747     uriValue->setReferrer(m_context.referrer());
   4748 
   4749     CSSParserValue* value = m_valueList->next();
   4750     if (!value) {
   4751         valueList->append(uriValue.release());
   4752         return true;
   4753     }
   4754     if (value->unit == CSSParserValue::Operator && value->iValue == ',') {
   4755         m_valueList->next();
   4756         valueList->append(uriValue.release());
   4757         return true;
   4758     }
   4759 
   4760     if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format("))
   4761         return false;
   4762 
   4763     // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
   4764     // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
   4765     CSSParserValueList* args = value->function->args.get();
   4766     if (!args || args->size() != 1 || (args->current()->unit != CSSPrimitiveValue::CSS_STRING && args->current()->unit != CSSPrimitiveValue::CSS_IDENT))
   4767         return false;
   4768     uriValue->setFormat(args->current()->string);
   4769     valueList->append(uriValue.release());
   4770     value = m_valueList->next();
   4771     if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
   4772         m_valueList->next();
   4773     return true;
   4774 }
   4775 
   4776 bool CSSPropertyParser::parseFontFaceSrcLocal(CSSValueList* valueList)
   4777 {
   4778     CSSParserValueList* args = m_valueList->current()->function->args.get();
   4779     if (!args || !args->size())
   4780         return false;
   4781 
   4782     if (args->size() == 1 && args->current()->unit == CSSPrimitiveValue::CSS_STRING)
   4783         valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->string));
   4784     else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) {
   4785         StringBuilder builder;
   4786         for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) {
   4787             if (localValue->unit != CSSPrimitiveValue::CSS_IDENT)
   4788                 return false;
   4789             if (!builder.isEmpty())
   4790                 builder.append(' ');
   4791             builder.append(localValue->string);
   4792         }
   4793         valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString()));
   4794     } else
   4795         return false;
   4796 
   4797     if (CSSParserValue* value = m_valueList->next()) {
   4798         if (value->unit == CSSParserValue::Operator && value->iValue == ',')
   4799             m_valueList->next();
   4800     }
   4801     return true;
   4802 }
   4803 
   4804 bool CSSPropertyParser::parseFontFaceSrc()
   4805 {
   4806     RefPtrWillBeRawPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
   4807 
   4808     while (CSSParserValue* value = m_valueList->current()) {
   4809         if (value->unit == CSSPrimitiveValue::CSS_URI) {
   4810             if (!parseFontFaceSrcURI(values.get()))
   4811                 return false;
   4812         } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) {
   4813             if (!parseFontFaceSrcLocal(values.get()))
   4814                 return false;
   4815         } else
   4816             return false;
   4817     }
   4818     if (!values->length())
   4819         return false;
   4820 
   4821     addProperty(CSSPropertySrc, values.release(), m_important);
   4822     m_valueList->next();
   4823     return true;
   4824 }
   4825 
   4826 bool CSSPropertyParser::parseFontFaceUnicodeRange()
   4827 {
   4828     RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   4829     bool failed = false;
   4830     bool operatorExpected = false;
   4831     for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
   4832         if (operatorExpected) {
   4833             if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
   4834                 continue;
   4835             failed = true;
   4836             break;
   4837         }
   4838         if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
   4839             failed = true;
   4840             break;
   4841         }
   4842 
   4843         String rangeString = m_valueList->current()->string;
   4844         UChar32 from = 0;
   4845         UChar32 to = 0;
   4846         unsigned length = rangeString.length();
   4847 
   4848         if (length < 3) {
   4849             failed = true;
   4850             break;
   4851         }
   4852 
   4853         unsigned i = 2;
   4854         while (i < length) {
   4855             UChar c = rangeString[i];
   4856             if (c == '-' || c == '?')
   4857                 break;
   4858             from *= 16;
   4859             if (c >= '0' && c <= '9')
   4860                 from += c - '0';
   4861             else if (c >= 'A' && c <= 'F')
   4862                 from += 10 + c - 'A';
   4863             else if (c >= 'a' && c <= 'f')
   4864                 from += 10 + c - 'a';
   4865             else {
   4866                 failed = true;
   4867                 break;
   4868             }
   4869             i++;
   4870         }
   4871         if (failed)
   4872             break;
   4873 
   4874         if (i == length)
   4875             to = from;
   4876         else if (rangeString[i] == '?') {
   4877             unsigned span = 1;
   4878             while (i < length && rangeString[i] == '?') {
   4879                 span *= 16;
   4880                 from *= 16;
   4881                 i++;
   4882             }
   4883             if (i < length)
   4884                 failed = true;
   4885             to = from + span - 1;
   4886         } else {
   4887             if (length < i + 2) {
   4888                 failed = true;
   4889                 break;
   4890             }
   4891             i++;
   4892             while (i < length) {
   4893                 UChar c = rangeString[i];
   4894                 to *= 16;
   4895                 if (c >= '0' && c <= '9')
   4896                     to += c - '0';
   4897                 else if (c >= 'A' && c <= 'F')
   4898                     to += 10 + c - 'A';
   4899                 else if (c >= 'a' && c <= 'f')
   4900                     to += 10 + c - 'a';
   4901                 else {
   4902                     failed = true;
   4903                     break;
   4904                 }
   4905                 i++;
   4906             }
   4907             if (failed)
   4908                 break;
   4909         }
   4910         if (from <= to)
   4911             values->append(CSSUnicodeRangeValue::create(from, to));
   4912     }
   4913     if (failed || !values->length())
   4914         return false;
   4915     addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
   4916     return true;
   4917 }
   4918 
   4919 // Returns the number of characters which form a valid double
   4920 // and are terminated by the given terminator character
   4921 template <typename CharacterType>
   4922 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
   4923 {
   4924     int length = end - string;
   4925     if (length < 1)
   4926         return 0;
   4927 
   4928     bool decimalMarkSeen = false;
   4929     int processedLength = 0;
   4930 
   4931     for (int i = 0; i < length; ++i) {
   4932         if (string[i] == terminator) {
   4933             processedLength = i;
   4934             break;
   4935         }
   4936         if (!isASCIIDigit(string[i])) {
   4937             if (!decimalMarkSeen && string[i] == '.')
   4938                 decimalMarkSeen = true;
   4939             else
   4940                 return 0;
   4941         }
   4942     }
   4943 
   4944     if (decimalMarkSeen && processedLength == 1)
   4945         return 0;
   4946 
   4947     return processedLength;
   4948 }
   4949 
   4950 // Returns the number of characters consumed for parsing a valid double
   4951 // terminated by the given terminator character
   4952 template <typename CharacterType>
   4953 static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
   4954 {
   4955     int length = checkForValidDouble(string, end, terminator);
   4956     if (!length)
   4957         return 0;
   4958 
   4959     int position = 0;
   4960     double localValue = 0;
   4961 
   4962     // The consumed characters here are guaranteed to be
   4963     // ASCII digits with or without a decimal mark
   4964     for (; position < length; ++position) {
   4965         if (string[position] == '.')
   4966             break;
   4967         localValue = localValue * 10 + string[position] - '0';
   4968     }
   4969 
   4970     if (++position == length) {
   4971         value = localValue;
   4972         return length;
   4973     }
   4974 
   4975     double fraction = 0;
   4976     double scale = 1;
   4977 
   4978     while (position < length && scale < MAX_SCALE) {
   4979         fraction = fraction * 10 + string[position++] - '0';
   4980         scale *= 10;
   4981     }
   4982 
   4983     value = localValue + fraction / scale;
   4984     return length;
   4985 }
   4986 
   4987 template <typename CharacterType>
   4988 static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitType& expect, int& value)
   4989 {
   4990     const CharacterType* current = string;
   4991     double localValue = 0;
   4992     bool negative = false;
   4993     while (current != end && isHTMLSpace<CharacterType>(*current))
   4994         current++;
   4995     if (current != end && *current == '-') {
   4996         negative = true;
   4997         current++;
   4998     }
   4999     if (current == end || !isASCIIDigit(*current))
   5000         return false;
   5001     while (current != end && isASCIIDigit(*current)) {
   5002         double newValue = localValue * 10 + *current++ - '0';
   5003         if (newValue >= 255) {
   5004             // Clamp values at 255.
   5005             localValue = 255;
   5006             while (current != end && isASCIIDigit(*current))
   5007                 ++current;
   5008             break;
   5009         }
   5010         localValue = newValue;
   5011     }
   5012 
   5013     if (current == end)
   5014         return false;
   5015 
   5016     if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
   5017         return false;
   5018 
   5019     if (*current == '.') {
   5020         // We already parsed the integral part, try to parse
   5021         // the fraction part of the percentage value.
   5022         double percentage = 0;
   5023         int numCharactersParsed = parseDouble(current, end, '%', percentage);
   5024         if (!numCharactersParsed)
   5025             return false;
   5026         current += numCharactersParsed;
   5027         if (*current != '%')
   5028             return false;
   5029         localValue += percentage;
   5030     }
   5031 
   5032     if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
   5033         return false;
   5034 
   5035     if (*current == '%') {
   5036         expect = CSSPrimitiveValue::CSS_PERCENTAGE;
   5037         localValue = localValue / 100.0 * 256.0;
   5038         // Clamp values at 255 for percentages over 100%
   5039         if (localValue > 255)
   5040             localValue = 255;
   5041         current++;
   5042     } else
   5043         expect = CSSPrimitiveValue::CSS_NUMBER;
   5044 
   5045     while (current != end && isHTMLSpace<CharacterType>(*current))
   5046         current++;
   5047     if (current == end || *current++ != terminator)
   5048         return false;
   5049     // Clamp negative values at zero.
   5050     value = negative ? 0 : static_cast<int>(localValue);
   5051     string = current;
   5052     return true;
   5053 }
   5054 
   5055 template <typename CharacterType>
   5056 static inline bool isTenthAlpha(const CharacterType* string, const int length)
   5057 {
   5058     // "0.X"
   5059     if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
   5060         return true;
   5061 
   5062     // ".X"
   5063     if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
   5064         return true;
   5065 
   5066     return false;
   5067 }
   5068 
   5069 template <typename CharacterType>
   5070 static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
   5071 {
   5072     while (string != end && isHTMLSpace<CharacterType>(*string))
   5073         string++;
   5074 
   5075     bool negative = false;
   5076 
   5077     if (string != end && *string == '-') {
   5078         negative = true;
   5079         string++;
   5080     }
   5081 
   5082     value = 0;
   5083 
   5084     int length = end - string;
   5085     if (length < 2)
   5086         return false;
   5087 
   5088     if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
   5089         return false;
   5090 
   5091     if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
   5092         if (checkForValidDouble(string, end, terminator)) {
   5093             value = negative ? 0 : 255;
   5094             string = end;
   5095             return true;
   5096         }
   5097         return false;
   5098     }
   5099 
   5100     if (length == 2 && string[0] != '.') {
   5101         value = !negative && string[0] == '1' ? 255 : 0;
   5102         string = end;
   5103         return true;
   5104     }
   5105 
   5106     if (isTenthAlpha(string, length - 1)) {
   5107         static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
   5108         value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
   5109         string = end;
   5110         return true;
   5111     }
   5112 
   5113     double alpha = 0;
   5114     if (!parseDouble(string, end, terminator, alpha))
   5115         return false;
   5116     value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
   5117     string = end;
   5118     return true;
   5119 }
   5120 
   5121 template <typename CharacterType>
   5122 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
   5123 {
   5124     if (length < 5)
   5125         return false;
   5126     return characters[4] == '('
   5127         && isASCIIAlphaCaselessEqual(characters[0], 'r')
   5128         && isASCIIAlphaCaselessEqual(characters[1], 'g')
   5129         && isASCIIAlphaCaselessEqual(characters[2], 'b')
   5130         && isASCIIAlphaCaselessEqual(characters[3], 'a');
   5131 }
   5132 
   5133 template <typename CharacterType>
   5134 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
   5135 {
   5136     if (length < 4)
   5137         return false;
   5138     return characters[3] == '('
   5139         && isASCIIAlphaCaselessEqual(characters[0], 'r')
   5140         && isASCIIAlphaCaselessEqual(characters[1], 'g')
   5141         && isASCIIAlphaCaselessEqual(characters[2], 'b');
   5142 }
   5143 
   5144 template <typename CharacterType>
   5145 static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict)
   5146 {
   5147     CSSPrimitiveValue::UnitType expect = CSSPrimitiveValue::CSS_UNKNOWN;
   5148 
   5149     if (length >= 4 && characters[0] == '#')
   5150         return Color::parseHexColor(characters + 1, length - 1, rgb);
   5151 
   5152     if (!strict && length >= 3) {
   5153         if (Color::parseHexColor(characters, length, rgb))
   5154             return true;
   5155     }
   5156 
   5157     // Try rgba() syntax.
   5158     if (mightBeRGBA(characters, length)) {
   5159         const CharacterType* current = characters + 5;
   5160         const CharacterType* end = characters + length;
   5161         int red;
   5162         int green;
   5163         int blue;
   5164         int alpha;
   5165 
   5166         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
   5167             return false;
   5168         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
   5169             return false;
   5170         if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
   5171             return false;
   5172         if (!parseAlphaValue(current, end, ')', alpha))
   5173             return false;
   5174         if (current != end)
   5175             return false;
   5176         rgb = makeRGBA(red, green, blue, alpha);
   5177         return true;
   5178     }
   5179 
   5180     // Try rgb() syntax.
   5181     if (mightBeRGB(characters, length)) {
   5182         const CharacterType* current = characters + 4;
   5183         const CharacterType* end = characters + length;
   5184         int red;
   5185         int green;
   5186         int blue;
   5187         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
   5188             return false;
   5189         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
   5190             return false;
   5191         if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
   5192             return false;
   5193         if (current != end)
   5194             return false;
   5195         rgb = makeRGB(red, green, blue);
   5196         return true;
   5197     }
   5198 
   5199     return false;
   5200 }
   5201 
   5202 template<typename StringType>
   5203 bool CSSPropertyParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict)
   5204 {
   5205     unsigned length = name.length();
   5206     bool parseResult;
   5207 
   5208     if (!length)
   5209         return false;
   5210 
   5211     if (name.is8Bit())
   5212         parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict);
   5213     else
   5214         parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict);
   5215 
   5216     if (parseResult)
   5217         return true;
   5218 
   5219     // Try named colors.
   5220     Color tc;
   5221     if (!tc.setNamedColor(name))
   5222         return false;
   5223     rgb = tc.rgb();
   5224     return true;
   5225 }
   5226 
   5227 template bool CSSPropertyParser::fastParseColor(RGBA32&, const String&, bool strict);
   5228 
   5229 bool CSSPropertyParser::isCalculation(CSSParserValue* value)
   5230 {
   5231     return (value->unit == CSSParserValue::Function)
   5232         && (equalIgnoringCase(value->function->name, "calc(")
   5233             || equalIgnoringCase(value->function->name, "-webkit-calc(")
   5234             || equalIgnoringCase(value->function->name, "-webkit-min(")
   5235             || equalIgnoringCase(value->function->name, "-webkit-max("));
   5236 }
   5237 
   5238 inline int CSSPropertyParser::colorIntFromValue(CSSParserValue* v)
   5239 {
   5240     bool isPercent;
   5241     double value;
   5242 
   5243     if (m_parsedCalculation) {
   5244         isPercent = m_parsedCalculation->category() == CalcPercent;
   5245         value = m_parsedCalculation->doubleValue();
   5246         m_parsedCalculation.release();
   5247     } else {
   5248         isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE;
   5249         value = v->fValue;
   5250     }
   5251 
   5252     if (value <= 0.0)
   5253         return 0;
   5254 
   5255     if (isPercent) {
   5256         if (value >= 100.0)
   5257             return 255;
   5258         return static_cast<int>(value * 256.0 / 100.0);
   5259     }
   5260 
   5261     if (value >= 255.0)
   5262         return 255;
   5263 
   5264     return static_cast<int>(value);
   5265 }
   5266 
   5267 bool CSSPropertyParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
   5268 {
   5269     CSSParserValueList* args = value->function->args.get();
   5270     CSSParserValue* v = args->current();
   5271     Units unitType = FUnknown;
   5272     // Get the first value and its type
   5273     if (validUnit(v, FInteger, HTMLStandardMode))
   5274         unitType = FInteger;
   5275     else if (validUnit(v, FPercent, HTMLStandardMode))
   5276         unitType = FPercent;
   5277     else
   5278         return false;
   5279 
   5280     colorArray[0] = colorIntFromValue(v);
   5281     for (int i = 1; i < 3; i++) {
   5282         v = args->next();
   5283         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   5284             return false;
   5285         v = args->next();
   5286         if (!validUnit(v, unitType, HTMLStandardMode))
   5287             return false;
   5288         colorArray[i] = colorIntFromValue(v);
   5289     }
   5290     if (parseAlpha) {
   5291         v = args->next();
   5292         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   5293             return false;
   5294         v = args->next();
   5295         if (!validUnit(v, FNumber, HTMLStandardMode))
   5296             return false;
   5297         // Convert the floating pointer number of alpha to an integer in the range [0, 256),
   5298         // with an equal distribution across all 256 values.
   5299         colorArray[3] = static_cast<int>(std::max(0.0, std::min(1.0, v->fValue)) * nextafter(256.0, 0.0));
   5300     }
   5301     return true;
   5302 }
   5303 
   5304 // The CSS3 specification defines the format of a HSL color as
   5305 // hsl(<number>, <percent>, <percent>)
   5306 // and with alpha, the format is
   5307 // hsla(<number>, <percent>, <percent>, <number>)
   5308 // The first value, HUE, is in an angle with a value between 0 and 360
   5309 bool CSSPropertyParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
   5310 {
   5311     CSSParserValueList* args = value->function->args.get();
   5312     CSSParserValue* v = args->current();
   5313     // Get the first value
   5314     if (!validUnit(v, FNumber, HTMLStandardMode))
   5315         return false;
   5316     // normalize the Hue value and change it to be between 0 and 1.0
   5317     colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
   5318     for (int i = 1; i < 3; i++) {
   5319         v = args->next();
   5320         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   5321             return false;
   5322         v = args->next();
   5323         if (!validUnit(v, FPercent, HTMLStandardMode))
   5324             return false;
   5325         double percentValue = m_parsedCalculation ? m_parsedCalculation.release()->doubleValue() : v->fValue;
   5326         colorArray[i] = std::max(0.0, std::min(100.0, percentValue)) / 100.0; // needs to be value between 0 and 1.0
   5327     }
   5328     if (parseAlpha) {
   5329         v = args->next();
   5330         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
   5331             return false;
   5332         v = args->next();
   5333         if (!validUnit(v, FNumber, HTMLStandardMode))
   5334             return false;
   5335         colorArray[3] = std::max(0.0, std::min(1.0, v->fValue));
   5336     }
   5337     return true;
   5338 }
   5339 
   5340 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseColor(CSSParserValue* value)
   5341 {
   5342     RGBA32 c = Color::transparent;
   5343     if (!parseColorFromValue(value ? value : m_valueList->current(), c))
   5344         return nullptr;
   5345     return cssValuePool().createColorValue(c);
   5346 }
   5347 
   5348 bool CSSPropertyParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
   5349 {
   5350     if (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_NUMBER
   5351         && value->fValue >= 0. && value->fValue < 1000000.) {
   5352         String str = String::format("%06d", static_cast<int>((value->fValue+.5)));
   5353         // FIXME: This should be strict parsing for SVG as well.
   5354         if (!fastParseColor(c, str, !inQuirksMode()))
   5355             return false;
   5356     } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
   5357                 value->unit == CSSPrimitiveValue::CSS_IDENT ||
   5358                 (inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
   5359         if (!fastParseColor(c, value->string, !inQuirksMode() && value->unit == CSSPrimitiveValue::CSS_IDENT))
   5360             return false;
   5361     } else if (value->unit == CSSParserValue::Function &&
   5362                 value->function->args != 0 &&
   5363                 value->function->args->size() == 5 /* rgb + two commas */ &&
   5364                 equalIgnoringCase(value->function->name, "rgb(")) {
   5365         int colorValues[3];
   5366         if (!parseColorParameters(value, colorValues, false))
   5367             return false;
   5368         c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
   5369     } else {
   5370         if (value->unit == CSSParserValue::Function &&
   5371                 value->function->args != 0 &&
   5372                 value->function->args->size() == 7 /* rgba + three commas */ &&
   5373                 equalIgnoringCase(value->function->name, "rgba(")) {
   5374             int colorValues[4];
   5375             if (!parseColorParameters(value, colorValues, true))
   5376                 return false;
   5377             c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
   5378         } else if (value->unit == CSSParserValue::Function &&
   5379                     value->function->args != 0 &&
   5380                     value->function->args->size() == 5 /* hsl + two commas */ &&
   5381                     equalIgnoringCase(value->function->name, "hsl(")) {
   5382             double colorValues[3];
   5383             if (!parseHSLParameters(value, colorValues, false))
   5384                 return false;
   5385             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
   5386         } else if (value->unit == CSSParserValue::Function &&
   5387                     value->function->args != 0 &&
   5388                     value->function->args->size() == 7 /* hsla + three commas */ &&
   5389                     equalIgnoringCase(value->function->name, "hsla(")) {
   5390             double colorValues[4];
   5391             if (!parseHSLParameters(value, colorValues, true))
   5392                 return false;
   5393             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
   5394         } else
   5395             return false;
   5396     }
   5397 
   5398     return true;
   5399 }
   5400 
   5401 // This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
   5402 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
   5403 class ShadowParseContext {
   5404     STACK_ALLOCATED();
   5405 public:
   5406     ShadowParseContext(CSSPropertyID prop, CSSPropertyParser* parser)
   5407         : property(prop)
   5408         , m_parser(parser)
   5409         , allowX(true)
   5410         , allowY(false)
   5411         , allowBlur(false)
   5412         , allowSpread(false)
   5413         , allowColor(true)
   5414         , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow)
   5415         , allowBreak(true)
   5416     {
   5417     }
   5418 
   5419     bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
   5420 
   5421     void commitValue()
   5422     {
   5423         // Handle the ,, case gracefully by doing nothing.
   5424         if (x || y || blur || spread || color || style) {
   5425             if (!values)
   5426                 values = CSSValueList::createCommaSeparated();
   5427 
   5428             // Construct the current shadow value and add it to the list.
   5429             values->append(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
   5430         }
   5431 
   5432         // Now reset for the next shadow value.
   5433         x = nullptr;
   5434         y = nullptr;
   5435         blur = nullptr;
   5436         spread = nullptr;
   5437         style = nullptr;
   5438         color = nullptr;
   5439 
   5440         allowX = true;
   5441         allowColor = true;
   5442         allowBreak = true;
   5443         allowY = false;
   5444         allowBlur = false;
   5445         allowSpread = false;
   5446         allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   5447     }
   5448 
   5449     void commitLength(CSSParserValue* v)
   5450     {
   5451         RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
   5452 
   5453         if (allowX) {
   5454             x = val.release();
   5455             allowX = false;
   5456             allowY = true;
   5457             allowColor = false;
   5458             allowStyle = false;
   5459             allowBreak = false;
   5460         } else if (allowY) {
   5461             y = val.release();
   5462             allowY = false;
   5463             allowBlur = true;
   5464             allowColor = true;
   5465             allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   5466             allowBreak = true;
   5467         } else if (allowBlur) {
   5468             blur = val.release();
   5469             allowBlur = false;
   5470             allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   5471         } else if (allowSpread) {
   5472             spread = val.release();
   5473             allowSpread = false;
   5474         }
   5475     }
   5476 
   5477     void commitColor(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val)
   5478     {
   5479         color = val;
   5480         allowColor = false;
   5481         if (allowX) {
   5482             allowStyle = false;
   5483             allowBreak = false;
   5484         } else {
   5485             allowBlur = false;
   5486             allowSpread = false;
   5487             allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow;
   5488         }
   5489     }
   5490 
   5491     void commitStyle(CSSParserValue* v)
   5492     {
   5493         style = cssValuePool().createIdentifierValue(v->id);
   5494         allowStyle = false;
   5495         if (allowX)
   5496             allowBreak = false;
   5497         else {
   5498             allowBlur = false;
   5499             allowSpread = false;
   5500             allowColor = false;
   5501         }
   5502     }
   5503 
   5504     CSSPropertyID property;
   5505     CSSPropertyParser* m_parser;
   5506 
   5507     RefPtrWillBeMember<CSSValueList> values;
   5508     RefPtrWillBeMember<CSSPrimitiveValue> x;
   5509     RefPtrWillBeMember<CSSPrimitiveValue> y;
   5510     RefPtrWillBeMember<CSSPrimitiveValue> blur;
   5511     RefPtrWillBeMember<CSSPrimitiveValue> spread;
   5512     RefPtrWillBeMember<CSSPrimitiveValue> style;
   5513     RefPtrWillBeMember<CSSPrimitiveValue> color;
   5514 
   5515     bool allowX;
   5516     bool allowY;
   5517     bool allowBlur;
   5518     bool allowSpread;
   5519     bool allowColor;
   5520     bool allowStyle; // inset or not.
   5521     bool allowBreak;
   5522 };
   5523 
   5524 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId)
   5525 {
   5526     ShadowParseContext context(propId, this);
   5527     CSSParserValue* val;
   5528     while ((val = valueList->current())) {
   5529         // Check for a comma break first.
   5530         if (val->unit == CSSParserValue::Operator) {
   5531             if (val->iValue != ',' || !context.allowBreak) {
   5532                 // Other operators aren't legal or we aren't done with the current shadow
   5533                 // value.  Treat as invalid.
   5534                 return nullptr;
   5535             }
   5536             // The value is good.  Commit it.
   5537             context.commitValue();
   5538         } else if (validUnit(val, FLength, HTMLStandardMode)) {
   5539             // We required a length and didn't get one. Invalid.
   5540             if (!context.allowLength())
   5541                 return nullptr;
   5542 
   5543             // Blur radius must be non-negative.
   5544             if (context.allowBlur && !validUnit(val, FLength | FNonNeg, HTMLStandardMode))
   5545                 return nullptr;
   5546 
   5547             // A length is allowed here.  Construct the value and add it.
   5548             context.commitLength(val);
   5549         } else if (val->id == CSSValueInset) {
   5550             if (!context.allowStyle)
   5551                 return nullptr;
   5552 
   5553             context.commitStyle(val);
   5554         } else {
   5555             // The only other type of value that's ok is a color value.
   5556             RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedColor = nullptr;
   5557             bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu
   5558                             || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode())
   5559                             || val->id == CSSValueCurrentcolor);
   5560             if (isColor) {
   5561                 if (!context.allowColor)
   5562                     return nullptr;
   5563                 parsedColor = cssValuePool().createIdentifierValue(val->id);
   5564             }
   5565 
   5566             if (!parsedColor)
   5567                 // It's not built-in. Try to parse it as a color.
   5568                 parsedColor = parseColor(val);
   5569 
   5570             if (!parsedColor || !context.allowColor)
   5571                 return nullptr; // This value is not a color or length and is invalid or
   5572                           // it is a color, but a color isn't allowed at this point.
   5573 
   5574             context.commitColor(parsedColor.release());
   5575         }
   5576 
   5577         valueList->next();
   5578     }
   5579 
   5580     if (context.allowBreak) {
   5581         context.commitValue();
   5582         if (context.values && context.values->length())
   5583             return context.values.release();
   5584     }
   5585 
   5586     return nullptr;
   5587 }
   5588 
   5589 bool CSSPropertyParser::parseReflect(CSSPropertyID propId, bool important)
   5590 {
   5591     // box-reflect: <direction> <offset> <mask>
   5592 
   5593     // Direction comes first.
   5594     CSSParserValue* val = m_valueList->current();
   5595     RefPtrWillBeRawPtr<CSSPrimitiveValue> direction = nullptr;
   5596     switch (val->id) {
   5597     case CSSValueAbove:
   5598     case CSSValueBelow:
   5599     case CSSValueLeft:
   5600     case CSSValueRight:
   5601         direction = cssValuePool().createIdentifierValue(val->id);
   5602         break;
   5603     default:
   5604         return false;
   5605     }
   5606 
   5607     // The offset comes next.
   5608     val = m_valueList->next();
   5609     RefPtrWillBeRawPtr<CSSPrimitiveValue> offset = nullptr;
   5610     if (!val)
   5611         offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
   5612     else {
   5613         if (!validUnit(val, FLength | FPercent))
   5614             return false;
   5615         offset = createPrimitiveNumericValue(val);
   5616     }
   5617 
   5618     // Now for the mask.
   5619     RefPtrWillBeRawPtr<CSSValue> mask = nullptr;
   5620     val = m_valueList->next();
   5621     if (val) {
   5622         mask = parseBorderImage(propId);
   5623         if (!mask)
   5624             return false;
   5625     }
   5626 
   5627     RefPtrWillBeRawPtr<CSSReflectValue> reflectValue = CSSReflectValue::create(direction.release(), offset.release(), mask.release());
   5628     addProperty(propId, reflectValue.release(), important);
   5629     m_valueList->next();
   5630     return true;
   5631 }
   5632 
   5633 bool CSSPropertyParser::parseFlex(CSSParserValueList* args, bool important)
   5634 {
   5635     if (!args || !args->size() || args->size() > 3)
   5636         return false;
   5637     static const double unsetValue = -1;
   5638     double flexGrow = unsetValue;
   5639     double flexShrink = unsetValue;
   5640     RefPtrWillBeRawPtr<CSSPrimitiveValue> flexBasis = nullptr;
   5641 
   5642     while (CSSParserValue* arg = args->current()) {
   5643         if (validUnit(arg, FNumber | FNonNeg)) {
   5644             if (flexGrow == unsetValue)
   5645                 flexGrow = arg->fValue;
   5646             else if (flexShrink == unsetValue)
   5647                 flexShrink = arg->fValue;
   5648             else if (!arg->fValue) {
   5649                 // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
   5650                 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
   5651             } else {
   5652                 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid.
   5653                 return false;
   5654             }
   5655         } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLength | FPercent | FNonNeg)))
   5656             flexBasis = parseValidPrimitive(arg->id, arg);
   5657         else {
   5658             // Not a valid arg for flex.
   5659             return false;
   5660         }
   5661         args->next();
   5662     }
   5663 
   5664     if (flexGrow == unsetValue)
   5665         flexGrow = 1;
   5666     if (flexShrink == unsetValue)
   5667         flexShrink = 1;
   5668     if (!flexBasis)
   5669         flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX);
   5670 
   5671     addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
   5672     addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
   5673     addProperty(CSSPropertyFlexBasis, flexBasis, important);
   5674     return true;
   5675 }
   5676 
   5677 bool CSSPropertyParser::parseObjectPosition(bool important)
   5678 {
   5679     RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
   5680     RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
   5681     parseFillPosition(m_valueList.get(), xValue, yValue);
   5682     if (!xValue || !yValue)
   5683         return false;
   5684     addProperty(
   5685         CSSPropertyObjectPosition,
   5686         createPrimitiveValuePair(toCSSPrimitiveValue(xValue.get()), toCSSPrimitiveValue(yValue.get()), Pair::KeepIdenticalValues),
   5687         important);
   5688     return true;
   5689 }
   5690 
   5691 class BorderImageParseContext {
   5692     STACK_ALLOCATED();
   5693 public:
   5694     BorderImageParseContext()
   5695     : m_canAdvance(false)
   5696     , m_allowCommit(true)
   5697     , m_allowImage(true)
   5698     , m_allowImageSlice(true)
   5699     , m_allowRepeat(true)
   5700     , m_allowForwardSlashOperator(false)
   5701     , m_requireWidth(false)
   5702     , m_requireOutset(false)
   5703     {}
   5704 
   5705     bool canAdvance() const { return m_canAdvance; }
   5706     void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
   5707 
   5708     bool allowCommit() const { return m_allowCommit; }
   5709     bool allowImage() const { return m_allowImage; }
   5710     bool allowImageSlice() const { return m_allowImageSlice; }
   5711     bool allowRepeat() const { return m_allowRepeat; }
   5712     bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; }
   5713 
   5714     bool requireWidth() const { return m_requireWidth; }
   5715     bool requireOutset() const { return m_requireOutset; }
   5716 
   5717     void commitImage(PassRefPtrWillBeRawPtr<CSSValue> image)
   5718     {
   5719         m_image = image;
   5720         m_canAdvance = true;
   5721         m_allowCommit = true;
   5722         m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
   5723         m_allowImageSlice = !m_imageSlice;
   5724         m_allowRepeat = !m_repeat;
   5725     }
   5726     void commitImageSlice(PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> slice)
   5727     {
   5728         m_imageSlice = slice;
   5729         m_canAdvance = true;
   5730         m_allowCommit = m_allowForwardSlashOperator = true;
   5731         m_allowImageSlice = m_requireWidth = m_requireOutset = false;
   5732         m_allowImage = !m_image;
   5733         m_allowRepeat = !m_repeat;
   5734     }
   5735     void commitForwardSlashOperator()
   5736     {
   5737         m_canAdvance = true;
   5738         m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false;
   5739         if (!m_borderSlice) {
   5740             m_requireWidth = true;
   5741             m_requireOutset = false;
   5742         } else {
   5743             m_requireOutset = true;
   5744             m_requireWidth = false;
   5745         }
   5746     }
   5747     void commitBorderWidth(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> slice)
   5748     {
   5749         m_borderSlice = slice;
   5750         m_canAdvance = true;
   5751         m_allowCommit = m_allowForwardSlashOperator = true;
   5752         m_allowImageSlice = m_requireWidth = m_requireOutset = false;
   5753         m_allowImage = !m_image;
   5754         m_allowRepeat = !m_repeat;
   5755     }
   5756     void commitBorderOutset(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> outset)
   5757     {
   5758         m_outset = outset;
   5759         m_canAdvance = true;
   5760         m_allowCommit = true;
   5761         m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
   5762         m_allowImage = !m_image;
   5763         m_allowRepeat = !m_repeat;
   5764     }
   5765     void commitRepeat(PassRefPtrWillBeRawPtr<CSSValue> repeat)
   5766     {
   5767         m_repeat = repeat;
   5768         m_canAdvance = true;
   5769         m_allowCommit = true;
   5770         m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false;
   5771         m_allowImageSlice = !m_imageSlice;
   5772         m_allowImage = !m_image;
   5773     }
   5774 
   5775     PassRefPtrWillBeRawPtr<CSSValue> commitCSSValue()
   5776     {
   5777         return createBorderImageValue(m_image, m_imageSlice.get(), m_borderSlice.get(), m_outset.get(), m_repeat.get());
   5778     }
   5779 
   5780     void commitMaskBoxImage(CSSPropertyParser* parser, bool important)
   5781     {
   5782         commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, parser, m_image, important);
   5783         commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, parser, m_imageSlice.get(), important);
   5784         commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, parser, m_borderSlice.get(), important);
   5785         commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, parser, m_outset.get(), important);
   5786         commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, parser, m_repeat.get(), important);
   5787     }
   5788 
   5789     void commitBorderImage(CSSPropertyParser* parser, bool important)
   5790     {
   5791         commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important);
   5792         commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice.get(), important);
   5793         commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice.get(), important);
   5794         commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset.get(), important);
   5795         commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important);
   5796     }
   5797 
   5798     void commitBorderImageProperty(CSSPropertyID propId, CSSPropertyParser* parser, PassRefPtrWillBeRawPtr<CSSValue> value, bool important)
   5799     {
   5800         if (value)
   5801             parser->addProperty(propId, value, important);
   5802         else
   5803             parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true);
   5804     }
   5805 
   5806     static bool buildFromParser(CSSPropertyParser&, CSSPropertyID, BorderImageParseContext&);
   5807 
   5808     bool m_canAdvance;
   5809 
   5810     bool m_allowCommit;
   5811     bool m_allowImage;
   5812     bool m_allowImageSlice;
   5813     bool m_allowRepeat;
   5814     bool m_allowForwardSlashOperator;
   5815 
   5816     bool m_requireWidth;
   5817     bool m_requireOutset;
   5818 
   5819     RefPtrWillBeMember<CSSValue> m_image;
   5820     RefPtrWillBeMember<CSSBorderImageSliceValue> m_imageSlice;
   5821     RefPtrWillBeMember<CSSPrimitiveValue> m_borderSlice;
   5822     RefPtrWillBeMember<CSSPrimitiveValue> m_outset;
   5823 
   5824     RefPtrWillBeMember<CSSValue> m_repeat;
   5825 };
   5826 
   5827 bool BorderImageParseContext::buildFromParser(CSSPropertyParser& parser, CSSPropertyID propId, BorderImageParseContext& context)
   5828 {
   5829     CSSPropertyParser::ShorthandScope scope(&parser, propId);
   5830     while (CSSParserValue* val = parser.m_valueList->current()) {
   5831         context.setCanAdvance(false);
   5832 
   5833         if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val))
   5834             context.commitForwardSlashOperator();
   5835 
   5836         if (!context.canAdvance() && context.allowImage()) {
   5837             if (val->unit == CSSPrimitiveValue::CSS_URI) {
   5838                 context.commitImage(parser.createCSSImageValueWithReferrer(val->string, parser.m_context.completeURL(val->string)));
   5839             } else if (isGeneratedImageValue(val)) {
   5840                 RefPtrWillBeRawPtr<CSSValue> value = nullptr;
   5841                 if (parser.parseGeneratedImage(parser.m_valueList.get(), value))
   5842                     context.commitImage(value.release());
   5843                 else
   5844                     return false;
   5845             } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set(")) {
   5846                 RefPtrWillBeRawPtr<CSSValue> value = parser.parseImageSet(parser.m_valueList.get());
   5847                 if (value)
   5848                     context.commitImage(value.release());
   5849                 else
   5850                     return false;
   5851             } else if (val->id == CSSValueNone)
   5852                 context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone));
   5853         }
   5854 
   5855         if (!context.canAdvance() && context.allowImageSlice()) {
   5856             RefPtrWillBeRawPtr<CSSBorderImageSliceValue> imageSlice = nullptr;
   5857             if (parser.parseBorderImageSlice(propId, imageSlice))
   5858                 context.commitImageSlice(imageSlice.release());
   5859         }
   5860 
   5861         if (!context.canAdvance() && context.allowRepeat()) {
   5862             RefPtrWillBeRawPtr<CSSValue> repeat = nullptr;
   5863             if (parser.parseBorderImageRepeat(repeat))
   5864                 context.commitRepeat(repeat.release());
   5865         }
   5866 
   5867         if (!context.canAdvance() && context.requireWidth()) {
   5868             RefPtrWillBeRawPtr<CSSPrimitiveValue> borderSlice = nullptr;
   5869             if (parser.parseBorderImageWidth(borderSlice))
   5870                 context.commitBorderWidth(borderSlice.release());
   5871         }
   5872 
   5873         if (!context.canAdvance() && context.requireOutset()) {
   5874             RefPtrWillBeRawPtr<CSSPrimitiveValue> borderOutset = nullptr;
   5875             if (parser.parseBorderImageOutset(borderOutset))
   5876                 context.commitBorderOutset(borderOutset.release());
   5877         }
   5878 
   5879         if (!context.canAdvance())
   5880             return false;
   5881 
   5882         parser.m_valueList->next();
   5883     }
   5884 
   5885     return context.allowCommit();
   5886 }
   5887 
   5888 bool CSSPropertyParser::parseBorderImageShorthand(CSSPropertyID propId, bool important)
   5889 {
   5890     BorderImageParseContext context;
   5891     if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
   5892         switch (propId) {
   5893         case CSSPropertyWebkitMaskBoxImage:
   5894             context.commitMaskBoxImage(this, important);
   5895             return true;
   5896         case CSSPropertyBorderImage:
   5897             context.commitBorderImage(this, important);
   5898             return true;
   5899         default:
   5900             ASSERT_NOT_REACHED();
   5901             return false;
   5902         }
   5903     }
   5904     return false;
   5905 }
   5906 
   5907 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBorderImage(CSSPropertyID propId)
   5908 {
   5909     BorderImageParseContext context;
   5910     if (BorderImageParseContext::buildFromParser(*this, propId, context)) {
   5911         return context.commitCSSValue();
   5912     }
   5913     return nullptr;
   5914 }
   5915 
   5916 static bool isBorderImageRepeatKeyword(int id)
   5917 {
   5918     return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
   5919 }
   5920 
   5921 bool CSSPropertyParser::parseBorderImageRepeat(RefPtrWillBeRawPtr<CSSValue>& result)
   5922 {
   5923     RefPtrWillBeRawPtr<CSSPrimitiveValue> firstValue = nullptr;
   5924     RefPtrWillBeRawPtr<CSSPrimitiveValue> secondValue = nullptr;
   5925     CSSParserValue* val = m_valueList->current();
   5926     if (!val)
   5927         return false;
   5928     if (isBorderImageRepeatKeyword(val->id))
   5929         firstValue = cssValuePool().createIdentifierValue(val->id);
   5930     else
   5931         return false;
   5932 
   5933     val = m_valueList->next();
   5934     if (val) {
   5935         if (isBorderImageRepeatKeyword(val->id))
   5936             secondValue = cssValuePool().createIdentifierValue(val->id);
   5937         else if (!inShorthand()) {
   5938             // If we're not parsing a shorthand then we are invalid.
   5939             return false;
   5940         } else {
   5941             // We need to rewind the value list, so that when its advanced we'll
   5942             // end up back at this value.
   5943             m_valueList->previous();
   5944             secondValue = firstValue;
   5945         }
   5946     } else
   5947         secondValue = firstValue;
   5948 
   5949     result = createPrimitiveValuePair(firstValue, secondValue);
   5950     return true;
   5951 }
   5952 
   5953 class BorderImageSliceParseContext {
   5954     STACK_ALLOCATED();
   5955 public:
   5956     BorderImageSliceParseContext(CSSPropertyParser* parser)
   5957     : m_parser(parser)
   5958     , m_allowNumber(true)
   5959     , m_allowFill(true)
   5960     , m_allowFinalCommit(false)
   5961     , m_fill(false)
   5962     { }
   5963 
   5964     bool allowNumber() const { return m_allowNumber; }
   5965     bool allowFill() const { return m_allowFill; }
   5966     bool allowFinalCommit() const { return m_allowFinalCommit; }
   5967     CSSPrimitiveValue* top() const { return m_top.get(); }
   5968 
   5969     void commitNumber(CSSParserValue* v)
   5970     {
   5971         RefPtrWillBeRawPtr<CSSPrimitiveValue> val = m_parser->createPrimitiveNumericValue(v);
   5972         if (!m_top)
   5973             m_top = val;
   5974         else if (!m_right)
   5975             m_right = val;
   5976         else if (!m_bottom)
   5977             m_bottom = val;
   5978         else {
   5979             ASSERT(!m_left);
   5980             m_left = val;
   5981         }
   5982 
   5983         m_allowNumber = !m_left;
   5984         m_allowFinalCommit = true;
   5985     }
   5986 
   5987     void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; }
   5988 
   5989     PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> commitBorderImageSlice()
   5990     {
   5991         // We need to clone and repeat values for any omissions.
   5992         ASSERT(m_top);
   5993         if (!m_right) {
   5994             m_right = m_top;
   5995             m_bottom = m_top;
   5996             m_left = m_top;
   5997         }
   5998         if (!m_bottom) {
   5999             m_bottom = m_top;
   6000             m_left = m_right;
   6001         }
   6002         if (!m_left)
   6003             m_left = m_right;
   6004 
   6005         // Now build a rect value to hold all four of our primitive values.
   6006         RefPtrWillBeRawPtr<Quad> quad = Quad::create();
   6007         quad->setTop(m_top);
   6008         quad->setRight(m_right);
   6009         quad->setBottom(m_bottom);
   6010         quad->setLeft(m_left);
   6011 
   6012         // Make our new border image value now.
   6013         return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), m_fill);
   6014     }
   6015 
   6016 private:
   6017     CSSPropertyParser* m_parser;
   6018 
   6019     bool m_allowNumber;
   6020     bool m_allowFill;
   6021     bool m_allowFinalCommit;
   6022 
   6023     RefPtrWillBeMember<CSSPrimitiveValue> m_top;
   6024     RefPtrWillBeMember<CSSPrimitiveValue> m_right;
   6025     RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
   6026     RefPtrWillBeMember<CSSPrimitiveValue> m_left;
   6027 
   6028     bool m_fill;
   6029 };
   6030 
   6031 bool CSSPropertyParser::parseBorderImageSlice(CSSPropertyID propId, RefPtrWillBeRawPtr<CSSBorderImageSliceValue>& result)
   6032 {
   6033     BorderImageSliceParseContext context(this);
   6034     CSSParserValue* val;
   6035     while ((val = m_valueList->current())) {
   6036         // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values are not created yet.
   6037         if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInteger | FNonNeg | FPercent, HTMLStandardMode)) {
   6038             context.commitNumber(val);
   6039         } else if (context.allowFill() && val->id == CSSValueFill)
   6040             context.commitFill();
   6041         else if (!inShorthand()) {
   6042             // If we're not parsing a shorthand then we are invalid.
   6043             return false;
   6044         } else {
   6045             if (context.allowFinalCommit()) {
   6046                 // We're going to successfully parse, but we don't want to consume this token.
   6047                 m_valueList->previous();
   6048             }
   6049             break;
   6050         }
   6051         m_valueList->next();
   6052     }
   6053 
   6054     if (context.allowFinalCommit()) {
   6055         // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
   6056         // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
   6057         if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect)
   6058             context.commitFill();
   6059 
   6060         // Need to fully commit as a single value.
   6061         result = context.commitBorderImageSlice();
   6062         return true;
   6063     }
   6064 
   6065     return false;
   6066 }
   6067 
   6068 class BorderImageQuadParseContext {
   6069     STACK_ALLOCATED();
   6070 public:
   6071     BorderImageQuadParseContext(CSSPropertyParser* parser)
   6072     : m_parser(parser)
   6073     , m_allowNumber(true)
   6074     , m_allowFinalCommit(false)
   6075     { }
   6076 
   6077     bool allowNumber() const { return m_allowNumber; }
   6078     bool allowFinalCommit() const { return m_allowFinalCommit; }
   6079     CSSPrimitiveValue* top() const { return m_top.get(); }
   6080 
   6081     void commitNumber(CSSParserValue* v)
   6082     {
   6083         RefPtrWillBeRawPtr<CSSPrimitiveValue> val = nullptr;
   6084         if (v->id == CSSValueAuto)
   6085             val = cssValuePool().createIdentifierValue(v->id);
   6086         else
   6087             val = m_parser->createPrimitiveNumericValue(v);
   6088 
   6089         if (!m_top)
   6090             m_top = val;
   6091         else if (!m_right)
   6092             m_right = val;
   6093         else if (!m_bottom)
   6094             m_bottom = val;
   6095         else {
   6096             ASSERT(!m_left);
   6097             m_left = val;
   6098         }
   6099 
   6100         m_allowNumber = !m_left;
   6101         m_allowFinalCommit = true;
   6102     }
   6103 
   6104     void setTop(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) { m_top = val; }
   6105 
   6106     PassRefPtrWillBeRawPtr<CSSPrimitiveValue> commitBorderImageQuad()
   6107     {
   6108         // We need to clone and repeat values for any omissions.
   6109         ASSERT(m_top);
   6110         if (!m_right) {
   6111             m_right = m_top;
   6112             m_bottom = m_top;
   6113             m_left = m_top;
   6114         }
   6115         if (!m_bottom) {
   6116             m_bottom = m_top;
   6117             m_left = m_right;
   6118         }
   6119         if (!m_left)
   6120             m_left = m_right;
   6121 
   6122         // Now build a quad value to hold all four of our primitive values.
   6123         RefPtrWillBeRawPtr<Quad> quad = Quad::create();
   6124         quad->setTop(m_top);
   6125         quad->setRight(m_right);
   6126         quad->setBottom(m_bottom);
   6127         quad->setLeft(m_left);
   6128 
   6129         // Make our new value now.
   6130         return cssValuePool().createValue(quad.release());
   6131     }
   6132 
   6133 private:
   6134     CSSPropertyParser* m_parser;
   6135 
   6136     bool m_allowNumber;
   6137     bool m_allowFinalCommit;
   6138 
   6139     RefPtrWillBeMember<CSSPrimitiveValue> m_top;
   6140     RefPtrWillBeMember<CSSPrimitiveValue> m_right;
   6141     RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
   6142     RefPtrWillBeMember<CSSPrimitiveValue> m_left;
   6143 };
   6144 
   6145 bool CSSPropertyParser::parseBorderImageQuad(Units validUnits, RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
   6146 {
   6147     BorderImageQuadParseContext context(this);
   6148     CSSParserValue* val;
   6149     while ((val = m_valueList->current())) {
   6150         if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMode) || val->id == CSSValueAuto)) {
   6151             context.commitNumber(val);
   6152         } else if (!inShorthand()) {
   6153             // If we're not parsing a shorthand then we are invalid.
   6154             return false;
   6155         } else {
   6156             if (context.allowFinalCommit())
   6157                 m_valueList->previous(); // The shorthand loop will advance back to this point.
   6158             break;
   6159         }
   6160         m_valueList->next();
   6161     }
   6162 
   6163     if (context.allowFinalCommit()) {
   6164         // Need to fully commit as a single value.
   6165         result = context.commitBorderImageQuad();
   6166         return true;
   6167     }
   6168     return false;
   6169 }
   6170 
   6171 bool CSSPropertyParser::parseBorderImageWidth(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
   6172 {
   6173     return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
   6174 }
   6175 
   6176 bool CSSPropertyParser::parseBorderImageOutset(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
   6177 {
   6178     return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
   6179 }
   6180 
   6181 bool CSSPropertyParser::parseBorderRadius(CSSPropertyID propId, bool important)
   6182 {
   6183     unsigned num = m_valueList->size();
   6184     if (num > 9)
   6185         return false;
   6186 
   6187     ShorthandScope scope(this, propId);
   6188     RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4];
   6189 #if ENABLE(OILPAN)
   6190     // Zero initialize the array of raw pointers.
   6191     memset(&radii, 0, sizeof(radii));
   6192 #endif
   6193 
   6194     unsigned indexAfterSlash = 0;
   6195     for (unsigned i = 0; i < num; ++i) {
   6196         CSSParserValue* value = m_valueList->valueAt(i);
   6197         if (value->unit == CSSParserValue::Operator) {
   6198             if (value->iValue != '/')
   6199                 return false;
   6200 
   6201             if (!i || indexAfterSlash || i + 1 == num || num > i + 5)
   6202                 return false;
   6203 
   6204             indexAfterSlash = i + 1;
   6205             completeBorderRadii(radii[0]);
   6206             continue;
   6207         }
   6208 
   6209         if (i - indexAfterSlash >= 4)
   6210             return false;
   6211 
   6212         if (!validUnit(value, FLength | FPercent | FNonNeg))
   6213             return false;
   6214 
   6215         RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericValue(value);
   6216 
   6217         if (!indexAfterSlash) {
   6218             radii[0][i] = radius;
   6219 
   6220             // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
   6221             if (num == 2 && propId == CSSPropertyWebkitBorderRadius) {
   6222                 indexAfterSlash = 1;
   6223                 completeBorderRadii(radii[0]);
   6224             }
   6225         } else
   6226             radii[1][i - indexAfterSlash] = radius.release();
   6227     }
   6228 
   6229     if (!indexAfterSlash) {
   6230         completeBorderRadii(radii[0]);
   6231         for (unsigned i = 0; i < 4; ++i)
   6232             radii[1][i] = radii[0][i];
   6233     } else
   6234         completeBorderRadii(radii[1]);
   6235 
   6236     ImplicitScope implicitScope(this, PropertyImplicit);
   6237     addProperty(CSSPropertyBorderTopLeftRadius, createPrimitiveValuePair(radii[0][0].release(), radii[1][0].release()), important);
   6238     addProperty(CSSPropertyBorderTopRightRadius, createPrimitiveValuePair(radii[0][1].release(), radii[1][1].release()), important);
   6239     addProperty(CSSPropertyBorderBottomRightRadius, createPrimitiveValuePair(radii[0][2].release(), radii[1][2].release()), important);
   6240     addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important);
   6241     return true;
   6242 }
   6243 
   6244 bool CSSPropertyParser::parseAspectRatio(bool important)
   6245 {
   6246     unsigned num = m_valueList->size();
   6247     if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
   6248         addProperty(CSSPropertyWebkitAspectRatio, cssValuePool().createIdentifierValue(CSSValueNone), important);
   6249         return true;
   6250     }
   6251 
   6252     if (num != 3)
   6253         return false;
   6254 
   6255     CSSParserValue* lvalue = m_valueList->valueAt(0);
   6256     CSSParserValue* op = m_valueList->valueAt(1);
   6257     CSSParserValue* rvalue = m_valueList->valueAt(2);
   6258 
   6259     if (!isForwardSlashOperator(op))
   6260         return false;
   6261 
   6262     if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
   6263         return false;
   6264 
   6265     if (!lvalue->fValue || !rvalue->fValue)
   6266         return false;
   6267 
   6268     addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important);
   6269 
   6270     return true;
   6271 }
   6272 
   6273 bool CSSPropertyParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important)
   6274 {
   6275     enum { ID, VAL } state = ID;
   6276 
   6277     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
   6278     RefPtrWillBeRawPtr<CSSPrimitiveValue> counterName = nullptr;
   6279 
   6280     while (true) {
   6281         CSSParserValue* val = m_valueList->current();
   6282         switch (state) {
   6283             case ID:
   6284                 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
   6285                     counterName = createPrimitiveStringValue(val);
   6286                     state = VAL;
   6287                     m_valueList->next();
   6288                     continue;
   6289                 }
   6290                 break;
   6291             case VAL: {
   6292                 int i = defaultValue;
   6293                 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
   6294                     i = clampToInteger(val->fValue);
   6295                     m_valueList->next();
   6296                 }
   6297 
   6298                 list->append(createPrimitiveValuePair(counterName.release(),
   6299                     cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER)));
   6300                 state = ID;
   6301                 continue;
   6302             }
   6303         }
   6304         break;
   6305     }
   6306 
   6307     if (list->length() > 0) {
   6308         addProperty(propId, list.release(), important);
   6309         return true;
   6310     }
   6311 
   6312     return false;
   6313 }
   6314 
   6315 // This should go away once we drop support for -webkit-gradient
   6316 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal)
   6317 {
   6318     RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
   6319     if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
   6320         if ((equalIgnoringCase(a, "left") && horizontal)
   6321             || (equalIgnoringCase(a, "top") && !horizontal))
   6322             result = cssValuePool().createValue(0., CSSPrimitiveValue::CSS_PERCENTAGE);
   6323         else if ((equalIgnoringCase(a, "right") && horizontal)
   6324                  || (equalIgnoringCase(a, "bottom") && !horizontal))
   6325             result = cssValuePool().createValue(100., CSSPrimitiveValue::CSS_PERCENTAGE);
   6326         else if (equalIgnoringCase(a, "center"))
   6327             result = cssValuePool().createValue(50., CSSPrimitiveValue::CSS_PERCENTAGE);
   6328     } else if (a->unit == CSSPrimitiveValue::CSS_NUMBER || a->unit == CSSPrimitiveValue::CSS_PERCENTAGE) {
   6329         result = cssValuePool().createValue(a->fValue, static_cast<CSSPrimitiveValue::UnitType>(a->unit));
   6330     }
   6331     return result;
   6332 }
   6333 
   6334 bool parseDeprecatedGradientColorStop(CSSPropertyParser* p, CSSParserValue* a, CSSGradientColorStop& stop)
   6335 {
   6336     if (a->unit != CSSParserValue::Function)
   6337         return false;
   6338 
   6339     if (!equalIgnoringCase(a->function->name, "from(") &&
   6340         !equalIgnoringCase(a->function->name, "to(") &&
   6341         !equalIgnoringCase(a->function->name, "color-stop("))
   6342         return false;
   6343 
   6344     CSSParserValueList* args = a->function->args.get();
   6345     if (!args)
   6346         return false;
   6347 
   6348     if (equalIgnoringCase(a->function->name, "from(")
   6349         || equalIgnoringCase(a->function->name, "to(")) {
   6350         // The "from" and "to" stops expect 1 argument.
   6351         if (args->size() != 1)
   6352             return false;
   6353 
   6354         if (equalIgnoringCase(a->function->name, "from("))
   6355             stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
   6356         else
   6357             stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
   6358 
   6359         CSSValueID id = args->current()->id;
   6360         if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
   6361             stop.m_color = cssValuePool().createIdentifierValue(id);
   6362         else
   6363             stop.m_color = p->parseColor(args->current());
   6364         if (!stop.m_color)
   6365             return false;
   6366     }
   6367 
   6368     // The "color-stop" function expects 3 arguments.
   6369     if (equalIgnoringCase(a->function->name, "color-stop(")) {
   6370         if (args->size() != 3)
   6371             return false;
   6372 
   6373         CSSParserValue* stopArg = args->current();
   6374         if (stopArg->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
   6375             stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::CSS_NUMBER);
   6376         else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER)
   6377             stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER);
   6378         else
   6379             return false;
   6380 
   6381         stopArg = args->next();
   6382         if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',')
   6383             return false;
   6384 
   6385         stopArg = args->next();
   6386         CSSValueID id = stopArg->id;
   6387         if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu)
   6388             stop.m_color = cssValuePool().createIdentifierValue(id);
   6389         else
   6390             stop.m_color = p->parseColor(stopArg);
   6391         if (!stop.m_color)
   6392             return false;
   6393     }
   6394 
   6395     return true;
   6396 }
   6397 
   6398 bool CSSPropertyParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient)
   6399 {
   6400     // Walk the arguments.
   6401     CSSParserValueList* args = valueList->current()->function->args.get();
   6402     if (!args || args->size() == 0)
   6403         return false;
   6404 
   6405     // The first argument is the gradient type.  It is an identifier.
   6406     CSSGradientType gradientType;
   6407     CSSParserValue* a = args->current();
   6408     if (!a || a->unit != CSSPrimitiveValue::CSS_IDENT)
   6409         return false;
   6410     if (equalIgnoringCase(a, "linear"))
   6411         gradientType = CSSDeprecatedLinearGradient;
   6412     else if (equalIgnoringCase(a, "radial"))
   6413         gradientType = CSSDeprecatedRadialGradient;
   6414     else
   6415         return false;
   6416 
   6417     RefPtrWillBeRawPtr<CSSGradientValue> result = nullptr;
   6418     switch (gradientType) {
   6419     case CSSDeprecatedLinearGradient:
   6420         result = CSSLinearGradientValue::create(NonRepeating, gradientType);
   6421         break;
   6422     case CSSDeprecatedRadialGradient:
   6423         result = CSSRadialGradientValue::create(NonRepeating, gradientType);
   6424         break;
   6425     default:
   6426         // The rest of the gradient types shouldn't appear here.
   6427         ASSERT_NOT_REACHED();
   6428     }
   6429 
   6430     // Comma.
   6431     a = args->next();
   6432     if (!isComma(a))
   6433         return false;
   6434 
   6435     // Next comes the starting point for the gradient as an x y pair.  There is no
   6436     // comma between the x and the y values.
   6437     // First X.  It can be left, right, number or percent.
   6438     a = args->next();
   6439     if (!a)
   6440         return false;
   6441     RefPtrWillBeRawPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a, true);
   6442     if (!point)
   6443         return false;
   6444     result->setFirstX(point.release());
   6445 
   6446     // First Y.  It can be top, bottom, number or percent.
   6447     a = args->next();
   6448     if (!a)
   6449         return false;
   6450     point = parseDeprecatedGradientPoint(a, false);
   6451     if (!point)
   6452         return false;
   6453     result->setFirstY(point.release());
   6454 
   6455     // Comma after the first point.
   6456     a = args->next();
   6457     if (!isComma(a))
   6458         return false;
   6459 
   6460     // For radial gradients only, we now expect a numeric radius.
   6461     if (gradientType == CSSDeprecatedRadialGradient) {
   6462         a = args->next();
   6463         if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
   6464             return false;
   6465         toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a));
   6466 
   6467         // Comma after the first radius.
   6468         a = args->next();
   6469         if (!isComma(a))
   6470             return false;
   6471     }
   6472 
   6473     // Next is the ending point for the gradient as an x, y pair.
   6474     // Second X.  It can be left, right, number or percent.
   6475     a = args->next();
   6476     if (!a)
   6477         return false;
   6478     point = parseDeprecatedGradientPoint(a, true);
   6479     if (!point)
   6480         return false;
   6481     result->setSecondX(point.release());
   6482 
   6483     // Second Y.  It can be top, bottom, number or percent.
   6484     a = args->next();
   6485     if (!a)
   6486         return false;
   6487     point = parseDeprecatedGradientPoint(a, false);
   6488     if (!point)
   6489         return false;
   6490     result->setSecondY(point.release());
   6491 
   6492     // For radial gradients only, we now expect the second radius.
   6493     if (gradientType == CSSDeprecatedRadialGradient) {
   6494         // Comma after the second point.
   6495         a = args->next();
   6496         if (!isComma(a))
   6497             return false;
   6498 
   6499         a = args->next();
   6500         if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER)
   6501             return false;
   6502         toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a));
   6503     }
   6504 
   6505     // We now will accept any number of stops (0 or more).
   6506     a = args->next();
   6507     while (a) {
   6508         // Look for the comma before the next stop.
   6509         if (!isComma(a))
   6510             return false;
   6511 
   6512         // Now examine the stop itself.
   6513         a = args->next();
   6514         if (!a)
   6515             return false;
   6516 
   6517         // The function name needs to be one of "from", "to", or "color-stop."
   6518         CSSGradientColorStop stop;
   6519         if (!parseDeprecatedGradientColorStop(this, a, stop))
   6520             return false;
   6521         result->addStop(stop);
   6522 
   6523         // Advance
   6524         a = args->next();
   6525     }
   6526 
   6527     gradient = result.release();
   6528     return true;
   6529 }
   6530 
   6531 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal)
   6532 {
   6533     if (a->unit != CSSPrimitiveValue::CSS_IDENT)
   6534         return nullptr;
   6535 
   6536     switch (a->id) {
   6537         case CSSValueLeft:
   6538         case CSSValueRight:
   6539             isHorizontal = true;
   6540             break;
   6541         case CSSValueTop:
   6542         case CSSValueBottom:
   6543             isHorizontal = false;
   6544             break;
   6545         default:
   6546             return nullptr;
   6547     }
   6548     return cssValuePool().createIdentifierValue(a->id);
   6549 }
   6550 
   6551 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseGradientColorOrKeyword(CSSPropertyParser* p, CSSParserValue* value)
   6552 {
   6553     CSSValueID id = value->id;
   6554     if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor)
   6555         return cssValuePool().createIdentifierValue(id);
   6556 
   6557     return p->parseColor(value);
   6558 }
   6559 
   6560 bool CSSPropertyParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   6561 {
   6562     RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient);
   6563 
   6564     // Walk the arguments.
   6565     CSSParserValueList* args = valueList->current()->function->args.get();
   6566     if (!args || !args->size())
   6567         return false;
   6568 
   6569     CSSParserValue* a = args->current();
   6570     if (!a)
   6571         return false;
   6572 
   6573     bool expectComma = false;
   6574     // Look for angle.
   6575     if (validUnit(a, FAngle, HTMLStandardMode)) {
   6576         result->setAngle(createPrimitiveNumericValue(a));
   6577 
   6578         args->next();
   6579         expectComma = true;
   6580     } else {
   6581         // Look one or two optional keywords that indicate a side or corner.
   6582         RefPtrWillBeRawPtr<CSSPrimitiveValue> startX = nullptr;
   6583         RefPtrWillBeRawPtr<CSSPrimitiveValue> startY = nullptr;
   6584 
   6585         RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
   6586         bool isHorizontal = false;
   6587         if ((location = valueFromSideKeyword(a, isHorizontal))) {
   6588             if (isHorizontal)
   6589                 startX = location;
   6590             else
   6591                 startY = location;
   6592 
   6593             if ((a = args->next())) {
   6594                 if ((location = valueFromSideKeyword(a, isHorizontal))) {
   6595                     if (isHorizontal) {
   6596                         if (startX)
   6597                             return false;
   6598                         startX = location;
   6599                     } else {
   6600                         if (startY)
   6601                             return false;
   6602                         startY = location;
   6603                     }
   6604 
   6605                     args->next();
   6606                 }
   6607             }
   6608 
   6609             expectComma = true;
   6610         }
   6611 
   6612         if (!startX && !startY)
   6613             startY = cssValuePool().createIdentifierValue(CSSValueTop);
   6614 
   6615         result->setFirstX(startX.release());
   6616         result->setFirstY(startY.release());
   6617     }
   6618 
   6619     if (!parseGradientColorStops(args, result.get(), expectComma))
   6620         return false;
   6621 
   6622     if (!result->stopCount())
   6623         return false;
   6624 
   6625     gradient = result.release();
   6626     return true;
   6627 }
   6628 
   6629 bool CSSPropertyParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   6630 {
   6631     RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
   6632 
   6633     // Walk the arguments.
   6634     CSSParserValueList* args = valueList->current()->function->args.get();
   6635     if (!args || !args->size())
   6636         return false;
   6637 
   6638     CSSParserValue* a = args->current();
   6639     if (!a)
   6640         return false;
   6641 
   6642     bool expectComma = false;
   6643 
   6644     // Optional background-position
   6645     RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
   6646     RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
   6647     // parse2ValuesFillPosition advances the args next pointer.
   6648     parse2ValuesFillPosition(args, centerX, centerY);
   6649     a = args->current();
   6650     if (!a)
   6651         return false;
   6652 
   6653     if (centerX || centerY) {
   6654         // Comma
   6655         if (!isComma(a))
   6656             return false;
   6657 
   6658         a = args->next();
   6659         if (!a)
   6660             return false;
   6661     }
   6662 
   6663     result->setFirstX(toCSSPrimitiveValue(centerX.get()));
   6664     result->setSecondX(toCSSPrimitiveValue(centerX.get()));
   6665     // CSS3 radial gradients always share the same start and end point.
   6666     result->setFirstY(toCSSPrimitiveValue(centerY.get()));
   6667     result->setSecondY(toCSSPrimitiveValue(centerY.get()));
   6668 
   6669     RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
   6670     RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
   6671 
   6672     // Optional shape and/or size in any order.
   6673     for (int i = 0; i < 2; ++i) {
   6674         if (a->unit != CSSPrimitiveValue::CSS_IDENT)
   6675             break;
   6676 
   6677         bool foundValue = false;
   6678         switch (a->id) {
   6679         case CSSValueCircle:
   6680         case CSSValueEllipse:
   6681             shapeValue = cssValuePool().createIdentifierValue(a->id);
   6682             foundValue = true;
   6683             break;
   6684         case CSSValueClosestSide:
   6685         case CSSValueClosestCorner:
   6686         case CSSValueFarthestSide:
   6687         case CSSValueFarthestCorner:
   6688         case CSSValueContain:
   6689         case CSSValueCover:
   6690             sizeValue = cssValuePool().createIdentifierValue(a->id);
   6691             foundValue = true;
   6692             break;
   6693         default:
   6694             break;
   6695         }
   6696 
   6697         if (foundValue) {
   6698             a = args->next();
   6699             if (!a)
   6700                 return false;
   6701 
   6702             expectComma = true;
   6703         }
   6704     }
   6705 
   6706     result->setShape(shapeValue);
   6707     result->setSizingBehavior(sizeValue);
   6708 
   6709     // Or, two lengths or percentages
   6710     RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
   6711     RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
   6712 
   6713     if (!shapeValue && !sizeValue) {
   6714         if (validUnit(a, FLength | FPercent)) {
   6715             horizontalSize = createPrimitiveNumericValue(a);
   6716             a = args->next();
   6717             if (!a)
   6718                 return false;
   6719 
   6720             expectComma = true;
   6721         }
   6722 
   6723         if (validUnit(a, FLength | FPercent)) {
   6724             verticalSize = createPrimitiveNumericValue(a);
   6725 
   6726             a = args->next();
   6727             if (!a)
   6728                 return false;
   6729             expectComma = true;
   6730         }
   6731     }
   6732 
   6733     // Must have neither or both.
   6734     if (!horizontalSize != !verticalSize)
   6735         return false;
   6736 
   6737     result->setEndHorizontalSize(horizontalSize);
   6738     result->setEndVerticalSize(verticalSize);
   6739 
   6740     if (!parseGradientColorStops(args, result.get(), expectComma))
   6741         return false;
   6742 
   6743     gradient = result.release();
   6744     return true;
   6745 }
   6746 
   6747 bool CSSPropertyParser::parseLinearGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   6748 {
   6749     RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
   6750 
   6751     CSSParserValueList* args = valueList->current()->function->args.get();
   6752     if (!args || !args->size())
   6753         return false;
   6754 
   6755     CSSParserValue* a = args->current();
   6756     if (!a)
   6757         return false;
   6758 
   6759     bool expectComma = false;
   6760     // Look for angle.
   6761     if (validUnit(a, FAngle, HTMLStandardMode)) {
   6762         result->setAngle(createPrimitiveNumericValue(a));
   6763 
   6764         args->next();
   6765         expectComma = true;
   6766     } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
   6767         // to [ [left | right] || [top | bottom] ]
   6768         a = args->next();
   6769         if (!a)
   6770             return false;
   6771 
   6772         RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = nullptr;
   6773         RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = nullptr;
   6774         RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr;
   6775         bool isHorizontal = false;
   6776 
   6777         location = valueFromSideKeyword(a, isHorizontal);
   6778         if (!location)
   6779             return false;
   6780 
   6781         if (isHorizontal)
   6782             endX = location;
   6783         else
   6784             endY = location;
   6785 
   6786         a = args->next();
   6787         if (!a)
   6788             return false;
   6789 
   6790         location = valueFromSideKeyword(a, isHorizontal);
   6791         if (location) {
   6792             if (isHorizontal) {
   6793                 if (endX)
   6794                     return false;
   6795                 endX = location;
   6796             } else {
   6797                 if (endY)
   6798                     return false;
   6799                 endY = location;
   6800             }
   6801 
   6802             args->next();
   6803         }
   6804 
   6805         expectComma = true;
   6806         result->setFirstX(endX.release());
   6807         result->setFirstY(endY.release());
   6808     }
   6809 
   6810     if (!parseGradientColorStops(args, result.get(), expectComma))
   6811         return false;
   6812 
   6813     if (!result->stopCount())
   6814         return false;
   6815 
   6816     gradient = result.release();
   6817     return true;
   6818 }
   6819 
   6820 bool CSSPropertyParser::parseRadialGradient(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating)
   6821 {
   6822     RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
   6823 
   6824     CSSParserValueList* args = valueList->current()->function->args.get();
   6825     if (!args || !args->size())
   6826         return false;
   6827 
   6828     CSSParserValue* a = args->current();
   6829     if (!a)
   6830         return false;
   6831 
   6832     bool expectComma = false;
   6833 
   6834     RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr;
   6835     RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr;
   6836     RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr;
   6837     RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr;
   6838 
   6839     // First part of grammar, the size/shape clause:
   6840     // [ circle || <length> ] |
   6841     // [ ellipse || [ <length> | <percentage> ]{2} ] |
   6842     // [ [ circle | ellipse] || <size-keyword> ]
   6843     for (int i = 0; i < 3; ++i) {
   6844         if (a->unit == CSSPrimitiveValue::CSS_IDENT) {
   6845             bool badIdent = false;
   6846             switch (a->id) {
   6847             case CSSValueCircle:
   6848             case CSSValueEllipse:
   6849                 if (shapeValue)
   6850                     return false;
   6851                 shapeValue = cssValuePool().createIdentifierValue(a->id);
   6852                 break;
   6853             case CSSValueClosestSide:
   6854             case CSSValueClosestCorner:
   6855             case CSSValueFarthestSide:
   6856             case CSSValueFarthestCorner:
   6857                 if (sizeValue || horizontalSize)
   6858                     return false;
   6859                 sizeValue = cssValuePool().createIdentifierValue(a->id);
   6860                 break;
   6861             default:
   6862                 badIdent = true;
   6863             }
   6864 
   6865             if (badIdent)
   6866                 break;
   6867 
   6868             a = args->next();
   6869             if (!a)
   6870                 return false;
   6871         } else if (validUnit(a, FLength | FPercent)) {
   6872 
   6873             if (sizeValue || horizontalSize)
   6874                 return false;
   6875             horizontalSize = createPrimitiveNumericValue(a);
   6876 
   6877             a = args->next();
   6878             if (!a)
   6879                 return false;
   6880 
   6881             if (validUnit(a, FLength | FPercent)) {
   6882                 verticalSize = createPrimitiveNumericValue(a);
   6883                 ++i;
   6884                 a = args->next();
   6885                 if (!a)
   6886                     return false;
   6887             }
   6888         } else
   6889             break;
   6890     }
   6891 
   6892     // You can specify size as a keyword or a length/percentage, not both.
   6893     if (sizeValue && horizontalSize)
   6894         return false;
   6895     // Circles must have 0 or 1 lengths.
   6896     if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize)
   6897         return false;
   6898     // Ellipses must have 0 or 2 length/percentages.
   6899     if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
   6900         return false;
   6901     // If there's only one size, it must be a length.
   6902     if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
   6903         return false;
   6904 
   6905     result->setShape(shapeValue);
   6906     result->setSizingBehavior(sizeValue);
   6907     result->setEndHorizontalSize(horizontalSize);
   6908     result->setEndVerticalSize(verticalSize);
   6909 
   6910     // Second part of grammar, the center-position clause:
   6911     // at <position>
   6912     RefPtrWillBeRawPtr<CSSValue> centerX = nullptr;
   6913     RefPtrWillBeRawPtr<CSSValue> centerY = nullptr;
   6914     if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) {
   6915         a = args->next();
   6916         if (!a)
   6917             return false;
   6918 
   6919         parseFillPosition(args, centerX, centerY);
   6920         if (!(centerX && centerY))
   6921             return false;
   6922 
   6923         a = args->current();
   6924         if (!a)
   6925             return false;
   6926         result->setFirstX(toCSSPrimitiveValue(centerX.get()));
   6927         result->setFirstY(toCSSPrimitiveValue(centerY.get()));
   6928         // Right now, CSS radial gradients have the same start and end centers.
   6929         result->setSecondX(toCSSPrimitiveValue(centerX.get()));
   6930         result->setSecondY(toCSSPrimitiveValue(centerY.get()));
   6931     }
   6932 
   6933     if (shapeValue || sizeValue || horizontalSize || centerX || centerY)
   6934         expectComma = true;
   6935 
   6936     if (!parseGradientColorStops(args, result.get(), expectComma))
   6937         return false;
   6938 
   6939     gradient = result.release();
   6940     return true;
   6941 }
   6942 
   6943 bool CSSPropertyParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma)
   6944 {
   6945     CSSParserValue* a = valueList->current();
   6946 
   6947     // Now look for color stops.
   6948     while (a) {
   6949         // Look for the comma before the next stop.
   6950         if (expectComma) {
   6951             if (!isComma(a))
   6952                 return false;
   6953 
   6954             a = valueList->next();
   6955             if (!a)
   6956                 return false;
   6957         }
   6958 
   6959         // <color-stop> = <color> [ <percentage> | <length> ]?
   6960         CSSGradientColorStop stop;
   6961         stop.m_color = parseGradientColorOrKeyword(this, a);
   6962         if (!stop.m_color)
   6963             return false;
   6964 
   6965         a = valueList->next();
   6966         if (a) {
   6967             if (validUnit(a, FLength | FPercent)) {
   6968                 stop.m_position = createPrimitiveNumericValue(a);
   6969                 a = valueList->next();
   6970             }
   6971         }
   6972 
   6973         gradient->addStop(stop);
   6974         expectComma = true;
   6975     }
   6976 
   6977     // Must have 2 or more stops to be valid.
   6978     return gradient->stopCount() >= 2;
   6979 }
   6980 
   6981 bool CSSPropertyParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value)
   6982 {
   6983     CSSParserValue* val = valueList->current();
   6984 
   6985     if (val->unit != CSSParserValue::Function)
   6986         return false;
   6987 
   6988     if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) {
   6989         // FIXME: This should send a deprecation message.
   6990         if (m_context.useCounter())
   6991             m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
   6992         return parseDeprecatedGradient(valueList, value);
   6993     }
   6994 
   6995     if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) {
   6996         // FIXME: This should send a deprecation message.
   6997         if (m_context.useCounter())
   6998             m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradient);
   6999         return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
   7000     }
   7001 
   7002     if (equalIgnoringCase(val->function->name, "linear-gradient("))
   7003         return parseLinearGradient(valueList, value, NonRepeating);
   7004 
   7005     if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")) {
   7006         // FIXME: This should send a deprecation message.
   7007         if (m_context.useCounter())
   7008             m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
   7009         return parseDeprecatedLinearGradient(valueList, value, Repeating);
   7010     }
   7011 
   7012     if (equalIgnoringCase(val->function->name, "repeating-linear-gradient("))
   7013         return parseLinearGradient(valueList, value, Repeating);
   7014 
   7015     if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) {
   7016         // FIXME: This should send a deprecation message.
   7017         if (m_context.useCounter())
   7018             m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradient);
   7019         return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
   7020     }
   7021 
   7022     if (equalIgnoringCase(val->function->name, "radial-gradient("))
   7023         return parseRadialGradient(valueList, value, NonRepeating);
   7024 
   7025     if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")) {
   7026         if (m_context.useCounter())
   7027             m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingRadialGradient);
   7028         return parseDeprecatedRadialGradient(valueList, value, Repeating);
   7029     }
   7030 
   7031     if (equalIgnoringCase(val->function->name, "repeating-radial-gradient("))
   7032         return parseRadialGradient(valueList, value, Repeating);
   7033 
   7034     if (equalIgnoringCase(val->function->name, "-webkit-canvas("))
   7035         return parseCanvas(valueList, value);
   7036 
   7037     if (equalIgnoringCase(val->function->name, "-webkit-cross-fade("))
   7038         return parseCrossfade(valueList, value);
   7039 
   7040     return false;
   7041 }
   7042 
   7043 bool CSSPropertyParser::parseCrossfade(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& crossfade)
   7044 {
   7045     // Walk the arguments.
   7046     CSSParserValueList* args = valueList->current()->function->args.get();
   7047     if (!args || args->size() != 5)
   7048         return false;
   7049     CSSParserValue* a = args->current();
   7050     RefPtrWillBeRawPtr<CSSValue> fromImageValue = nullptr;
   7051     RefPtrWillBeRawPtr<CSSValue> toImageValue = nullptr;
   7052 
   7053     // The first argument is the "from" image. It is a fill image.
   7054     if (!a || !parseFillImage(args, fromImageValue))
   7055         return false;
   7056     a = args->next();
   7057 
   7058     // Skip a comma
   7059     if (!isComma(a))
   7060         return false;
   7061     a = args->next();
   7062 
   7063     // The second argument is the "to" image. It is a fill image.
   7064     if (!a || !parseFillImage(args, toImageValue))
   7065         return false;
   7066     a = args->next();
   7067 
   7068     // Skip a comma
   7069     if (!isComma(a))
   7070         return false;
   7071     a = args->next();
   7072 
   7073     // The third argument is the crossfade value. It is a percentage or a fractional number.
   7074     RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr;
   7075     if (!a)
   7076         return false;
   7077 
   7078     if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
   7079         percentage = cssValuePool().createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
   7080     else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
   7081         percentage = cssValuePool().createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
   7082     else
   7083         return false;
   7084 
   7085     RefPtrWillBeRawPtr<CSSCrossfadeValue> result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
   7086     result->setPercentage(percentage);
   7087 
   7088     crossfade = result;
   7089 
   7090     return true;
   7091 }
   7092 
   7093 bool CSSPropertyParser::parseCanvas(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& canvas)
   7094 {
   7095     // Walk the arguments.
   7096     CSSParserValueList* args = valueList->current()->function->args.get();
   7097     if (!args || args->size() != 1)
   7098         return false;
   7099 
   7100     // The first argument is the canvas name.  It is an identifier.
   7101     CSSParserValue* value = args->current();
   7102     if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT)
   7103         return false;
   7104 
   7105     canvas = CSSCanvasValue::create(value->string);
   7106     return true;
   7107 }
   7108 
   7109 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseImageSet(CSSParserValueList* valueList)
   7110 {
   7111     CSSParserValue* function = valueList->current();
   7112 
   7113     if (function->unit != CSSParserValue::Function)
   7114         return nullptr;
   7115 
   7116     CSSParserValueList* functionArgs = valueList->current()->function->args.get();
   7117     if (!functionArgs || !functionArgs->size() || !functionArgs->current())
   7118         return nullptr;
   7119 
   7120     RefPtrWillBeRawPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create();
   7121 
   7122     CSSParserValue* arg = functionArgs->current();
   7123     while (arg) {
   7124         if (arg->unit != CSSPrimitiveValue::CSS_URI)
   7125             return nullptr;
   7126 
   7127         RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg->string, completeURL(arg->string));
   7128         imageSet->append(image);
   7129 
   7130         arg = functionArgs->next();
   7131         if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION)
   7132             return nullptr;
   7133 
   7134         double imageScaleFactor = 0;
   7135         const String& string = arg->string;
   7136         unsigned length = string.length();
   7137         if (!length)
   7138             return nullptr;
   7139         if (string.is8Bit()) {
   7140             const LChar* start = string.characters8();
   7141             parseDouble(start, start + length, 'x', imageScaleFactor);
   7142         } else {
   7143             const UChar* start = string.characters16();
   7144             parseDouble(start, start + length, 'x', imageScaleFactor);
   7145         }
   7146         if (imageScaleFactor <= 0)
   7147             return nullptr;
   7148         imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER));
   7149 
   7150         // If there are no more arguments, we're done.
   7151         arg = functionArgs->next();
   7152         if (!arg)
   7153             break;
   7154 
   7155         // If there are more arguments, they should be after a comma.
   7156         if (!isComma(arg))
   7157             return nullptr;
   7158 
   7159         // Skip the comma and move on to the next argument.
   7160         arg = functionArgs->next();
   7161     }
   7162 
   7163     return imageSet.release();
   7164 }
   7165 
   7166 bool CSSPropertyParser::parseWillChange(bool important)
   7167 {
   7168     ASSERT(RuntimeEnabledFeatures::cssWillChangeEnabled());
   7169 
   7170     RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
   7171     if (m_valueList->current()->id == CSSValueAuto) {
   7172         if (m_valueList->next())
   7173             return false;
   7174     }
   7175 
   7176     CSSParserValue* currentValue;
   7177     bool expectComma = false;
   7178 
   7179     // Every comma-separated list of CSS_IDENTs is a valid will-change value,
   7180     // unless the list includes an explicitly disallowed CSS_IDENT.
   7181     while ((currentValue = m_valueList->current())) {
   7182         if (expectComma) {
   7183             if (!isComma(currentValue))
   7184                 return false;
   7185             expectComma = false;
   7186             m_valueList->next();
   7187             continue;
   7188         }
   7189 
   7190         if (currentValue->unit != CSSPrimitiveValue::CSS_IDENT)
   7191             return false;
   7192 
   7193         CSSPropertyID property = cssPropertyID(currentValue->string);
   7194         if (property && RuntimeCSSEnabled::isCSSPropertyEnabled(property)) {
   7195             // Now "all" is used by both CSSValue and CSSPropertyValue.
   7196             // Need to return false when currentValue is CSSPropertyAll.
   7197             if (property == CSSPropertyWillChange || property == CSSPropertyAll)
   7198                 return false;
   7199             values->append(cssValuePool().createIdentifierValue(property));
   7200         } else {
   7201             switch (currentValue->id) {
   7202             case CSSValueNone:
   7203             case CSSValueAll:
   7204             case CSSValueAuto:
   7205             case CSSValueDefault:
   7206             case CSSValueInitial:
   7207             case CSSValueInherit:
   7208                 return false;
   7209             case CSSValueContents:
   7210             case CSSValueScrollPosition:
   7211                 values->append(cssValuePool().createIdentifierValue(currentValue->id));
   7212                 break;
   7213             default:
   7214                 break;
   7215             }
   7216         }
   7217         expectComma = true;
   7218         m_valueList->next();
   7219     }
   7220 
   7221     addProperty(CSSPropertyWillChange, values.release(), important);
   7222     return true;
   7223 }
   7224 
   7225 static void filterInfoForName(const CSSParserString& name, CSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
   7226 {
   7227     if (equalIgnoringCase(name, "grayscale("))
   7228         filterType = CSSFilterValue::GrayscaleFilterOperation;
   7229     else if (equalIgnoringCase(name, "sepia("))
   7230         filterType = CSSFilterValue::SepiaFilterOperation;
   7231     else if (equalIgnoringCase(name, "saturate("))
   7232         filterType = CSSFilterValue::SaturateFilterOperation;
   7233     else if (equalIgnoringCase(name, "hue-rotate("))
   7234         filterType = CSSFilterValue::HueRotateFilterOperation;
   7235     else if (equalIgnoringCase(name, "invert("))
   7236         filterType = CSSFilterValue::InvertFilterOperation;
   7237     else if (equalIgnoringCase(name, "opacity("))
   7238         filterType = CSSFilterValue::OpacityFilterOperation;
   7239     else if (equalIgnoringCase(name, "brightness("))
   7240         filterType = CSSFilterValue::BrightnessFilterOperation;
   7241     else if (equalIgnoringCase(name, "contrast("))
   7242         filterType = CSSFilterValue::ContrastFilterOperation;
   7243     else if (equalIgnoringCase(name, "blur("))
   7244         filterType = CSSFilterValue::BlurFilterOperation;
   7245     else if (equalIgnoringCase(name, "drop-shadow(")) {
   7246         filterType = CSSFilterValue::DropShadowFilterOperation;
   7247         maximumArgumentCount = 4;  // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
   7248     }
   7249 }
   7250 
   7251 PassRefPtrWillBeRawPtr<CSSFilterValue> CSSPropertyParser::parseBuiltinFilterArguments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
   7252 {
   7253     RefPtrWillBeRawPtr<CSSFilterValue> filterValue = CSSFilterValue::create(filterType);
   7254     ASSERT(args);
   7255 
   7256     switch (filterType) {
   7257     case CSSFilterValue::GrayscaleFilterOperation:
   7258     case CSSFilterValue::SepiaFilterOperation:
   7259     case CSSFilterValue::SaturateFilterOperation:
   7260     case CSSFilterValue::InvertFilterOperation:
   7261     case CSSFilterValue::OpacityFilterOperation:
   7262     case CSSFilterValue::ContrastFilterOperation: {
   7263         // One optional argument, 0-1 or 0%-100%, if missing use 100%.
   7264         if (args->size() > 1)
   7265             return nullptr;
   7266 
   7267         if (args->size()) {
   7268             CSSParserValue* value = args->current();
   7269             // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
   7270             if (value->unit != CSSPrimitiveValue::CSS_PERCENTAGE && !validUnit(value, FNumber | FNonNeg, HTMLStandardMode))
   7271                 return nullptr;
   7272 
   7273             double amount = value->fValue;
   7274             if (amount < 0)
   7275                 return nullptr;
   7276 
   7277             // Saturate and Contrast allow values over 100%.
   7278             if (filterType != CSSFilterValue::SaturateFilterOperation
   7279                 && filterType != CSSFilterValue::ContrastFilterOperation) {
   7280                 double maxAllowed = value->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 100.0 : 1.0;
   7281                 if (amount > maxAllowed)
   7282                     return nullptr;
   7283             }
   7284 
   7285             filterValue->append(cssValuePool().createValue(amount, static_cast<CSSPrimitiveValue::UnitType>(value->unit)));
   7286         }
   7287         break;
   7288     }
   7289     case CSSFilterValue::BrightnessFilterOperation: {
   7290         // One optional argument, if missing use 100%.
   7291         if (args->size() > 1)
   7292             return nullptr;
   7293 
   7294         if (args->size()) {
   7295             CSSParserValue* value = args->current();
   7296             // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
   7297             if (value->unit != CSSPrimitiveValue::CSS_PERCENTAGE && !validUnit(value, FNumber, HTMLStandardMode))
   7298                 return nullptr;
   7299 
   7300             filterValue->append(cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitType>(value->unit)));
   7301         }
   7302         break;
   7303     }
   7304     case CSSFilterValue::HueRotateFilterOperation: {
   7305         // hue-rotate() takes one optional angle.
   7306         if (args->size() > 1)
   7307             return nullptr;
   7308 
   7309         if (args->size()) {
   7310             CSSParserValue* argument = args->current();
   7311             if (!validUnit(argument, FAngle, HTMLStandardMode))
   7312                 return nullptr;
   7313 
   7314             filterValue->append(createPrimitiveNumericValue(argument));
   7315         }
   7316         break;
   7317     }
   7318     case CSSFilterValue::BlurFilterOperation: {
   7319         // Blur takes a single length. Zero parameters are allowed.
   7320         if (args->size() > 1)
   7321             return nullptr;
   7322 
   7323         if (args->size()) {
   7324             CSSParserValue* argument = args->current();
   7325             if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode))
   7326                 return nullptr;
   7327 
   7328             filterValue->append(createPrimitiveNumericValue(argument));
   7329         }
   7330         break;
   7331     }
   7332     case CSSFilterValue::DropShadowFilterOperation: {
   7333         // drop-shadow() takes a single shadow.
   7334         RefPtrWillBeRawPtr<CSSValueList> shadowValueList = parseShadow(args, CSSPropertyWebkitFilter);
   7335         if (!shadowValueList || shadowValueList->length() != 1)
   7336             return nullptr;
   7337 
   7338         filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0));
   7339         break;
   7340     }
   7341     default:
   7342         ASSERT_NOT_REACHED();
   7343     }
   7344     return filterValue.release();
   7345 }
   7346 
   7347 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFilter()
   7348 {
   7349     if (!m_valueList)
   7350         return nullptr;
   7351 
   7352     // The filter is a list of functional primitives that specify individual operations.
   7353     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   7354     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   7355         if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function))
   7356             return nullptr;
   7357 
   7358         CSSFilterValue::FilterOperationType filterType = CSSFilterValue::UnknownFilterOperation;
   7359 
   7360         // See if the specified primitive is one we understand.
   7361         if (value->unit == CSSPrimitiveValue::CSS_URI) {
   7362             RefPtrWillBeRawPtr<CSSFilterValue> referenceFilterValue = CSSFilterValue::create(CSSFilterValue::ReferenceFilterOperation);
   7363             list->append(referenceFilterValue);
   7364             referenceFilterValue->append(CSSSVGDocumentValue::create(value->string));
   7365         } else {
   7366             const CSSParserString name = value->function->name;
   7367             unsigned maximumArgumentCount = 1;
   7368 
   7369             filterInfoForName(name, filterType, maximumArgumentCount);
   7370 
   7371             if (filterType == CSSFilterValue::UnknownFilterOperation)
   7372                 return nullptr;
   7373 
   7374             CSSParserValueList* args = value->function->args.get();
   7375             if (!args)
   7376                 return nullptr;
   7377 
   7378             RefPtrWillBeRawPtr<CSSFilterValue> filterValue = parseBuiltinFilterArguments(args, filterType);
   7379             if (!filterValue)
   7380                 return nullptr;
   7381 
   7382             list->append(filterValue);
   7383         }
   7384     }
   7385 
   7386     return list.release();
   7387 }
   7388 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransformOrigin()
   7389 {
   7390     CSSParserValue* value = m_valueList->current();
   7391     CSSValueID id = value->id;
   7392     RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
   7393     RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
   7394     RefPtrWillBeRawPtr<CSSValue> zValue = nullptr;
   7395     if (id == CSSValueLeft || id == CSSValueRight) {
   7396         xValue = cssValuePool().createIdentifierValue(id);
   7397     } else if (id == CSSValueTop || id == CSSValueBottom) {
   7398         yValue = cssValuePool().createIdentifierValue(id);
   7399     } else if (id == CSSValueCenter) {
   7400         // Unresolved as to whether this is X or Y.
   7401     } else if (validUnit(value, FPercent | FLength)) {
   7402         xValue = createPrimitiveNumericValue(value);
   7403     } else {
   7404         return nullptr;
   7405     }
   7406 
   7407     if ((value = m_valueList->next())) {
   7408         id = value->id;
   7409         if (!xValue && (id == CSSValueLeft || id == CSSValueRight)) {
   7410             xValue = cssValuePool().createIdentifierValue(id);
   7411         } else if (!yValue && (id == CSSValueTop || id == CSSValueBottom)) {
   7412             yValue = cssValuePool().createIdentifierValue(id);
   7413         } else if (id == CSSValueCenter) {
   7414             // Resolved below.
   7415         } else if (!yValue && validUnit(value, FPercent | FLength)) {
   7416             yValue = createPrimitiveNumericValue(value);
   7417         } else {
   7418             return nullptr;
   7419         }
   7420 
   7421         // If X or Y have not been resolved, they must be center.
   7422         if (!xValue)
   7423             xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
   7424         if (!yValue)
   7425             yValue = cssValuePool().createIdentifierValue(CSSValueCenter);
   7426 
   7427         if ((value = m_valueList->next())) {
   7428             if (!validUnit(value, FLength))
   7429                 return nullptr;
   7430             zValue = createPrimitiveNumericValue(value);
   7431 
   7432             if ((value = m_valueList->next()))
   7433                 return nullptr;
   7434         }
   7435     } else if (!xValue) {
   7436         if (yValue) {
   7437             xValue = cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
   7438         } else {
   7439             xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
   7440         }
   7441     }
   7442 
   7443     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   7444     list->append(xValue.release());
   7445     if (yValue)
   7446         list->append(yValue.release());
   7447     if (zValue)
   7448         list->append(zValue.release());
   7449     return list.release();
   7450 }
   7451 
   7452 bool CSSPropertyParser::parseWebkitTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtrWillBeRawPtr<CSSValue>& value, RefPtrWillBeRawPtr<CSSValue>& value2, RefPtrWillBeRawPtr<CSSValue>& value3)
   7453 {
   7454     propId1 = propId;
   7455     propId2 = propId;
   7456     propId3 = propId;
   7457     if (propId == CSSPropertyWebkitTransformOrigin) {
   7458         propId1 = CSSPropertyWebkitTransformOriginX;
   7459         propId2 = CSSPropertyWebkitTransformOriginY;
   7460         propId3 = CSSPropertyWebkitTransformOriginZ;
   7461     }
   7462 
   7463     switch (propId) {
   7464         case CSSPropertyWebkitTransformOrigin:
   7465             if (!parseWebkitTransformOriginShorthand(value, value2, value3))
   7466                 return false;
   7467             // parseWebkitTransformOriginShorthand advances the m_valueList pointer
   7468             break;
   7469         case CSSPropertyWebkitTransformOriginX: {
   7470             value = parseFillPositionX(m_valueList.get());
   7471             if (value)
   7472                 m_valueList->next();
   7473             break;
   7474         }
   7475         case CSSPropertyWebkitTransformOriginY: {
   7476             value = parseFillPositionY(m_valueList.get());
   7477             if (value)
   7478                 m_valueList->next();
   7479             break;
   7480         }
   7481         case CSSPropertyWebkitTransformOriginZ: {
   7482             if (validUnit(m_valueList->current(), FLength))
   7483                 value = createPrimitiveNumericValue(m_valueList->current());
   7484             if (value)
   7485                 m_valueList->next();
   7486             break;
   7487         }
   7488         default:
   7489             ASSERT_NOT_REACHED();
   7490             return false;
   7491     }
   7492 
   7493     return value;
   7494 }
   7495 
   7496 bool CSSPropertyParser::parseWebkitPerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtrWillBeRawPtr<CSSValue>& value, RefPtrWillBeRawPtr<CSSValue>& value2)
   7497 {
   7498     propId1 = propId;
   7499     propId2 = propId;
   7500     if (propId == CSSPropertyWebkitPerspectiveOrigin) {
   7501         propId1 = CSSPropertyWebkitPerspectiveOriginX;
   7502         propId2 = CSSPropertyWebkitPerspectiveOriginY;
   7503     }
   7504 
   7505     switch (propId) {
   7506         case CSSPropertyWebkitPerspectiveOrigin:
   7507             if (m_valueList->size() > 2)
   7508                 return false;
   7509             parse2ValuesFillPosition(m_valueList.get(), value, value2);
   7510             break;
   7511         case CSSPropertyWebkitPerspectiveOriginX: {
   7512             value = parseFillPositionX(m_valueList.get());
   7513             if (value)
   7514                 m_valueList->next();
   7515             break;
   7516         }
   7517         case CSSPropertyWebkitPerspectiveOriginY: {
   7518             value = parseFillPositionY(m_valueList.get());
   7519             if (value)
   7520                 m_valueList->next();
   7521             break;
   7522         }
   7523         default:
   7524             ASSERT_NOT_REACHED();
   7525             return false;
   7526     }
   7527 
   7528     return value;
   7529 }
   7530 
   7531 bool CSSPropertyParser::parseTouchAction(bool important)
   7532 {
   7533     if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
   7534         return false;
   7535 
   7536     CSSParserValue* value = m_valueList->current();
   7537     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   7538     if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value->id == CSSValueNone || value->id == CSSValueManipulation)) {
   7539         list->append(cssValuePool().createIdentifierValue(value->id));
   7540         addProperty(CSSPropertyTouchAction, list.release(), important);
   7541         m_valueList->next();
   7542         return true;
   7543     }
   7544 
   7545     bool isValid = true;
   7546     while (isValid && value) {
   7547         switch (value->id) {
   7548         case CSSValuePanX:
   7549         case CSSValuePanY: {
   7550             RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentifierValue(value->id);
   7551             if (list->hasValue(panValue.get())) {
   7552                 isValid = false;
   7553                 break;
   7554             }
   7555             list->append(panValue.release());
   7556             break;
   7557         }
   7558         default:
   7559             isValid = false;
   7560             break;
   7561         }
   7562         if (isValid)
   7563             value = m_valueList->next();
   7564     }
   7565 
   7566     if (list->length() && isValid) {
   7567         addProperty(CSSPropertyTouchAction, list.release(), important);
   7568         return true;
   7569     }
   7570 
   7571     return false;
   7572 }
   7573 
   7574 void CSSPropertyParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important)
   7575 {
   7576     // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set.
   7577     if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) {
   7578         for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
   7579             if (m_parsedProperties[i].id() == CSSPropertyTextDecorationLine)
   7580                 return;
   7581         }
   7582     }
   7583     addProperty(propId, value, important);
   7584 }
   7585 
   7586 bool CSSPropertyParser::parseTextDecoration(CSSPropertyID propId, bool important)
   7587 {
   7588     if (propId == CSSPropertyTextDecorationLine
   7589         && !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
   7590         return false;
   7591 
   7592     CSSParserValue* value = m_valueList->current();
   7593     if (value && value->id == CSSValueNone) {
   7594         addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important);
   7595         m_valueList->next();
   7596         return true;
   7597     }
   7598 
   7599     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   7600     bool isValid = true;
   7601     while (isValid && value) {
   7602         switch (value->id) {
   7603         case CSSValueUnderline:
   7604         case CSSValueOverline:
   7605         case CSSValueLineThrough:
   7606         case CSSValueBlink:
   7607             list->append(cssValuePool().createIdentifierValue(value->id));
   7608             break;
   7609         default:
   7610             isValid = false;
   7611             break;
   7612         }
   7613         if (isValid)
   7614             value = m_valueList->next();
   7615     }
   7616 
   7617     // Values are either valid or in shorthand scope.
   7618     if (list->length() && (isValid || inShorthand())) {
   7619         addTextDecorationProperty(propId, list.release(), important);
   7620         return true;
   7621     }
   7622 
   7623     return false;
   7624 }
   7625 
   7626 bool CSSPropertyParser::parseTextUnderlinePosition(bool important)
   7627 {
   7628     // The text-underline-position property has syntax "auto | [ under || [ left | right ] ]".
   7629     // However, values 'left' and 'right' are not implemented yet, so we will parse syntax
   7630     // "auto | under" for now.
   7631     CSSParserValue* value = m_valueList->current();
   7632     switch (value->id) {
   7633     case CSSValueAuto:
   7634     case CSSValueUnder:
   7635         if (m_valueList->next())
   7636             return false;
   7637         addProperty(CSSPropertyTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important);
   7638         return true;
   7639     default:
   7640         return false;
   7641     }
   7642 }
   7643 
   7644 bool CSSPropertyParser::parseTextEmphasisStyle(bool important)
   7645 {
   7646     unsigned valueListSize = m_valueList->size();
   7647 
   7648     RefPtrWillBeRawPtr<CSSPrimitiveValue> fill = nullptr;
   7649     RefPtrWillBeRawPtr<CSSPrimitiveValue> shape = nullptr;
   7650 
   7651     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   7652         if (value->unit == CSSPrimitiveValue::CSS_STRING) {
   7653             if (fill || shape || (valueListSize != 1 && !inShorthand()))
   7654                 return false;
   7655             addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important);
   7656             m_valueList->next();
   7657             return true;
   7658         }
   7659 
   7660         if (value->id == CSSValueNone) {
   7661             if (fill || shape || (valueListSize != 1 && !inShorthand()))
   7662                 return false;
   7663             addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important);
   7664             m_valueList->next();
   7665             return true;
   7666         }
   7667 
   7668         if (value->id == CSSValueOpen || value->id == CSSValueFilled) {
   7669             if (fill)
   7670                 return false;
   7671             fill = cssValuePool().createIdentifierValue(value->id);
   7672         } else if (value->id == CSSValueDot || value->id == CSSValueCircle || value->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) {
   7673             if (shape)
   7674                 return false;
   7675             shape = cssValuePool().createIdentifierValue(value->id);
   7676         } else if (!inShorthand())
   7677             return false;
   7678         else
   7679             break;
   7680     }
   7681 
   7682     if (fill && shape) {
   7683         RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
   7684         parsedValues->append(fill.release());
   7685         parsedValues->append(shape.release());
   7686         addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important);
   7687         return true;
   7688     }
   7689     if (fill) {
   7690         addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important);
   7691         return true;
   7692     }
   7693     if (shape) {
   7694         addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important);
   7695         return true;
   7696     }
   7697 
   7698     return false;
   7699 }
   7700 
   7701 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextIndent()
   7702 {
   7703     RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
   7704 
   7705     bool hasLengthOrPercentage = false;
   7706     bool hasEachLine = false;
   7707     bool hasHanging = false;
   7708 
   7709     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   7710         // <length> | <percentage> | inherit when RuntimeEnabledFeatures::css3TextEnabled() returns false
   7711         if (!hasLengthOrPercentage && validUnit(value, FLength | FPercent)) {
   7712             list->append(createPrimitiveNumericValue(value));
   7713             hasLengthOrPercentage = true;
   7714             continue;
   7715         }
   7716 
   7717         // [ <length> | <percentage> ] && hanging? && each-line? | inherit
   7718         // when RuntimeEnabledFeatures::css3TextEnabled() returns true
   7719         if (RuntimeEnabledFeatures::css3TextEnabled()) {
   7720             if (!hasEachLine && value->id == CSSValueEachLine) {
   7721                 list->append(cssValuePool().createIdentifierValue(CSSValueEachLine));
   7722                 hasEachLine = true;
   7723                 continue;
   7724             }
   7725             if (!hasHanging && value->id == CSSValueHanging) {
   7726                 list->append(cssValuePool().createIdentifierValue(CSSValueHanging));
   7727                 hasHanging = true;
   7728                 continue;
   7729             }
   7730         }
   7731         return nullptr;
   7732     }
   7733 
   7734     if (!hasLengthOrPercentage)
   7735         return nullptr;
   7736 
   7737     return list.release();
   7738 }
   7739 
   7740 bool CSSPropertyParser::parseLineBoxContain(bool important)
   7741 {
   7742     LineBoxContain lineBoxContain = LineBoxContainNone;
   7743 
   7744     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   7745         if (value->id == CSSValueBlock) {
   7746             if (lineBoxContain & LineBoxContainBlock)
   7747                 return false;
   7748             lineBoxContain |= LineBoxContainBlock;
   7749         } else if (value->id == CSSValueInline) {
   7750             if (lineBoxContain & LineBoxContainInline)
   7751                 return false;
   7752             lineBoxContain |= LineBoxContainInline;
   7753         } else if (value->id == CSSValueFont) {
   7754             if (lineBoxContain & LineBoxContainFont)
   7755                 return false;
   7756             lineBoxContain |= LineBoxContainFont;
   7757         } else if (value->id == CSSValueGlyphs) {
   7758             if (lineBoxContain & LineBoxContainGlyphs)
   7759                 return false;
   7760             lineBoxContain |= LineBoxContainGlyphs;
   7761         } else if (value->id == CSSValueReplaced) {
   7762             if (lineBoxContain & LineBoxContainReplaced)
   7763                 return false;
   7764             lineBoxContain |= LineBoxContainReplaced;
   7765         } else if (value->id == CSSValueInlineBox) {
   7766             if (lineBoxContain & LineBoxContainInlineBox)
   7767                 return false;
   7768             lineBoxContain |= LineBoxContainInlineBox;
   7769         } else
   7770             return false;
   7771     }
   7772 
   7773     if (!lineBoxContain)
   7774         return false;
   7775 
   7776     addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important);
   7777     return true;
   7778 }
   7779 
   7780 bool CSSPropertyParser::parseFontFeatureTag(CSSValueList* settings)
   7781 {
   7782     // Feature tag name consists of 4-letter characters.
   7783     static const unsigned tagNameLength = 4;
   7784 
   7785     CSSParserValue* value = m_valueList->current();
   7786     // Feature tag name comes first
   7787     if (value->unit != CSSPrimitiveValue::CSS_STRING)
   7788         return false;
   7789     if (value->string.length() != tagNameLength)
   7790         return false;
   7791     for (unsigned i = 0; i < tagNameLength; ++i) {
   7792         // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
   7793         UChar character = value->string[i];
   7794         if (character < 0x20 || character > 0x7E)
   7795             return false;
   7796     }
   7797 
   7798     AtomicString tag = value->string;
   7799     int tagValue = 1;
   7800     // Feature tag values could follow: <integer> | on | off
   7801     value = m_valueList->next();
   7802     if (value) {
   7803         if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
   7804             tagValue = clampToInteger(value->fValue);
   7805             if (tagValue < 0)
   7806                 return false;
   7807             m_valueList->next();
   7808         } else if (value->id == CSSValueOn || value->id == CSSValueOff) {
   7809             tagValue = value->id == CSSValueOn;
   7810             m_valueList->next();
   7811         }
   7812     }
   7813     settings->append(CSSFontFeatureValue::create(tag, tagValue));
   7814     return true;
   7815 }
   7816 
   7817 bool CSSPropertyParser::parseFontFeatureSettings(bool important)
   7818 {
   7819     if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) {
   7820         RefPtrWillBeRawPtr<CSSPrimitiveValue> normalValue = cssValuePool().createIdentifierValue(CSSValueNormal);
   7821         m_valueList->next();
   7822         addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important);
   7823         return true;
   7824     }
   7825 
   7826     RefPtrWillBeRawPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
   7827     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   7828         if (!parseFontFeatureTag(settings.get()))
   7829             return false;
   7830 
   7831         // If the list isn't parsed fully, the current value should be comma.
   7832         value = m_valueList->current();
   7833         if (value && !isComma(value))
   7834             return false;
   7835     }
   7836     if (settings->length()) {
   7837         addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important);
   7838         return true;
   7839     }
   7840     return false;
   7841 }
   7842 
   7843 bool CSSPropertyParser::parseFontVariantLigatures(bool important)
   7844 {
   7845     RefPtrWillBeRawPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
   7846     bool sawCommonLigaturesValue = false;
   7847     bool sawDiscretionaryLigaturesValue = false;
   7848     bool sawHistoricalLigaturesValue = false;
   7849     bool sawContextualLigaturesValue = false;
   7850 
   7851     for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
   7852         if (value->unit != CSSPrimitiveValue::CSS_IDENT)
   7853             return false;
   7854 
   7855         switch (value->id) {
   7856         case CSSValueNoCommonLigatures:
   7857         case CSSValueCommonLigatures:
   7858             if (sawCommonLigaturesValue)
   7859                 return false;
   7860             sawCommonLigaturesValue = true;
   7861             ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
   7862             break;
   7863         case CSSValueNoDiscretionaryLigatures:
   7864         case CSSValueDiscretionaryLigatures:
   7865             if (sawDiscretionaryLigaturesValue)
   7866                 return false;
   7867             sawDiscretionaryLigaturesValue = true;
   7868             ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
   7869             break;
   7870         case CSSValueNoHistoricalLigatures:
   7871         case CSSValueHistoricalLigatures:
   7872             if (sawHistoricalLigaturesValue)
   7873                 return false;
   7874             sawHistoricalLigaturesValue = true;
   7875             ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
   7876             break;
   7877         case CSSValueNoContextual:
   7878         case CSSValueContextual:
   7879             if (sawContextualLigaturesValue)
   7880                 return false;
   7881             sawContextualLigaturesValue = true;
   7882             ligatureValues->append(cssValuePool().createIdentifierValue(value->id));
   7883             break;
   7884         default:
   7885             return false;
   7886         }
   7887     }
   7888 
   7889     if (!ligatureValues->length())
   7890         return false;
   7891 
   7892     addProperty(CSSPropertyFontVariantLigatures, ligatureValues.release(), important);
   7893     return true;
   7894 }
   7895 
   7896 bool CSSPropertyParser::parseCalculation(CSSParserValue* value, ValueRange range)
   7897 {
   7898     ASSERT(isCalculation(value));
   7899 
   7900     CSSParserValueList* args = value->function->args.get();
   7901     if (!args || !args->size())
   7902         return false;
   7903 
   7904     ASSERT(!m_parsedCalculation);
   7905     m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
   7906 
   7907     if (!m_parsedCalculation)
   7908         return false;
   7909 
   7910     return true;
   7911 }
   7912 
   7913 bool CSSPropertyParser::parseViewportProperty(CSSPropertyID propId, bool important)
   7914 {
   7915     ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
   7916 
   7917     CSSParserValue* value = m_valueList->current();
   7918     if (!value)
   7919         return false;
   7920 
   7921     CSSValueID id = value->id;
   7922     bool validPrimitive = false;
   7923 
   7924     switch (propId) {
   7925     case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage>
   7926     case CSSPropertyMaxWidth:
   7927     case CSSPropertyMinHeight:
   7928     case CSSPropertyMaxHeight:
   7929         if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
   7930             validPrimitive = true;
   7931         else
   7932             validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
   7933         break;
   7934     case CSSPropertyWidth: // shorthand
   7935         return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important);
   7936     case CSSPropertyHeight:
   7937         return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important);
   7938     case CSSPropertyMinZoom: // auto | <number> | <percentage>
   7939     case CSSPropertyMaxZoom:
   7940     case CSSPropertyZoom:
   7941         if (id == CSSValueAuto)
   7942             validPrimitive = true;
   7943         else
   7944             validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg));
   7945         break;
   7946     case CSSPropertyUserZoom: // zoom | fixed
   7947         if (id == CSSValueZoom || id == CSSValueFixed)
   7948             validPrimitive = true;
   7949         break;
   7950     case CSSPropertyOrientation: // auto | portrait | landscape
   7951         if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape)
   7952             validPrimitive = true;
   7953     default:
   7954         break;
   7955     }
   7956 
   7957     RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
   7958     if (validPrimitive) {
   7959         parsedValue = parseValidPrimitive(id, value);
   7960         m_valueList->next();
   7961     }
   7962 
   7963     if (parsedValue) {
   7964         if (!m_valueList->current() || inShorthand()) {
   7965             addProperty(propId, parsedValue.release(), important);
   7966             return true;
   7967         }
   7968     }
   7969 
   7970     return false;
   7971 }
   7972 
   7973 bool CSSPropertyParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important)
   7974 {
   7975     ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
   7976     unsigned numValues = m_valueList->size();
   7977 
   7978     if (numValues > 2)
   7979         return false;
   7980 
   7981     ShorthandScope scope(this, propId);
   7982 
   7983     if (!parseViewportProperty(first, important))
   7984         return false;
   7985 
   7986     // If just one value is supplied, the second value
   7987     // is implicitly initialized with the first value.
   7988     if (numValues == 1)
   7989         m_valueList->previous();
   7990 
   7991     return parseViewportProperty(second, important);
   7992 }
   7993 
   7994 template <typename CharacterType>
   7995 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
   7996 {
   7997     char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character
   7998 
   7999     for (unsigned i = 0; i != length; ++i) {
   8000         CharacterType c = propertyName[i];
   8001         if (c == 0 || c >= 0x7F)
   8002             return CSSPropertyInvalid; // illegal character
   8003         buffer[i] = toASCIILower(c);
   8004     }
   8005     buffer[length] = '\0';
   8006 
   8007     const char* name = buffer;
   8008     const Property* hashTableEntry = findProperty(name, length);
   8009     return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
   8010 }
   8011 
   8012 CSSPropertyID cssPropertyID(const String& string)
   8013 {
   8014     unsigned length = string.length();
   8015 
   8016     if (!length)
   8017         return CSSPropertyInvalid;
   8018     if (length > maxCSSPropertyNameLength)
   8019         return CSSPropertyInvalid;
   8020 
   8021     return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
   8022 }
   8023 
   8024 CSSPropertyID cssPropertyID(const CSSParserString& string)
   8025 {
   8026     unsigned length = string.length();
   8027 
   8028     if (!length)
   8029         return CSSPropertyInvalid;
   8030     if (length > maxCSSPropertyNameLength)
   8031         return CSSPropertyInvalid;
   8032 
   8033     return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
   8034 }
   8035 
   8036 template <typename CharacterType>
   8037 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
   8038 {
   8039     char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character
   8040 
   8041     for (unsigned i = 0; i != length; ++i) {
   8042         CharacterType c = valueKeyword[i];
   8043         if (c == 0 || c >= 0x7F)
   8044             return CSSValueInvalid; // illegal character
   8045         buffer[i] = WTF::toASCIILower(c);
   8046     }
   8047     buffer[length] = '\0';
   8048 
   8049     const Value* hashTableEntry = findValue(buffer, length);
   8050     return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
   8051 }
   8052 
   8053 CSSValueID cssValueKeywordID(const CSSParserString& string)
   8054 {
   8055     unsigned length = string.length();
   8056     if (!length)
   8057         return CSSValueInvalid;
   8058     if (length > maxCSSValueKeywordLength)
   8059         return CSSValueInvalid;
   8060 
   8061     return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
   8062 }
   8063 
   8064 bool isValidNthToken(const CSSParserString& token)
   8065 {
   8066     // The tokenizer checks for the construct of an+b.
   8067     // However, since the {ident} rule precedes the {nth} rule, some of those
   8068     // tokens are identified as string literal. Furthermore we need to accept
   8069     // "odd" and "even" which does not match to an+b.
   8070     return equalIgnoringCase(token, "odd") || equalIgnoringCase(token, "even")
   8071         || equalIgnoringCase(token, "n") || equalIgnoringCase(token, "-n");
   8072 }
   8073 
   8074 bool CSSPropertyParser::isSystemColor(int id)
   8075 {
   8076     return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu;
   8077 }
   8078 
   8079 bool CSSPropertyParser::parseSVGValue(CSSPropertyID propId, bool important)
   8080 {
   8081     CSSParserValue* value = m_valueList->current();
   8082     if (!value)
   8083         return false;
   8084 
   8085     CSSValueID id = value->id;
   8086 
   8087     bool validPrimitive = false;
   8088     RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
   8089 
   8090     switch (propId) {
   8091     /* The comment to the right defines all valid value of these
   8092      * properties as defined in SVG 1.1, Appendix N. Property index */
   8093     case CSSPropertyAlignmentBaseline:
   8094     // auto | baseline | before-edge | text-before-edge | middle |
   8095     // central | after-edge | text-after-edge | ideographic | alphabetic |
   8096     // hanging | mathematical | inherit
   8097         if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle
   8098             || (id >= CSSValueBeforeEdge && id <= CSSValueMathematical))
   8099             validPrimitive = true;
   8100         break;
   8101 
   8102     case CSSPropertyBaselineShift:
   8103     // baseline | super | sub | <percentage> | <length> | inherit
   8104         if (id == CSSValueBaseline || id == CSSValueSub
   8105             || id >= CSSValueSuper)
   8106             validPrimitive = true;
   8107         else
   8108             validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
   8109         break;
   8110 
   8111     case CSSPropertyDominantBaseline:
   8112     // auto | use-script | no-change | reset-size | ideographic |
   8113     // alphabetic | hanging | mathematical | central | middle |
   8114     // text-after-edge | text-before-edge | inherit
   8115         if (id == CSSValueAuto || id == CSSValueMiddle
   8116             || (id >= CSSValueUseScript && id <= CSSValueResetSize)
   8117             || (id >= CSSValueCentral && id <= CSSValueMathematical))
   8118             validPrimitive = true;
   8119         break;
   8120 
   8121     case CSSPropertyEnableBackground:
   8122     // accumulate | new [x] [y] [width] [height] | inherit
   8123         if (id == CSSValueAccumulate) // TODO : new
   8124             validPrimitive = true;
   8125         break;
   8126 
   8127     case CSSPropertyMarkerStart:
   8128     case CSSPropertyMarkerMid:
   8129     case CSSPropertyMarkerEnd:
   8130     case CSSPropertyMask:
   8131         if (id == CSSValueNone) {
   8132             validPrimitive = true;
   8133         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
   8134             parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
   8135             if (parsedValue)
   8136                 m_valueList->next();
   8137         }
   8138         break;
   8139 
   8140     case CSSPropertyClipRule: // nonzero | evenodd | inherit
   8141     case CSSPropertyFillRule:
   8142         if (id == CSSValueNonzero || id == CSSValueEvenodd)
   8143             validPrimitive = true;
   8144         break;
   8145 
   8146     case CSSPropertyStrokeMiterlimit: // <miterlimit> | inherit
   8147         validPrimitive = validUnit(value, FNumber | FNonNeg, SVGAttributeMode);
   8148         break;
   8149 
   8150     case CSSPropertyStrokeLinejoin: // miter | round | bevel | inherit
   8151         if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel)
   8152             validPrimitive = true;
   8153         break;
   8154 
   8155     case CSSPropertyStrokeLinecap: // butt | round | square | inherit
   8156         if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare)
   8157             validPrimitive = true;
   8158         break;
   8159 
   8160     case CSSPropertyStrokeOpacity: // <opacity-value> | inherit
   8161     case CSSPropertyFillOpacity:
   8162     case CSSPropertyStopOpacity:
   8163     case CSSPropertyFloodOpacity:
   8164         validPrimitive = (!id && validUnit(value, FNumber | FPercent, SVGAttributeMode));
   8165         break;
   8166 
   8167     case CSSPropertyShapeRendering:
   8168     // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
   8169         if (id == CSSValueAuto || id == CSSValueOptimizespeed
   8170             || id == CSSValueCrispedges || id == CSSValueGeometricprecision)
   8171             validPrimitive = true;
   8172         break;
   8173 
   8174     case CSSPropertyImageRendering: // auto | optimizeSpeed |
   8175     case CSSPropertyColorRendering: // optimizeQuality | inherit
   8176         if (id == CSSValueAuto || id == CSSValueOptimizespeed
   8177             || id == CSSValueOptimizequality)
   8178             validPrimitive = true;
   8179         break;
   8180 
   8181     case CSSPropertyBufferedRendering: // auto | dynamic | static
   8182         if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic)
   8183             validPrimitive = true;
   8184         break;
   8185 
   8186     case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit
   8187     case CSSPropertyColorInterpolationFilters:
   8188         if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
   8189             validPrimitive = true;
   8190         break;
   8191 
   8192     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
   8193      * correctly and allows optimization in applyRule(..)
   8194      */
   8195 
   8196     case CSSPropertyTextAnchor: // start | middle | end | inherit
   8197         if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
   8198             validPrimitive = true;
   8199         break;
   8200 
   8201     case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
   8202         if (id == CSSValueAuto) {
   8203             validPrimitive = true;
   8204             break;
   8205         }
   8206     /* fallthrough intentional */
   8207     case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
   8208         if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
   8209             parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
   8210 
   8211             if (parsedValue)
   8212                 m_valueList->next();
   8213         }
   8214         break;
   8215 
   8216     case CSSPropertyFill: // <paint> | inherit
   8217     case CSSPropertyStroke: // <paint> | inherit
   8218         {
   8219             if (id == CSSValueNone) {
   8220                 parsedValue = SVGPaint::createNone();
   8221             } else if (id == CSSValueCurrentcolor) {
   8222                 parsedValue = SVGPaint::createCurrentColor();
   8223             } else if (isSystemColor(id)) {
   8224                 parsedValue = SVGPaint::createColor(RenderTheme::theme().systemColor(id));
   8225             } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
   8226                 RGBA32 c = Color::transparent;
   8227                 if (m_valueList->next()) {
   8228                     if (parseColorFromValue(m_valueList->current(), c))
   8229                         parsedValue = SVGPaint::createURIAndColor(value->string, c);
   8230                     else if (m_valueList->current()->id == CSSValueNone)
   8231                         parsedValue = SVGPaint::createURIAndNone(value->string);
   8232                     else if (m_valueList->current()->id == CSSValueCurrentcolor)
   8233                         parsedValue = SVGPaint::createURIAndCurrentColor(value->string);
   8234                 }
   8235                 if (!parsedValue)
   8236                     parsedValue = SVGPaint::createURI(value->string);
   8237             } else {
   8238                 parsedValue = parseSVGPaint();
   8239             }
   8240 
   8241             if (parsedValue)
   8242                 m_valueList->next();
   8243         }
   8244         break;
   8245 
   8246     case CSSPropertyStopColor: // TODO : icccolor
   8247     case CSSPropertyFloodColor:
   8248     case CSSPropertyLightingColor:
   8249         if (isSystemColor(id)) {
   8250             parsedValue = cssValuePool().createColorValue(RenderTheme::theme().systemColor(id).rgb());
   8251         } else if ((id >= CSSValueAqua && id <= CSSValueTransparent)
   8252             || (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) || id == CSSValueGrey) {
   8253             StyleColor styleColor = SVGPaint::colorFromRGBColorString(value->string);
   8254             ASSERT(!styleColor.isCurrentColor());
   8255             parsedValue = cssValuePool().createColorValue(styleColor.color().rgb());
   8256         } else if (id == CSSValueCurrentcolor) {
   8257             parsedValue = cssValuePool().createIdentifierValue(id);
   8258         } else { // TODO : svgcolor (iccColor)
   8259             parsedValue = parseColor();
   8260         }
   8261 
   8262         if (parsedValue)
   8263             m_valueList->next();
   8264 
   8265         break;
   8266 
   8267     case CSSPropertyPaintOrder:
   8268         if (m_valueList->size() == 1 && id == CSSValueNormal)
   8269             validPrimitive = true;
   8270         else if ((parsedValue = parsePaintOrder()))
   8271             m_valueList->next();
   8272         break;
   8273 
   8274     case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit
   8275         if (id == CSSValueNone || id == CSSValueNonScalingStroke)
   8276             validPrimitive = true;
   8277         break;
   8278 
   8279     case CSSPropertyWritingMode:
   8280     // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
   8281         if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb)
   8282             validPrimitive = true;
   8283         break;
   8284 
   8285     case CSSPropertyStrokeWidth: // <length> | inherit
   8286     case CSSPropertyStrokeDashoffset:
   8287         validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
   8288         break;
   8289     case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit
   8290         if (id == CSSValueNone)
   8291             validPrimitive = true;
   8292         else
   8293             parsedValue = parseSVGStrokeDasharray();
   8294 
   8295         break;
   8296 
   8297     case CSSPropertyClipPath: // <uri> | none | inherit
   8298     case CSSPropertyFilter:
   8299         if (id == CSSValueNone) {
   8300             validPrimitive = true;
   8301         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
   8302             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitType) value->unit);
   8303             if (parsedValue)
   8304                 m_valueList->next();
   8305         }
   8306         break;
   8307     case CSSPropertyMaskType: // luminance | alpha | inherit
   8308         if (id == CSSValueLuminance || id == CSSValueAlpha)
   8309             validPrimitive = true;
   8310         break;
   8311 
   8312     /* shorthand properties */
   8313     case CSSPropertyMarker: {
   8314         ShorthandScope scope(this, propId);
   8315         CSSPropertyParser::ImplicitScope implicitScope(this, PropertyImplicit);
   8316         if (!parseValue(CSSPropertyMarkerStart, important))
   8317             return false;
   8318         if (m_valueList->current()) {
   8319             rollbackLastProperties(1);
   8320             return false;
   8321         }
   8322         CSSValue* value = m_parsedProperties.last().value();
   8323         addProperty(CSSPropertyMarkerMid, value, important);
   8324         addProperty(CSSPropertyMarkerEnd, value, important);
   8325         return true;
   8326     }
   8327     default:
   8328         // If you crash here, it's because you added a css property and are not handling it
   8329         // in either this switch statement or the one in CSSPropertyParser::parseValue
   8330         ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
   8331         return false;
   8332     }
   8333 
   8334     if (validPrimitive) {
   8335         if (id)
   8336             parsedValue = CSSPrimitiveValue::createIdentifier(id);
   8337         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
   8338             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitType) value->unit);
   8339         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
   8340             parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitType) value->unit);
   8341         else if (value->unit >= CSSParserValue::Q_EMS)
   8342             parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
   8343         if (isCalculation(value)) {
   8344             // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie
   8345             // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release());
   8346             m_parsedCalculation.release();
   8347             parsedValue = nullptr;
   8348         }
   8349         m_valueList->next();
   8350     }
   8351     if (!parsedValue || (m_valueList->current() && !inShorthand()))
   8352         return false;
   8353 
   8354     addProperty(propId, parsedValue.release(), important);
   8355     return true;
   8356 }
   8357 
   8358 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGStrokeDasharray()
   8359 {
   8360     RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
   8361     CSSParserValue* value = m_valueList->current();
   8362     bool validPrimitive = true;
   8363     while (value) {
   8364         validPrimitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode);
   8365         if (!validPrimitive)
   8366             break;
   8367         if (value->id)
   8368             ret->append(CSSPrimitiveValue::createIdentifier(value->id));
   8369         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
   8370             ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitType) value->unit));
   8371         value = m_valueList->next();
   8372         if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
   8373             value = m_valueList->next();
   8374     }
   8375     if (!validPrimitive)
   8376         return nullptr;
   8377     return ret.release();
   8378 }
   8379 
   8380 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGPaint()
   8381 {
   8382     RGBA32 c = Color::transparent;
   8383     if (!parseColorFromValue(m_valueList->current(), c))
   8384         return SVGPaint::createUnknown();
   8385     return SVGPaint::createColor(Color(c));
   8386 }
   8387 
   8388 // normal | [ fill || stroke || markers ]
   8389 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parsePaintOrder() const
   8390 {
   8391     if (m_valueList->size() > 3)
   8392         return nullptr;
   8393 
   8394     CSSParserValue* value = m_valueList->current();
   8395     if (!value)
   8396         return nullptr;
   8397 
   8398     RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
   8399 
   8400     // The default paint-order is: Fill, Stroke, Markers.
   8401     bool seenFill = false, seenStroke = false, seenMarkers = false;
   8402 
   8403     do {
   8404         switch (value->id) {
   8405         case CSSValueNormal:
   8406             // normal inside [fill || stroke || markers] not valid
   8407             return nullptr;
   8408         case CSSValueFill:
   8409             if (seenFill)
   8410                 return nullptr;
   8411 
   8412             seenFill = true;
   8413             break;
   8414         case CSSValueStroke:
   8415             if (seenStroke)
   8416                 return nullptr;
   8417 
   8418             seenStroke = true;
   8419             break;
   8420         case CSSValueMarkers:
   8421             if (seenMarkers)
   8422                 return nullptr;
   8423 
   8424             seenMarkers = true;
   8425             break;
   8426         default:
   8427             return nullptr;
   8428         }
   8429 
   8430         parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
   8431     } while ((value = m_valueList->next()));
   8432 
   8433     // fill out the rest of the paint order
   8434     if (!seenFill)
   8435         parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueFill));
   8436     if (!seenStroke)
   8437         parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke));
   8438     if (!seenMarkers)
   8439         parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers));
   8440 
   8441     return parsedValues.release();
   8442 }
   8443 
   8444 } // namespace WebCore
   8445