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