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