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