1/*
2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@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@nickshanks.com>
6 * Copyright (C) 2008 Eric Seidel <eric@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
84namespace blink {
85
86static const double MAX_SCALE = 1000000;
87
88template <unsigned N>
89static 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
98template <unsigned N>
99static 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
105static 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
110CSSPropertyParser::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
125bool 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
133void 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
152void 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
176void 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
183KURL CSSPropertyParser::completeURL(const String& url) const
184{
185    return m_context.completeURL(url);
186}
187
188bool 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
249inline 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
255bool 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
320PassRefPtrWillBeRawPtr<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
334inline 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
340inline 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
347static inline bool isComma(CSSParserValue* value)
348{
349    return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
350}
351
352static bool consumeComma(CSSParserValueList* valueList)
353{
354    if (!isComma(valueList->current()))
355        return false;
356    valueList->next();
357    return true;
358}
359
360static inline bool isForwardSlashOperator(CSSParserValue* value)
361{
362    ASSERT(value);
363    return value->unit == CSSParserValue::Operator && value->iValue == '/';
364}
365
366static 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
384bool 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
392inline 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
414void 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
430bool 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
1532void 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
1549static 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
1559const int cMaxFillProperties = 9;
1560
1561bool 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
1714static 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
1729bool 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
1790bool 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
1846PassRefPtrWillBeRawPtr<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
1859PassRefPtrWillBeRawPtr<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
1871bool 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
1926bool 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
1973bool 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>
2032bool 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] ]
2054bool 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
2084CSSPropertyParser::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
2127PassRefPtrWillBeRawPtr<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
2146bool 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
2211PassRefPtrWillBeRawPtr<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
2234PassRefPtrWillBeRawPtr<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
2243bool 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
2266PassRefPtrWillBeRawPtr<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
2282PassRefPtrWillBeRawPtr<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
2298PassRefPtrWillBeRawPtr<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
2347static 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
2358static bool isFillPositionKeyword(CSSValueID value)
2359{
2360    return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter;
2361}
2362
2363void 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}
2411void 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
2502inline bool CSSPropertyParser::isPotentialPositionValue(CSSParserValue* value)
2503{
2504    return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue);
2505}
2506
2507void 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
2570void 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
2612void 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
2653PassRefPtrWillBeRawPtr<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
2701bool 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
2888PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDelay()
2889{
2890    CSSParserValue* value = m_valueList->current();
2891    if (validUnit(value, FTime))
2892        return createPrimitiveNumericValue(value);
2893    return nullptr;
2894}
2895
2896PassRefPtrWillBeRawPtr<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
2904PassRefPtrWillBeRawPtr<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
2912PassRefPtrWillBeRawPtr<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
2920PassRefPtrWillBeRawPtr<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
2930PassRefPtrWillBeRawPtr<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
2943PassRefPtrWillBeRawPtr<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
2951PassRefPtrWillBeRawPtr<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
2973bool 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
2997bool 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
3010PassRefPtrWillBeRawPtr<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
3091PassRefPtrWillBeRawPtr<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
3147PassRefPtrWillBeRawPtr<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
3168static inline bool isCSSWideKeyword(CSSParserValue& value)
3169{
3170    return value.id == CSSValueInitial || value.id == CSSValueInherit || value.id == CSSValueDefault;
3171}
3172
3173static 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').
3180bool 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
3206PassRefPtrWillBeRawPtr<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
3262static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* value)
3263{
3264    if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString())
3265        return value;
3266
3267    return cssValuePool().createIdentifierValue(CSSValueAuto);
3268}
3269
3270bool 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
3300bool 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
3360bool 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
3414bool 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
3474bool 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
3514bool 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
3529bool 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
3558PassRefPtrWillBeRawPtr<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
3602bool 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
3654PassRefPtrWillBeRawPtr<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
3687PassRefPtrWillBeRawPtr<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
3708bool 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
3771PassRefPtrWillBeRawPtr<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
3789PassRefPtrWillBeRawPtr<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
3833PassRefPtrWillBeRawPtr<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
3885bool 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
3926static 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.
3940PassRefPtrWillBeRawPtr<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
4008PassRefPtrWillBeRawPtr<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
4058static bool isBaselinePositionKeyword(CSSValueID id)
4059{
4060    return id == CSSValueBaseline || id == CSSValueLastBaseline;
4061}
4062
4063static 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
4070bool 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
4095bool 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
4148PassRefPtrWillBeRawPtr<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
4159PassRefPtrWillBeRawPtr<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
4205PassRefPtrWillBeRawPtr<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
4253PassRefPtrWillBeRawPtr<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
4300static 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
4315PassRefPtrWillBeRawPtr<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
4335PassRefPtrWillBeRawPtr<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
4371PassRefPtrWillBeRawPtr<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'
4399bool 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
4479class FontFamilyValueBuilder {
4480    DISALLOW_ALLOCATION();
4481public:
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
4508private:
4509    StringBuilder m_builder;
4510    CSSValueList* m_list;
4511};
4512
4513PassRefPtrWillBeRawPtr<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
4586bool 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
4601bool 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
4616bool 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
4665bool 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
4682bool 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
4714bool 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
4742PassRefPtrWillBeRawPtr<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
4764PassRefPtrWillBeRawPtr<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
4838template <typename CharacterType>
4839static 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
4869template <typename CharacterType>
4870static 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
4904template <typename CharacterType>
4905static 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
4972template <typename CharacterType>
4973static 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
4986template <typename CharacterType>
4987static 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
5038template <typename CharacterType>
5039static 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
5050template <typename CharacterType>
5051static 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
5061template <typename CharacterType>
5062static 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
5119template<typename StringType>
5120bool 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
5144template bool CSSPropertyParser::fastParseColor(RGBA32&, const String&, bool strict);
5145
5146bool 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
5153inline 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
5182bool 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
5224bool 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
5255PassRefPtrWillBeRawPtr<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
5263bool 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.
5318class ShadowParseContext {
5319    STACK_ALLOCATED();
5320public:
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
5439PassRefPtrWillBeRawPtr<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
5501PassRefPtrWillBeRawPtr<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
5542static bool isFlexBasisMiddleArg(double flexGrow, double flexShrink, double unsetValue, int argSize)
5543{
5544    return flexGrow != unsetValue && flexShrink == unsetValue &&  argSize == 3;
5545}
5546
5547bool 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
5591PassRefPtrWillBeRawPtr<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
5601class BorderImageParseContext {
5602    STACK_ALLOCATED();
5603public:
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
5737bool 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
5798bool 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
5817PassRefPtrWillBeRawPtr<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
5826static bool isBorderImageRepeatKeyword(int id)
5827{
5828    return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound;
5829}
5830
5831bool 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
5863class BorderImageSliceParseContext {
5864    STACK_ALLOCATED();
5865public:
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
5926private:
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
5941bool 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
5976class BorderImageQuadParseContext {
5977    STACK_ALLOCATED();
5978public:
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
6041private:
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
6053bool 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
6077bool CSSPropertyParser::parseBorderImageWidth(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6078{
6079    return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result);
6080}
6081
6082bool CSSPropertyParser::parseBorderImageOutset(RefPtrWillBeRawPtr<CSSPrimitiveValue>& result)
6083{
6084    return parseBorderImageQuad(FLength | FNumber | FNonNeg, result);
6085}
6086
6087bool 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
6150PassRefPtrWillBeRawPtr<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
6178PassRefPtrWillBeRawPtr<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
6206static 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
6224bool 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
6288bool 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
6421static 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
6441PassRefPtrWillBeRawPtr<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
6450bool 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
6520bool 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
6632bool 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
6705bool 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
6828bool 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
6866bool 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
6928bool 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
6974bool 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
6990PassRefPtrWillBeRawPtr<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
7044PassRefPtrWillBeRawPtr<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
7094static 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
7120PassRefPtrWillBeRawPtr<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
7204PassRefPtrWillBeRawPtr<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}
7245PassRefPtrWillBeRawPtr<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
7312PassRefPtrWillBeRawPtr<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
7344void 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
7356bool 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
7394bool 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
7412bool 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
7469PassRefPtrWillBeRawPtr<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
7508bool 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
7541bool 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
7578bool 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
7600bool 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
7653bool 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
7670bool 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
7730bool 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
7751template <typename CharacterType>
7752static 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
7774CSSPropertyID 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
7786CSSPropertyID 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
7798template <typename CharacterType>
7799static 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
7815CSSValueID 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
7826bool 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
7836bool CSSPropertyParser::isSystemColor(int id)
7837{
7838    return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu;
7839}
7840
7841bool 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
8105PassRefPtrWillBeRawPtr<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 ]
8128PassRefPtrWillBeRawPtr<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