687235f79053451b58980bb1289b3604c60f3486
[WebKit.git] / WebCore / css / CSSParser.cpp
1 /*
2  * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
5  * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
6  * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
7  * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include "config.h"
26 #include "CSSParser.h"
27
28 #include "CSSTimingFunctionValue.h"
29 #include "CSSBorderImageValue.h"
30 #include "CSSCanvasValue.h"
31 #include "CSSCharsetRule.h"
32 #include "CSSCursorImageValue.h"
33 #include "CSSHelper.h"
34 #include "CSSImageValue.h"
35 #include "CSSFontFaceRule.h"
36 #include "CSSFontFaceSrcValue.h"
37 #include "CSSGradientValue.h"
38 #include "CSSImportRule.h"
39 #include "CSSInheritedValue.h"
40 #include "CSSInitialValue.h"
41 #include "CSSMediaRule.h"
42 #include "CSSMutableStyleDeclaration.h"
43 #include "CSSPageRule.h"
44 #include "CSSPrimitiveValue.h"
45 #include "CSSProperty.h"
46 #include "CSSPropertyNames.h"
47 #include "CSSQuirkPrimitiveValue.h"
48 #include "CSSReflectValue.h"
49 #include "CSSRuleList.h"
50 #include "CSSSelector.h"
51 #include "CSSStyleRule.h"
52 #include "CSSStyleSheet.h"
53 #include "CSSUnicodeRangeValue.h"
54 #include "CSSValueKeywords.h"
55 #include "CSSValueList.h"
56 #include "CSSVariableDependentValue.h"
57 #include "CSSVariablesDeclaration.h"
58 #include "CSSVariablesRule.h"
59 #include "Counter.h"
60 #include "Document.h"
61 #include "FloatConversion.h"
62 #include "FontFamilyValue.h"
63 #include "FontValue.h"
64 #include "MediaList.h"
65 #include "MediaQueryExp.h"
66 #include "Pair.h"
67 #include "Rect.h"
68 #include "ShadowValue.h"
69 #include "WebKitCSSKeyframeRule.h"
70 #include "WebKitCSSKeyframesRule.h"
71 #include "WebKitCSSTransformValue.h"
72 #include <limits.h>
73 #include <wtf/dtoa.h>
74 #include <wtf/text/StringBuffer.h>
75
76 #if ENABLE(DASHBOARD_SUPPORT)
77 #include "DashboardRegion.h"
78 #endif
79
80 #define YYDEBUG 0
81
82 #if YYDEBUG > 0
83 extern int cssyydebug;
84 #endif
85
86 extern int cssyyparse(void* parser);
87
88 using namespace std;
89 using namespace WTF;
90
91 #include "CSSPropertyNames.cpp"
92 #include "CSSValueKeywords.cpp"
93
94 namespace WebCore {
95
96 static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
97
98 static bool equal(const CSSParserString& a, const char* b)
99 {
100     for (int i = 0; i < a.length; ++i) {
101         if (!b[i])
102             return false;
103         if (a.characters[i] != b[i])
104             return false;
105     }
106     return !b[a.length];
107 }
108
109 static bool equalIgnoringCase(const CSSParserString& a, const char* b)
110 {
111     for (int i = 0; i < a.length; ++i) {
112         if (!b[i])
113             return false;
114         ASSERT(!isASCIIUpper(b[i]));
115         if (toASCIILower(a.characters[i]) != b[i])
116             return false;
117     }
118     return !b[a.length];
119 }
120
121 static bool hasPrefix(const char* string, unsigned length, const char* prefix)
122 {
123     for (unsigned i = 0; i < length; ++i) {
124         if (!prefix[i])
125             return true;
126         if (string[i] != prefix[i])
127             return false;
128     }
129     return false;
130 }
131
132 CSSParser::CSSParser(bool strictParsing)
133     : m_strict(strictParsing)
134     , m_important(false)
135     , m_id(0)
136     , m_styleSheet(0)
137     , m_valueList(0)
138     , m_parsedProperties(static_cast<CSSProperty**>(fastMalloc(32 * sizeof(CSSProperty*))))
139     , m_numParsedProperties(0)
140     , m_maxParsedProperties(32)
141     , m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
142     , m_inParseShorthand(0)
143     , m_currentShorthand(0)
144     , m_implicitShorthand(false)
145     , m_hasFontFaceOnlyValues(false)
146     , m_hadSyntacticallyValidCSSRule(false)
147     , m_defaultNamespace(starAtom)
148     , m_ruleBodyStartOffset(0)
149     , m_ruleBodyEndOffset(0)
150     , m_ruleRanges(0)
151     , m_data(0)
152     , yy_start(1)
153     , m_lineNumber(0)
154     , m_lastSelectorLineNumber(0)
155     , m_allowImportRules(true)
156     , m_allowVariablesRules(true)
157     , m_allowNamespaceDeclarations(true)
158 {
159 #if YYDEBUG > 0
160     cssyydebug = 1;
161 #endif
162 }
163
164 CSSParser::~CSSParser()
165 {
166     clearProperties();
167     fastFree(m_parsedProperties);
168
169     clearVariables();
170
171     delete m_valueList;
172
173     fastFree(m_data);
174
175     if (m_floatingMediaQueryExpList)
176         deleteAllValues(*m_floatingMediaQueryExpList);
177     fastDeleteAllValues(m_floatingSelectors);
178     deleteAllValues(m_floatingValueLists);
179     deleteAllValues(m_floatingFunctions);
180     deleteAllValues(m_reusableSelectorVector);
181 }
182
183 void CSSParserString::lower()
184 {
185     // FIXME: If we need Unicode lowercasing here, then we probably want the real kind
186     // that can potentially change the length of the string rather than the character
187     // by character kind. If we don't need Unicode lowercasing, it would be good to
188     // simplify this function.
189
190     if (charactersAreAllASCII(characters, length)) {
191         // Fast case for all-ASCII.
192         for (int i = 0; i < length; i++)
193             characters[i] = toASCIILower(characters[i]);
194     } else {
195         for (int i = 0; i < length; i++)
196             characters[i] = Unicode::toLower(characters[i]);
197     }
198 }
199
200 void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
201 {
202     int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
203
204     fastFree(m_data);
205     m_data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar)));
206     for (unsigned i = 0; i < strlen(prefix); i++)
207         m_data[i] = prefix[i];
208
209     memcpy(m_data + strlen(prefix), string.characters(), string.length() * sizeof(UChar));
210
211     unsigned start = strlen(prefix) + string.length();
212     unsigned end = start + strlen(suffix);
213     for (unsigned i = start; i < end; i++)
214         m_data[i] = suffix[i - start];
215
216     m_data[length - 1] = 0;
217     m_data[length - 2] = 0;
218
219     yy_hold_char = 0;
220     yyleng = 0;
221     yytext = yy_c_buf_p = m_data;
222     yy_hold_char = *yy_c_buf_p;
223     resetRuleBodyMarks();
224 }
225
226 void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string, int startLineNumber, StyleRuleRanges* ruleRangeMap)
227 {
228     m_styleSheet = sheet;
229     m_defaultNamespace = starAtom; // Reset the default namespace.
230     m_ruleRanges = ruleRangeMap;
231
232     m_lineNumber = startLineNumber;
233     setupParser("", string, "");
234     cssyyparse(this);
235     m_ruleRanges = 0;
236     m_rule = 0;
237 }
238
239 PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string)
240 {
241     m_styleSheet = sheet;
242     m_allowNamespaceDeclarations = false;
243     setupParser("@-webkit-rule{", string, "} ");
244     cssyyparse(this);
245     return m_rule.release();
246 }
247
248 PassRefPtr<CSSRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string)
249 {
250     m_styleSheet = sheet;
251     setupParser("@-webkit-keyframe-rule{ ", string, "} ");
252     cssyyparse(this);
253     return m_keyframe.release();
254 }
255
256 bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int id, const String& string, bool important)
257 {
258     ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
259     m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
260
261     setupParser("@-webkit-value{", string, "} ");
262
263     m_id = id;
264     m_important = important;
265
266     cssyyparse(this);
267
268     m_rule = 0;
269
270     bool ok = false;
271     if (m_hasFontFaceOnlyValues)
272         deleteFontFaceOnlyValues();
273     if (m_numParsedProperties) {
274         ok = true;
275         declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
276         clearProperties();
277     }
278
279     return ok;
280 }
281
282 // color will only be changed when string contains a valid css color, making it
283 // possible to set up a default color.
284 bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
285 {
286     // First try creating a color specified by name, rgba(), rgb() or "#" syntax.
287     if (parseColor(string, color, strict))
288         return true;
289
290     CSSParser parser(true);
291     RefPtr<CSSMutableStyleDeclaration> dummyStyleDeclaration = CSSMutableStyleDeclaration::create();
292
293     // Now try to create a color from rgba() syntax.
294     if (!parser.parseColor(dummyStyleDeclaration.get(), string))
295         return false;
296
297     CSSValue* value = parser.m_parsedProperties[0]->value();
298     if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
299         CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
300         color = primitiveValue->getRGBA32Value();
301     }
302
303     return true;
304 }
305
306 bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string)
307 {
308     ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
309     m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
310
311     setupParser("@-webkit-decls{color:", string, "} ");
312     cssyyparse(this);
313     m_rule = 0;
314
315     return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor);
316 }
317
318 void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList)
319 {
320     RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc);
321
322     m_styleSheet = dummyStyleSheet.get();
323     m_selectorListForParseSelector = &selectorList;
324
325     setupParser("@-webkit-selector{", string, "}");
326
327     cssyyparse(this);
328
329     m_selectorListForParseSelector = 0;
330 }
331
332 bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string)
333 {
334     ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet());
335     m_styleSheet = static_cast<CSSStyleSheet*>(declaration->stylesheet());
336
337     setupParser("@-webkit-decls{", string, "} ");
338     cssyyparse(this);
339     m_rule = 0;
340
341     bool ok = false;
342     if (m_hasFontFaceOnlyValues)
343         deleteFontFaceOnlyValues();
344     if (m_numParsedProperties) {
345         ok = true;
346         declaration->addParsedProperties(m_parsedProperties, m_numParsedProperties);
347         clearProperties();
348     }
349
350     return ok;
351 }
352
353 bool CSSParser::parseMediaQuery(MediaList* queries, const String& string)
354 {
355     if (string.isEmpty())
356         return true;
357
358     ASSERT(!m_mediaQuery);
359
360     // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
361     // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
362     setupParser("@-webkit-mediaquery ", string, "} ");
363     cssyyparse(this);
364
365     bool ok = false;
366     if (m_mediaQuery) {
367         ok = true;
368         queries->appendMediaQuery(m_mediaQuery.release());
369     }
370
371     return ok;
372 }
373
374
375 void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important)
376 {
377     OwnPtr<CSSProperty> prop(new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand));
378     if (m_numParsedProperties >= m_maxParsedProperties) {
379         m_maxParsedProperties += 32;
380         if (m_maxParsedProperties > UINT_MAX / sizeof(CSSProperty*))
381             return;
382         m_parsedProperties = static_cast<CSSProperty**>(fastRealloc(m_parsedProperties,
383             m_maxParsedProperties * sizeof(CSSProperty*)));
384     }
385     m_parsedProperties[m_numParsedProperties++] = prop.leakPtr();
386 }
387
388 void CSSParser::rollbackLastProperties(int num)
389 {
390     ASSERT(num >= 0);
391     ASSERT(m_numParsedProperties >= static_cast<unsigned>(num));
392
393     for (int i = 0; i < num; ++i)
394         delete m_parsedProperties[--m_numParsedProperties];
395 }
396
397 void CSSParser::clearProperties()
398 {
399     for (unsigned i = 0; i < m_numParsedProperties; i++)
400         delete m_parsedProperties[i];
401     m_numParsedProperties = 0;
402     m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
403     m_hasFontFaceOnlyValues = false;
404 }
405
406 Document* CSSParser::document() const
407 {
408     StyleBase* root = m_styleSheet;
409     while (root && root->parent())
410         root = root->parent();
411     if (!root)
412         return 0;
413     if (!root->isCSSStyleSheet())
414         return 0;
415     return static_cast<CSSStyleSheet*>(root)->document();
416 }
417
418 bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, bool strict)
419 {
420     bool b = false;
421     switch (value->unit) {
422     case CSSPrimitiveValue::CSS_NUMBER:
423         b = (unitflags & FNumber);
424         if (!b && ((unitflags & (FLength | FAngle | FTime)) && (value->fValue == 0 || !strict))) {
425             value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
426                           ((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
427             b = true;
428         }
429         if (!b && (unitflags & FInteger) && value->isInt)
430             b = true;
431         break;
432     case CSSPrimitiveValue::CSS_PERCENTAGE:
433         b = (unitflags & FPercent);
434         break;
435     case CSSParserValue::Q_EMS:
436     case CSSPrimitiveValue::CSS_EMS:
437     case CSSPrimitiveValue::CSS_REMS:
438     case CSSPrimitiveValue::CSS_EXS:
439     case CSSPrimitiveValue::CSS_PX:
440     case CSSPrimitiveValue::CSS_CM:
441     case CSSPrimitiveValue::CSS_MM:
442     case CSSPrimitiveValue::CSS_IN:
443     case CSSPrimitiveValue::CSS_PT:
444     case CSSPrimitiveValue::CSS_PC:
445         b = (unitflags & FLength);
446         break;
447     case CSSPrimitiveValue::CSS_MS:
448     case CSSPrimitiveValue::CSS_S:
449         b = (unitflags & FTime);
450         break;
451     case CSSPrimitiveValue::CSS_DEG:
452     case CSSPrimitiveValue::CSS_RAD:
453     case CSSPrimitiveValue::CSS_GRAD:
454     case CSSPrimitiveValue::CSS_TURN:
455         b = (unitflags & FAngle);
456         break;
457     case CSSPrimitiveValue::CSS_HZ:
458     case CSSPrimitiveValue::CSS_KHZ:
459     case CSSPrimitiveValue::CSS_DIMENSION:
460     default:
461         break;
462     }
463     if (b && unitflags & FNonNeg && value->fValue < 0)
464         b = false;
465     return b;
466 }
467
468 static int unitFromString(CSSParserValue* value)
469 {
470     if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id)
471         return 0;
472
473     if (equal(value->string, "em"))
474         return CSSPrimitiveValue::CSS_EMS;
475     if (equal(value->string, "rem"))
476         return CSSPrimitiveValue::CSS_REMS;
477     if (equal(value->string, "ex"))
478         return CSSPrimitiveValue::CSS_EXS;
479     if (equal(value->string, "px"))
480         return CSSPrimitiveValue::CSS_PX;
481     if (equal(value->string, "cm"))
482         return CSSPrimitiveValue::CSS_CM;
483     if (equal(value->string, "mm"))
484         return CSSPrimitiveValue::CSS_MM;
485     if (equal(value->string, "in"))
486         return CSSPrimitiveValue::CSS_IN;
487     if (equal(value->string, "pt"))
488         return CSSPrimitiveValue::CSS_PT;
489     if (equal(value->string, "pc"))
490         return CSSPrimitiveValue::CSS_PC;
491     if (equal(value->string, "deg"))
492         return CSSPrimitiveValue::CSS_DEG;
493     if (equal(value->string, "rad"))
494         return CSSPrimitiveValue::CSS_RAD;
495     if (equal(value->string, "grad"))
496         return CSSPrimitiveValue::CSS_GRAD;
497     if (equal(value->string, "turn"))
498         return CSSPrimitiveValue::CSS_TURN;
499     if (equal(value->string, "ms"))
500         return CSSPrimitiveValue::CSS_MS;
501     if (equal(value->string, "s"))
502         return CSSPrimitiveValue::CSS_S;
503     if (equal(value->string, "Hz"))
504         return CSSPrimitiveValue::CSS_HZ;
505     if (equal(value->string, "kHz"))
506         return CSSPrimitiveValue::CSS_KHZ;
507
508     return 0;
509 }
510
511 void CSSParser::checkForOrphanedUnits()
512 {
513     if (m_strict || inShorthand())
514         return;
515
516     // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values
517     // by whitespace, so e.g., width: 20 px instead of width:20px.  This is invalid CSS, so we don't do this in strict mode.
518     CSSParserValue* numericVal = 0;
519     unsigned size = m_valueList->size();
520     for (unsigned i = 0; i < size; i++) {
521         CSSParserValue* value = m_valueList->valueAt(i);
522
523         if (numericVal) {
524             // Change the unit type of the numeric val to match.
525             int unit = unitFromString(value);
526             if (unit) {
527                 numericVal->unit = unit;
528                 numericVal = 0;
529
530                 // Now delete the bogus unit value.
531                 m_valueList->deleteValueAt(i);
532                 i--; // We're safe even though |i| is unsigned, since we only hit this code if we had a previous numeric value (so |i| is always > 0 here).
533                 size--;
534                 continue;
535             }
536         }
537
538         numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0;
539     }
540 }
541
542 bool CSSParser::parseValue(int propId, bool important)
543 {
544     if (!m_valueList)
545         return false;
546
547     CSSParserValue *value = m_valueList->current();
548
549     if (!value)
550         return false;
551
552     int id = value->id;
553
554     // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to
555     // by a space.  We go ahead and associate the unit with the number even though it is invalid CSS.
556     checkForOrphanedUnits();
557
558     int num = inShorthand() ? 1 : m_valueList->size();
559
560     if (id == CSSValueInherit) {
561         if (num != 1)
562             return false;
563         addProperty(propId, CSSInheritedValue::create(), important);
564         return true;
565     }
566     else if (id == CSSValueInitial) {
567         if (num != 1)
568             return false;
569         addProperty(propId, CSSInitialValue::createExplicit(), important);
570         return true;
571     }
572
573     // If we have any variables, then we don't parse the list of values yet.  We add them to the declaration
574     // as unresolved, and allow them to be parsed later.  The parse is considered "successful" for now, even though
575     // it might ultimately fail once the variable has been resolved.
576     if (!inShorthand() && checkForVariables(m_valueList)) {
577         addUnresolvedProperty(propId, important);
578         return true;
579     }
580
581     bool validPrimitive = false;
582     RefPtr<CSSValue> parsedValue;
583
584     switch (static_cast<CSSPropertyID>(propId)) {
585         /* The comment to the left defines all valid value of this properties as defined
586          * in CSS 2, Appendix F. Property index
587          */
588
589         /* All the CSS properties are not supported by the renderer at the moment.
590          * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
591          * (see parseAuralValues). As we don't support them at all this seems reasonable.
592          */
593
594     case CSSPropertySize:                 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
595         return parseSize(propId, important);
596
597     case CSSPropertyQuotes:               // [<string> <string>]+ | none | inherit
598         if (id)
599             validPrimitive = true;
600         break;
601     case CSSPropertyUnicodeBidi:         // normal | embed | bidi-override | inherit
602         if (id == CSSValueNormal ||
603              id == CSSValueEmbed ||
604              id == CSSValueBidiOverride)
605             validPrimitive = true;
606         break;
607
608     case CSSPropertyPosition:             // static | relative | absolute | fixed | inherit
609         if (id == CSSValueStatic ||
610              id == CSSValueRelative ||
611              id == CSSValueAbsolute ||
612              id == CSSValueFixed)
613             validPrimitive = true;
614         break;
615
616     case CSSPropertyPageBreakAfter:     // auto | always | avoid | left | right | inherit
617     case CSSPropertyPageBreakBefore:
618     case CSSPropertyWebkitColumnBreakAfter:
619     case CSSPropertyWebkitColumnBreakBefore:
620         if (id == CSSValueAuto ||
621              id == CSSValueAlways ||
622              id == CSSValueAvoid ||
623              id == CSSValueLeft ||
624              id == CSSValueRight)
625             validPrimitive = true;
626         break;
627
628     case CSSPropertyPageBreakInside:    // avoid | auto | inherit
629     case CSSPropertyWebkitColumnBreakInside:
630         if (id == CSSValueAuto || id == CSSValueAvoid)
631             validPrimitive = true;
632         break;
633
634     case CSSPropertyEmptyCells:          // show | hide | inherit
635         if (id == CSSValueShow ||
636              id == CSSValueHide)
637             validPrimitive = true;
638         break;
639
640     case CSSPropertyContent:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
641         // close-quote | no-open-quote | no-close-quote ]+ | inherit
642         return parseContent(propId, important);
643
644     case CSSPropertyWhiteSpace:          // normal | pre | nowrap | inherit
645         if (id == CSSValueNormal ||
646             id == CSSValuePre ||
647             id == CSSValuePreWrap ||
648             id == CSSValuePreLine ||
649             id == CSSValueNowrap)
650             validPrimitive = true;
651         break;
652
653     case CSSPropertyClip:                 // <shape> | auto | inherit
654         if (id == CSSValueAuto)
655             validPrimitive = true;
656         else if (value->unit == CSSParserValue::Function)
657             return parseShape(propId, important);
658         break;
659
660     /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
661      * correctly and allows optimization in WebCore::applyRule(..)
662      */
663     case CSSPropertyCaptionSide:         // top | bottom | left | right | inherit
664         if (id == CSSValueLeft || id == CSSValueRight ||
665             id == CSSValueTop || id == CSSValueBottom)
666             validPrimitive = true;
667         break;
668
669     case CSSPropertyBorderCollapse:      // collapse | separate | inherit
670         if (id == CSSValueCollapse || id == CSSValueSeparate)
671             validPrimitive = true;
672         break;
673
674     case CSSPropertyVisibility:           // visible | hidden | collapse | inherit
675         if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueCollapse)
676             validPrimitive = true;
677         break;
678
679     case CSSPropertyOverflow: {
680         ShorthandScope scope(this, propId);
681         if (num != 1 || !parseValue(CSSPropertyOverflowX, important))
682             return false;
683         CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
684         addProperty(CSSPropertyOverflowY, value, important);
685         return true;
686     }
687     case CSSPropertyOverflowX:
688     case CSSPropertyOverflowY:           // visible | hidden | scroll | auto | marquee | overlay | inherit
689         if (id == CSSValueVisible || id == CSSValueHidden || id == CSSValueScroll || id == CSSValueAuto ||
690             id == CSSValueOverlay || id == CSSValueWebkitMarquee)
691             validPrimitive = true;
692         break;
693
694     case CSSPropertyListStylePosition:  // inside | outside | inherit
695         if (id == CSSValueInside || id == CSSValueOutside)
696             validPrimitive = true;
697         break;
698
699     case CSSPropertyListStyleType:
700         // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
701         // for the list of supported list-style-types.
702         if ((id >= CSSValueDisc && id <= CSSValueKatakanaIroha) || id == CSSValueNone)
703             validPrimitive = true;
704         break;
705
706     case CSSPropertyDisplay:
707         // inline | block | list-item | run-in | inline-block | table |
708         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
709         // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
710 #if ENABLE(WCSS)
711         if ((id >= CSSValueInline && id <= CSSValueWapMarquee) || id == CSSValueNone)
712 #else
713         if ((id >= CSSValueInline && id <= CSSValueWebkitInlineBox) || id == CSSValueNone)
714 #endif
715             validPrimitive = true;
716         break;
717
718     case CSSPropertyDirection:            // ltr | rtl | inherit
719         if (id == CSSValueLtr || id == CSSValueRtl)
720             validPrimitive = true;
721         break;
722
723     case CSSPropertyTextTransform:       // capitalize | uppercase | lowercase | none | inherit
724         if ((id >= CSSValueCapitalize && id <= CSSValueLowercase) || id == CSSValueNone)
725             validPrimitive = true;
726         break;
727
728     case CSSPropertyFloat:                // left | right | none | inherit + center for buggy CSS
729         if (id == CSSValueLeft || id == CSSValueRight ||
730              id == CSSValueNone || id == CSSValueCenter)
731             validPrimitive = true;
732         break;
733
734     case CSSPropertyClear:                // none | left | right | both | inherit
735         if (id == CSSValueNone || id == CSSValueLeft ||
736              id == CSSValueRight|| id == CSSValueBoth)
737             validPrimitive = true;
738         break;
739
740     case CSSPropertyTextAlign:
741         // left | right | center | justify | webkit_left | webkit_right | webkit_center | start | end | <string> | inherit
742         if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitCenter) || id == CSSValueStart || id == CSSValueEnd ||
743              value->unit == CSSPrimitiveValue::CSS_STRING)
744             validPrimitive = true;
745         break;
746
747     case CSSPropertyOutlineStyle:        // (<border-style> except hidden) | auto | inherit
748         if (id == CSSValueAuto || id == CSSValueNone || (id >= CSSValueInset && id <= CSSValueDouble))
749             validPrimitive = true;
750         break;
751
752     case CSSPropertyBorderTopStyle:     //// <border-style> | inherit
753     case CSSPropertyBorderRightStyle:   //   Defined as:    none | hidden | dotted | dashed |
754     case CSSPropertyBorderBottomStyle:  //   solid | double | groove | ridge | inset | outset
755     case CSSPropertyBorderLeftStyle:
756     case CSSPropertyWebkitBorderStartStyle:
757     case CSSPropertyWebkitBorderEndStyle:
758     case CSSPropertyWebkitColumnRuleStyle:
759         if (id >= CSSValueNone && id <= CSSValueDouble)
760             validPrimitive = true;
761         break;
762
763     case CSSPropertyFontWeight:  // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
764         return parseFontWeight(important);
765
766     case CSSPropertyBorderSpacing: {
767         const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing,
768                                     CSSPropertyWebkitBorderVerticalSpacing };
769         if (num == 1) {
770             ShorthandScope scope(this, CSSPropertyBorderSpacing);
771             if (!parseValue(properties[0], important))
772                 return false;
773             CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
774             addProperty(properties[1], value, important);
775             return true;
776         }
777         else if (num == 2) {
778             ShorthandScope scope(this, CSSPropertyBorderSpacing);
779             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
780                 return false;
781             return true;
782         }
783         return false;
784     }
785     case CSSPropertyWebkitBorderHorizontalSpacing:
786     case CSSPropertyWebkitBorderVerticalSpacing:
787         validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
788         break;
789     case CSSPropertyOutlineColor:        // <color> | invert | inherit
790         // Outline color has "invert" as additional keyword.
791         // Also, we want to allow the special focus color even in strict parsing mode.
792         if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
793             validPrimitive = true;
794             break;
795         }
796         /* nobreak */
797     case CSSPropertyBackgroundColor: // <color> | inherit
798     case CSSPropertyBorderTopColor: // <color> | inherit
799     case CSSPropertyBorderRightColor:
800     case CSSPropertyBorderBottomColor:
801     case CSSPropertyBorderLeftColor:
802     case CSSPropertyWebkitBorderStartColor:
803     case CSSPropertyWebkitBorderEndColor:
804     case CSSPropertyColor: // <color> | inherit
805     case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
806     case CSSPropertyTextUnderlineColor:
807     case CSSPropertyTextOverlineColor:
808     case CSSPropertyWebkitColumnRuleColor:
809     case CSSPropertyWebkitTextFillColor:
810     case CSSPropertyWebkitTextStrokeColor:
811         if (id == CSSValueWebkitText)
812             validPrimitive = true; // Always allow this, even when strict parsing is on,
813                                     // since we use this in our UA sheets.
814         else if (id == CSSValueCurrentcolor)
815             validPrimitive = true;
816         else if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu ||
817              (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && !m_strict)) {
818             validPrimitive = true;
819         } else {
820             parsedValue = parseColor();
821             if (parsedValue)
822                 m_valueList->next();
823         }
824         break;
825
826     case CSSPropertyCursor: {
827         // [<uri>,]*  [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
828         // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
829         // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
830         // vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
831         // -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
832         RefPtr<CSSValueList> list;
833         while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
834             if (!list)
835                 list = CSSValueList::createCommaSeparated();
836             String uri = value->string;
837             Vector<int> coords;
838             value = m_valueList->next();
839             while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
840                 coords.append(int(value->fValue));
841                 value = m_valueList->next();
842             }
843             IntPoint hotSpot(-1, -1);
844             int nrcoords = coords.size();
845             if (nrcoords > 0 && nrcoords != 2)
846                 return false;
847             if (nrcoords == 2)
848                 hotSpot = IntPoint(coords[0], coords[1]);
849
850             if (!uri.isNull() && m_styleSheet) {
851                 // FIXME: The completeURL call should be done when using the CSSCursorImageValue,
852                 // not when creating it.
853                 list->append(CSSCursorImageValue::create(m_styleSheet->completeURL(uri), hotSpot));
854             }
855
856             if ((m_strict && !value) || (value && !(value->unit == CSSParserValue::Operator && value->iValue == ',')))
857                 return false;
858             value = m_valueList->next(); // comma
859         }
860         if (list) {
861             if (!value) { // no value after url list (MSIE 5 compatibility)
862                 if (list->length() != 1)
863                     return false;
864             } else if (!m_strict && value->id == CSSValueHand) // MSIE 5 compatibility :/
865                 list->append(CSSPrimitiveValue::createIdentifier(CSSValuePointer));
866             else if (value && ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone))
867                 list->append(CSSPrimitiveValue::createIdentifier(value->id));
868             m_valueList->next();
869             parsedValue = list.release();
870             break;
871         }
872         id = value->id;
873         if (!m_strict && value->id == CSSValueHand) { // MSIE 5 compatibility :/
874             id = CSSValuePointer;
875             validPrimitive = true;
876         } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
877             validPrimitive = true;
878         break;
879     }
880
881     case CSSPropertyBackgroundAttachment:
882     case CSSPropertyBackgroundClip:
883     case CSSPropertyWebkitBackgroundClip:
884     case CSSPropertyWebkitBackgroundComposite:
885     case CSSPropertyBackgroundImage:
886     case CSSPropertyBackgroundOrigin:
887     case CSSPropertyWebkitBackgroundOrigin:
888     case CSSPropertyBackgroundPosition:
889     case CSSPropertyBackgroundPositionX:
890     case CSSPropertyBackgroundPositionY:
891     case CSSPropertyBackgroundSize:
892     case CSSPropertyWebkitBackgroundSize:
893     case CSSPropertyBackgroundRepeat:
894     case CSSPropertyBackgroundRepeatX:
895     case CSSPropertyBackgroundRepeatY:
896     case CSSPropertyWebkitMaskAttachment:
897     case CSSPropertyWebkitMaskClip:
898     case CSSPropertyWebkitMaskComposite:
899     case CSSPropertyWebkitMaskImage:
900     case CSSPropertyWebkitMaskOrigin:
901     case CSSPropertyWebkitMaskPosition:
902     case CSSPropertyWebkitMaskPositionX:
903     case CSSPropertyWebkitMaskPositionY:
904     case CSSPropertyWebkitMaskSize:
905     case CSSPropertyWebkitMaskRepeat:
906     case CSSPropertyWebkitMaskRepeatX:
907     case CSSPropertyWebkitMaskRepeatY: {
908         RefPtr<CSSValue> val1;
909         RefPtr<CSSValue> val2;
910         int propId1, propId2;
911         bool result = false;
912         if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
913             OwnPtr<ShorthandScope> shorthandScope;
914             if (propId == CSSPropertyBackgroundPosition ||
915                 propId == CSSPropertyBackgroundRepeat ||
916                 propId == CSSPropertyWebkitMaskPosition ||
917                 propId == CSSPropertyWebkitMaskRepeat) {
918                 shorthandScope.set(new ShorthandScope(this, propId));
919             }
920             addProperty(propId1, val1.release(), important);
921             if (val2)
922                 addProperty(propId2, val2.release(), important);
923             result = true;
924         }
925         m_implicitShorthand = false;
926         return result;
927     }
928     case CSSPropertyListStyleImage:     // <uri> | none | inherit
929         if (id == CSSValueNone) {
930             parsedValue = CSSImageValue::create();
931             m_valueList->next();
932         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
933             if (m_styleSheet) {
934                 // FIXME: The completeURL call should be done when using the CSSImageValue,
935                 // not when creating it.
936                 parsedValue = CSSImageValue::create(m_styleSheet->completeURL(value->string));
937                 m_valueList->next();
938             }
939         } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-gradient(")) {
940             if (parseGradient(parsedValue))
941                 m_valueList->next();
942             else
943                 return false;
944         }
945         break;
946
947     case CSSPropertyWebkitTextStrokeWidth:
948     case CSSPropertyOutlineWidth:        // <border-width> | inherit
949     case CSSPropertyBorderTopWidth:     //// <border-width> | inherit
950     case CSSPropertyBorderRightWidth:   //   Which is defined as
951     case CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
952     case CSSPropertyBorderLeftWidth:
953     case CSSPropertyWebkitBorderStartWidth:
954     case CSSPropertyWebkitBorderEndWidth:
955     case CSSPropertyWebkitColumnRuleWidth:
956         if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
957             validPrimitive = true;
958         else
959             validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
960         break;
961
962     case CSSPropertyLetterSpacing:       // normal | <length> | inherit
963     case CSSPropertyWordSpacing:         // normal | <length> | inherit
964         if (id == CSSValueNormal)
965             validPrimitive = true;
966         else
967             validPrimitive = validUnit(value, FLength, m_strict);
968         break;
969
970     case CSSPropertyWordBreak:          // normal | break-all | break-word (this is a custom extension)
971         if (id == CSSValueNormal || id == CSSValueBreakAll || id == CSSValueBreakWord)
972             validPrimitive = true;
973         break;
974
975     case CSSPropertyWordWrap:           // normal | break-word
976         if (id == CSSValueNormal || id == CSSValueBreakWord)
977             validPrimitive = true;
978         break;
979
980     case CSSPropertyTextIndent:          // <length> | <percentage> | inherit
981         validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
982         break;
983
984     case CSSPropertyPaddingTop:          //// <padding-width> | inherit
985     case CSSPropertyPaddingRight:        //   Which is defined as
986     case CSSPropertyPaddingBottom:       //   <length> | <percentage>
987     case CSSPropertyPaddingLeft:         ////
988     case CSSPropertyWebkitPaddingStart:
989     case CSSPropertyWebkitPaddingEnd:
990         validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
991         break;
992
993     case CSSPropertyMaxHeight:           // <length> | <percentage> | none | inherit
994     case CSSPropertyMaxWidth:            // <length> | <percentage> | none | inherit
995         if (id == CSSValueNone || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic) {
996             validPrimitive = true;
997             break;
998         }
999         /* nobreak */
1000     case CSSPropertyMinHeight:           // <length> | <percentage> | inherit
1001     case CSSPropertyMinWidth:            // <length> | <percentage> | inherit
1002         if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
1003             validPrimitive = true;
1004         else
1005             validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1006         break;
1007
1008     case CSSPropertyFontSize:
1009         // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
1010         if (id >= CSSValueXxSmall && id <= CSSValueLarger)
1011             validPrimitive = true;
1012         else
1013             validPrimitive = (validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1014         break;
1015
1016     case CSSPropertyFontStyle:           // normal | italic | oblique | inherit
1017         return parseFontStyle(important);
1018
1019     case CSSPropertyFontVariant:         // normal | small-caps | inherit
1020         return parseFontVariant(important);
1021
1022     case CSSPropertyVerticalAlign:
1023         // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
1024         // <percentage> | <length> | inherit
1025
1026         if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
1027             validPrimitive = true;
1028         else
1029             validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
1030         break;
1031
1032     case CSSPropertyHeight:               // <length> | <percentage> | auto | inherit
1033     case CSSPropertyWidth:                // <length> | <percentage> | auto | inherit
1034         if (id == CSSValueAuto || id == CSSValueIntrinsic || id == CSSValueMinIntrinsic)
1035             validPrimitive = true;
1036         else
1037             // ### handle multilength case where we allow relative units
1038             validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, m_strict));
1039         break;
1040
1041     case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
1042     case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
1043     case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
1044     case CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
1045     case CSSPropertyMarginTop:           //// <margin-width> | inherit
1046     case CSSPropertyMarginRight:         //   Which is defined as
1047     case CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
1048     case CSSPropertyMarginLeft:          ////
1049     case CSSPropertyWebkitMarginStart:
1050     case CSSPropertyWebkitMarginEnd:
1051         if (id == CSSValueAuto)
1052             validPrimitive = true;
1053         else
1054             validPrimitive = (!id && validUnit(value, FLength | FPercent, m_strict));
1055         break;
1056
1057     case CSSPropertyZIndex:              // auto | <integer> | inherit
1058         if (id == CSSValueAuto) {
1059             validPrimitive = true;
1060             break;
1061         }
1062         /* nobreak */
1063     case CSSPropertyOrphans:              // <integer> | inherit
1064     case CSSPropertyWidows:               // <integer> | inherit
1065         // ### not supported later on
1066         validPrimitive = (!id && validUnit(value, FInteger, false));
1067         break;
1068
1069     case CSSPropertyLineHeight:          // normal | <number> | <length> | <percentage> | inherit
1070         if (id == CSSValueNormal)
1071             validPrimitive = true;
1072         else
1073             validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict));
1074         break;
1075     case CSSPropertyCounterIncrement:    // [ <identifier> <integer>? ]+ | none | inherit
1076         if (id != CSSValueNone)
1077             return parseCounter(propId, 1, important);
1078         validPrimitive = true;
1079         break;
1080      case CSSPropertyCounterReset:        // [ <identifier> <integer>? ]+ | none | inherit
1081         if (id != CSSValueNone)
1082             return parseCounter(propId, 0, important);
1083         validPrimitive = true;
1084         break;
1085     case CSSPropertyFontFamily:
1086         // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
1087     {
1088         parsedValue = parseFontFamily();
1089         break;
1090     }
1091
1092     case CSSPropertyTextDecoration:
1093     case CSSPropertyWebkitTextDecorationsInEffect:
1094         // none | [ underline || overline || line-through || blink ] | inherit
1095         if (id == CSSValueNone) {
1096             validPrimitive = true;
1097         } else {
1098             RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1099             bool isValid = true;
1100             while (isValid && value) {
1101                 switch (value->id) {
1102                 case CSSValueBlink:
1103                     break;
1104                 case CSSValueUnderline:
1105                 case CSSValueOverline:
1106                 case CSSValueLineThrough:
1107                     list->append(CSSPrimitiveValue::createIdentifier(value->id));
1108                     break;
1109                 default:
1110                     isValid = false;
1111                 }
1112                 value = m_valueList->next();
1113             }
1114             if (list->length() && isValid) {
1115                 parsedValue = list.release();
1116                 m_valueList->next();
1117             }
1118         }
1119         break;
1120
1121     case CSSPropertyZoom:          // normal | reset | document | <number> | <percentage> | inherit
1122         if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
1123             validPrimitive = true;
1124         else
1125             validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, true));
1126         break;
1127
1128     case CSSPropertyTableLayout:         // auto | fixed | inherit
1129         if (id == CSSValueAuto || id == CSSValueFixed)
1130             validPrimitive = true;
1131         break;
1132
1133     case CSSPropertySrc:  // Only used within @font-face, so cannot use inherit | initial or be !important.  This is a list of urls or local references.
1134         return parseFontFaceSrc();
1135
1136     case CSSPropertyUnicodeRange:
1137         return parseFontFaceUnicodeRange();
1138
1139     /* CSS3 properties */
1140     case CSSPropertyWebkitAppearance:
1141         if ((id >= CSSValueCheckbox && id <= CSSValueTextarea) || id == CSSValueNone)
1142             validPrimitive = true;
1143         break;
1144
1145     case CSSPropertyWebkitBorderImage:
1146     case CSSPropertyWebkitMaskBoxImage:
1147         if (id == CSSValueNone)
1148             validPrimitive = true;
1149         else {
1150             RefPtr<CSSValue> result;
1151             if (parseBorderImage(propId, important, result)) {
1152                 addProperty(propId, result, important);
1153                 return true;
1154             }
1155         }
1156         break;
1157     case CSSPropertyBorderTopRightRadius:
1158     case CSSPropertyBorderTopLeftRadius:
1159     case CSSPropertyBorderBottomLeftRadius:
1160     case CSSPropertyBorderBottomRightRadius: {
1161         if (num != 1 && num != 2)
1162             return false;
1163         validPrimitive = validUnit(value, FLength | FPercent, m_strict);
1164         if (!validPrimitive)
1165             return false;
1166         RefPtr<CSSPrimitiveValue> parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1167         RefPtr<CSSPrimitiveValue> parsedValue2;
1168         if (num == 2) {
1169             value = m_valueList->next();
1170             validPrimitive = validUnit(value, FLength | FPercent, m_strict);
1171             if (!validPrimitive)
1172                 return false;
1173             parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1174         } else
1175             parsedValue2 = parsedValue1;
1176
1177         RefPtr<Pair> pair = Pair::create(parsedValue1.release(), parsedValue2.release());
1178         RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(pair.release());
1179         addProperty(propId, val.release(), important);
1180         return true;
1181     }
1182     case CSSPropertyBorderRadius:
1183     case CSSPropertyWebkitBorderRadius:
1184         return parseBorderRadius(propId, important);
1185     case CSSPropertyOutlineOffset:
1186         validPrimitive = validUnit(value, FLength | FPercent, m_strict);
1187         break;
1188     case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
1189     case CSSPropertyWebkitBoxShadow:
1190         if (id == CSSValueNone)
1191             validPrimitive = true;
1192         else
1193             return parseShadow(propId, important);
1194         break;
1195     case CSSPropertyWebkitBoxReflect:
1196         if (id == CSSValueNone)
1197             validPrimitive = true;
1198         else
1199             return parseReflect(propId, important);
1200         break;
1201     case CSSPropertyOpacity:
1202         validPrimitive = validUnit(value, FNumber, m_strict);
1203         break;
1204     case CSSPropertyWebkitBoxAlign:
1205         if (id == CSSValueStretch || id == CSSValueStart || id == CSSValueEnd ||
1206             id == CSSValueCenter || id == CSSValueBaseline)
1207             validPrimitive = true;
1208         break;
1209     case CSSPropertyWebkitBoxDirection:
1210         if (id == CSSValueNormal || id == CSSValueReverse)
1211             validPrimitive = true;
1212         break;
1213     case CSSPropertyWebkitBoxLines:
1214         if (id == CSSValueSingle || id == CSSValueMultiple)
1215             validPrimitive = true;
1216         break;
1217     case CSSPropertyWebkitBoxOrient:
1218         if (id == CSSValueHorizontal || id == CSSValueVertical ||
1219             id == CSSValueInlineAxis || id == CSSValueBlockAxis)
1220             validPrimitive = true;
1221         break;
1222     case CSSPropertyWebkitBoxPack:
1223         if (id == CSSValueStart || id == CSSValueEnd ||
1224             id == CSSValueCenter || id == CSSValueJustify)
1225             validPrimitive = true;
1226         break;
1227     case CSSPropertyWebkitBoxFlex:
1228         validPrimitive = validUnit(value, FNumber, m_strict);
1229         break;
1230     case CSSPropertyWebkitBoxFlexGroup:
1231     case CSSPropertyWebkitBoxOrdinalGroup:
1232         validPrimitive = validUnit(value, FInteger | FNonNeg, true);
1233         break;
1234     case CSSPropertyWebkitBoxSizing:
1235         validPrimitive = id == CSSValueBorderBox || id == CSSValueContentBox;
1236         break;
1237     case CSSPropertyWebkitColorCorrection:
1238         validPrimitive = id == CSSValueSrgb || id == CSSValueDefault;
1239         break;
1240     case CSSPropertyWebkitMarquee: {
1241         const int properties[5] = { CSSPropertyWebkitMarqueeDirection, CSSPropertyWebkitMarqueeIncrement,
1242                                     CSSPropertyWebkitMarqueeRepetition,
1243                                     CSSPropertyWebkitMarqueeStyle, CSSPropertyWebkitMarqueeSpeed };
1244         return parseShorthand(propId, properties, 5, important);
1245     }
1246     case CSSPropertyWebkitMarqueeDirection:
1247         if (id == CSSValueForwards || id == CSSValueBackwards || id == CSSValueAhead ||
1248             id == CSSValueReverse || id == CSSValueLeft || id == CSSValueRight || id == CSSValueDown ||
1249             id == CSSValueUp || id == CSSValueAuto)
1250             validPrimitive = true;
1251         break;
1252     case CSSPropertyWebkitMarqueeIncrement:
1253         if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
1254             validPrimitive = true;
1255         else
1256             validPrimitive = validUnit(value, FLength | FPercent, m_strict);
1257         break;
1258     case CSSPropertyWebkitMarqueeStyle:
1259         if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
1260             validPrimitive = true;
1261         break;
1262     case CSSPropertyWebkitMarqueeRepetition:
1263         if (id == CSSValueInfinite)
1264             validPrimitive = true;
1265         else
1266             validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
1267         break;
1268     case CSSPropertyWebkitMarqueeSpeed:
1269         if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
1270             validPrimitive = true;
1271         else
1272             validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
1273         break;
1274 #if ENABLE(WCSS)
1275     case CSSPropertyWapMarqueeDir:
1276         if (id == CSSValueLtr || id == CSSValueRtl)
1277             validPrimitive = true;
1278         break;
1279     case CSSPropertyWapMarqueeStyle:
1280         if (id == CSSValueNone || id == CSSValueSlide || id == CSSValueScroll || id == CSSValueAlternate)
1281             validPrimitive = true;
1282         break;
1283     case CSSPropertyWapMarqueeLoop:
1284         if (id == CSSValueInfinite)
1285             validPrimitive = true;
1286         else
1287             validPrimitive = validUnit(value, FInteger | FNonNeg, m_strict);
1288         break;
1289     case CSSPropertyWapMarqueeSpeed:
1290         if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
1291             validPrimitive = true;
1292         else
1293             validPrimitive = validUnit(value, FTime | FInteger | FNonNeg, m_strict);
1294         break;
1295 #endif
1296     case CSSPropertyWebkitUserDrag: // auto | none | element
1297         if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueElement)
1298             validPrimitive = true;
1299         break;
1300     case CSSPropertyWebkitUserModify: // read-only | read-write
1301         if (id == CSSValueReadOnly || id == CSSValueReadWrite || id == CSSValueReadWritePlaintextOnly)
1302             validPrimitive = true;
1303         break;
1304     case CSSPropertyWebkitUserSelect: // auto | none | text
1305         if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueText)
1306             validPrimitive = true;
1307         break;
1308     case CSSPropertyTextOverflow: // clip | ellipsis
1309         if (id == CSSValueClip || id == CSSValueEllipsis)
1310             validPrimitive = true;
1311         break;
1312     case CSSPropertyWebkitTransform:
1313         if (id == CSSValueNone)
1314             validPrimitive = true;
1315         else {
1316             PassRefPtr<CSSValue> val = parseTransform();
1317             if (val) {
1318                 addProperty(propId, val, important);
1319                 return true;
1320             }
1321             return false;
1322         }
1323         break;
1324     case CSSPropertyWebkitTransformOrigin:
1325     case CSSPropertyWebkitTransformOriginX:
1326     case CSSPropertyWebkitTransformOriginY:
1327     case CSSPropertyWebkitTransformOriginZ: {
1328         RefPtr<CSSValue> val1;
1329         RefPtr<CSSValue> val2;
1330         RefPtr<CSSValue> val3;
1331         int propId1, propId2, propId3;
1332         if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) {
1333             addProperty(propId1, val1.release(), important);
1334             if (val2)
1335                 addProperty(propId2, val2.release(), important);
1336             if (val3)
1337                 addProperty(propId3, val3.release(), important);
1338             return true;
1339         }
1340         return false;
1341     }
1342     case CSSPropertyWebkitTransformStyle:
1343         if (value->id == CSSValueFlat || value->id == CSSValuePreserve3d)
1344             validPrimitive = true;
1345         break;
1346     case CSSPropertyWebkitBackfaceVisibility:
1347         if (value->id == CSSValueVisible || value->id == CSSValueHidden)
1348             validPrimitive = true;
1349         break;
1350     case CSSPropertyWebkitPerspective:
1351         if (id == CSSValueNone)
1352             validPrimitive = true;
1353         else {
1354             // Accepting valueless numbers is a quirk of the -webkit prefixed version of the property.
1355             if (validUnit(value, FNumber | FLength | FNonNeg, m_strict)) {
1356                 RefPtr<CSSValue> val = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1357                 if (val) {
1358                     addProperty(propId, val.release(), important);
1359                     return true;
1360                 }
1361                 return false;
1362             }
1363         }
1364         break;
1365     case CSSPropertyWebkitPerspectiveOrigin:
1366     case CSSPropertyWebkitPerspectiveOriginX:
1367     case CSSPropertyWebkitPerspectiveOriginY: {
1368         RefPtr<CSSValue> val1;
1369         RefPtr<CSSValue> val2;
1370         int propId1, propId2;
1371         if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) {
1372             addProperty(propId1, val1.release(), important);
1373             if (val2)
1374                 addProperty(propId2, val2.release(), important);
1375             return true;
1376         }
1377         return false;
1378     }
1379     case CSSPropertyWebkitAnimationDelay:
1380     case CSSPropertyWebkitAnimationDirection:
1381     case CSSPropertyWebkitAnimationDuration:
1382     case CSSPropertyWebkitAnimationFillMode:
1383     case CSSPropertyWebkitAnimationName:
1384     case CSSPropertyWebkitAnimationPlayState:
1385     case CSSPropertyWebkitAnimationIterationCount:
1386     case CSSPropertyWebkitAnimationTimingFunction:
1387     case CSSPropertyWebkitTransitionDelay:
1388     case CSSPropertyWebkitTransitionDuration:
1389     case CSSPropertyWebkitTransitionTimingFunction:
1390     case CSSPropertyWebkitTransitionProperty: {
1391         RefPtr<CSSValue> val;
1392         if (parseAnimationProperty(propId, val)) {
1393             addProperty(propId, val.release(), important);
1394             return true;
1395         }
1396         return false;
1397     }
1398     case CSSPropertyWebkitMarginCollapse: {
1399         const int properties[2] = { CSSPropertyWebkitMarginTopCollapse,
1400             CSSPropertyWebkitMarginBottomCollapse };
1401         if (num == 1) {
1402             ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1403             if (!parseValue(properties[0], important))
1404                 return false;
1405             CSSValue* value = m_parsedProperties[m_numParsedProperties-1]->value();
1406             addProperty(properties[1], value, important);
1407             return true;
1408         }
1409         else if (num == 2) {
1410             ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse);
1411             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
1412                 return false;
1413             return true;
1414         }
1415         return false;
1416     }
1417     case CSSPropertyWebkitMarginTopCollapse:
1418     case CSSPropertyWebkitMarginBottomCollapse:
1419         if (id == CSSValueCollapse || id == CSSValueSeparate || id == CSSValueDiscard)
1420             validPrimitive = true;
1421         break;
1422     case CSSPropertyTextLineThroughMode:
1423     case CSSPropertyTextOverlineMode:
1424     case CSSPropertyTextUnderlineMode:
1425         if (id == CSSValueContinuous || id == CSSValueSkipWhiteSpace)
1426             validPrimitive = true;
1427         break;
1428     case CSSPropertyTextLineThroughStyle:
1429     case CSSPropertyTextOverlineStyle:
1430     case CSSPropertyTextUnderlineStyle:
1431         if (id == CSSValueNone || id == CSSValueSolid || id == CSSValueDouble ||
1432             id == CSSValueDashed || id == CSSValueDotDash || id == CSSValueDotDotDash ||
1433             id == CSSValueWave)
1434             validPrimitive = true;
1435         break;
1436     case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
1437         if (id == CSSValueAuto || id == CSSValueOptimizespeed || id == CSSValueOptimizelegibility
1438             || id == CSSValueGeometricprecision)
1439             validPrimitive = true;
1440         break;
1441     case CSSPropertyTextLineThroughWidth:
1442     case CSSPropertyTextOverlineWidth:
1443     case CSSPropertyTextUnderlineWidth:
1444         if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin ||
1445             id == CSSValueMedium || id == CSSValueThick)
1446             validPrimitive = true;
1447         else
1448             validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent, m_strict);
1449         break;
1450     case CSSPropertyResize: // none | both | horizontal | vertical | auto
1451         if (id == CSSValueNone || id == CSSValueBoth || id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto)
1452             validPrimitive = true;
1453         break;
1454     case CSSPropertyWebkitColumnCount:
1455         if (id == CSSValueAuto)
1456             validPrimitive = true;
1457         else
1458             validPrimitive = !id && validUnit(value, FInteger | FNonNeg, false);
1459         break;
1460     case CSSPropertyWebkitColumnGap:         // normal | <length>
1461         if (id == CSSValueNormal)
1462             validPrimitive = true;
1463         else
1464             validPrimitive = validUnit(value, FLength | FNonNeg, m_strict);
1465         break;
1466     case CSSPropertyWebkitColumnSpan:        // all | 1
1467         if (id == CSSValueAll)
1468             validPrimitive = true;
1469         else
1470             validPrimitive = validUnit(value, FNumber | FNonNeg, m_strict) && value->fValue == 1;
1471         break;
1472     case CSSPropertyWebkitColumnWidth:         // auto | <length>
1473         if (id == CSSValueAuto)
1474             validPrimitive = true;
1475         else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
1476             validPrimitive = validUnit(value, FLength, true);
1477         break;
1478     case CSSPropertyPointerEvents:
1479         // none | visiblePainted | visibleFill | visibleStroke | visible |
1480         // painted | fill | stroke | auto | all | inherit
1481         if (id == CSSValueVisible || id == CSSValueNone || id == CSSValueAll || id == CSSValueAuto ||
1482             (id >= CSSValueVisiblepainted && id <= CSSValueStroke))
1483             validPrimitive = true;
1484         break;
1485
1486     // End of CSS3 properties
1487
1488     // Apple specific properties.  These will never be standardized and are purely to
1489     // support custom WebKit-based Apple applications.
1490     case CSSPropertyWebkitLineClamp:
1491         // When specifying number of lines, don't allow 0 as a valid value
1492         // When specifying either type of unit, require non-negative integers
1493         validPrimitive = (!id && (value->unit == CSSPrimitiveValue::CSS_PERCENTAGE || value->fValue) && validUnit(value, FInteger | FPercent | FNonNeg, false));
1494         break;
1495     case CSSPropertyWebkitTextSizeAdjust:
1496         if (id == CSSValueAuto || id == CSSValueNone)
1497             validPrimitive = true;
1498         break;
1499     case CSSPropertyWebkitRtlOrdering:
1500         if (id == CSSValueLogical || id == CSSValueVisual)
1501             validPrimitive = true;
1502         break;
1503
1504     case CSSPropertyWebkitFontSizeDelta:           // <length>
1505         validPrimitive = validUnit(value, FLength, m_strict);
1506         break;
1507
1508     case CSSPropertyWebkitNbspMode:     // normal | space
1509         if (id == CSSValueNormal || id == CSSValueSpace)
1510             validPrimitive = true;
1511         break;
1512
1513     case CSSPropertyWebkitLineBreak:   // normal | after-white-space
1514         if (id == CSSValueNormal || id == CSSValueAfterWhiteSpace)
1515             validPrimitive = true;
1516         break;
1517
1518     case CSSPropertyWebkitMatchNearestMailBlockquoteColor:   // normal | match
1519         if (id == CSSValueNormal || id == CSSValueMatch)
1520             validPrimitive = true;
1521         break;
1522
1523     case CSSPropertyWebkitHighlight:
1524         if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING)
1525             validPrimitive = true;
1526         break;
1527
1528     case CSSPropertyWebkitHyphens:
1529         if (id == CSSValueNone || id == CSSValueManual || id == CSSValueAuto)
1530             validPrimitive = true;
1531         break;
1532
1533     case CSSPropertyWebkitHyphenateCharacter:
1534         if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1535             validPrimitive = true;
1536         break;
1537
1538     case CSSPropertyWebkitHyphenateLocale:
1539         if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING)
1540             validPrimitive = true;
1541         break;
1542
1543     case CSSPropertyWebkitBorderFit:
1544         if (id == CSSValueBorder || id == CSSValueLines)
1545             validPrimitive = true;
1546         break;
1547
1548     case CSSPropertyWebkitTextSecurity:
1549         // disc | circle | square | none | inherit
1550         if (id == CSSValueDisc || id == CSSValueCircle || id == CSSValueSquare|| id == CSSValueNone)
1551             validPrimitive = true;
1552         break;
1553
1554     case CSSPropertyWebkitFontSmoothing:
1555         if (id == CSSValueAuto || id == CSSValueNone
1556             || id == CSSValueAntialiased || id == CSSValueSubpixelAntialiased)
1557             validPrimitive = true;
1558         break;
1559
1560 #if ENABLE(DASHBOARD_SUPPORT)
1561     case CSSPropertyWebkitDashboardRegion: // <dashboard-region> | <dashboard-region>
1562         if (value->unit == CSSParserValue::Function || id == CSSValueNone)
1563             return parseDashboardRegions(propId, important);
1564         break;
1565 #endif
1566     // End Apple-specific properties
1567
1568         /* shorthand properties */
1569     case CSSPropertyBackground: {
1570         // Position must come before color in this array because a plain old "0" is a legal color
1571         // in quirks mode but it's usually the X coordinate of a position.
1572         // FIXME: Add CSSPropertyBackgroundSize to the shorthand.
1573         const int properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
1574                                    CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
1575                                    CSSPropertyBackgroundColor };
1576         return parseFillShorthand(propId, properties, 6, important);
1577     }
1578     case CSSPropertyWebkitMask: {
1579         const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
1580                                    CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition,
1581                                    CSSPropertyWebkitMaskOrigin };
1582         return parseFillShorthand(propId, properties, 5, important);
1583     }
1584     case CSSPropertyBorder:
1585         // [ 'border-width' || 'border-style' || <color> ] | inherit
1586     {
1587         const int properties[3] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle,
1588                                     CSSPropertyBorderColor };
1589         return parseShorthand(propId, properties, 3, important);
1590     }
1591     case CSSPropertyBorderTop:
1592         // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1593     {
1594         const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle,
1595                                     CSSPropertyBorderTopColor};
1596         return parseShorthand(propId, properties, 3, important);
1597     }
1598     case CSSPropertyBorderRight:
1599         // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1600     {
1601         const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle,
1602                                     CSSPropertyBorderRightColor };
1603         return parseShorthand(propId, properties, 3, important);
1604     }
1605     case CSSPropertyBorderBottom:
1606         // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1607     {
1608         const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle,
1609                                     CSSPropertyBorderBottomColor };
1610         return parseShorthand(propId, properties, 3, important);
1611     }
1612     case CSSPropertyBorderLeft:
1613         // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1614     {
1615         const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle,
1616                                     CSSPropertyBorderLeftColor };
1617         return parseShorthand(propId, properties, 3, important);
1618     }
1619     case CSSPropertyWebkitBorderStart:
1620         // [ '-webkit-border-start-width' || 'border-style' || <color> ] | inherit
1621     {
1622         const int properties[3] = { CSSPropertyWebkitBorderStartWidth, CSSPropertyWebkitBorderStartStyle,
1623             CSSPropertyWebkitBorderStartColor };
1624         return parseShorthand(propId, properties, 3, important);
1625     }
1626     case CSSPropertyWebkitBorderEnd:
1627         // [ '-webkit-border-end-width' || 'border-style' || <color> ] | inherit
1628     {
1629         const int properties[3] = { CSSPropertyWebkitBorderEndWidth, CSSPropertyWebkitBorderEndStyle,
1630             CSSPropertyWebkitBorderEndColor };
1631         return parseShorthand(propId, properties, 3, important);
1632     }
1633     case CSSPropertyOutline:
1634         // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1635     {
1636         const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle,
1637                                     CSSPropertyOutlineColor };
1638         return parseShorthand(propId, properties, 3, important);
1639     }
1640     case CSSPropertyBorderColor:
1641         // <color>{1,4} | inherit
1642     {
1643         const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor,
1644                                     CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor };
1645         return parse4Values(propId, properties, important);
1646     }
1647     case CSSPropertyBorderWidth:
1648         // <border-width>{1,4} | inherit
1649     {
1650         const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth,
1651                                     CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth };
1652         return parse4Values(propId, properties, important);
1653     }
1654     case CSSPropertyBorderStyle:
1655         // <border-style>{1,4} | inherit
1656     {
1657         const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle,
1658                                     CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle };
1659         return parse4Values(propId, properties, important);
1660     }
1661     case CSSPropertyMargin:
1662         // <margin-width>{1,4} | inherit
1663     {
1664         const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight,
1665                                     CSSPropertyMarginBottom, CSSPropertyMarginLeft };
1666         return parse4Values(propId, properties, important);
1667     }
1668     case CSSPropertyPadding:
1669         // <padding-width>{1,4} | inherit
1670     {
1671         const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight,
1672                                     CSSPropertyPaddingBottom, CSSPropertyPaddingLeft };
1673         return parse4Values(propId, properties, important);
1674     }
1675     case CSSPropertyFont:
1676         // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1677         // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1678         if (id >= CSSValueCaption && id <= CSSValueStatusBar)
1679             validPrimitive = true;
1680         else
1681             return parseFont(important);
1682         break;
1683     case CSSPropertyListStyle:
1684     {
1685         const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition,
1686                                     CSSPropertyListStyleImage };
1687         return parseShorthand(propId, properties, 3, important);
1688     }
1689     case CSSPropertyWebkitColumns: {
1690         const int properties[2] = { CSSPropertyWebkitColumnWidth, CSSPropertyWebkitColumnCount };
1691         return parseShorthand(propId, properties, 2, important);
1692     }
1693     case CSSPropertyWebkitColumnRule: {
1694         const int properties[3] = { CSSPropertyWebkitColumnRuleWidth, CSSPropertyWebkitColumnRuleStyle,
1695                                     CSSPropertyWebkitColumnRuleColor };
1696         return parseShorthand(propId, properties, 3, important);
1697     }
1698     case CSSPropertyWebkitTextStroke: {
1699         const int properties[2] = { CSSPropertyWebkitTextStrokeWidth, CSSPropertyWebkitTextStrokeColor };
1700         return parseShorthand(propId, properties, 2, important);
1701     }
1702     case CSSPropertyWebkitAnimation:
1703         return parseAnimationShorthand(important);
1704     case CSSPropertyWebkitTransition:
1705         return parseTransitionShorthand(important);
1706     case CSSPropertyInvalid:
1707         return false;
1708     case CSSPropertyPage:
1709         return parsePage(propId, important);
1710     case CSSPropertyFontStretch:
1711     case CSSPropertyTextLineThrough:
1712     case CSSPropertyTextOverline:
1713     case CSSPropertyTextUnderline:
1714     case CSSPropertyWebkitVariableDeclarationBlock:
1715         return false;
1716 #if ENABLE(WCSS)
1717     case CSSPropertyWapInputFormat:
1718         validPrimitive = true;
1719         break;
1720     case CSSPropertyWapInputRequired:
1721         parsedValue = parseWCSSInputProperty();
1722         break;
1723 #endif
1724
1725 #if ENABLE(SVG)
1726     default:
1727         return parseSVGValue(propId, important);
1728 #endif
1729     }
1730
1731     if (validPrimitive) {
1732         if (id != 0)
1733             parsedValue = CSSPrimitiveValue::createIdentifier(id);
1734         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
1735             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
1736         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1737             parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
1738         else if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_REMS)
1739             parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
1740         else if (value->unit >= CSSParserValue::Q_EMS)
1741             parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS);
1742         m_valueList->next();
1743     }
1744     if (parsedValue) {
1745         if (!m_valueList->current() || inShorthand()) {
1746             addProperty(propId, parsedValue.release(), important);
1747             return true;
1748         }
1749     }
1750     return false;
1751 }
1752
1753 #if ENABLE(WCSS)
1754 PassRefPtr<CSSValue> CSSParser::parseWCSSInputProperty()
1755 {
1756     RefPtr<CSSValue> parsedValue = 0;
1757     CSSParserValue* value = m_valueList->current();
1758     String inputProperty;
1759     if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT)
1760         inputProperty = String(value->string);
1761
1762     if (!inputProperty.isEmpty())
1763        parsedValue = CSSPrimitiveValue::create(inputProperty, CSSPrimitiveValue::CSS_STRING);
1764
1765     while (m_valueList->next()) {
1766     // pass all other values, if any. If we don't do this,
1767     // the parser will think that it's not done and won't process this property
1768     }
1769
1770     return parsedValue;
1771 }
1772 #endif
1773
1774 void CSSParser::addFillValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
1775 {
1776     if (lval) {
1777         if (lval->isValueList())
1778             static_cast<CSSValueList*>(lval.get())->append(rval);
1779         else {
1780             PassRefPtr<CSSValue> oldlVal(lval.release());
1781             PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1782             list->append(oldlVal);
1783             list->append(rval);
1784             lval = list;
1785         }
1786     }
1787     else
1788         lval = rval;
1789 }
1790
1791 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr<CSSValue>& cssValue)
1792 {
1793     if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox || parserValue->id == CSSValueWebkitText) {
1794         cssValue = CSSPrimitiveValue::createIdentifier(parserValue->id);
1795         return true;
1796     }
1797     return false;
1798 }
1799
1800 const int cMaxFillProperties = 9;
1801
1802 bool CSSParser::parseFillShorthand(int propId, const int* properties, int numProperties, bool important)
1803 {
1804     ASSERT(numProperties <= cMaxFillProperties);
1805     if (numProperties > cMaxFillProperties)
1806         return false;
1807
1808     ShorthandScope scope(this, propId);
1809
1810     bool parsedProperty[cMaxFillProperties] = { false };
1811     RefPtr<CSSValue> values[cMaxFillProperties];
1812     RefPtr<CSSValue> clipValue;
1813     RefPtr<CSSValue> positionYValue;
1814     RefPtr<CSSValue> repeatYValue;
1815     int i;
1816
1817     while (m_valueList->current()) {
1818         CSSParserValue* val = m_valueList->current();
1819         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1820             // We hit the end.  Fill in all remaining values with the initial value.
1821             m_valueList->next();
1822             for (i = 0; i < numProperties; ++i) {
1823                 if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i])
1824                     // Color is not allowed except as the last item in a list for backgrounds.
1825                     // Reject the entire property.
1826                     return false;
1827
1828                 if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) {
1829                     addFillValue(values[i], CSSInitialValue::createImplicit());
1830                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1831                         addFillValue(positionYValue, CSSInitialValue::createImplicit());
1832                     if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1833                         addFillValue(repeatYValue, CSSInitialValue::createImplicit());
1834                     if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
1835                         // If background-origin wasn't present, then reset background-clip also.
1836                         addFillValue(clipValue, CSSInitialValue::createImplicit());
1837                     }
1838                 }
1839                 parsedProperty[i] = false;
1840             }
1841             if (!m_valueList->current())
1842                 break;
1843         }
1844
1845         bool found = false;
1846         for (i = 0; !found && i < numProperties; ++i) {
1847             if (!parsedProperty[i]) {
1848                 RefPtr<CSSValue> val1;
1849                 RefPtr<CSSValue> val2;
1850                 int propId1, propId2;
1851                 CSSParserValue* parserValue = m_valueList->current();
1852                 if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) {
1853                     parsedProperty[i] = found = true;
1854                     addFillValue(values[i], val1.release());
1855                     if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1856                         addFillValue(positionYValue, val2.release());
1857                     if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1858                         addFillValue(repeatYValue, val2.release());
1859                     if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) {
1860                         // Reparse the value as a clip, and see if we succeed.
1861                         if (parseBackgroundClip(parserValue, val1))
1862                             addFillValue(clipValue, val1.release()); // The property parsed successfully.
1863                         else
1864                             addFillValue(clipValue, CSSInitialValue::createImplicit()); // Some value was used for origin that is not supported by clip. Just reset clip instead.
1865                     }
1866                 }
1867             }
1868         }
1869
1870         // if we didn't find at least one match, this is an
1871         // invalid shorthand and we have to ignore it
1872         if (!found)
1873             return false;
1874     }
1875
1876     // Fill in any remaining properties with the initial value.
1877     for (i = 0; i < numProperties; ++i) {
1878         if (!parsedProperty[i]) {
1879             addFillValue(values[i], CSSInitialValue::createImplicit());
1880             if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition)
1881                 addFillValue(positionYValue, CSSInitialValue::createImplicit());
1882             if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat)
1883                 addFillValue(repeatYValue, CSSInitialValue::createImplicit());
1884             if ((properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) {
1885                 // If background-origin wasn't present, then reset background-clip also.
1886                 addFillValue(clipValue, CSSInitialValue::createImplicit());
1887             }
1888         }
1889     }
1890
1891     // Now add all of the properties we found.
1892     for (i = 0; i < numProperties; i++) {
1893         if (properties[i] == CSSPropertyBackgroundPosition) {
1894             addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important);
1895             // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once
1896             addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important);
1897         } else if (properties[i] == CSSPropertyWebkitMaskPosition) {
1898             addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important);
1899             // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once
1900             addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important);
1901         } else if (properties[i] == CSSPropertyBackgroundRepeat) {
1902             addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important);
1903             // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
1904             addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important);
1905         } else if (properties[i] == CSSPropertyWebkitMaskRepeat) {
1906             addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important);
1907             // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once
1908             addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important);
1909         } else
1910             addProperty(properties[i], values[i].release(), important);
1911
1912         // Add in clip values when we hit the corresponding origin property.
1913         if (properties[i] == CSSPropertyBackgroundOrigin)
1914             addProperty(CSSPropertyBackgroundClip, clipValue.release(), important);
1915         else  if (properties[i] == CSSPropertyWebkitMaskOrigin)
1916             addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important);
1917     }
1918
1919     return true;
1920 }
1921
1922 void CSSParser::addAnimationValue(RefPtr<CSSValue>& lval, PassRefPtr<CSSValue> rval)
1923 {
1924     if (lval) {
1925         if (lval->isValueList())
1926             static_cast<CSSValueList*>(lval.get())->append(rval);
1927         else {
1928             PassRefPtr<CSSValue> oldVal(lval.release());
1929             PassRefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1930             list->append(oldVal);
1931             list->append(rval);
1932             lval = list;
1933         }
1934     }
1935     else
1936         lval = rval;
1937 }
1938
1939 bool CSSParser::parseAnimationShorthand(bool important)
1940 {
1941     const int properties[] = {  CSSPropertyWebkitAnimationName,
1942                                 CSSPropertyWebkitAnimationDuration,
1943                                 CSSPropertyWebkitAnimationTimingFunction,
1944                                 CSSPropertyWebkitAnimationDelay,
1945                                 CSSPropertyWebkitAnimationIterationCount,
1946                                 CSSPropertyWebkitAnimationDirection,
1947                                 CSSPropertyWebkitAnimationFillMode };
1948     const int numProperties = sizeof(properties) / sizeof(properties[0]);
1949
1950     ShorthandScope scope(this, CSSPropertyWebkitAnimation);
1951
1952     bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
1953     RefPtr<CSSValue> values[numProperties];
1954
1955     int i;
1956     while (m_valueList->current()) {
1957         CSSParserValue* val = m_valueList->current();
1958         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
1959             // We hit the end.  Fill in all remaining values with the initial value.
1960             m_valueList->next();
1961             for (i = 0; i < numProperties; ++i) {
1962                 if (!parsedProperty[i])
1963                     addAnimationValue(values[i], CSSInitialValue::createImplicit());
1964                 parsedProperty[i] = false;
1965             }
1966             if (!m_valueList->current())
1967                 break;
1968         }
1969
1970         bool found = false;
1971         for (i = 0; !found && i < numProperties; ++i) {
1972             if (!parsedProperty[i]) {
1973                 RefPtr<CSSValue> val;
1974                 if (parseAnimationProperty(properties[i], val)) {
1975                     parsedProperty[i] = found = true;
1976                     addAnimationValue(values[i], val.release());
1977                 }
1978             }
1979         }
1980
1981         // if we didn't find at least one match, this is an
1982         // invalid shorthand and we have to ignore it
1983         if (!found)
1984             return false;
1985     }
1986
1987     // Fill in any remaining properties with the initial value.
1988     for (i = 0; i < numProperties; ++i) {
1989         if (!parsedProperty[i])
1990             addAnimationValue(values[i], CSSInitialValue::createImplicit());
1991     }
1992
1993     // Now add all of the properties we found.
1994     for (i = 0; i < numProperties; i++)
1995         addProperty(properties[i], values[i].release(), important);
1996
1997     return true;
1998 }
1999
2000 bool CSSParser::parseTransitionShorthand(bool important)
2001 {
2002     const int properties[] = { CSSPropertyWebkitTransitionProperty,
2003                                CSSPropertyWebkitTransitionDuration,
2004                                CSSPropertyWebkitTransitionTimingFunction,
2005                                CSSPropertyWebkitTransitionDelay };
2006     const int numProperties = sizeof(properties) / sizeof(properties[0]);
2007
2008     ShorthandScope scope(this, CSSPropertyWebkitTransition);
2009
2010     bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
2011     RefPtr<CSSValue> values[numProperties];
2012
2013     int i;
2014     while (m_valueList->current()) {
2015         CSSParserValue* val = m_valueList->current();
2016         if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
2017             // We hit the end.  Fill in all remaining values with the initial value.
2018             m_valueList->next();
2019             for (i = 0; i < numProperties; ++i) {
2020                 if (!parsedProperty[i])
2021                     addAnimationValue(values[i], CSSInitialValue::createImplicit());
2022                 parsedProperty[i] = false;
2023             }
2024             if (!m_valueList->current())
2025                 break;
2026         }
2027
2028         bool found = false;
2029         for (i = 0; !found && i < numProperties; ++i) {
2030             if (!parsedProperty[i]) {
2031                 RefPtr<CSSValue> val;
2032                 if (parseAnimationProperty(properties[i], val)) {
2033                     parsedProperty[i] = found = true;
2034                     addAnimationValue(values[i], val.release());
2035                 }
2036             }
2037         }
2038
2039         // if we didn't find at least one match, this is an
2040         // invalid shorthand and we have to ignore it
2041         if (!found)
2042             return false;
2043     }
2044
2045     // Fill in any remaining properties with the initial value.
2046     for (i = 0; i < numProperties; ++i) {
2047         if (!parsedProperty[i])
2048             addAnimationValue(values[i], CSSInitialValue::createImplicit());
2049     }
2050
2051     // Now add all of the properties we found.
2052     for (i = 0; i < numProperties; i++)
2053         addProperty(properties[i], values[i].release(), important);
2054
2055     return true;
2056 }
2057
2058 bool CSSParser::parseShorthand(int propId, const int *properties, int numProperties, bool important)
2059 {
2060     // We try to match as many properties as possible
2061     // We set up an array of booleans to mark which property has been found,
2062     // and we try to search for properties until it makes no longer any sense.
2063     ShorthandScope scope(this, propId);
2064
2065     bool found = false;
2066     bool fnd[6]; // Trust me ;)
2067     for (int i = 0; i < numProperties; i++)
2068         fnd[i] = false;
2069
2070     while (m_valueList->current()) {
2071         found = false;
2072         for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
2073             if (!fnd[propIndex]) {
2074                 if (parseValue(properties[propIndex], important))
2075                     fnd[propIndex] = found = true;
2076             }
2077         }
2078
2079         // if we didn't find at least one match, this is an
2080         // invalid shorthand and we have to ignore it
2081         if (!found)
2082             return false;
2083     }
2084
2085     // Fill in any remaining properties with the initial value.
2086     m_implicitShorthand = true;
2087     for (int i = 0; i < numProperties; ++i) {
2088         if (!fnd[i])
2089             addProperty(properties[i], CSSInitialValue::createImplicit(), important);
2090     }
2091     m_implicitShorthand = false;
2092
2093     return true;
2094 }
2095
2096 bool CSSParser::parse4Values(int propId, const int *properties,  bool important)
2097 {
2098     /* From the CSS 2 specs, 8.3
2099      * If there is only one value, it applies to all sides. If there are two values, the top and
2100      * bottom margins are set to the first value and the right and left margins are set to the second.
2101      * If there are three values, the top is set to the first value, the left and right are set to the
2102      * second, and the bottom is set to the third. If there are four values, they apply to the top,
2103      * right, bottom, and left, respectively.
2104      */
2105
2106     int num = inShorthand() ? 1 : m_valueList->size();
2107
2108     ShorthandScope scope(this, propId);
2109
2110     // the order is top, right, bottom, left
2111     switch (num) {
2112         case 1: {
2113             if (!parseValue(properties[0], important))
2114                 return false;
2115             CSSValue *value = m_parsedProperties[m_numParsedProperties-1]->value();
2116             m_implicitShorthand = true;
2117             addProperty(properties[1], value, important);
2118             addProperty(properties[2], value, important);
2119             addProperty(properties[3], value, important);
2120             m_implicitShorthand = false;
2121             break;
2122         }
2123         case 2: {
2124             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
2125                 return false;
2126             CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
2127             m_implicitShorthand = true;
2128             addProperty(properties[2], value, important);
2129             value = m_parsedProperties[m_numParsedProperties-2]->value();
2130             addProperty(properties[3], value, important);
2131             m_implicitShorthand = false;
2132             break;
2133         }
2134         case 3: {
2135             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
2136                 return false;
2137             CSSValue *value = m_parsedProperties[m_numParsedProperties-2]->value();
2138             m_implicitShorthand = true;
2139             addProperty(properties[3], value, important);
2140             m_implicitShorthand = false;
2141             break;
2142         }
2143         case 4: {
2144             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
2145                 !parseValue(properties[2], important) || !parseValue(properties[3], important))
2146                 return false;
2147             break;
2148         }
2149         default: {
2150             return false;
2151         }
2152     }
2153
2154     return true;
2155 }
2156
2157 // auto | <identifier>
2158 bool CSSParser::parsePage(int propId, bool important)
2159 {
2160     ASSERT(propId == CSSPropertyPage);
2161
2162     if (m_valueList->size() != 1)
2163         return false;
2164
2165     CSSParserValue* value = m_valueList->current();
2166     if (!value)
2167         return false;
2168
2169     if (value->id == CSSValueAuto) {
2170         addProperty(propId, CSSPrimitiveValue::createIdentifier(value->id), important);
2171         return true;
2172     } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) {
2173         addProperty(propId, CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING), important);
2174         return true;
2175     }
2176     return false;
2177 }
2178
2179 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
2180 bool CSSParser::parseSize(int propId, bool important)
2181 {
2182     ASSERT(propId == CSSPropertySize);
2183
2184     if (m_valueList->size() > 2)
2185         return false;
2186
2187     CSSParserValue* value = m_valueList->current();
2188     if (!value)
2189         return false;
2190
2191     RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
2192
2193     // First parameter.
2194     SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None);
2195     if (paramType == None)
2196         return false;
2197
2198     // Second parameter, if any.
2199     value = m_valueList->next();
2200     if (value) {
2201         paramType = parseSizeParameter(parsedValues.get(), value, paramType);
2202         if (paramType == None)
2203             return false;
2204     }
2205
2206     addProperty(propId, parsedValues.release(), important);
2207     return true;
2208 }
2209
2210 CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType)
2211 {
2212     switch (value->id) {
2213     case CSSValueAuto:
2214         if (prevParamType == None) {
2215             parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
2216             return Auto;
2217         }
2218         return None;
2219     case CSSValueLandscape:
2220     case CSSValuePortrait:
2221         if (prevParamType == None || prevParamType == PageSize) {
2222             parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
2223             return Orientation;
2224         }
2225         return None;
2226     case CSSValueA3:
2227     case CSSValueA4:
2228     case CSSValueA5:
2229     case CSSValueB4:
2230     case CSSValueB5:
2231     case CSSValueLedger:
2232     case CSSValueLegal:
2233     case CSSValueLetter:
2234         if (prevParamType == None || prevParamType == Orientation) {
2235             // Normalize to Page Size then Orientation order by prepending.
2236             // This is not specified by the CSS3 Paged Media specification, but for simpler processing later (CSSStyleSelector::applyPageSizeProperty).
2237             parsedValues->prepend(CSSPrimitiveValue::createIdentifier(value->id));
2238             return PageSize;
2239         }
2240         return None;
2241     case 0:
2242         if (validUnit(value, FLength | FNonNeg, m_strict) && (prevParamType == None || prevParamType == Length)) {
2243             parsedValues->append(CSSPrimitiveValue::create(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit)));
2244             return Length;
2245         }
2246         return None;
2247     default:
2248         return None;
2249     }
2250 }
2251
2252 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2253 // in CSS 2.1 this got somewhat reduced:
2254 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
2255 bool CSSParser::parseContent(int propId, bool important)
2256 {
2257     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
2258
2259     while (CSSParserValue* val = m_valueList->current()) {
2260         RefPtr<CSSValue> parsedValue;
2261         if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
2262             // url
2263             // FIXME: The completeURL call should be done when using the CSSImageValue,
2264             // not when creating it.
2265             parsedValue = CSSImageValue::create(m_styleSheet->completeURL(val->string));
2266         } else if (val->unit == CSSParserValue::Function) {
2267             // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...)
2268             CSSParserValueList* args = val->function->args.get();
2269             if (!args)
2270                 return false;
2271             if (equalIgnoringCase(val->function->name, "attr(")) {
2272                 parsedValue = parseAttr(args);
2273                 if (!parsedValue)
2274                     return false;
2275             } else if (equalIgnoringCase(val->function->name, "counter(")) {
2276                 parsedValue = parseCounterContent(args, false);
2277                 if (!parsedValue)
2278                     return false;
2279             } else if (equalIgnoringCase(val->function->name, "counters(")) {
2280                 parsedValue = parseCounterContent(args, true);
2281                 if (!parsedValue)
2282                     return false;
2283             } else if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) {
2284                 if (!parseGradient(parsedValue))
2285                     return false;
2286             } else if (equalIgnoringCase(val->function->name, "-webkit-canvas(")) {
2287                 if (!parseCanvas(parsedValue))
2288                     return false;
2289             } else
2290                 return false;
2291         } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
2292             // open-quote
2293             // close-quote
2294             // no-open-quote
2295             // no-close-quote
2296             // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
2297         } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
2298             parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
2299         }
2300         if (!parsedValue)
2301             break;
2302         values->append(parsedValue.release());
2303         m_valueList->next();
2304     }
2305
2306     if (values->length()) {
2307         addProperty(propId, values.release(), important);
2308         m_valueList->next();
2309         return true;
2310     }
2311
2312     return false;
2313 }
2314
2315 PassRefPtr<CSSValue> CSSParser::parseAttr(CSSParserValueList* args)
2316 {
2317     if (args->size() != 1)
2318         return 0;
2319
2320     CSSParserValue* a = args->current();
2321
2322     if (a->unit != CSSPrimitiveValue::CSS_IDENT)
2323         return 0;
2324
2325     String attrName = a->string;
2326     // CSS allows identifiers with "-" at the start, like "-webkit-mask-image".
2327     // But HTML attribute names can't have those characters, and we should not
2328     // even parse them inside attr().
2329     if (attrName[0] == '-')
2330         return 0;
2331
2332     if (document() && document()->isHTMLDocument())
2333         attrName = attrName.lower();
2334
2335     return CSSPrimitiveValue::create(attrName, CSSPrimitiveValue::CSS_ATTR);
2336 }
2337
2338 PassRefPtr<CSSValue> CSSParser::parseBackgroundColor()
2339 {
2340     int id = m_valueList->current()->id;
2341     if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor ||
2342         (id >= CSSValueGrey && id < CSSValueWebkitText && !m_strict))
2343        return CSSPrimitiveValue::createIdentifier(id);
2344     return parseColor();
2345 }
2346
2347 bool CSSParser::parseFillImage(RefPtr<CSSValue>& value)
2348 {
2349     if (m_valueList->current()->id == CSSValueNone) {
2350         value = CSSImageValue::create();
2351         return true;
2352     }
2353     if (m_valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
2354         // FIXME: The completeURL call should be done when using the CSSImageValue,
2355         // not when creating it.
2356         if (m_styleSheet)
2357             value = CSSImageValue::create(m_styleSheet->completeURL(m_valueList->current()->string));
2358         return true;
2359     }
2360
2361     if (m_valueList->current()->unit == CSSParserValue::Function) {
2362         if (equalIgnoringCase(m_valueList->current()->function->name, "-webkit-gradient("))
2363             return parseGradient(value);
2364         if (equalIgnoringCase(m_valueList->current()->function->name, "-webkit-canvas("))
2365             return parseCanvas(value);
2366     }
2367
2368     return false;
2369 }
2370
2371 PassRefPtr<CSSValue> CSSParser::parseFillPositionXY(bool& xFound, bool& yFound)
2372 {
2373     int id = m_valueList->current()->id;
2374     if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) {
2375         int percent = 0;
2376         if (id == CSSValueLeft || id == CSSValueRight) {
2377             if (xFound)
2378                 return 0;
2379             xFound = true;
2380             if (id == CSSValueRight)
2381                 percent = 100;
2382         }
2383         else if (id == CSSValueTop || id == CSSValueBottom) {
2384             if (yFound)
2385                 return 0;
2386             yFound = true;
2387             if (id == CSSValueBottom)
2388                 percent = 100;
2389         }
2390         else if (id == CSSValueCenter)
2391             // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
2392             percent = 50;
2393         return CSSPrimitiveValue::create(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
2394     }
2395     if (validUnit(m_valueList->current(), FPercent | FLength, m_strict))
2396         return CSSPrimitiveValue::create(m_valueList->current()->fValue,
2397                                          (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
2398
2399     return 0;
2400 }
2401
2402 void CSSParser::parseFillPosition(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
2403 {
2404     CSSParserValue* value = m_valueList->current();
2405
2406     // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
2407     bool value1IsX = false, value1IsY = false;
2408     value1 = parseFillPositionXY(value1IsX, value1IsY);
2409     if (!value1)
2410         return;
2411
2412     // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
2413     // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
2414     // value was explicitly specified for our property.
2415     value = m_valueList->next();
2416
2417     // First check for the comma.  If so, we are finished parsing this value or value pair.
2418     if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
2419         value = 0;
2420
2421     bool value2IsX = false, value2IsY = false;
2422     if (value) {
2423         value2 = parseFillPositionXY(value2IsX, value2IsY);
2424         if (value2)
2425             m_valueList->next();
2426         else {
2427             if (!inShorthand()) {
2428                 value1.clear();
2429                 return;
2430             }
2431         }
2432     }
2433
2434     if (!value2)
2435         // Only one value was specified.  If that value was not a keyword, then it sets the x position, and the y position
2436         // is simply 50%.  This is our default.
2437         // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
2438         // For left/right/center, the default of 50% in the y is still correct.
2439         value2 = CSSPrimitiveValue::create(50, CSSPrimitiveValue::CSS_PERCENTAGE);
2440
2441     if (value1IsY || value2IsX)
2442         value1.swap(value2);
2443 }
2444
2445 void CSSParser::parseFillRepeat(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2)
2446 {
2447     CSSParserValue* value = m_valueList->current();
2448
2449     int id = m_valueList->current()->id;
2450     if (id == CSSValueRepeatX) {
2451         m_implicitShorthand = true;
2452         value1 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
2453         value2 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
2454         m_valueList->next();
2455         return;
2456     }
2457     if (id == CSSValueRepeatY) {
2458         m_implicitShorthand = true;
2459         value1 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
2460         value2 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
2461         m_valueList->next();
2462         return;
2463     }
2464     if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)
2465         value1 = CSSPrimitiveValue::createIdentifier(id);
2466     else {
2467         value1 = 0;
2468         return;
2469     }
2470
2471     value = m_valueList->next();
2472
2473     // First check for the comma.  If so, we are finished parsing this value or value pair.
2474     if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
2475         value = 0;
2476
2477     if (value)
2478         id = m_valueList->current()->id;
2479
2480     if (value && (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace)) {
2481         value2 = CSSPrimitiveValue::createIdentifier(id);
2482         m_valueList->next();
2483     } else {
2484         // If only one value was specified, value2 is the same as value1.
2485         m_implicitShorthand = true;
2486         value2 = CSSPrimitiveValue::createIdentifier(static_cast<CSSPrimitiveValue*>(value1.get())->getIdent());
2487     }
2488 }
2489
2490 PassRefPtr<CSSValue> CSSParser::parseFillSize(int propId, bool& allowComma)
2491 {
2492     allowComma = true;
2493     CSSParserValue* value = m_valueList->current();
2494
2495     if (value->id == CSSValueContain || value->id == CSSValueCover)
2496         return CSSPrimitiveValue::createIdentifier(value->id);
2497
2498     RefPtr<CSSPrimitiveValue> parsedValue1;
2499
2500     if (value->id == CSSValueAuto)
2501         parsedValue1 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN);
2502     else {
2503         if (!validUnit(value, FLength | FPercent, m_strict))
2504             return 0;
2505         parsedValue1 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2506     }
2507
2508     CSSPropertyID property = static_cast<CSSPropertyID>(propId);
2509     RefPtr<CSSPrimitiveValue> parsedValue2;
2510     if ((value = m_valueList->next())) {
2511         if (value->id == CSSValueAuto)
2512             parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN);
2513         else if (value->unit == CSSParserValue::Operator && value->iValue == ',')
2514             allowComma = false;
2515         else {
2516             if (!validUnit(value, FLength | FPercent, m_strict))
2517                 return 0;
2518             parsedValue2 = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2519         }
2520     }
2521     if (!parsedValue2) {
2522         if (property == CSSPropertyWebkitBackgroundSize || property == CSSPropertyWebkitMaskSize)
2523             parsedValue2 = parsedValue1;
2524         else
2525             parsedValue2 = CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_UNKNOWN);
2526     }
2527
2528     return CSSPrimitiveValue::create(Pair::create(parsedValue1.release(), parsedValue2.release()));
2529 }
2530
2531 bool CSSParser::parseFillProperty(int propId, int& propId1, int& propId2,
2532                                   RefPtr<CSSValue>& retValue1, RefPtr<CSSValue>& retValue2)
2533 {
2534     RefPtr<CSSValueList> values;
2535     RefPtr<CSSValueList> values2;
2536     CSSParserValue* val;
2537     RefPtr<CSSValue> value;
2538     RefPtr<CSSValue> value2;
2539
2540     bool allowComma = false;
2541
2542     retValue1 = retValue2 = 0;
2543     propId1 = propId;
2544     propId2 = propId;
2545     if (propId == CSSPropertyBackgroundPosition) {
2546         propId1 = CSSPropertyBackgroundPositionX;
2547         propId2 = CSSPropertyBackgroundPositionY;
2548     } else if (propId == CSSPropertyWebkitMaskPosition) {
2549         propId1 = CSSPropertyWebkitMaskPositionX;
2550         propId2 = CSSPropertyWebkitMaskPositionY;
2551     } else if (propId == CSSPropertyBackgroundRepeat) {
2552         propId1 = CSSPropertyBackgroundRepeatX;
2553         propId2 = CSSPropertyBackgroundRepeatY;
2554     } else if (propId == CSSPropertyWebkitMaskRepeat) {
2555         propId1 = CSSPropertyWebkitMaskRepeatX;
2556         propId2 = CSSPropertyWebkitMaskRepeatY;
2557     }
2558
2559     while ((val = m_valueList->current())) {
2560         RefPtr<CSSValue> currValue;
2561         RefPtr<CSSValue> currValue2;
2562
2563         if (allowComma) {
2564             if (val->unit != CSSParserValue::Operator || val->iValue != ',')
2565                 return false;
2566             m_valueList->next();
2567             allowComma = false;
2568         } else {
2569             allowComma = true;
2570             switch (propId) {
2571                 case CSSPropertyBackgroundColor:
2572                     currValue = parseBackgroundColor();
2573                     if (currValue)
2574                         m_valueList->next();
2575                     break;
2576                 case CSSPropertyBackgroundAttachment:
2577                 case CSSPropertyWebkitMaskAttachment:
2578                     if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) {
2579                         currValue = CSSPrimitiveValue::createIdentifier(val->id);
2580                         m_valueList->next();
2581                     }
2582                     break;
2583                 case CSSPropertyBackgroundImage:
2584                 case CSSPropertyWebkitMaskImage:
2585                     if (parseFillImage(currValue))
2586                         m_valueList->next();
2587                     break;
2588                 case CSSPropertyWebkitBackgroundClip:
2589                 case CSSPropertyWebkitBackgroundOrigin:
2590                 case CSSPropertyWebkitMaskClip:
2591                 case CSSPropertyWebkitMaskOrigin:
2592                     // The first three values here are deprecated and do not apply to the version of the property that has
2593                     // the -webkit- prefix removed.
2594                     if (val->id == CSSValueBorder || val->id == CSSValuePadding || val->id == CSSValueContent ||
2595                         val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox ||
2596                         ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSPropertyWebkitMaskClip) &&
2597                          (val->id == CSSValueText || val->id == CSSValueWebkitText))) {
2598                         currValue = CSSPrimitiveValue::createIdentifier(val->id);
2599                         m_valueList->next();
2600                     }
2601                     break;
2602                 case CSSPropertyBackgroundClip:
2603                     if (parseBackgroundClip(val, currValue))
2604                         m_valueList->next();
2605                     break;
2606                 case CSSPropertyBackgroundOrigin:
2607                     if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) {
2608                         currValue = CSSPrimitiveValue::createIdentifier(val->id);
2609                         m_valueList->next();
2610                     }
2611                     break;
2612                 case CSSPropertyBackgroundPosition:
2613                 case CSSPropertyWebkitMaskPosition:
2614                     parseFillPosition(currValue, currValue2);
2615                     // parseFillPosition advances the m_valueList pointer
2616                     break;
2617                 case CSSPropertyBackgroundPositionX:
2618                 case CSSPropertyWebkitMaskPositionX: {
2619                     bool xFound = false, yFound = true;
2620                     currValue = parseFillPositionXY(xFound, yFound);
2621                     if (currValue)
2622                         m_valueList->next();
2623                     break;
2624                 }
2625                 case CSSPropertyBackgroundPositionY:
2626                 case CSSPropertyWebkitMaskPositionY: {
2627                     bool xFound = true, yFound = false;
2628                     currValue = parseFillPositionXY(xFound, yFound);
2629                     if (currValue)
2630                         m_valueList->next();
2631                     break;
2632                 }
2633                 case CSSPropertyWebkitBackgroundComposite:
2634                 case CSSPropertyWebkitMaskComposite:
2635                     if ((val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) || val->id == CSSValueHighlight) {
2636                         currValue = CSSPrimitiveValue::createIdentifier(val->id);
2637                         m_valueList->next();
2638                     }
2639                     break;
2640                 case CSSPropertyBackgroundRepeat:
2641                 case CSSPropertyWebkitMaskRepeat:
2642                     parseFillRepeat(currValue, currValue2);
2643                     // parseFillRepeat advances the m_valueList pointer
2644                     break;
2645                 case CSSPropertyBackgroundSize:
2646                 case CSSPropertyWebkitBackgroundSize:
2647                 case CSSPropertyWebkitMaskSize: {
2648                     currValue = parseFillSize(propId, allowComma);
2649                     if (currValue)
2650                         m_valueList->next();
2651                     break;
2652                 }
2653             }
2654             if (!currValue)
2655                 return false;
2656
2657             if (value && !values) {
2658                 values = CSSValueList::createCommaSeparated();
2659                 values->append(value.release());
2660             }
2661
2662             if (value2 && !values2) {
2663                 values2 = CSSValueList::createCommaSeparated();
2664                 values2->append(value2.release());
2665             }
2666
2667             if (values)
2668                 values->append(currValue.release());
2669             else
2670                 value = currValue.release();
2671             if (currValue2) {
2672                 if (values2)
2673                     values2->append(currValue2.release());
2674                 else
2675                     value2 = currValue2.release();
2676             }
2677         }
2678
2679         // When parsing any fill shorthand property, we let it handle building up the lists for all
2680         // properties.
2681         if (inShorthand())
2682             break;
2683     }
2684
2685     if (values && values->length()) {
2686         retValue1 = values.release();
2687         if (values2 && values2->length())
2688             retValue2 = values2.release();
2689         return true;
2690     }
2691     if (value) {
2692         retValue1 = value.release();
2693         retValue2 = value2.release();
2694         return true;
2695     }
2696     return false;
2697 }
2698
2699 PassRefPtr<CSSValue> CSSParser::parseAnimationDelay()
2700 {
2701     CSSParserValue* value = m_valueList->current();
2702     if (validUnit(value, FTime, m_strict))
2703         return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2704     return 0;
2705 }
2706
2707 PassRefPtr<CSSValue> CSSParser::parseAnimationDirection()
2708 {
2709     CSSParserValue* value = m_valueList->current();
2710     if (value->id == CSSValueNormal || value->id == CSSValueAlternate)
2711         return CSSPrimitiveValue::createIdentifier(value->id);
2712     return 0;
2713 }
2714
2715 PassRefPtr<CSSValue> CSSParser::parseAnimationDuration()
2716 {
2717     CSSParserValue* value = m_valueList->current();
2718     if (validUnit(value, FTime | FNonNeg, m_strict))
2719         return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2720     return 0;
2721 }
2722
2723 PassRefPtr<CSSValue> CSSParser::parseAnimationFillMode()
2724 {
2725     CSSParserValue* value = m_valueList->current();
2726     if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth)
2727         return CSSPrimitiveValue::createIdentifier(value->id);
2728     return 0;
2729 }
2730
2731 PassRefPtr<CSSValue> CSSParser::parseAnimationIterationCount()
2732 {
2733     CSSParserValue* value = m_valueList->current();
2734     if (value->id == CSSValueInfinite)
2735         return CSSPrimitiveValue::createIdentifier(value->id);
2736     if (validUnit(value, FInteger | FNonNeg, m_strict))
2737         return CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2738     return 0;
2739 }
2740
2741 PassRefPtr<CSSValue> CSSParser::parseAnimationName()
2742 {
2743     CSSParserValue* value = m_valueList->current();
2744     if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
2745         if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none"))) {
2746             return CSSPrimitiveValue::createIdentifier(CSSValueNone);
2747         } else {
2748             return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_STRING);
2749         }
2750     }
2751     return 0;
2752 }
2753
2754 PassRefPtr<CSSValue> CSSParser::parseAnimationPlayState()
2755 {
2756     CSSParserValue* value = m_valueList->current();
2757     if (value->id == CSSValueRunning || value->id == CSSValuePaused)
2758         return CSSPrimitiveValue::createIdentifier(value->id);
2759     return 0;
2760 }
2761
2762 PassRefPtr<CSSValue> CSSParser::parseAnimationProperty()
2763 {
2764     CSSParserValue* value = m_valueList->current();
2765     if (value->unit != CSSPrimitiveValue::CSS_IDENT)
2766         return 0;
2767     int result = cssPropertyID(value->string);
2768     if (result)
2769         return CSSPrimitiveValue::createIdentifier(result);
2770     if (equalIgnoringCase(value->string, "all"))
2771         return CSSPrimitiveValue::createIdentifier(CSSValueAll);
2772     if (equalIgnoringCase(value->string, "none"))
2773         return CSSPrimitiveValue::createIdentifier(CSSValueNone);
2774     return 0;
2775 }
2776
2777 void CSSParser::parseTransformOriginShorthand(RefPtr<CSSValue>& value1, RefPtr<CSSValue>& value2, RefPtr<CSSValue>& value3)
2778 {
2779     parseFillPosition(value1, value2);
2780
2781     // now get z
2782     if (m_valueList->current() && validUnit(m_valueList->current(), FLength, m_strict))
2783         value3 = CSSPrimitiveValue::create(m_valueList->current()->fValue,
2784                                          (CSSPrimitiveValue::UnitTypes)m_valueList->current()->unit);
2785     if (value3)
2786         m_valueList->next();
2787 }
2788
2789 bool CSSParser::parseTimingFunctionValue(CSSParserValueList*& args, double& result)
2790 {
2791     CSSParserValue* v = args->current();
2792     if (!validUnit(v, FNumber, m_strict))
2793         return false;
2794     result = v->fValue;
2795     if (result < 0 || result > 1.0)
2796         return false;
2797     v = args->next();
2798     if (!v)
2799         // The last number in the function has no comma after it, so we're done.
2800         return true;
2801     if (v->unit != CSSParserValue::Operator && v->iValue != ',')
2802         return false;
2803     v = args->next();
2804     return true;
2805 }
2806
2807 PassRefPtr<CSSValue> CSSParser::parseAnimationTimingFunction()
2808 {
2809     CSSParserValue* value = m_valueList->current();
2810     if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut || value->id == CSSValueEaseInOut)
2811         return CSSPrimitiveValue::createIdentifier(value->id);
2812
2813     // We must be a function.
2814     if (value->unit != CSSParserValue::Function)
2815         return 0;
2816
2817     // The only timing function we accept for now is a cubic bezier function.  4 points must be specified.
2818     CSSParserValueList* args = value->function->args.get();
2819     if (!equalIgnoringCase(value->function->name, "cubic-bezier(") || !args || args->size() != 7)
2820         return 0;
2821
2822     // There are two points specified.  The values must be between 0 and 1.
2823     double x1, y1, x2, y2;
2824
2825     if (!parseTimingFunctionValue(args, x1))
2826         return 0;
2827     if (!parseTimingFunctionValue(args, y1))
2828         return 0;
2829     if (!parseTimingFunctionValue(args, x2))
2830         return 0;
2831     if (!parseTimingFunctionValue(args, y2))
2832         return 0;
2833
2834     return CSSTimingFunctionValue::create(x1, y1, x2, y2);
2835 }
2836
2837 bool CSSParser::parseAnimationProperty(int propId, RefPtr<CSSValue>& result)
2838 {
2839     RefPtr<CSSValueList> values;
2840     CSSParserValue* val;
2841     RefPtr<CSSValue> value;
2842     bool allowComma = false;
2843
2844     result = 0;
2845
2846     while ((val = m_valueList->current())) {
2847         RefPtr<CSSValue> currValue;
2848         if (allowComma) {
2849             if (val->unit != CSSParserValue::Operator || val->iValue != ',')
2850                 return false;
2851             m_valueList->next();
2852             allowComma = false;
2853         }
2854         else {
2855             switch (propId) {
2856                 case CSSPropertyWebkitAnimationDelay:
2857                 case CSSPropertyWebkitTransitionDelay:
2858                     currValue = parseAnimationDelay();
2859                     if (currValue)
2860                         m_valueList->next();
2861                     break;
2862                 case CSSPropertyWebkitAnimationDirection:
2863                     currValue = parseAnimationDirection();
2864                     if (currValue)
2865                         m_valueList->next();
2866                     break;
2867                 case CSSPropertyWebkitAnimationDuration:
2868                 case CSSPropertyWebkitTransitionDuration:
2869                     currValue = parseAnimationDuration();
2870                     if (currValue)
2871                         m_valueList->next();
2872                     break;
2873                 case CSSPropertyWebkitAnimationFillMode:
2874                     currValue = parseAnimationFillMode();
2875                     if (currValue)
2876                         m_valueList->next();
2877                     break;
2878                 case CSSPropertyWebkitAnimationIterationCount:
2879                     currValue = parseAnimationIterationCount();
2880                     if (currValue)
2881                         m_valueList->next();
2882                     break;
2883                 case CSSPropertyWebkitAnimationName:
2884                     currValue = parseAnimationName();
2885                     if (currValue)
2886                         m_valueList->next();
2887                     break;
2888                 case CSSPropertyWebkitAnimationPlayState:
2889                     currValue = parseAnimationPlayState();
2890                     if (currValue)
2891                         m_valueList->next();
2892                     break;
2893                 case CSSPropertyWebkitTransitionProperty:
2894                     currValue = parseAnimationProperty();
2895                     if (currValue)
2896                         m_valueList->next();
2897                     break;
2898                 case CSSPropertyWebkitAnimationTimingFunction:
2899                 case CSSPropertyWebkitTransitionTimingFunction:
2900                     currValue = parseAnimationTimingFunction();
2901                     if (currValue)
2902                         m_valueList->next();
2903                     break;
2904             }
2905
2906             if (!currValue)
2907                 return false;
2908
2909             if (value && !values) {
2910                 values = CSSValueList::createCommaSeparated();
2911                 values->append(value.release());
2912             }
2913
2914             if (values)
2915                 values->append(currValue.release());
2916             else
2917                 value = currValue.release();
2918
2919             allowComma = true;
2920         }
2921
2922         // When parsing the 'transition' shorthand property, we let it handle building up the lists for all
2923         // properties.
2924         if (inShorthand())
2925             break;
2926     }
2927
2928     if (values && values->length()) {
2929         result = values.release();
2930         return true;
2931     }
2932     if (value) {
2933         result = value.release();
2934         return true;
2935     }
2936     return false;
2937 }
2938
2939
2940
2941 #if ENABLE(DASHBOARD_SUPPORT)
2942
2943 #define DASHBOARD_REGION_NUM_PARAMETERS  6
2944 #define DASHBOARD_REGION_SHORT_NUM_PARAMETERS  2
2945
2946 static CSSParserValue* skipCommaInDashboardRegion(CSSParserValueList *args)
2947 {
2948     if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
2949          args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
2950         CSSParserValue* current = args->current();
2951         if (current->unit == CSSParserValue::Operator && current->iValue == ',')
2952             return args->next();
2953     }
2954     return args->current();
2955 }
2956
2957 bool CSSParser::parseDashboardRegions(int propId, bool important)
2958 {
2959     bool valid = true;
2960
2961     CSSParserValue* value = m_valueList->current();
2962
2963     if (value->id == CSSValueNone) {
2964         if (m_valueList->next())
2965             return false;
2966         addProperty(propId, CSSPrimitiveValue::createIdentifier(value->id), important);
2967         return valid;
2968     }
2969
2970     RefPtr<DashboardRegion> firstRegion = DashboardRegion::create();
2971     DashboardRegion* region = 0;
2972
2973     while (value) {
2974         if (region == 0) {
2975             region = firstRegion.get();
2976         } else {
2977             RefPtr<DashboardRegion> nextRegion = DashboardRegion::create();
2978             region->m_next = nextRegion;
2979             region = nextRegion.get();
2980         }
2981
2982         if (value->unit != CSSParserValue::Function) {
2983             valid = false;
2984             break;
2985         }
2986
2987         // Commas count as values, so allow:
2988         // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
2989         // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
2990         // also allow
2991         // dashboard-region(label, type) or dashboard-region(label type)
2992         // dashboard-region(label, type) or dashboard-region(label type)
2993         CSSParserValueList* args = value->function->args.get();
2994         if (!equalIgnoringCase(value->function->name, "dashboard-region(") || !args) {
2995             valid = false;
2996             break;
2997         }
2998
2999         int numArgs = args->size();
3000         if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
3001             (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) {
3002             valid = false;
3003             break;
3004         }
3005
3006         // First arg is a label.
3007         CSSParserValue* arg = args->current();
3008         if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
3009             valid = false;
3010             break;
3011         }
3012
3013         region->m_label = arg->string;
3014
3015         // Second arg is a type.
3016         arg = args->next();
3017         arg = skipCommaInDashboardRegion(args);
3018         if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
3019             valid = false;
3020             break;
3021         }
3022
3023         if (equalIgnoringCase(arg->string, "circle"))
3024             region->m_isCircle = true;
3025         else if (equalIgnoringCase(arg->string, "rectangle"))
3026             region->m_isRectangle = true;
3027         else {
3028             valid = false;
3029             break;
3030         }
3031
3032         region->m_geometryType = arg->string;
3033
3034         if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
3035             // This originally used CSSValueInvalid by accident. It might be more logical to use something else.
3036             RefPtr<CSSPrimitiveValue> amount = CSSPrimitiveValue::createIdentifier(CSSValueInvalid);
3037
3038             region->setTop(amount);
3039             region->setRight(amount);
3040             region->setBottom(amount);
3041             region->setLeft(amount);
3042         } else {
3043             // Next four arguments must be offset numbers
3044             int i;
3045             for (i = 0; i < 4; i++) {
3046                 arg = args->next();
3047                 arg = skipCommaInDashboardRegion(args);
3048
3049                 valid = arg->id == CSSValueAuto || validUnit(arg, FLength, m_strict);
3050                 if (!valid)
3051                     break;
3052
3053                 RefPtr<CSSPrimitiveValue> amount = arg->id == CSSValueAuto ?
3054                     CSSPrimitiveValue::createIdentifier(CSSValueAuto) :
3055                     CSSPrimitiveValue::create(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit);
3056
3057                 if (i == 0)
3058                     region->setTop(amount);
3059                 else if (i == 1)
3060                     region->setRight(amount);
3061                 else if (i == 2)
3062                     region->setBottom(amount);
3063                 else
3064                     region->setLeft(amount);
3065             }
3066         }
3067
3068         if (args->next())
3069             return false;
3070
3071         value = m_valueList->next();
3072     }
3073
3074     if (valid)
3075         addProperty(propId, CSSPrimitiveValue::create(firstRegion.release()), important);
3076
3077     return valid;
3078 }
3079
3080 #endif /* ENABLE(DASHBOARD_SUPPORT) */
3081
3082 PassRefPtr<CSSValue> CSSParser::parseCounterContent(CSSParserValueList* args, bool counters)
3083 {
3084     unsigned numArgs = args->size();
3085     if (counters && numArgs != 3 && numArgs != 5)
3086         return 0;
3087     if (!counters && numArgs != 1 && numArgs != 3)
3088         return 0;
3089
3090     CSSParserValue* i = args->current();
3091     if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3092         return 0;
3093     RefPtr<CSSPrimitiveValue> identifier = CSSPrimitiveValue::create(i->string, CSSPrimitiveValue::CSS_STRING);
3094
3095     RefPtr<CSSPrimitiveValue> separator;
3096     if (!counters)
3097         separator = CSSPrimitiveValue::create(String(), CSSPrimitiveValue::CSS_STRING);
3098     else {
3099         i = args->next();
3100         if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3101             return 0;
3102
3103         i = args->next();
3104         if (i->unit != CSSPrimitiveValue::CSS_STRING)
3105             return 0;
3106
3107         separator = CSSPrimitiveValue::create(i->string, (CSSPrimitiveValue::UnitTypes) i->unit);
3108     }
3109
3110     RefPtr<CSSPrimitiveValue> listStyle;
3111     i = args->next();
3112     if (!i) // Make the list style default decimal
3113         listStyle = CSSPrimitiveValue::create(CSSValueDecimal - CSSValueDisc, CSSPrimitiveValue::CSS_NUMBER);
3114     else {
3115         if (i->unit != CSSParserValue::Operator || i->iValue != ',')
3116             return 0;
3117
3118         i = args->next();
3119         if (i->unit != CSSPrimitiveValue::CSS_IDENT)
3120             return 0;
3121
3122         short ls = 0;
3123         if (i->id == CSSValueNone)
3124             ls = CSSValueKatakanaIroha - CSSValueDisc + 1;
3125         else if (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha)
3126             ls = i->id - CSSValueDisc;
3127         else
3128             return 0;
3129
3130         listStyle = CSSPrimitiveValue::create(ls, (CSSPrimitiveValue::UnitTypes) i->unit);
3131     }
3132
3133     return CSSPrimitiveValue::create(Counter::create(identifier.release(), listStyle.release(), separator.release()));
3134 }
3135
3136 bool CSSParser::parseShape(int propId, bool important)
3137 {
3138     CSSParserValue* value = m_valueList->current();
3139     CSSParserValueList* args = value->function->args.get();
3140
3141     if (!equalIgnoringCase(value->function->name, "rect(") || !args)
3142         return false;
3143
3144     // rect(t, r, b, l) || rect(t r b l)
3145     if (args->size() != 4 && args->size() != 7)
3146         return false;
3147     RefPtr<Rect> rect = Rect::create();
3148     bool valid = true;
3149     int i = 0;
3150     CSSParserValue* a = args->current();
3151     while (a) {
3152         valid = a->id == CSSValueAuto || validUnit(a, FLength, m_strict);
3153         if (!valid)
3154             break;
3155         RefPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ?
3156             CSSPrimitiveValue::createIdentifier(CSSValueAuto) :
3157             CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
3158         if (i == 0)
3159             rect->setTop(length);
3160         else if (i == 1)
3161             rect->setRight(length);
3162         else if (i == 2)
3163             rect->setBottom(length);
3164         else
3165             rect->setLeft(length);
3166         a = args->next();
3167         if (a && args->size() == 7) {
3168             if (a->unit == CSSParserValue::Operator && a->iValue == ',') {
3169                 a = args->next();
3170             } else {
3171                 valid = false;
3172                 break;
3173             }
3174         }
3175         i++;
3176     }
3177     if (valid) {
3178         addProperty(propId, CSSPrimitiveValue::create(rect.release()), important);
3179         m_valueList->next();
3180         return true;
3181     }
3182     return false;
3183 }
3184
3185 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
3186 bool CSSParser::parseFont(bool important)
3187 {
3188     bool valid = true;
3189     CSSParserValue *value = m_valueList->current();
3190     RefPtr<FontValue> font = FontValue::create();
3191     // optional font-style, font-variant and font-weight
3192     while (value) {
3193         int id = value->id;
3194         if (id) {
3195             if (id == CSSValueNormal) {
3196                 // do nothing, it's the inital value for all three
3197             } else if (id == CSSValueItalic || id == CSSValueOblique) {
3198                 if (font->style)
3199                     return false;
3200                 font->style = CSSPrimitiveValue::createIdentifier(id);
3201             } else if (id == CSSValueSmallCaps) {
3202                 if (font->variant)
3203                     return false;
3204                 font->variant = CSSPrimitiveValue::createIdentifier(id);
3205             } else if (id >= CSSValueBold && id <= CSSValueLighter) {
3206                 if (font->weight)
3207                     return false;
3208                 font->weight = CSSPrimitiveValue::createIdentifier(id);
3209             } else {
3210                 valid = false;
3211             }
3212         } else if (!font->weight && validUnit(value, FInteger | FNonNeg, true)) {
3213             int weight = (int)value->fValue;
3214             int val = 0;
3215             if (weight == 100)
3216                 val = CSSValue100;
3217             else if (weight == 200)
3218                 val = CSSValue200;
3219             else if (weight == 300)
3220                 val = CSSValue300;
3221             else if (weight == 400)
3222                 val = CSSValue400;
3223             else if (weight == 500)
3224                 val = CSSValue500;
3225             else if (weight == 600)
3226                 val = CSSValue600;
3227             else if (weight == 700)
3228                 val = CSSValue700;
3229             else if (weight == 800)
3230                 val = CSSValue800;
3231             else if (weight == 900)
3232                 val = CSSValue900;
3233
3234             if (val)
3235                 font->weight = CSSPrimitiveValue::createIdentifier(val);
3236             else
3237                 valid = false;
3238         } else {
3239             valid = false;
3240         }
3241         if (!valid)
3242             break;
3243         value = m_valueList->next();
3244     }
3245     if (!value)
3246         return false;
3247
3248     // set undefined values to default
3249     if (!font->style)
3250         font->style = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
3251     if (!font->variant)
3252         font->variant = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
3253     if (!font->weight)
3254         font->weight = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
3255
3256     // now a font size _must_ come
3257     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
3258     if (value->id >= CSSValueXxSmall && value->id <= CSSValueLarger)
3259         font->size = CSSPrimitiveValue::createIdentifier(value->id);
3260     else if (validUnit(value, FLength | FPercent | FNonNeg, m_strict))
3261         font->size = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
3262     value = m_valueList->next();
3263     if (!font->size || !value)
3264         return false;
3265
3266     if (value->unit == CSSParserValue::Operator && value->iValue == '/') {
3267         // line-height
3268         value = m_valueList->next();
3269         if (!value)
3270             return false;
3271         if (value->id == CSSValueNormal) {
3272             // default value, nothing to do
3273         } else if (validUnit(value, FNumber | FLength | FPercent | FNonNeg, m_strict))
3274             font->lineHeight = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
3275         else
3276             return false;
3277         value = m_valueList->next();
3278         if (!value)
3279             return false;
3280     }
3281
3282     if (!font->lineHeight)
3283         font->lineHeight = CSSPrimitiveValue::createIdentifier(CSSValueNormal);
3284
3285     // font family must come now
3286     font->family = parseFontFamily();
3287
3288     if (m_valueList->current() || !font->family)
3289         return false;
3290
3291     addProperty(CSSPropertyFont, font.release(), important);
3292     return true;
3293 }
3294
3295 PassRefPtr<CSSValueList> CSSParser::parseFontFamily()
3296 {
3297     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
3298     CSSParserValue* value = m_valueList->current();
3299
3300     FontFamilyValue* currFamily = 0;
3301     while (value) {
3302         CSSParserValue* nextValue = m_valueList->next();
3303         bool nextValBreaksFont = !nextValue ||
3304                                  (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ',');
3305         bool nextValIsFontName = nextValue &&
3306             ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
3307             (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
3308
3309         if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) {
3310             if (currFamily)
3311                 currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
3312             else if (nextValBreaksFont || !nextValIsFontName)
3313                 list->append(CSSPrimitiveValue::createIdentifier(value->id));
3314             else {
3315                 RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
3316                 currFamily = newFamily.get();
3317                 list->append(newFamily.release());
3318             }
3319         } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
3320             // Strings never share in a family name.
3321             currFamily = 0;
3322             list->append(FontFamilyValue::create(value->string));
3323         } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
3324             if (currFamily)
3325                 currFamily->appendSpaceSeparated(value->string.characters, value->string.length);
3326             else if (nextValBreaksFont || !nextValIsFontName)
3327                 list->append(FontFamilyValue::create(value->string));
3328             else {
3329                 RefPtr<FontFamilyValue> newFamily = FontFamilyValue::create(value->string);
3330                 currFamily = newFamily.get();
3331                 list->append(newFamily.release());
3332             }
3333         } else {
3334             break;
3335         }
3336
3337         if (!nextValue)
3338             break;
3339
3340         if (nextValBreaksFont) {
3341             value = m_valueList->next();
3342             currFamily = 0;
3343         }
3344         else if (nextValIsFontName)
3345             value = nextValue;
3346         else
3347             break;
3348     }
3349     if (!list->length())
3350         list = 0;
3351     return list.release();
3352 }
3353
3354 bool CSSParser::parseFontStyle(bool important)
3355 {
3356     RefPtr<CSSValueList> values;
3357     if (m_valueList->size() > 1)
3358         values = CSSValueList::createCommaSeparated();
3359     CSSParserValue* val;
3360     bool expectComma = false;
3361     while ((val = m_valueList->current())) {
3362         RefPtr<CSSPrimitiveValue> parsedValue;
3363         if (!expectComma) {
3364             expectComma = true;
3365             if (val->id == CSSValueNormal || val->id == CSSValueItalic || val->id == CSSValueOblique)
3366                 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3367             else if (val->id == CSSValueAll && !values) {
3368                 // 'all' is only allowed in @font-face and with no other values. Make a value list to
3369                 // indicate that we are in the @font-face case.
3370                 values = CSSValueList::createCommaSeparated();
3371                 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3372             }
3373         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3374             expectComma = false;
3375             m_valueList->next();
3376             continue;
3377         }
3378
3379         if (!parsedValue)
3380             return false;
3381
3382         m_valueList->next();
3383
3384         if (values)
3385             values->append(parsedValue.release());
3386         else {
3387             addProperty(CSSPropertyFontStyle, parsedValue.release(), important);
3388             return true;
3389         }
3390     }
3391
3392     if (values && values->length()) {
3393         m_hasFontFaceOnlyValues = true;
3394         addProperty(CSSPropertyFontStyle, values.release(), important);
3395         return true;
3396     }
3397
3398     return false;
3399 }
3400
3401 bool CSSParser::parseFontVariant(bool important)
3402 {
3403     RefPtr<CSSValueList> values;
3404     if (m_valueList->size() > 1)
3405         values = CSSValueList::createCommaSeparated();
3406     CSSParserValue* val;
3407     bool expectComma = false;
3408     while ((val = m_valueList->current())) {
3409         RefPtr<CSSPrimitiveValue> parsedValue;
3410         if (!expectComma) {
3411             expectComma = true;
3412             if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps)
3413                 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3414             else if (val->id == CSSValueAll && !values) {
3415                 // 'all' is only allowed in @font-face and with no other values. Make a value list to
3416                 // indicate that we are in the @font-face case.
3417                 values = CSSValueList::createCommaSeparated();
3418                 parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3419             }
3420         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3421             expectComma = false;
3422             m_valueList->next();
3423             continue;
3424         }
3425
3426         if (!parsedValue)
3427             return false;
3428
3429         m_valueList->next();
3430
3431         if (values)
3432             values->append(parsedValue.release());
3433         else {
3434             addProperty(CSSPropertyFontVariant, parsedValue.release(), important);
3435             return true;
3436         }
3437     }
3438
3439     if (values && values->length()) {
3440         m_hasFontFaceOnlyValues = true;
3441         addProperty(CSSPropertyFontVariant, values.release(), important);
3442         return true;
3443     }
3444
3445     return false;
3446 }
3447
3448 bool CSSParser::parseFontWeight(bool important)
3449 {
3450     RefPtr<CSSValueList> values;
3451     if (m_valueList->size() > 1)
3452         values = CSSValueList::createCommaSeparated();
3453     CSSParserValue* val;
3454     bool expectComma = false;
3455     while ((val = m_valueList->current())) {
3456         RefPtr<CSSPrimitiveValue> parsedValue;
3457         if (!expectComma) {
3458             expectComma = true;
3459             if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
3460                 if (val->id >= CSSValueNormal && val->id <= CSSValue900)
3461                     parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3462                 else if (val->id == CSSValueAll && !values) {
3463                     // 'all' is only allowed in @font-face and with no other values. Make a value list to
3464                     // indicate that we are in the @font-face case.
3465                     values = CSSValueList::createCommaSeparated();
3466                     parsedValue = CSSPrimitiveValue::createIdentifier(val->id);
3467                 }
3468             } else if (validUnit(val, FInteger | FNonNeg, false)) {
3469                 int weight = static_cast<int>(val->fValue);
3470                 if (!(weight % 100) && weight >= 100 && weight <= 900)
3471                     parsedValue = CSSPrimitiveValue::createIdentifier(CSSValue100 + weight / 100 - 1);
3472             }
3473         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',') {
3474             expectComma = false;
3475             m_valueList->next();
3476             continue;
3477         }
3478
3479         if (!parsedValue)
3480             return false;
3481
3482         m_valueList->next();
3483
3484         if (values)
3485             values->append(parsedValue.release());
3486         else {
3487             addProperty(CSSPropertyFontWeight, parsedValue.release(), important);
3488             return true;
3489         }
3490     }
3491
3492     if (values && values->length()) {
3493         m_hasFontFaceOnlyValues = true;
3494         addProperty(CSSPropertyFontWeight, values.release(), important);
3495         return true;
3496     }
3497
3498     return false;
3499 }
3500
3501 static bool isValidFormatFunction(CSSParserValue* val)
3502 {
3503     CSSParserValueList* args = val->function->args.get();
3504     return equalIgnoringCase(val->function->name, "format(") && (args->current()->unit == CSSPrimitiveValue::CSS_STRING || args->current()->unit == CSSPrimitiveValue::CSS_IDENT);
3505 }
3506
3507 bool CSSParser::parseFontFaceSrc()
3508 {
3509     RefPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
3510     CSSParserValue* val;
3511     bool expectComma = false;
3512     bool allowFormat = false;
3513     bool failed = false;
3514     RefPtr<CSSFontFaceSrcValue> uriValue;
3515     while ((val = m_valueList->current())) {
3516         RefPtr<CSSFontFaceSrcValue> parsedValue;
3517         if (val->unit == CSSPrimitiveValue::CSS_URI && !expectComma && m_styleSheet) {
3518             // FIXME: The completeURL call should be done when using the CSSFontFaceSrcValue,
3519             // not when creating it.
3520             parsedValue = CSSFontFaceSrcValue::create(m_styleSheet->completeURL(val->string));
3521             uriValue = parsedValue;
3522             allowFormat = true;
3523             expectComma = true;
3524         } else if (val->unit == CSSParserValue::Function) {
3525             // There are two allowed functions: local() and format().
3526             CSSParserValueList* args = val->function->args.get();
3527             if (args && args->size() == 1) {
3528                 if (equalIgnoringCase(val->function->name, "local(") && !expectComma) {
3529                     expectComma = true;
3530                     allowFormat = false;
3531                     CSSParserValue* a = args->current();
3532                     uriValue.clear();
3533                     parsedValue = CSSFontFaceSrcValue::createLocal(a->string);
3534                 } else if (allowFormat && uriValue && isValidFormatFunction(val)) {
3535                     expectComma = true;
3536                     allowFormat = false;
3537                     uriValue->setFormat(args->current()->string);
3538                     uriValue.clear();
3539                     m_valueList->next();
3540                     continue;
3541                 }
3542             }
3543         } else if (val->unit == CSSParserValue::Operator && val->iValue == ',' && expectComma) {
3544             expectComma = false;
3545             allowFormat = false;
3546             uriValue.clear();
3547             m_valueList->next();
3548             continue;
3549         }
3550
3551         if (parsedValue)
3552             values->append(parsedValue.release());
3553         else {
3554             failed = true;
3555             break;
3556         }
3557         m_valueList->next();
3558     }
3559
3560     if (values->length() && !failed) {
3561         addProperty(CSSPropertySrc, values.release(), m_important);
3562         m_valueList->next();
3563         return true;
3564     }
3565
3566     return false;
3567 }
3568
3569 bool CSSParser::parseFontFaceUnicodeRange()
3570 {
3571     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3572     bool failed = false;
3573     bool operatorExpected = false;
3574     for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) {
3575         if (operatorExpected) {
3576             if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',')
3577                 continue;
3578             failed = true;
3579             break;
3580         }
3581         if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) {
3582             failed = true;
3583             break;
3584         }
3585
3586         String rangeString = m_valueList->current()->string;
3587         UChar32 from = 0;
3588         UChar32 to = 0;
3589         unsigned length = rangeString.length();
3590
3591         if (length < 3) {
3592             failed = true;
3593             break;
3594         }
3595
3596         unsigned i = 2;
3597         while (i < length) {
3598             UChar c = rangeString[i];
3599             if (c == '-' || c == '?')
3600                 break;
3601             from *= 16;
3602             if (c >= '0' && c <= '9')
3603                 from += c - '0';
3604             else if (c >= 'A' && c <= 'F')
3605                 from += 10 + c - 'A';
3606             else if (c >= 'a' && c <= 'f')
3607                 from += 10 + c - 'a';
3608             else {
3609                 failed = true;
3610                 break;
3611             }
3612             i++;
3613         }
3614         if (failed)
3615             break;
3616
3617         if (i == length)
3618             to = from;
3619         else if (rangeString[i] == '?') {
3620             unsigned span = 1;
3621             while (i < length && rangeString[i] == '?') {
3622                 span *= 16;
3623                 from *= 16;
3624                 i++;
3625             }
3626             if (i < length)
3627                 failed = true;
3628             to = from + span - 1;
3629         } else {
3630             if (length < i + 2) {
3631                 failed = true;
3632                 break;
3633             }
3634             i++;
3635             while (i < length) {
3636                 UChar c = rangeString[i];
3637                 to *= 16;
3638                 if (c >= '0' && c <= '9')
3639                     to += c - '0';
3640                 else if (c >= 'A' && c <= 'F')
3641                     to += 10 + c - 'A';
3642                 else if (c >= 'a' && c <= 'f')
3643                     to += 10 + c - 'a';
3644                 else {
3645                     failed = true;
3646                     break;
3647                 }
3648                 i++;
3649             }
3650             if (failed)
3651                 break;
3652         }
3653         if (from <= to)
3654             values->append(CSSUnicodeRangeValue::create(from, to));
3655     }
3656     if (failed || !values->length())
3657         return false;
3658     addProperty(CSSPropertyUnicodeRange, values.release(), m_important);
3659     return true;
3660 }
3661
3662 static inline bool isCSSWhitespace(UChar c)
3663 {
3664     return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f';
3665 }
3666
3667 static inline bool parseColorInt(const UChar*& string, const UChar* end, UChar terminator, int& value)
3668 {
3669     const UChar* current = string;
3670     int localValue = 0;
3671     bool negative = false;
3672     while (current != end && isCSSWhitespace(*current))
3673         current++;
3674     if (current != end && *current == '-') {
3675         negative = true;
3676         current++;
3677     }
3678     if (current == end || !isASCIIDigit(*current))
3679         return false;
3680     while (current != end && isASCIIDigit(*current)) {
3681         int newValue = localValue * 10 + *current++ - '0';
3682         if (newValue >= 255) {
3683             // Clamp values at 255.
3684             localValue = 255;
3685             while (current != end && isASCIIDigit(*current))
3686                 ++current;
3687             break;
3688         }
3689         localValue = newValue;
3690     }
3691     while (current != end && isCSSWhitespace(*current))
3692         current++;
3693     if (current == end || *current++ != terminator)
3694         return false;
3695     // Clamp negative values at zero.
3696     value = negative ? 0 : localValue;
3697     string = current;
3698     return true;
3699 }
3700
3701 static inline bool isTenthAlpha(const UChar* string, const int length)
3702 {
3703     // "0.X"
3704     if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
3705         return true;
3706
3707     // ".X"
3708     if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
3709         return true;
3710
3711     return false;
3712 }
3713
3714 static inline bool parseAlphaValue(const UChar*& string, const UChar* end, UChar terminator, int& value)
3715 {
3716     while (string != end && isCSSWhitespace(*string))
3717         string++;
3718
3719     value = 0;
3720
3721     int length = end - string;
3722     if (length < 2)
3723         return false;
3724
3725     if (string[0] != '0' && string[0] != '1' && string[0] != '.')
3726         return false;
3727
3728     if (string[length - 1] != terminator)
3729         return false;
3730
3731     if (length == 2 && string[0] != '.') {
3732         value = string[0] == '1' ? 255 : 0;
3733         string = end;
3734         return true;
3735     }
3736
3737     if (isTenthAlpha(string, length - 1)) {
3738         static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
3739         value = tenthAlphaValues[string[length - 2] - '0'];
3740         string = end;
3741         return true;
3742     }
3743
3744     Vector<char, 8> bytes(length + 1);
3745     for (int i = 0; i < length; ++i) {
3746         if (!isASCIIDigit(string[i]) && string[i] != '.' && string[i] != terminator)
3747             return false;
3748         bytes[i] = string[i];
3749     }
3750     bytes[length] = '\0';
3751     char* foundTerminator;
3752     double d = WTF::strtod(bytes.data(), &foundTerminator);
3753     value = static_cast<int>(d * nextafter(256.0, 0.0));
3754     string += (foundTerminator - bytes.data()) + 1;
3755     return *foundTerminator == terminator;
3756 }
3757
3758 static inline bool mightBeRGBA(const UChar* characters, unsigned length)
3759 {
3760     if (length < 5)
3761         return false;
3762     return characters[4] == '('
3763         && (characters[0] | 0x20) == 'r'
3764         && (characters[1] | 0x20) == 'g'
3765         && (characters[2] | 0x20) == 'b'
3766         && (characters[3] | 0x20) == 'a';
3767 }
3768
3769 static inline bool mightBeRGB(const UChar* characters, unsigned length)
3770 {
3771     if (length < 4)
3772         return false;
3773     return characters[3] == '('
3774         && (characters[0] | 0x20) == 'r'
3775         && (characters[1] | 0x20) == 'g'
3776         && (characters[2] | 0x20) == 'b';
3777 }
3778
3779 bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict)
3780 {
3781     const UChar* characters = name.characters();
3782     unsigned length = name.length();
3783
3784     if (!strict && length >= 3) {
3785         if (name[0] == '#') {
3786             if (Color::parseHexColor(characters + 1, length - 1, rgb))
3787                 return true;
3788         } else {
3789             if (Color::parseHexColor(characters, length, rgb))
3790                 return true;
3791         }
3792     }
3793
3794     // Try rgba() syntax.
3795     if (mightBeRGBA(characters, length)) {
3796         const UChar* current = characters + 5;
3797         const UChar* end = characters + length;
3798         int red;
3799         int green;
3800         int blue;
3801         int alpha;
3802         if (!parseColorInt(current, end, ',', red))
3803             return false;
3804         if (!parseColorInt(current, end, ',', green))
3805             return false;
3806         if (!parseColorInt(current, end, ',', blue))
3807             return false;
3808         if (!parseAlphaValue(current, end, ')', alpha))
3809             return false;
3810         if (current != end)
3811             return false;
3812         rgb = makeRGBA(red, green, blue, alpha);
3813         return true;
3814     }
3815
3816     // Try rgb() syntax.
3817     if (mightBeRGB(characters, length)) {
3818         const UChar* current = characters + 4;
3819         const UChar* end = characters + length;
3820         int red;
3821         int green;
3822         int blue;
3823         if (!parseColorInt(current, end, ',', red))
3824             return false;
3825         if (!parseColorInt(current, end, ',', green))
3826             return false;
3827         if (!parseColorInt(current, end, ')', blue))
3828             return false;
3829         if (current != end)
3830             return false;
3831         rgb = makeRGB(red, green, blue);
3832         return true;
3833     }
3834
3835     // Try named colors.
3836     Color tc;
3837     tc.setNamedColor(name);
3838     if (tc.isValid()) {
3839         rgb = tc.rgb();
3840         return true;
3841     }
3842     return false;
3843 }
3844
3845 static inline int colorIntFromValue(CSSParserValue* v)
3846 {
3847     if (v->fValue <= 0.0)
3848         return 0;
3849
3850     if (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE) {
3851         if (v->fValue >= 100.0)
3852             return 255;
3853         return static_cast<int>(v->fValue * 256.0 / 100.0);
3854     }
3855
3856     if (v->fValue >= 255.0)
3857         return 255;
3858
3859     return static_cast<int>(v->fValue);
3860 }
3861
3862 bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha)
3863 {
3864     CSSParserValueList* args = value->function->args.get();
3865     CSSParserValue* v = args->current();
3866     Units unitType = FUnknown;
3867     // Get the first value and its type
3868     if (validUnit(v, FInteger, true))
3869         unitType = FInteger;
3870     else if (validUnit(v, FPercent, true))
3871         unitType = FPercent;
3872     else
3873         return false;
3874     colorArray[0] = colorIntFromValue(v);
3875     for (int i = 1; i < 3; i++) {
3876         v = args->next();
3877         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3878             return false;
3879         v = args->next();
3880         if (!validUnit(v, unitType, true))
3881             return false;
3882         colorArray[i] = colorIntFromValue(v);
3883     }
3884     if (parseAlpha) {
3885         v = args->next();
3886         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3887             return false;
3888         v = args->next();
3889         if (!validUnit(v, FNumber, true))
3890             return false;
3891         // Convert the floating pointer number of alpha to an integer in the range [0, 256),
3892         // with an equal distribution across all 256 values.
3893         colorArray[3] = static_cast<int>(max(0.0, min(1.0, v->fValue)) * nextafter(256.0, 0.0));
3894     }
3895     return true;
3896 }
3897
3898 // The CSS3 specification defines the format of a HSL color as
3899 // hsl(<number>, <percent>, <percent>)
3900 // and with alpha, the format is
3901 // hsla(<number>, <percent>, <percent>, <number>)
3902 // The first value, HUE, is in an angle with a value between 0 and 360
3903 bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha)
3904 {
3905     CSSParserValueList* args = value->function->args.get();
3906     CSSParserValue* v = args->current();
3907     // Get the first value
3908     if (!validUnit(v, FNumber, true))
3909         return false;
3910     // normalize the Hue value and change it to be between 0 and 1.0
3911     colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
3912     for (int i = 1; i < 3; i++) {
3913         v = args->next();
3914         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3915             return false;
3916         v = args->next();
3917         if (!validUnit(v, FPercent, true))
3918             return false;
3919         colorArray[i] = max(0.0, min(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0
3920     }
3921     if (parseAlpha) {
3922         v = args->next();
3923         if (v->unit != CSSParserValue::Operator && v->iValue != ',')
3924             return false;
3925         v = args->next();
3926         if (!validUnit(v, FNumber, true))
3927             return false;
3928         colorArray[3] = max(0.0, min(1.0, v->fValue));
3929     }
3930     return true;
3931 }
3932
3933 PassRefPtr<CSSPrimitiveValue> CSSParser::parseColor(CSSParserValue* value)
3934 {
3935     RGBA32 c = Color::transparent;
3936     if (!parseColorFromValue(value ? value : m_valueList->current(), c))
3937         return 0;
3938     return CSSPrimitiveValue::createColor(c);
3939 }
3940
3941 bool CSSParser::parseColorFromValue(CSSParserValue* value, RGBA32& c)
3942 {
3943     if (!m_strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
3944         value->fValue >= 0. && value->fValue < 1000000.) {
3945         String str = String::format("%06d", (int)(value->fValue+.5));
3946         if (!CSSParser::parseColor(str, c, m_strict))
3947             return false;
3948     } else if (value->unit == CSSPrimitiveValue::CSS_PARSER_HEXCOLOR ||
3949                 value->unit == CSSPrimitiveValue::CSS_IDENT ||
3950                 (!m_strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
3951         if (!CSSParser::parseColor(value->string, c, m_strict && value->unit == CSSPrimitiveValue::CSS_IDENT))
3952             return false;
3953     } else if (value->unit == CSSParserValue::Function &&
3954                 value->function->args != 0 &&
3955                 value->function->args->size() == 5 /* rgb + two commas */ &&
3956                 equalIgnoringCase(value->function->name, "rgb(")) {
3957         int colorValues[3];
3958         if (!parseColorParameters(value, colorValues, false))
3959             return false;
3960         c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
3961     } else {
3962         if (value->unit == CSSParserValue::Function &&
3963                 value->function->args != 0 &&
3964                 value->function->args->size() == 7 /* rgba + three commas */ &&
3965                 equalIgnoringCase(value->function->name, "rgba(")) {
3966             int colorValues[4];
3967             if (!parseColorParameters(value, colorValues, true))
3968                 return false;
3969             c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
3970         } else if (value->unit == CSSParserValue::Function &&
3971                     value->function->args != 0 &&
3972                     value->function->args->size() == 5 /* hsl + two commas */ &&
3973                     equalIgnoringCase(value->function->name, "hsl(")) {
3974             double colorValues[3];
3975             if (!parseHSLParameters(value, colorValues, false))
3976                 return false;
3977             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
3978         } else if (value->unit == CSSParserValue::Function &&
3979                     value->function->args != 0 &&
3980                     value->function->args->size() == 7 /* hsla + three commas */ &&
3981                     equalIgnoringCase(value->function->name, "hsla(")) {
3982             double colorValues[4];
3983             if (!parseHSLParameters(value, colorValues, true))
3984                 return false;
3985             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
3986         } else
3987             return false;
3988     }
3989
3990     return true;
3991 }
3992
3993 // This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
3994 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
3995 struct ShadowParseContext {
3996     ShadowParseContext(CSSPropertyID prop)
3997         : property(prop)
3998         , allowX(true)
3999         , allowY(false)
4000         , allowBlur(false)
4001         , allowSpread(false)
4002         , allowColor(true)
4003         , allowStyle(prop == CSSPropertyWebkitBoxShadow)
4004         , allowBreak(true)
4005     {
4006     }
4007
4008     bool allowLength() { return allowX || allowY || allowBlur || allowSpread; }
4009
4010     void commitValue()
4011     {
4012         // Handle the ,, case gracefully by doing nothing.
4013         if (x || y || blur || spread || color || style) {
4014             if (!values)
4015                 values = CSSValueList::createCommaSeparated();
4016
4017             // Construct the current shadow value and add it to the list.
4018             values->append(ShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release()));
4019         }
4020
4021         // Now reset for the next shadow value.
4022         x = 0;
4023         y = 0;
4024         blur = 0;
4025         spread = 0;
4026         style = 0;
4027         color = 0;
4028
4029         allowX = true;
4030         allowColor = true;
4031         allowBreak = true;
4032         allowY = false;
4033         allowBlur = false;
4034         allowSpread = false;
4035         allowStyle = property == CSSPropertyWebkitBoxShadow;
4036     }
4037
4038     void commitLength(CSSParserValue* v)
4039     {
4040         RefPtr<CSSPrimitiveValue> val = CSSPrimitiveValue::create(v->fValue, (CSSPrimitiveValue::UnitTypes)v->unit);
4041
4042         if (allowX) {
4043             x = val.release();
4044             allowX = false;
4045             allowY = true;
4046             allowColor = false;
4047             allowStyle = false;
4048             allowBreak = false;
4049         } else if (allowY) {
4050             y = val.release();
4051             allowY = false;
4052             allowBlur = true;
4053             allowColor = true;
4054             allowStyle = property == CSSPropertyWebkitBoxShadow;
4055             allowBreak = true;
4056         } else if (allowBlur) {
4057             blur = val.release();
4058             allowBlur = false;
4059             allowSpread = property == CSSPropertyWebkitBoxShadow;
4060         } else if (allowSpread) {
4061             spread = val.release();
4062             allowSpread = false;
4063         }
4064     }
4065
4066     void commitColor(PassRefPtr<CSSPrimitiveValue> val)
4067     {
4068         color = val;
4069         allowColor = false;