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