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