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