Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: Source/core/css/parser/CSSPropertyParser.cpp

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

Powered by Google App Engine
This is Rietveld 408576698