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