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