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