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