a0098c810440b1b699fc4001743d97a8af05fd63
[WebKit-https.git] / WebCore / css / cssparser.cpp
1 /*
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
5  * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
6  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
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., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include "config.h"
25 #include "cssparser.h"
26
27 #include "CSSBorderImageValue.h"
28 #include "CSSCursorImageValue.h"
29 #include "CSSImageValue.h"
30 #include "CSSCharsetRule.h"
31 #include "CSSImportRule.h"
32 #include "CSSInheritedValue.h"
33 #include "CSSInitialValue.h"
34 #include "CSSMediaRule.h"
35 #include "CSSMutableStyleDeclaration.h"
36 #include "CSSPrimitiveValue.h"
37 #include "CSSProperty.h"
38 #include "CSSPropertyNames.h"
39 #include "CSSRuleList.h"
40 #include "CSSSelector.h"
41 #include "CSSStyleRule.h"
42 #include "CSSStyleSheet.h"
43 #include "CSSQuirkPrimitiveValue.h"
44 #include "CSSValueKeywords.h"
45 #include "CSSValueList.h"
46 #include "Counter.h"
47 #include "DashboardRegion.h"
48 #include "Document.h"
49 #include "FontFamilyValue.h"
50 #include "FontValue.h"
51 #include "KURL.h"
52 #include "MediaList.h"
53 #include "Pair.h"
54 #include "ShadowValue.h"
55 #include "csshelper.h"
56 #include "MediaQueryExp.h"
57
58 #define YYDEBUG 0
59
60 #if YYDEBUG > 0
61 extern int cssyydebug;
62 #endif
63
64 extern int cssyyparse(void* parser);
65
66 using namespace std;
67 using namespace WTF;
68
69 namespace WebCore {
70
71 ValueList::~ValueList()
72 {
73      size_t numValues = m_values.size();
74      for (size_t i = 0; i < numValues; i++)
75          if (m_values[i].unit == Value::Function)
76              delete m_values[i].function;
77 }
78
79 namespace {
80     class ShorthandScope {
81     public:
82         ShorthandScope(CSSParser* parser, int propId) : m_parser(parser)
83         {
84             if (!(m_parser->m_inParseShorthand++))
85                 m_parser->m_currentShorthand = propId;
86         }
87         ~ShorthandScope()
88         {
89             if (!(--m_parser->m_inParseShorthand))
90                 m_parser->m_currentShorthand = 0;
91         }
92
93     private:
94         CSSParser* m_parser;
95     };
96 }
97
98 CSSParser* CSSParser::currentParser = 0;
99
100 CSSParser::CSSParser(bool strictParsing)
101     : m_floatingMediaQuery(0)
102     , m_floatingMediaQueryExp(0)
103     , m_floatingMediaQueryExpList(0)
104 {
105 #ifdef CSS_DEBUG
106     kdDebug(6080) << "CSSParser::CSSParser this=" << this << endl;
107 #endif
108     strict = strictParsing;
109
110     parsedProperties = (CSSProperty **)fastMalloc(32 * sizeof(CSSProperty *));
111     numParsedProperties = 0;
112     maxParsedProperties = 32;
113
114     data = 0;
115     valueList = 0;
116     id = 0;
117     important = false;
118     m_inParseShorthand = 0;
119     m_currentShorthand = 0;
120     m_implicitShorthand = false;
121
122     defaultNamespace = starAtom;
123     
124     yy_start = 1;
125
126 #if YYDEBUG > 0
127     cssyydebug = 1;
128 #endif
129 }
130
131 CSSParser::~CSSParser()
132 {
133     clearProperties();
134     fastFree(parsedProperties);
135
136     delete valueList;
137
138     fastFree(data);
139
140     if (m_floatingMediaQueryExpList) {
141         deleteAllValues(*m_floatingMediaQueryExpList);
142         delete m_floatingMediaQueryExpList;
143     }
144     delete m_floatingMediaQueryExp;
145     delete m_floatingMediaQuery;
146     deleteAllValues(m_floatingSelectors);
147     deleteAllValues(m_floatingValueLists);
148     deleteAllValues(m_floatingFunctions);
149 }
150
151 void ParseString::lower()
152 {
153     // Fast case for all-ASCII.
154     UChar ored = 0;
155     for (int i = 0; i < length; i++)
156         ored |= characters[i];
157     if (ored & ~0x7F)
158         for (int i = 0; i < length; i++)
159             characters[i] = Unicode::toLower(characters[i]);
160     else
161         for (int i = 0; i < length; i++)
162             characters[i] = tolower(characters[i]);
163 }
164
165 void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
166 {
167     int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
168
169     if (data)
170         fastFree(data);
171     
172     data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar)));
173     for (unsigned i = 0; i < strlen(prefix); i++)
174         data[i] = prefix[i];
175     
176     memcpy(data + strlen(prefix), string.characters(), string.length() * sizeof(UChar));
177
178     unsigned start = strlen(prefix) + string.length();
179     unsigned end = start + strlen(suffix);
180     for (unsigned i = start; i < end; i++)
181         data[i] = suffix[i - start];
182
183     data[length - 1] = 0;
184     data[length - 2] = 0;
185
186     yy_hold_char = 0;
187     yyleng = 0;
188     yytext = yy_c_buf_p = data;
189     yy_hold_char = *yy_c_buf_p;
190 }
191
192 void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string)
193 {
194     styleElement = sheet;
195     defaultNamespace = starAtom; // Reset the default namespace.
196     
197     setupParser("", string, "");
198
199     CSSParser* old = currentParser;
200     currentParser = this;
201     cssyyparse(this);
202     currentParser = old;
203
204     rule = 0;
205 }
206
207 PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet *sheet, const String &string)
208 {
209     styleElement = sheet;
210     
211     setupParser("@-webkit-rule{", string, "} ");
212
213     CSSParser* old = currentParser;
214     currentParser = this;
215     cssyyparse(this);
216     currentParser = old;
217
218     return rule.release();
219 }
220
221 bool CSSParser::parseValue(CSSMutableStyleDeclaration *declaration, int _id, const String &string, bool _important)
222 {
223     styleElement = declaration->stylesheet();
224
225     setupParser("@-webkit-value{", string, "} ");
226
227     id = _id;
228     important = _important;
229     
230     CSSParser* old = currentParser;
231     currentParser = this;
232     cssyyparse(this);
233     currentParser = old;
234     
235     rule = 0;
236
237     bool ok = false;
238     if (numParsedProperties) {
239         ok = true;
240         declaration->addParsedProperties(parsedProperties, numParsedProperties);
241         clearProperties();
242     }
243
244     return ok;
245 }
246
247 RGBA32 CSSParser::parseColor(const String &string, bool strict)
248 {
249     RGBA32 color = 0;
250     RefPtr<CSSMutableStyleDeclaration>dummyStyleDeclaration = new CSSMutableStyleDeclaration;
251
252     CSSParser parser(true);
253
254     // First try creating a color specified by name or the "#" syntax.
255     if (!parser.parseColor(string, color, strict)) {
256     
257         // Now try to create a color from the rgb() or rgba() syntax.
258         if (parser.parseColor(dummyStyleDeclaration.get(), string)) {
259             CSSValue* value = parser.parsedProperties[0]->value();
260             if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
261                 CSSPrimitiveValue *primitiveValue = static_cast<CSSPrimitiveValue *>(value);
262                 color = primitiveValue->getRGBColorValue();
263             }
264         }
265     }
266     
267     return color;
268 }
269
270 bool CSSParser::parseColor(CSSMutableStyleDeclaration *declaration, const String &string)
271 {
272     styleElement = declaration->stylesheet();
273
274     setupParser("@-webkit-decls{color:", string, "} ");
275
276     CSSParser* old = currentParser;
277     currentParser = this;
278     cssyyparse(this);
279     currentParser = old;
280
281     rule = 0;
282
283     bool ok = false;
284     if (numParsedProperties && parsedProperties[0]->m_id == CSS_PROP_COLOR)
285         ok = true;
286
287     return ok;
288 }
289
290 bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration *declaration, const String &string)
291 {
292     styleElement = declaration->stylesheet();
293
294     setupParser("@-webkit-decls{", string, "} ");
295
296     CSSParser* old = currentParser;
297     currentParser = this;
298     cssyyparse(this);
299     currentParser = old;
300
301     rule = 0;
302
303     bool ok = false;
304     if (numParsedProperties) {
305         ok = true;
306         declaration->addParsedProperties(parsedProperties, numParsedProperties);
307         clearProperties();
308     }
309
310     return ok;
311 }
312
313 bool CSSParser::parseMediaQuery(MediaList* queries, const String& string)
314 {
315     if (string.isEmpty() || string.isNull()) {
316         return true;
317     }
318
319     mediaQuery = 0;
320     // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
321     // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
322     setupParser ("@-webkit-mediaquery ", string, "} ");
323
324     CSSParser* old = currentParser;
325     currentParser = this;
326     cssyyparse(this);
327     currentParser = old;
328
329     bool ok = false;
330     if (mediaQuery) {
331         ok = true;
332         queries->appendMediaQuery(mediaQuery);
333         mediaQuery = 0;
334     }
335
336     return ok;
337 }
338
339
340 void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important)
341 {
342     CSSProperty *prop = new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand);
343     if (numParsedProperties >= maxParsedProperties) {
344         maxParsedProperties += 32;
345         parsedProperties = (CSSProperty **)fastRealloc(parsedProperties,
346                                                        maxParsedProperties*sizeof(CSSProperty *));
347     }
348     parsedProperties[numParsedProperties++] = prop;
349 }
350
351 void CSSParser::rollbackLastProperties(int num)
352 {
353     ASSERT(num >= 0);
354     ASSERT(numParsedProperties >= num);
355
356     for (int i = 0; i < num; ++i)
357         delete parsedProperties[--numParsedProperties];
358 }
359
360 void CSSParser::clearProperties()
361 {
362     for (int i = 0; i < numParsedProperties; i++)
363         delete parsedProperties[i];
364     numParsedProperties = 0;
365 }
366
367 Document *CSSParser::document() const
368 {
369     StyleBase *root = styleElement;
370     Document *doc = 0;
371     while (root->parent())
372         root = root->parent();
373     if (root->isCSSStyleSheet())
374         doc = static_cast<CSSStyleSheet*>(root)->doc();
375     return doc;
376 }
377
378 bool CSSParser::validUnit(Value* value, Units unitflags, bool strict)
379 {
380     if (unitflags & FNonNeg && value->fValue < 0)
381         return false;
382
383     bool b = false;
384     switch(value->unit) {
385     case CSSPrimitiveValue::CSS_NUMBER:
386         b = (unitflags & FNumber);
387         if (!b && ((unitflags & FLength) && (value->fValue == 0 || !strict))) {
388             value->unit = CSSPrimitiveValue::CSS_PX;
389             b = true;
390         }
391         if (!b && (unitflags & FInteger) && value->isInt)
392             b = true;
393         break;
394     case CSSPrimitiveValue::CSS_PERCENTAGE:
395         b = (unitflags & FPercent);
396         break;
397     case Value::Q_EMS:
398     case CSSPrimitiveValue::CSS_EMS:
399     case CSSPrimitiveValue::CSS_EXS:
400     case CSSPrimitiveValue::CSS_PX:
401     case CSSPrimitiveValue::CSS_CM:
402     case CSSPrimitiveValue::CSS_MM:
403     case CSSPrimitiveValue::CSS_IN:
404     case CSSPrimitiveValue::CSS_PT:
405     case CSSPrimitiveValue::CSS_PC:
406         b = (unitflags & FLength);
407         break;
408     case CSSPrimitiveValue::CSS_MS:
409     case CSSPrimitiveValue::CSS_S:
410         b = (unitflags & FTime);
411         break;
412     case CSSPrimitiveValue::CSS_DEG:
413     case CSSPrimitiveValue::CSS_RAD:
414     case CSSPrimitiveValue::CSS_GRAD:
415     case CSSPrimitiveValue::CSS_HZ:
416     case CSSPrimitiveValue::CSS_KHZ:
417     case CSSPrimitiveValue::CSS_DIMENSION:
418     default:
419         break;
420     }
421     return b;
422 }
423
424 bool CSSParser::parseValue(int propId, bool important)
425 {
426     if (!valueList)
427         return false;
428
429     Value *value = valueList->current();
430
431     if (!value)
432         return false;
433
434     int id = value->id;
435
436     int num = inShorthand() ? 1 : valueList->size();
437
438     if (id == CSS_VAL_INHERIT) {
439         if (num != 1)
440             return false;
441         addProperty(propId, new CSSInheritedValue(), important);
442         return true;
443     }
444     else if (id == CSS_VAL_INITIAL) {
445         if (num != 1)
446             return false;
447         addProperty(propId, new CSSInitialValue(), important);
448         return true;
449     }
450
451     bool valid_primitive = false;
452     CSSValue *parsedValue = 0;
453
454     switch(propId) {
455         /* The comment to the left defines all valid value of this properties as defined
456          * in CSS 2, Appendix F. Property index
457          */
458
459         /* All the CSS properties are not supported by the renderer at the moment.
460          * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
461          * (see parseAuralValues). As we don't support them at all this seems reasonable.
462          */
463
464     case CSS_PROP_SIZE:                 // <length>{1,2} | auto | portrait | landscape | inherit
465     case CSS_PROP_QUOTES:               // [<string> <string>]+ | none | inherit
466 //     case CSS_PROP_PAGE:                 // <identifier> | auto // ### CHECK
467         // ### To be done
468         if (id)
469             valid_primitive = true;
470         break;
471     case CSS_PROP_UNICODE_BIDI:         // normal | embed | bidi-override | inherit
472         if (id == CSS_VAL_NORMAL ||
473              id == CSS_VAL_EMBED ||
474              id == CSS_VAL_BIDI_OVERRIDE)
475             valid_primitive = true;
476         break;
477
478     case CSS_PROP_POSITION:             // static | relative | absolute | fixed | inherit
479         if (id == CSS_VAL_STATIC ||
480              id == CSS_VAL_RELATIVE ||
481              id == CSS_VAL_ABSOLUTE ||
482              id == CSS_VAL_FIXED)
483             valid_primitive = true;
484         break;
485
486     case CSS_PROP_PAGE_BREAK_AFTER:     // auto | always | avoid | left | right | inherit
487     case CSS_PROP_PAGE_BREAK_BEFORE:
488     case CSS_PROP__WEBKIT_COLUMN_BREAK_AFTER:
489     case CSS_PROP__WEBKIT_COLUMN_BREAK_BEFORE:
490         if (id == CSS_VAL_AUTO ||
491              id == CSS_VAL_ALWAYS ||
492              id == CSS_VAL_AVOID ||
493              id == CSS_VAL_LEFT ||
494              id == CSS_VAL_RIGHT)
495             valid_primitive = true;
496         break;
497
498     case CSS_PROP_PAGE_BREAK_INSIDE:    // avoid | auto | inherit
499     case CSS_PROP__WEBKIT_COLUMN_BREAK_INSIDE:
500         if (id == CSS_VAL_AUTO || id == CSS_VAL_AVOID)
501             valid_primitive = true;
502         break;
503
504     case CSS_PROP_EMPTY_CELLS:          // show | hide | inherit
505         if (id == CSS_VAL_SHOW ||
506              id == CSS_VAL_HIDE)
507             valid_primitive = true;
508         break;
509
510     case CSS_PROP_CONTENT:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
511         // close-quote | no-open-quote | no-close-quote ]+ | inherit
512         return parseContent(propId, important);
513         break;
514
515     case CSS_PROP_WHITE_SPACE:          // normal | pre | nowrap | inherit
516         if (id == CSS_VAL_NORMAL ||
517             id == CSS_VAL_PRE ||
518             id == CSS_VAL_PRE_WRAP ||
519             id == CSS_VAL_PRE_LINE ||
520             id == CSS_VAL_NOWRAP)
521             valid_primitive = true;
522         break;
523
524     case CSS_PROP_CLIP:                 // <shape> | auto | inherit
525         if (id == CSS_VAL_AUTO)
526             valid_primitive = true;
527         else if (value->unit == Value::Function)
528             return parseShape(propId, important);
529         break;
530
531     /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
532      * correctly and allows optimization in WebCore::applyRule(..)
533      */
534     case CSS_PROP_CAPTION_SIDE:         // top | bottom | left | right | inherit
535         if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
536             id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM)
537             valid_primitive = true;
538         break;
539
540     case CSS_PROP_BORDER_COLLAPSE:      // collapse | separate | inherit
541         if (id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE)
542             valid_primitive = true;
543         break;
544
545     case CSS_PROP_VISIBILITY:           // visible | hidden | collapse | inherit
546         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE)
547             valid_primitive = true;
548         break;
549
550     case CSS_PROP_OVERFLOW: {
551         ShorthandScope scope(this, propId);
552         if (num != 1 || !parseValue(CSS_PROP_OVERFLOW_X, important))
553             return false;
554         CSSValue* value = parsedProperties[numParsedProperties - 1]->value();
555         addProperty(CSS_PROP_OVERFLOW_Y, value, important);
556         return true;
557     }
558     case CSS_PROP_OVERFLOW_X:
559     case CSS_PROP_OVERFLOW_Y:           // visible | hidden | scroll | auto | marquee | overlay | inherit
560         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ||
561             id == CSS_VAL_OVERLAY || id == CSS_VAL__WEBKIT_MARQUEE)
562             valid_primitive = true;
563         break;
564
565     case CSS_PROP_LIST_STYLE_POSITION:  // inside | outside | inherit
566         if (id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE)
567             valid_primitive = true;
568         break;
569
570     case CSS_PROP_LIST_STYLE_TYPE:
571         // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
572         // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
573         // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
574         // katakana | hiragana-iroha | katakana-iroha | none | inherit
575         if ((id >= CSS_VAL_DISC && id <= CSS_VAL_KATAKANA_IROHA) || id == CSS_VAL_NONE)
576             valid_primitive = true;
577         break;
578
579     case CSS_PROP_DISPLAY:
580         // inline | block | list-item | run-in | inline-block | table |
581         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
582         // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
583         if ((id >= CSS_VAL_INLINE && id <= CSS_VAL__WEBKIT_INLINE_BOX) || id == CSS_VAL_NONE)
584             valid_primitive = true;
585         break;
586
587     case CSS_PROP_DIRECTION:            // ltr | rtl | inherit
588         if (id == CSS_VAL_LTR || id == CSS_VAL_RTL)
589             valid_primitive = true;
590         break;
591
592     case CSS_PROP_TEXT_TRANSFORM:       // capitalize | uppercase | lowercase | none | inherit
593         if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE)
594             valid_primitive = true;
595         break;
596
597     case CSS_PROP_FLOAT:                // left | right | none | inherit + center for buggy CSS
598         if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
599              id == CSS_VAL_NONE || id == CSS_VAL_CENTER)
600             valid_primitive = true;
601         break;
602
603     case CSS_PROP_CLEAR:                // none | left | right | both | inherit
604         if (id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
605              id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH)
606             valid_primitive = true;
607         break;
608
609     case CSS_PROP_TEXT_ALIGN:
610         // left | right | center | justify | khtml_left | khtml_right | khtml_center | <string> | inherit
611         if ((id >= CSS_VAL__WEBKIT_AUTO && id <= CSS_VAL__WEBKIT_CENTER) ||
612              value->unit == CSSPrimitiveValue::CSS_STRING)
613             valid_primitive = true;
614         break;
615
616     case CSS_PROP_OUTLINE_STYLE:        // <border-style> | auto | inherit
617         if (id == CSS_VAL_AUTO) {
618             valid_primitive = true;
619             break;
620         } // Fall through!
621     case CSS_PROP_BORDER_TOP_STYLE:     //// <border-style> | inherit
622     case CSS_PROP_BORDER_RIGHT_STYLE:   //   Defined as:    none | hidden | dotted | dashed |
623     case CSS_PROP_BORDER_BOTTOM_STYLE:  //   solid | double | groove | ridge | inset | outset
624     case CSS_PROP_BORDER_LEFT_STYLE:
625     case CSS_PROP__WEBKIT_COLUMN_RULE_STYLE:
626         if (id >= CSS_VAL_NONE && id <= CSS_VAL_DOUBLE)
627             valid_primitive = true;
628         break;
629
630     case CSS_PROP_FONT_WEIGHT:  // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 |
631         // 500 | 600 | 700 | 800 | 900 | inherit
632         if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) {
633             // Allready correct id
634             valid_primitive = true;
635         } else if (validUnit(value, FInteger|FNonNeg, false)) {
636             int weight = (int)value->fValue;
637             if ((weight % 100))
638                 break;
639             weight /= 100;
640             if (weight >= 1 && weight <= 9) {
641                 id = CSS_VAL_100 + weight - 1;
642                 valid_primitive = true;
643             }
644         }
645         break;
646
647     case CSS_PROP_BORDER_SPACING: {
648         const int properties[2] = { CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING,
649                                     CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING };
650         if (num == 1) {
651             ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
652             if (!parseValue(properties[0], important))
653                 return false;
654             CSSValue* value = parsedProperties[numParsedProperties-1]->value();
655             addProperty(properties[1], value, important);
656             return true;
657         }
658         else if (num == 2) {
659             ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
660             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
661                 return false;
662             return true;
663         }
664         return false;
665     }
666     case CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING:
667     case CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING:
668         valid_primitive = validUnit(value, FLength|FNonNeg, strict);
669         break;
670     case CSS_PROP_SCROLLBAR_FACE_COLOR:         // IE5.5
671     case CSS_PROP_SCROLLBAR_SHADOW_COLOR:       // IE5.5
672     case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:    // IE5.5
673     case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:      // IE5.5
674     case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:   // IE5.5
675     case CSS_PROP_SCROLLBAR_TRACK_COLOR:        // IE5.5
676     case CSS_PROP_SCROLLBAR_ARROW_COLOR:        // IE5.5
677         if (strict)
678             break;
679         /* nobreak */
680     case CSS_PROP_OUTLINE_COLOR:        // <color> | invert | inherit
681         // Outline color has "invert" as additional keyword.
682         // Also, we want to allow the special focus color even in strict parsing mode.
683         if (propId == CSS_PROP_OUTLINE_COLOR && (id == CSS_VAL_INVERT || id == CSS_VAL__WEBKIT_FOCUS_RING_COLOR)) {
684             valid_primitive = true;
685             break;
686         }
687         /* nobreak */
688     case CSS_PROP_BACKGROUND_COLOR:     // <color> | inherit
689     case CSS_PROP_BORDER_TOP_COLOR:     // <color> | inherit
690     case CSS_PROP_BORDER_RIGHT_COLOR:   // <color> | inherit
691     case CSS_PROP_BORDER_BOTTOM_COLOR:  // <color> | inherit
692     case CSS_PROP_BORDER_LEFT_COLOR:    // <color> | inherit
693     case CSS_PROP_COLOR:                // <color> | inherit
694     case CSS_PROP_TEXT_LINE_THROUGH_COLOR: // CSS3 text decoration colors
695     case CSS_PROP_TEXT_UNDERLINE_COLOR:
696     case CSS_PROP_TEXT_OVERLINE_COLOR:
697     case CSS_PROP__WEBKIT_COLUMN_RULE_COLOR:
698     case CSS_PROP__WEBKIT_TEXT_FILL_COLOR:
699     case CSS_PROP__WEBKIT_TEXT_STROKE_COLOR:
700         if (id == CSS_VAL__WEBKIT_TEXT)
701             valid_primitive = true; // Always allow this, even when strict parsing is on,
702                                     // since we use this in our UA sheets.
703         else if (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT || id == CSS_VAL_MENU ||
704              (id >= CSS_VAL__WEBKIT_FOCUS_RING_COLOR && id < CSS_VAL__WEBKIT_TEXT && !strict)) {
705             valid_primitive = true;
706         } else {
707             parsedValue = parseColor();
708             if (parsedValue)
709                 valueList->next();
710         }
711         break;
712
713     case CSS_PROP_CURSOR: {
714         // [<uri>,]*  [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
715         // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize | 
716         // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help ] ] | inherit
717         CSSValueList* list = 0;
718         while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
719             if (!list)
720                 list = new CSSValueList; 
721             String uri = parseURL(domString(value->string));
722             Vector<int> coords;
723             value = valueList->next();
724             while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
725                 coords.append(int(value->fValue));
726                 value = valueList->next();
727             }
728             IntPoint hotspot;
729             int nrcoords = coords.size();
730             if (nrcoords > 0 && nrcoords != 2) {
731                 if (strict) { // only support hotspot pairs in strict mode
732                     delete list;
733                     return false;
734                 }
735             } else if(strict && nrcoords == 2)
736                 hotspot = IntPoint(coords[0], coords[1]);
737             if (strict || coords.size() == 0) {
738 #ifdef SVG_SUPPORT
739                 if (uri.startsWith("#"))
740                     list->append(new CSSPrimitiveValue(uri, CSSPrimitiveValue::CSS_URI));
741                 else
742 #endif
743                 if (!uri.isEmpty()) {
744                     list->append(new CSSCursorImageValue(
745                                  String(KURL(styleElement->baseURL().deprecatedString(), uri.deprecatedString()).url()),
746                                  hotspot, styleElement));
747                 }
748             }
749             if ((strict && !value) || (value && !(value->unit == Value::Operator && value->iValue == ','))) {
750                 delete list;
751                 return false;
752             }
753             value = valueList->next(); // comma
754         }
755         if (list) {
756             if (!value) { // no value after url list (MSIE 5 compatibility)
757                 if (list->length() != 1) {
758                     delete list;
759                     return false;
760                 }
761             } else if (!strict && value->id == CSS_VAL_HAND) // MSIE 5 compatibility :/
762                 list->append(new CSSPrimitiveValue(CSS_VAL_POINTER));
763             else if (value && ((value->id >= CSS_VAL_AUTO && value->id <= CSS_VAL_ALL_SCROLL) || value->id == CSS_VAL_COPY || value->id == CSS_VAL_NONE))
764                 list->append(new CSSPrimitiveValue(value->id));
765             valueList->next();
766             parsedValue = list;
767             break;
768         }
769         id = value->id;
770         if (!strict && value->id == CSS_VAL_HAND) { // MSIE 5 compatibility :/
771             id = CSS_VAL_POINTER;
772             valid_primitive = true;
773         } else if ((value->id >= CSS_VAL_AUTO && value->id <= CSS_VAL_ALL_SCROLL) || value->id == CSS_VAL_COPY || value->id == CSS_VAL_NONE)
774             valid_primitive = true;
775         break;
776     }
777
778     case CSS_PROP_BACKGROUND_ATTACHMENT:
779     case CSS_PROP__WEBKIT_BACKGROUND_CLIP:
780     case CSS_PROP__WEBKIT_BACKGROUND_COMPOSITE:
781     case CSS_PROP_BACKGROUND_IMAGE:
782     case CSS_PROP__WEBKIT_BACKGROUND_ORIGIN:
783     case CSS_PROP_BACKGROUND_POSITION:
784     case CSS_PROP_BACKGROUND_POSITION_X:
785     case CSS_PROP_BACKGROUND_POSITION_Y:
786     case CSS_PROP__WEBKIT_BACKGROUND_SIZE:
787     case CSS_PROP_BACKGROUND_REPEAT: {
788         CSSValue *val1 = 0, *val2 = 0;
789         int propId1, propId2;
790         if (parseBackgroundProperty(propId, propId1, propId2, val1, val2)) {
791             addProperty(propId1, val1, important);
792             if (val2)
793                 addProperty(propId2, val2, important);
794             return true;
795         }
796         return false;
797     }
798     case CSS_PROP_LIST_STYLE_IMAGE:     // <uri> | none | inherit
799         if (id == CSS_VAL_NONE) {
800             parsedValue = new CSSImageValue();
801             valueList->next();
802         }
803         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
804             // ### allow string in non strict mode?
805             String uri = parseURL(domString(value->string));
806             if (!uri.isEmpty()) {
807                 parsedValue = new CSSImageValue(
808                     String(KURL(styleElement->baseURL().deprecatedString(), uri.deprecatedString()).url()),
809                     styleElement);
810                 valueList->next();
811             }
812         }
813         break;
814
815     case CSS_PROP__WEBKIT_TEXT_STROKE_WIDTH:
816     case CSS_PROP_OUTLINE_WIDTH:        // <border-width> | inherit
817     case CSS_PROP_BORDER_TOP_WIDTH:     //// <border-width> | inherit
818     case CSS_PROP_BORDER_RIGHT_WIDTH:   //   Which is defined as
819     case CSS_PROP_BORDER_BOTTOM_WIDTH:  //   thin | medium | thick | <length>
820     case CSS_PROP_BORDER_LEFT_WIDTH:
821     case CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH:
822         if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
823             valid_primitive = true;
824         else
825             valid_primitive = validUnit(value, FLength, strict);
826         break;
827
828     case CSS_PROP_LETTER_SPACING:       // normal | <length> | inherit
829     case CSS_PROP_WORD_SPACING:         // normal | <length> | inherit
830         if (id == CSS_VAL_NORMAL)
831             valid_primitive = true;
832         else
833             valid_primitive = validUnit(value, FLength, strict);
834         break;
835
836     case CSS_PROP_WORD_WRAP:           // normal | break-word
837         if (id == CSS_VAL_NORMAL || id == CSS_VAL_BREAK_WORD)
838             valid_primitive = true;
839         break;
840
841     case CSS_PROP_TEXT_INDENT:          // <length> | <percentage> | inherit
842     case CSS_PROP_PADDING_TOP:          //// <padding-width> | inherit
843     case CSS_PROP_PADDING_RIGHT:        //   Which is defined as
844     case CSS_PROP_PADDING_BOTTOM:       //   <length> | <percentage>
845     case CSS_PROP_PADDING_LEFT:         ////
846     case CSS_PROP__WEBKIT_PADDING_START:
847         valid_primitive = (!id && validUnit(value, FLength|FPercent, strict));
848         break;
849
850     case CSS_PROP_MAX_HEIGHT:           // <length> | <percentage> | none | inherit
851     case CSS_PROP_MAX_WIDTH:            // <length> | <percentage> | none | inherit
852         if (id == CSS_VAL_NONE || id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC) {
853             valid_primitive = true;
854             break;
855         }
856         /* nobreak */
857     case CSS_PROP_MIN_HEIGHT:           // <length> | <percentage> | inherit
858     case CSS_PROP_MIN_WIDTH:            // <length> | <percentage> | inherit
859         if (id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC)
860             valid_primitive = true;
861         else
862             valid_primitive = (!id && validUnit(value, FLength|FPercent|FNonNeg, strict));
863         break;
864
865     case CSS_PROP_FONT_SIZE:
866         // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
867         if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER)
868             valid_primitive = true;
869         else
870             valid_primitive = (validUnit(value, FLength|FPercent, strict));
871         break;
872
873     case CSS_PROP_FONT_STYLE:           // normal | italic | oblique | inherit
874         if (id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE)
875             valid_primitive = true;
876         break;
877
878     case CSS_PROP_FONT_VARIANT:         // normal | small-caps | inherit
879         if (id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS)
880             valid_primitive = true;
881         break;
882
883     case CSS_PROP_VERTICAL_ALIGN:
884         // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
885         // <percentage> | <length> | inherit
886
887         if (id >= CSS_VAL_BASELINE && id <= CSS_VAL__WEBKIT_BASELINE_MIDDLE)
888             valid_primitive = true;
889         else
890             valid_primitive = (!id && validUnit(value, FLength|FPercent, strict));
891         break;
892
893     case CSS_PROP_HEIGHT:               // <length> | <percentage> | auto | inherit
894     case CSS_PROP_WIDTH:                // <length> | <percentage> | auto | inherit
895         if (id == CSS_VAL_AUTO || id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC)
896             valid_primitive = true;
897         else
898             // ### handle multilength case where we allow relative units
899             valid_primitive = (!id && validUnit(value, FLength|FPercent|FNonNeg, strict));
900         break;
901
902     case CSS_PROP_BOTTOM:               // <length> | <percentage> | auto | inherit
903     case CSS_PROP_LEFT:                 // <length> | <percentage> | auto | inherit
904     case CSS_PROP_RIGHT:                // <length> | <percentage> | auto | inherit
905     case CSS_PROP_TOP:                  // <length> | <percentage> | auto | inherit
906     case CSS_PROP_MARGIN_TOP:           //// <margin-width> | inherit
907     case CSS_PROP_MARGIN_RIGHT:         //   Which is defined as
908     case CSS_PROP_MARGIN_BOTTOM:        //   <length> | <percentage> | auto | inherit
909     case CSS_PROP_MARGIN_LEFT:          ////
910     case CSS_PROP__WEBKIT_MARGIN_START:
911         if (id == CSS_VAL_AUTO)
912             valid_primitive = true;
913         else
914             valid_primitive = (!id && validUnit(value, FLength|FPercent, strict));
915         break;
916
917     case CSS_PROP_Z_INDEX:              // auto | <integer> | inherit
918         if (id == CSS_VAL_AUTO) {
919             valid_primitive = true;
920             break;
921         }
922         /* nobreak */
923     case CSS_PROP_ORPHANS:              // <integer> | inherit
924     case CSS_PROP_WIDOWS:               // <integer> | inherit
925         // ### not supported later on
926         valid_primitive = (!id && validUnit(value, FInteger, false));
927         break;
928
929     case CSS_PROP_LINE_HEIGHT:          // normal | <number> | <length> | <percentage> | inherit
930         if (id == CSS_VAL_NORMAL)
931             valid_primitive = true;
932         else
933             valid_primitive = (!id && validUnit(value, FNumber|FLength|FPercent, strict));
934         break;
935     case CSS_PROP_COUNTER_INCREMENT:    // [ <identifier> <integer>? ]+ | none | inherit
936         if (id != CSS_VAL_NONE)
937             return parseCounter(propId, 1, important);
938         valid_primitive = true;
939         break;
940      case CSS_PROP_COUNTER_RESET:        // [ <identifier> <integer>? ]+ | none | inherit
941         if (id != CSS_VAL_NONE)
942             return parseCounter(propId, 0, important);
943         valid_primitive = true;
944         break;
945     case CSS_PROP_FONT_FAMILY:
946         // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
947     {
948         parsedValue = parseFontFamily();
949         break;
950     }
951
952     case CSS_PROP_TEXT_DECORATION:
953     case CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT:
954         // none | [ underline || overline || line-through || blink ] | inherit
955         if (id == CSS_VAL_NONE) {
956             valid_primitive = true;
957         } else {
958             CSSValueList *list = new CSSValueList;
959             bool is_valid = true;
960             while(is_valid && value) {
961                 switch (value->id) {
962                 case CSS_VAL_BLINK:
963                     break;
964                 case CSS_VAL_UNDERLINE:
965                 case CSS_VAL_OVERLINE:
966                 case CSS_VAL_LINE_THROUGH:
967                     list->append(new CSSPrimitiveValue(value->id));
968                     break;
969                 default:
970                     is_valid = false;
971                 }
972                 value = valueList->next();
973             }
974             if(list->length() && is_valid) {
975                 parsedValue = list;
976                 valueList->next();
977             } else
978                 delete list;
979         }
980         break;
981
982     case CSS_PROP_TABLE_LAYOUT:         // auto | fixed | inherit
983         if (id == CSS_VAL_AUTO || id == CSS_VAL_FIXED)
984             valid_primitive = true;
985         break;
986
987     /* CSS3 properties */
988     case CSS_PROP__WEBKIT_APPEARANCE:
989         if ((id >= CSS_VAL_CHECKBOX && id <= CSS_VAL_TEXTAREA) || id == CSS_VAL_NONE)
990             valid_primitive = true;
991         break;
992
993     case CSS_PROP__WEBKIT_BINDING:
994 #ifdef XBL_SUPPORT
995         if (id == CSS_VAL_NONE)
996             valid_primitive = true;
997         else {
998             CSSValueList* values = new CSSValueList();
999             Value* val;
1000             CSSValue* parsedValue = 0;
1001             while ((val = valueList->current())) {
1002                 if (val->unit == CSSPrimitiveValue::CSS_URI) {
1003                     String value = parseURL(domString(val->string));
1004                     parsedValue = new CSSPrimitiveValue(
1005                                     String(KURL(styleElement->baseURL().deprecatedString(), value.deprecatedString()).url()), 
1006                                     CSSPrimitiveValue::CSS_URI);
1007                 } 
1008                 
1009                 if (parsedValue)
1010                     values->append(parsedValue);
1011                 else
1012                     break;
1013                 valueList->next();
1014             }
1015             if (values->length()) {
1016                 addProperty(propId, values, important);
1017                 valueList->next();
1018                 return true;
1019             }
1020             delete values;
1021             return false;
1022         }
1023 #endif
1024         break;
1025     case CSS_PROP__WEBKIT_BORDER_IMAGE:
1026         if (id == CSS_VAL_NONE)
1027             valid_primitive = true;
1028         else
1029             return parseBorderImage(propId, important);
1030         break;
1031     case CSS_PROP__WEBKIT_BORDER_TOP_RIGHT_RADIUS:
1032     case CSS_PROP__WEBKIT_BORDER_TOP_LEFT_RADIUS:
1033     case CSS_PROP__WEBKIT_BORDER_BOTTOM_LEFT_RADIUS:
1034     case CSS_PROP__WEBKIT_BORDER_BOTTOM_RIGHT_RADIUS:
1035     case CSS_PROP__WEBKIT_BORDER_RADIUS: {
1036         if (num != 1 && num != 2)
1037             return false;
1038         valid_primitive = validUnit(value, FLength, strict);
1039         if (!valid_primitive)
1040             return false;
1041         CSSPrimitiveValue* parsedValue1 = new CSSPrimitiveValue(value->fValue,
1042                                                                         (CSSPrimitiveValue::UnitTypes)value->unit);
1043         CSSPrimitiveValue* parsedValue2 = parsedValue1;
1044         if (num == 2) {
1045             value = valueList->next();
1046             valid_primitive = validUnit(value, FLength, strict);
1047             if (!valid_primitive) {
1048                 delete parsedValue1;
1049                 return false;
1050             }
1051             parsedValue2 = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1052         }
1053         
1054         Pair* pair = new Pair(parsedValue1, parsedValue2);
1055         CSSPrimitiveValue* val = new CSSPrimitiveValue(pair);
1056         if (propId == CSS_PROP__WEBKIT_BORDER_RADIUS) {
1057             const int properties[4] = { CSS_PROP__WEBKIT_BORDER_TOP_RIGHT_RADIUS,
1058                                         CSS_PROP__WEBKIT_BORDER_TOP_LEFT_RADIUS,
1059                                         CSS_PROP__WEBKIT_BORDER_BOTTOM_LEFT_RADIUS,
1060                                         CSS_PROP__WEBKIT_BORDER_BOTTOM_RIGHT_RADIUS };
1061             for (int i = 0; i < 4; i++)
1062                 addProperty(properties[i], val, important);
1063         } else
1064             addProperty(propId, val, important);
1065         return true;
1066     }
1067     case CSS_PROP_OUTLINE_OFFSET:
1068         valid_primitive = validUnit(value, FLength, strict);
1069         break;
1070     case CSS_PROP_TEXT_SHADOW: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
1071     case CSS_PROP__WEBKIT_BOX_SHADOW:
1072         if (id == CSS_VAL_NONE)
1073             valid_primitive = true;
1074         else
1075             return parseShadow(propId, important);
1076         break;
1077     case CSS_PROP_OPACITY:
1078         valid_primitive = validUnit(value, FNumber, strict);
1079         break;
1080     case CSS_PROP__WEBKIT_BOX_ALIGN:
1081         if (id == CSS_VAL_STRETCH || id == CSS_VAL_START || id == CSS_VAL_END ||
1082             id == CSS_VAL_CENTER || id == CSS_VAL_BASELINE)
1083             valid_primitive = true;
1084         break;
1085     case CSS_PROP__WEBKIT_BOX_DIRECTION:
1086         if (id == CSS_VAL_NORMAL || id == CSS_VAL_REVERSE)
1087             valid_primitive = true;
1088         break;
1089     case CSS_PROP__WEBKIT_BOX_LINES:
1090         if (id == CSS_VAL_SINGLE || id == CSS_VAL_MULTIPLE)
1091             valid_primitive = true;
1092         break;
1093     case CSS_PROP__WEBKIT_BOX_ORIENT:
1094         if (id == CSS_VAL_HORIZONTAL || id == CSS_VAL_VERTICAL ||
1095             id == CSS_VAL_INLINE_AXIS || id == CSS_VAL_BLOCK_AXIS)
1096             valid_primitive = true;
1097         break;
1098     case CSS_PROP__WEBKIT_BOX_PACK:
1099         if (id == CSS_VAL_START || id == CSS_VAL_END ||
1100             id == CSS_VAL_CENTER || id == CSS_VAL_JUSTIFY)
1101             valid_primitive = true;
1102         break;
1103     case CSS_PROP__WEBKIT_BOX_FLEX:
1104         valid_primitive = validUnit(value, FNumber, strict);
1105         break;
1106     case CSS_PROP__WEBKIT_BOX_FLEX_GROUP:
1107     case CSS_PROP__WEBKIT_BOX_ORDINAL_GROUP:
1108         valid_primitive = validUnit(value, FInteger|FNonNeg, true);
1109         break;
1110     case CSS_PROP_BOX_SIZING: {
1111         // We don't preface this with -webkit, since MacIE defined this property without the prefix.
1112         // Thus the damage has been done, and it's known that this property's definition isn't going
1113         // to fluctuate.
1114         if (id == CSS_VAL_BORDER_BOX || id == CSS_VAL_CONTENT_BOX)
1115             valid_primitive = true;
1116         break;
1117     }
1118     case CSS_PROP__WEBKIT_MARQUEE: {
1119         const int properties[5] = { CSS_PROP__WEBKIT_MARQUEE_DIRECTION, CSS_PROP__WEBKIT_MARQUEE_INCREMENT,
1120                                     CSS_PROP__WEBKIT_MARQUEE_REPETITION,
1121                                     CSS_PROP__WEBKIT_MARQUEE_STYLE, CSS_PROP__WEBKIT_MARQUEE_SPEED };
1122         return parseShorthand(propId, properties, 5, important);
1123     }
1124     case CSS_PROP__WEBKIT_MARQUEE_DIRECTION:
1125         if (id == CSS_VAL_FORWARDS || id == CSS_VAL_BACKWARDS || id == CSS_VAL_AHEAD ||
1126             id == CSS_VAL_REVERSE || id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_DOWN ||
1127             id == CSS_VAL_UP || id == CSS_VAL_AUTO)
1128             valid_primitive = true;
1129         break;
1130     case CSS_PROP__WEBKIT_MARQUEE_INCREMENT:
1131         if (id == CSS_VAL_SMALL || id == CSS_VAL_LARGE || id == CSS_VAL_MEDIUM)
1132             valid_primitive = true;
1133         else
1134             valid_primitive = validUnit(value, FLength|FPercent, strict);
1135         break;
1136     case CSS_PROP__WEBKIT_MARQUEE_STYLE:
1137         if (id == CSS_VAL_NONE || id == CSS_VAL_SLIDE || id == CSS_VAL_SCROLL || id == CSS_VAL_ALTERNATE)
1138             valid_primitive = true;
1139         break;
1140     case CSS_PROP__WEBKIT_MARQUEE_REPETITION:
1141         if (id == CSS_VAL_INFINITE)
1142             valid_primitive = true;
1143         else
1144             valid_primitive = validUnit(value, FInteger|FNonNeg, strict);
1145         break;
1146     case CSS_PROP__WEBKIT_MARQUEE_SPEED:
1147         if (id == CSS_VAL_NORMAL || id == CSS_VAL_SLOW || id == CSS_VAL_FAST)
1148             valid_primitive = true;
1149         else
1150             valid_primitive = validUnit(value, FTime|FInteger|FNonNeg, strict);
1151         break;
1152     case CSS_PROP__WEBKIT_USER_DRAG: // auto | none | element
1153         if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE || id == CSS_VAL_ELEMENT)
1154             valid_primitive = true;
1155         break;
1156     case CSS_PROP__WEBKIT_USER_MODIFY: // read-only | read-write
1157         if (id == CSS_VAL_READ_ONLY || id == CSS_VAL_READ_WRITE || CSS_VAL_READ_WRITE_PLAINTEXT_ONLY)
1158             valid_primitive = true;
1159         break;
1160     case CSS_PROP__WEBKIT_USER_SELECT: // auto | none | text
1161         if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE || id == CSS_VAL_TEXT || id == CSS_VAL_IGNORE)
1162             valid_primitive = true;
1163         break;
1164     case CSS_PROP_TEXT_OVERFLOW: // clip | ellipsis
1165         if (id == CSS_VAL_CLIP || id == CSS_VAL_ELLIPSIS)
1166             valid_primitive = true;
1167         break;
1168     case CSS_PROP__WEBKIT_MARGIN_COLLAPSE: {
1169         const int properties[2] = { CSS_PROP__WEBKIT_MARGIN_TOP_COLLAPSE,
1170             CSS_PROP__WEBKIT_MARGIN_BOTTOM_COLLAPSE };
1171         if (num == 1) {
1172             ShorthandScope scope(this, CSS_PROP__WEBKIT_MARGIN_COLLAPSE);
1173             if (!parseValue(properties[0], important))
1174                 return false;
1175             CSSValue* value = parsedProperties[numParsedProperties-1]->value();
1176             addProperty(properties[1], value, important);
1177             return true;
1178         }
1179         else if (num == 2) {
1180             ShorthandScope scope(this, CSS_PROP__WEBKIT_MARGIN_COLLAPSE);
1181             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
1182                 return false;
1183             return true;
1184         }
1185         return false;
1186     }
1187     case CSS_PROP__WEBKIT_MARGIN_TOP_COLLAPSE:
1188     case CSS_PROP__WEBKIT_MARGIN_BOTTOM_COLLAPSE:
1189         if (id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE || id == CSS_VAL_DISCARD)
1190             valid_primitive = true;
1191         break;
1192     case CSS_PROP_TEXT_LINE_THROUGH_MODE:
1193     case CSS_PROP_TEXT_OVERLINE_MODE:
1194     case CSS_PROP_TEXT_UNDERLINE_MODE:
1195         if (id == CSS_VAL_CONTINUOUS || id == CSS_VAL_SKIP_WHITE_SPACE)
1196             valid_primitive = true;
1197         break;
1198     case CSS_PROP_TEXT_LINE_THROUGH_STYLE:
1199     case CSS_PROP_TEXT_OVERLINE_STYLE:
1200     case CSS_PROP_TEXT_UNDERLINE_STYLE:
1201         if (id == CSS_VAL_NONE || id == CSS_VAL_SOLID || id == CSS_VAL_DOUBLE ||
1202             id == CSS_VAL_DASHED || id == CSS_VAL_DOT_DASH || id == CSS_VAL_DOT_DOT_DASH ||
1203             id == CSS_VAL_WAVE)
1204             valid_primitive = true;
1205         break;
1206     case CSS_PROP_TEXT_LINE_THROUGH_WIDTH:
1207     case CSS_PROP_TEXT_OVERLINE_WIDTH:
1208     case CSS_PROP_TEXT_UNDERLINE_WIDTH:
1209         if (id == CSS_VAL_AUTO || id == CSS_VAL_NORMAL || id == CSS_VAL_THIN ||
1210             id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
1211             valid_primitive = true;
1212         else
1213             valid_primitive = !id && validUnit(value, FNumber|FLength|FPercent, strict);
1214         break;
1215     case CSS_PROP_RESIZE: // none | both | horizontal | vertical | auto
1216         if (id == CSS_VAL_NONE || id == CSS_VAL_BOTH || id == CSS_VAL_HORIZONTAL || id == CSS_VAL_VERTICAL || id == CSS_VAL_AUTO)
1217             valid_primitive = true;
1218         break;
1219     case CSS_PROP__WEBKIT_COLUMN_COUNT:
1220         if (id == CSS_VAL_AUTO)
1221             valid_primitive = true;
1222         else
1223             valid_primitive = !id && validUnit(value, FInteger | FNonNeg, false);
1224         break;
1225     case CSS_PROP__WEBKIT_COLUMN_GAP:         // normal | <length>
1226         if (id == CSS_VAL_NORMAL)
1227             valid_primitive = true;
1228         else
1229             valid_primitive = validUnit(value, FLength, strict);
1230         break;
1231     case CSS_PROP__WEBKIT_COLUMN_WIDTH:         // auto | <length>
1232         if (id == CSS_VAL_AUTO)
1233             valid_primitive = true;
1234         else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
1235             valid_primitive = validUnit(value, FLength, true);
1236         break;
1237     // End of CSS3 properties
1238
1239     // Apple specific properties.  These will never be standardized and are purely to
1240     // support custom WebKit-based Apple applications.
1241     case CSS_PROP__WEBKIT_LINE_CLAMP:
1242         valid_primitive = (!id && validUnit(value, FPercent, false));
1243         break;
1244     case CSS_PROP__WEBKIT_TEXT_SIZE_ADJUST:
1245         if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE)
1246             valid_primitive = true;
1247         break;
1248     case CSS_PROP__WEBKIT_RTL_ORDERING:
1249         if (id == CSS_VAL_LOGICAL || id == CSS_VAL_VISUAL)
1250             valid_primitive = true;
1251         break;
1252     
1253     case CSS_PROP__WEBKIT_FONT_SIZE_DELTA:           // <length>
1254         valid_primitive = validUnit(value, FLength, strict);
1255         break;
1256
1257     case CSS_PROP__WEBKIT_NBSP_MODE:     // normal | space
1258         if (id == CSS_VAL_NORMAL || id == CSS_VAL_SPACE)
1259             valid_primitive = true;
1260         break;
1261
1262     case CSS_PROP__WEBKIT_LINE_BREAK:   // normal | after-white-space
1263         if (id == CSS_VAL_NORMAL || id == CSS_VAL_AFTER_WHITE_SPACE)
1264             valid_primitive = true;
1265         break;
1266
1267     case CSS_PROP__WEBKIT_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR:   // normal | match
1268         if (id == CSS_VAL_NORMAL || id == CSS_VAL_MATCH)
1269             valid_primitive = true;
1270         break;
1271
1272     case CSS_PROP__WEBKIT_HIGHLIGHT:
1273         if (id == CSS_VAL_NONE || value->unit == CSSPrimitiveValue::CSS_STRING)
1274             valid_primitive = true;
1275         break;
1276
1277     case CSS_PROP__WEBKIT_TEXT_SECURITY:
1278         // disc | circle | square | none | inherit
1279         if (id == CSS_VAL_DISC || id == CSS_VAL_CIRCLE || id == CSS_VAL_SQUARE|| id == CSS_VAL_NONE)
1280             valid_primitive = true;
1281         break;
1282
1283 #if PLATFORM(MAC)
1284     case CSS_PROP__WEBKIT_DASHBOARD_REGION:                 // <dashboard-region> | <dashboard-region> 
1285         if (value->unit == Value::Function || id == CSS_VAL_NONE)
1286             return parseDashboardRegions(propId, important);
1287         break;
1288 #endif
1289     // End Apple-specific properties
1290
1291         /* shorthand properties */
1292     case CSS_PROP_BACKGROUND:
1293         // ['background-color' || 'background-image' || 'background-size' || 'background-repeat' ||
1294         // 'background-attachment' || 'background-position'] | inherit
1295         return parseBackgroundShorthand(important);
1296     case CSS_PROP_BORDER:
1297         // [ 'border-width' || 'border-style' || <color> ] | inherit
1298     {
1299         const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
1300                                     CSS_PROP_BORDER_COLOR };
1301         return parseShorthand(propId, properties, 3, important);
1302     }
1303     case CSS_PROP_BORDER_TOP:
1304         // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1305     {
1306         const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
1307                                     CSS_PROP_BORDER_TOP_COLOR};
1308         return parseShorthand(propId, properties, 3, important);
1309     }
1310     case CSS_PROP_BORDER_RIGHT:
1311         // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1312     {
1313         const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
1314                                     CSS_PROP_BORDER_RIGHT_COLOR };
1315         return parseShorthand(propId, properties, 3, important);
1316     }
1317     case CSS_PROP_BORDER_BOTTOM:
1318         // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1319     {
1320         const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
1321                                     CSS_PROP_BORDER_BOTTOM_COLOR };
1322         return parseShorthand(propId, properties, 3, important);
1323     }
1324     case CSS_PROP_BORDER_LEFT:
1325         // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1326     {
1327         const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
1328                                     CSS_PROP_BORDER_LEFT_COLOR };
1329         return parseShorthand(propId, properties, 3, important);
1330     }
1331     case CSS_PROP_OUTLINE:
1332         // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1333     {
1334         const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
1335                                     CSS_PROP_OUTLINE_COLOR };
1336         return parseShorthand(propId, properties, 3, important);
1337     }
1338     case CSS_PROP_BORDER_COLOR:
1339         // <color>{1,4} | inherit
1340     {
1341         const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
1342                                     CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
1343         return parse4Values(propId, properties, important);
1344     }
1345     case CSS_PROP_BORDER_WIDTH:
1346         // <border-width>{1,4} | inherit
1347     {
1348         const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
1349                                     CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
1350         return parse4Values(propId, properties, important);
1351     }
1352     case CSS_PROP_BORDER_STYLE:
1353         // <border-style>{1,4} | inherit
1354     {
1355         const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
1356                                     CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
1357         return parse4Values(propId, properties, important);
1358     }
1359     case CSS_PROP_MARGIN:
1360         // <margin-width>{1,4} | inherit
1361     {
1362         const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
1363                                     CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
1364         return parse4Values(propId, properties, important);
1365     }
1366     case CSS_PROP_PADDING:
1367         // <padding-width>{1,4} | inherit
1368     {
1369         const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
1370                                     CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
1371         return parse4Values(propId, properties, important);
1372     }
1373     case CSS_PROP_FONT:
1374         // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1375         // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1376         if (id >= CSS_VAL_CAPTION && id <= CSS_VAL_STATUS_BAR)
1377             valid_primitive = true;
1378         else
1379             return parseFont(important);
1380         break;
1381     case CSS_PROP_LIST_STYLE:
1382     {
1383         const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
1384                                     CSS_PROP_LIST_STYLE_IMAGE };
1385         return parseShorthand(propId, properties, 3, important);
1386     }
1387     case CSS_PROP__WEBKIT_COLUMNS: {
1388         const int properties[2] = { CSS_PROP__WEBKIT_COLUMN_WIDTH, CSS_PROP__WEBKIT_COLUMN_COUNT };
1389         return parseShorthand(propId, properties, 2, important);
1390     }
1391     case CSS_PROP__WEBKIT_COLUMN_RULE: {
1392         const int properties[3] = { CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH, CSS_PROP__WEBKIT_COLUMN_RULE_STYLE,
1393                                     CSS_PROP__WEBKIT_COLUMN_RULE_COLOR };
1394         return parseShorthand(propId, properties, 3, important);
1395     }
1396     case CSS_PROP__WEBKIT_TEXT_STROKE: {
1397         const int properties[2] = { CSS_PROP__WEBKIT_TEXT_STROKE_WIDTH, CSS_PROP__WEBKIT_TEXT_STROKE_COLOR };
1398         return parseShorthand(propId, properties, 2, important);
1399     }
1400     default:
1401 #ifdef SVG_SUPPORT
1402         if (parseSVGValue(propId, important))
1403             return true;
1404 #endif
1405         break;
1406     }
1407
1408     if (valid_primitive) {
1409         if (id != 0) {
1410             parsedValue = new CSSPrimitiveValue(id); }
1411         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
1412             parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
1413         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1414             parsedValue = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
1415         else if (value->unit >= Value::Q_EMS)
1416             parsedValue = new CSSQuirkPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_EMS);
1417         valueList->next();
1418     }
1419     if (parsedValue) {
1420         if (!valueList->current() || inShorthand()) {
1421             addProperty(propId, parsedValue, important);
1422             return true;
1423         }
1424         delete parsedValue;
1425     }
1426     return false;
1427 }
1428
1429 void CSSParser::addBackgroundValue(CSSValue*& lval, CSSValue* rval)
1430 {
1431     if (lval) {
1432         if (lval->isValueList())
1433             static_cast<CSSValueList*>(lval)->append(rval);
1434         else {
1435             CSSValue* oldVal = lval;
1436             CSSValueList* list = new CSSValueList();
1437             lval = list;
1438             list->append(oldVal);
1439             list->append(rval);
1440         }
1441     }
1442     else
1443         lval = rval;
1444 }
1445
1446 bool CSSParser::parseBackgroundShorthand(bool important)
1447 {
1448     // Position must come before color in this array because a plain old "0" is a legal color
1449     // in quirks mode but it's usually the X coordinate of a position.
1450     // FIXME: Add CSS_PROP__KHTML_BACKGROUND_SIZE to the shorthand.
1451     const int properties[] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT, 
1452         CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION, CSS_PROP__WEBKIT_BACKGROUND_CLIP,
1453         CSS_PROP__WEBKIT_BACKGROUND_ORIGIN, CSS_PROP_BACKGROUND_COLOR };
1454     const int numProperties = sizeof(properties) / sizeof(properties[0]);
1455     
1456     ShorthandScope scope(this, CSS_PROP_BACKGROUND);
1457
1458     bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
1459     CSSValue* values[numProperties] = { 0 }; // compiler will repeat 0 as necessary
1460     CSSValue* positionYValue = 0;
1461     int i;
1462
1463     while (valueList->current()) {
1464         Value* val = valueList->current();
1465         if (val->unit == Value::Operator && val->iValue == ',') {
1466             // We hit the end.  Fill in all remaining values with the initial value.
1467             valueList->next();
1468             for (i = 0; i < numProperties; ++i) {
1469                 if (properties[i] == CSS_PROP_BACKGROUND_COLOR && parsedProperty[i])
1470                     // Color is not allowed except as the last item in a list.  Reject the entire
1471                     // property.
1472                     goto fail;
1473
1474                 if (!parsedProperty[i] && properties[i] != CSS_PROP_BACKGROUND_COLOR) {
1475                     addBackgroundValue(values[i], new CSSInitialValue());
1476                     if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
1477                         addBackgroundValue(positionYValue, new CSSInitialValue());
1478                 }
1479                 parsedProperty[i] = false;
1480             }
1481             if (!valueList->current())
1482                 break;
1483         }
1484         
1485         bool found = false;
1486         for (i = 0; !found && i < numProperties; ++i) {
1487             if (!parsedProperty[i]) {
1488                 CSSValue *val1 = 0, *val2 = 0;
1489                 int propId1, propId2;
1490                 if (parseBackgroundProperty(properties[i], propId1, propId2, val1, val2)) {
1491                     parsedProperty[i] = found = true;
1492                     addBackgroundValue(values[i], val1);
1493                     if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
1494                         addBackgroundValue(positionYValue, val2);
1495                 }
1496             }
1497         }
1498
1499         // if we didn't find at least one match, this is an
1500         // invalid shorthand and we have to ignore it
1501         if (!found)
1502             goto fail;
1503     }
1504     
1505     // Fill in any remaining properties with the initial value.
1506     for (i = 0; i < numProperties; ++i) {
1507         if (!parsedProperty[i]) {
1508             addBackgroundValue(values[i], new CSSInitialValue());
1509             if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
1510                 addBackgroundValue(positionYValue, new CSSInitialValue());
1511         }
1512     }
1513     
1514     // Now add all of the properties we found.
1515     for (i = 0; i < numProperties; i++) {
1516         if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
1517             addProperty(CSS_PROP_BACKGROUND_POSITION_X, values[i], important);
1518             addProperty(CSS_PROP_BACKGROUND_POSITION_Y, positionYValue, important);
1519         }
1520         else
1521             addProperty(properties[i], values[i], important);
1522     }
1523     
1524     return true;
1525
1526 fail:
1527     for (int k = 0; k < numProperties; k++)
1528         delete values[k];
1529     delete positionYValue;
1530     return false;
1531 }
1532
1533 bool CSSParser::parseShorthand(int propId, const int *properties, int numProperties, bool important)
1534 {
1535     // We try to match as many properties as possible
1536     // We set up an array of booleans to mark which property has been found,
1537     // and we try to search for properties until it makes no longer any sense.
1538     ShorthandScope scope(this, propId);
1539
1540     bool found = false;
1541     bool fnd[6]; // Trust me ;)
1542     for (int i = 0; i < numProperties; i++)
1543         fnd[i] = false;
1544
1545     while (valueList->current()) {
1546         found = false;
1547         for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
1548             if (!fnd[propIndex]) {
1549                 if (parseValue(properties[propIndex], important))
1550                     fnd[propIndex] = found = true;
1551             }
1552         }
1553
1554         // if we didn't find at least one match, this is an
1555         // invalid shorthand and we have to ignore it
1556         if (!found)
1557             return false;
1558     }
1559     
1560     // Fill in any remaining properties with the initial value.
1561     m_implicitShorthand = true;
1562     for (int i = 0; i < numProperties; ++i) {
1563         if (!fnd[i])
1564             addProperty(properties[i], new CSSInitialValue(), important);
1565     }
1566     m_implicitShorthand = false;
1567
1568     return true;
1569 }
1570
1571 bool CSSParser::parse4Values(int propId, const int *properties,  bool important)
1572 {
1573     /* From the CSS 2 specs, 8.3
1574      * If there is only one value, it applies to all sides. If there are two values, the top and
1575      * bottom margins are set to the first value and the right and left margins are set to the second.
1576      * If there are three values, the top is set to the first value, the left and right are set to the
1577      * second, and the bottom is set to the third. If there are four values, they apply to the top,
1578      * right, bottom, and left, respectively.
1579      */
1580     
1581     int num = inShorthand() ? 1 : valueList->size();
1582     
1583     ShorthandScope scope(this, propId);
1584
1585     // the order is top, right, bottom, left
1586     switch (num) {
1587         case 1: {
1588             if (!parseValue(properties[0], important))
1589                 return false;
1590             CSSValue *value = parsedProperties[numParsedProperties-1]->value();
1591             m_implicitShorthand = true;
1592             addProperty(properties[1], value, important);
1593             addProperty(properties[2], value, important);
1594             addProperty(properties[3], value, important);
1595             m_implicitShorthand = false;
1596             break;
1597         }
1598         case 2: {
1599             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
1600                 return false;
1601             CSSValue *value = parsedProperties[numParsedProperties-2]->value();
1602             m_implicitShorthand = true;
1603             addProperty(properties[2], value, important);
1604             value = parsedProperties[numParsedProperties-2]->value();
1605             addProperty(properties[3], value, important);
1606             m_implicitShorthand = false;
1607             break;
1608         }
1609         case 3: {
1610             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
1611                 return false;
1612             CSSValue *value = parsedProperties[numParsedProperties-2]->value();
1613             m_implicitShorthand = true;
1614             addProperty(properties[3], value, important);
1615             m_implicitShorthand = false;
1616             break;
1617         }
1618         case 4: {
1619             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
1620                 !parseValue(properties[2], important) || !parseValue(properties[3], important))
1621                 return false;
1622             break;
1623         }
1624         default: {
1625             return false;
1626         }
1627     }
1628     
1629     return true;
1630 }
1631
1632 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1633 // in CSS 2.1 this got somewhat reduced:
1634 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1635 bool CSSParser::parseContent(int propId, bool important)
1636 {
1637     RefPtr<CSSValueList> values = new CSSValueList;
1638
1639     while (Value* val = valueList->current()) {
1640         RefPtr<CSSValue> parsedValue;
1641         if (val->unit == CSSPrimitiveValue::CSS_URI) {
1642             // url
1643             String value = parseURL(domString(val->string));
1644             parsedValue = new CSSImageValue(
1645                 String(KURL(styleElement->baseURL().deprecatedString(), value.deprecatedString()).url()), styleElement);
1646         } else if (val->unit == Value::Function) {
1647             // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z])
1648             ValueList *args = val->function->args;
1649             String fname = domString(val->function->name).lower();
1650             if (!args)
1651                 return false;
1652             if (fname == "attr(") {
1653                 if (args->size() != 1)
1654                     return false;
1655                 Value* a = args->current();
1656                 String attrName = domString(a->string);
1657                 if (document()->isHTMLDocument())
1658                     attrName = attrName.lower();
1659                 parsedValue = new CSSPrimitiveValue(attrName, CSSPrimitiveValue::CSS_ATTR);
1660             } else if (fname == "counter(") {
1661                 parsedValue = parseCounterContent(args, false);
1662                 if (!parsedValue) return false;
1663             } else if (fname == "counters(") {
1664                 parsedValue = parseCounterContent(args, true);
1665                 if (!parsedValue)
1666                     return false;
1667             } else
1668                 return false;
1669         } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
1670             // open-quote
1671             // close-quote
1672             // no-open-quote
1673             // no-close-quote
1674             // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
1675         } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
1676             parsedValue = new CSSPrimitiveValue(domString(val->string), CSSPrimitiveValue::CSS_STRING);
1677         }
1678         if (!parsedValue)
1679             break;
1680         values->append(parsedValue.release());
1681         valueList->next();
1682     }
1683
1684     if (values->length()) {
1685         addProperty(propId, values.release(), important);
1686         valueList->next();
1687         return true;
1688     }
1689
1690     return false;
1691 }
1692
1693 CSSValue* CSSParser::parseBackgroundColor()
1694 {
1695     int id = valueList->current()->id;
1696     if (id == CSS_VAL__WEBKIT_TEXT || (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || id == CSS_VAL_MENU ||
1697         (id >= CSS_VAL_GREY && id < CSS_VAL__WEBKIT_TEXT && !strict))
1698        return new CSSPrimitiveValue(id);
1699     return parseColor();
1700 }
1701
1702 CSSValue* CSSParser::parseBackgroundImage()
1703 {
1704     if (valueList->current()->id == CSS_VAL_NONE)
1705         return new CSSImageValue();
1706     if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
1707         String uri = parseURL(domString(valueList->current()->string));
1708         if (!uri.isEmpty())
1709             return new CSSImageValue(String(KURL(styleElement->baseURL().deprecatedString(), uri.deprecatedString()).url()), 
1710                                          styleElement);
1711     }
1712     return 0;
1713 }
1714
1715 CSSValue* CSSParser::parseBackgroundPositionXY(bool& xFound, bool& yFound)
1716 {
1717     int id = valueList->current()->id;
1718     if (id == CSS_VAL_LEFT || id == CSS_VAL_TOP || id == CSS_VAL_RIGHT || id == CSS_VAL_BOTTOM || id == CSS_VAL_CENTER) {
1719         int percent = 0;
1720         if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT) {
1721             if (xFound)
1722                 return 0;
1723             xFound = true;
1724             if (id == CSS_VAL_RIGHT)
1725                 percent = 100;
1726         }
1727         else if (id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
1728             if (yFound)
1729                 return 0;
1730             yFound = true;
1731             if (id == CSS_VAL_BOTTOM)
1732                 percent = 100;
1733         }
1734         else if (id == CSS_VAL_CENTER)
1735             // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
1736             percent = 50;
1737         return new CSSPrimitiveValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
1738     }
1739     if (validUnit(valueList->current(), FPercent|FLength, strict))
1740         return new CSSPrimitiveValue(valueList->current()->fValue,
1741                                          (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
1742                 
1743     return 0;
1744 }
1745
1746 void CSSParser::parseBackgroundPosition(CSSValue*& value1, CSSValue*& value2)
1747 {
1748     value1 = value2 = 0;
1749     Value* value = valueList->current();
1750     
1751     // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
1752     bool value1IsX = false, value1IsY = false;
1753     value1 = parseBackgroundPositionXY(value1IsX, value1IsY);
1754     if (!value1)
1755         return;
1756     
1757     // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
1758     // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
1759     // value was explicitly specified for our property.
1760     value = valueList->next();
1761     
1762     // First check for the comma.  If so, we are finished parsing this value or value pair.
1763     if (value && value->unit == Value::Operator && value->iValue == ',')
1764         value = 0;
1765     
1766     bool value2IsX = false, value2IsY = false;
1767     if (value) {
1768         value2 = parseBackgroundPositionXY(value2IsX, value2IsY);
1769         if (value2)
1770             valueList->next();
1771         else {
1772             if (!inShorthand()) {
1773                 delete value1;
1774                 value1 = 0;
1775                 return;
1776             }
1777         }
1778     }
1779     
1780     if (!value2)
1781         // Only one value was specified.  If that value was not a keyword, then it sets the x position, and the y position
1782         // is simply 50%.  This is our default.
1783         // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
1784         // For left/right/center, the default of 50% in the y is still correct.
1785         value2 = new CSSPrimitiveValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
1786
1787     if (value1IsY || value2IsX) {
1788         // Swap our two values.
1789         CSSValue* val = value2;
1790         value2 = value1;
1791         value1 = val;
1792     }
1793 }
1794
1795 CSSValue* CSSParser::parseBackgroundSize()
1796 {
1797     Value* value = valueList->current();
1798     CSSPrimitiveValue* parsedValue1;
1799     
1800     if (value->id == CSS_VAL_AUTO)
1801         parsedValue1 = new CSSPrimitiveValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
1802     else {
1803         if (!validUnit(value, FLength|FPercent, strict))
1804             return 0;
1805         parsedValue1 = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1806     }
1807     
1808     CSSPrimitiveValue* parsedValue2 = parsedValue1;
1809     if ((value = valueList->next())) {
1810         if (value->id == CSS_VAL_AUTO)
1811             parsedValue2 = new CSSPrimitiveValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
1812         else {
1813             if (!validUnit(value, FLength|FPercent, strict)) {
1814                 delete parsedValue1;
1815                 return 0;
1816             }
1817             parsedValue2 = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1818         }
1819     }
1820     
1821     Pair* pair = new Pair(parsedValue1, parsedValue2);
1822     return new CSSPrimitiveValue(pair);
1823 }
1824
1825 bool CSSParser::parseBackgroundProperty(int propId, int& propId1, int& propId2, 
1826                                         CSSValue*& retValue1, CSSValue*& retValue2)
1827 {
1828     CSSValueList *values = 0, *values2 = 0;
1829     Value* val;
1830     CSSValue *value = 0, *value2 = 0;
1831     bool allowComma = false;
1832     
1833     retValue1 = retValue2 = 0;
1834     propId1 = propId;
1835     propId2 = propId;
1836     if (propId == CSS_PROP_BACKGROUND_POSITION) {
1837         propId1 = CSS_PROP_BACKGROUND_POSITION_X;
1838         propId2 = CSS_PROP_BACKGROUND_POSITION_Y;
1839     }
1840
1841     while ((val = valueList->current())) {
1842         CSSValue *currValue = 0, *currValue2 = 0;
1843         if (allowComma) {
1844             if (val->unit != Value::Operator || val->iValue != ',')
1845                 goto failed;
1846             valueList->next();
1847             allowComma = false;
1848         }
1849         else {
1850             switch (propId) {
1851                 case CSS_PROP_BACKGROUND_ATTACHMENT:
1852                     if (val->id == CSS_VAL_SCROLL || val->id == CSS_VAL_FIXED) {
1853                         currValue = new CSSPrimitiveValue(val->id);
1854                         valueList->next();
1855                     }
1856                     break;
1857                 case CSS_PROP_BACKGROUND_COLOR:
1858                     currValue = parseBackgroundColor();
1859                     if (currValue)
1860                         valueList->next();
1861                     break;
1862                 case CSS_PROP_BACKGROUND_IMAGE:
1863                     currValue = parseBackgroundImage();
1864                     if (currValue)
1865                         valueList->next();
1866                     break;
1867                 case CSS_PROP__WEBKIT_BACKGROUND_CLIP:
1868                 case CSS_PROP__WEBKIT_BACKGROUND_ORIGIN:
1869                     if (val->id == CSS_VAL_BORDER || val->id == CSS_VAL_PADDING || val->id == CSS_VAL_CONTENT) {
1870                         currValue = new CSSPrimitiveValue(val->id);
1871                         valueList->next();
1872                     }
1873                     break;
1874                 case CSS_PROP_BACKGROUND_POSITION:
1875                     parseBackgroundPosition(currValue, currValue2);
1876                     // unlike the other functions, parseBackgroundPosition advances the valueList pointer
1877                     break;
1878                 case CSS_PROP_BACKGROUND_POSITION_X: {
1879                     bool xFound = false, yFound = true;
1880                     currValue = parseBackgroundPositionXY(xFound, yFound);
1881                     if (currValue)
1882                         valueList->next();
1883                     break;
1884                 }
1885                 case CSS_PROP_BACKGROUND_POSITION_Y: {
1886                     bool xFound = true, yFound = false;
1887                     currValue = parseBackgroundPositionXY(xFound, yFound);
1888                     if (currValue)
1889                         valueList->next();
1890                     break;
1891                 }
1892                 case CSS_PROP__WEBKIT_BACKGROUND_COMPOSITE:
1893                     if ((val->id >= CSS_VAL_CLEAR && val->id <= CSS_VAL_PLUS_LIGHTER) || val->id == CSS_VAL_HIGHLIGHT) {
1894                         currValue = new CSSPrimitiveValue(val->id);
1895                         valueList->next();
1896                     }
1897                     break;
1898                 case CSS_PROP_BACKGROUND_REPEAT:
1899                     if (val->id >= CSS_VAL_REPEAT && val->id <= CSS_VAL_NO_REPEAT) {
1900                         currValue = new CSSPrimitiveValue(val->id);
1901                         valueList->next();
1902                     }
1903                     break;
1904                 case CSS_PROP__WEBKIT_BACKGROUND_SIZE:
1905                     currValue = parseBackgroundSize();
1906                     if (currValue)
1907                         valueList->next();
1908                     break;
1909             }
1910             
1911             if (!currValue)
1912                 goto failed;
1913             
1914             if (value && !values) {
1915                 values = new CSSValueList();
1916                 values->append(value);
1917                 value = 0;
1918             }
1919             
1920             if (value2 && !values2) {
1921                 values2 = new CSSValueList();
1922                 values2->append(value2);
1923                 value2 = 0;
1924             }
1925             
1926             if (values)
1927                 values->append(currValue);
1928             else
1929                 value = currValue;
1930             if (currValue2) {
1931                 if (values2)
1932                     values2->append(currValue2);
1933                 else
1934                     value2 = currValue2;
1935             }
1936             allowComma = true;
1937         }
1938         
1939         // When parsing the 'background' shorthand property, we let it handle building up the lists for all
1940         // properties.
1941         if (inShorthand())
1942             break;
1943     }
1944     
1945     if (values && values->length()) {
1946         retValue1 = values;
1947         if (values2 && values2->length())
1948             retValue2 = values2;
1949         return true;
1950     }
1951     if (value) {
1952         retValue1 = value;
1953         retValue2 = value2;
1954         return true;
1955     }
1956
1957 failed:
1958     delete values; delete values2;
1959     delete value; delete value2;
1960     return false;
1961 }
1962
1963 #if PLATFORM(MAC)
1964
1965 #define DASHBOARD_REGION_NUM_PARAMETERS  6
1966 #define DASHBOARD_REGION_SHORT_NUM_PARAMETERS  2
1967
1968 static Value *skipCommaInDashboardRegion (ValueList *args)
1969 {
1970     if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
1971          args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
1972         Value *current = args->current();
1973         if (current->unit == Value::Operator && current->iValue == ',')
1974             return args->next();
1975     }
1976     return args->current();
1977 }
1978
1979 bool CSSParser::parseDashboardRegions(int propId, bool important)
1980 {
1981     bool valid = true;
1982     
1983     Value *value = valueList->current();
1984
1985     if (value->id == CSS_VAL_NONE) {
1986         addProperty(propId, new CSSPrimitiveValue(value->id), important);
1987         return valid;
1988     }
1989         
1990     RefPtr<DashboardRegion> firstRegion = new DashboardRegion;
1991     DashboardRegion* region = 0;
1992
1993     while (value) {
1994         if (region == 0) {
1995             region = firstRegion.get();
1996         } else {
1997             RefPtr<DashboardRegion> nextRegion = new DashboardRegion();
1998             region->m_next = nextRegion;
1999             region = nextRegion.get();
2000         }
2001         
2002         if (value->unit != Value::Function) {
2003             valid = false;
2004             break;
2005         }
2006             
2007         // Commas count as values, so allow:
2008         // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
2009         // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
2010         // also allow
2011         // dashboard-region(label, type) or dashboard-region(label type)
2012         // dashboard-region(label, type) or dashboard-region(label type)
2013         ValueList* args = value->function->args;
2014         String fname = domString(value->function->name).lower();
2015         if (fname != "dashboard-region(" || !args) {
2016             valid = false;
2017             break;
2018         }
2019         
2020         int numArgs = args->size();
2021         if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
2022             (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))){
2023             valid = false;
2024             break;
2025         }
2026             
2027         // First arg is a label.
2028         Value* arg = args->current();
2029         if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
2030             valid = false;
2031             break;
2032         }
2033             
2034         region->m_label = domString(arg->string);
2035
2036         // Second arg is a type.
2037         arg = args->next();
2038         arg = skipCommaInDashboardRegion (args);
2039         if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
2040             valid = false;
2041             break;
2042         }
2043
2044         String geometryType = domString(arg->string).lower();
2045         if (geometryType == "circle")
2046             region->m_isCircle = true;
2047         else if (geometryType == "rectangle")
2048             region->m_isRectangle = true;
2049         else {
2050             valid = false;
2051             break;
2052         }
2053             
2054         region->m_geometryType = domString(arg->string);
2055
2056         if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
2057             CSSPrimitiveValue *amount = arg->id == CSS_VAL_AUTO ?
2058                 new CSSPrimitiveValue(CSS_VAL_AUTO) :
2059                 new CSSPrimitiveValue((double)0, (CSSPrimitiveValue::UnitTypes) arg->unit);
2060                 
2061             region->setTop(amount);
2062             region->setRight(amount);
2063             region->setBottom(amount);
2064             region->setLeft(amount);
2065         }
2066         else {
2067             // Next four arguments must be offset numbers
2068             int i;
2069             for (i = 0; i < 4; i++) {
2070                 arg = args->next();
2071                 arg = skipCommaInDashboardRegion (args);
2072
2073                 valid = arg->id == CSS_VAL_AUTO || validUnit(arg, FLength, strict);
2074                 if (!valid)
2075                     break;
2076                     
2077                 CSSPrimitiveValue *amount = arg->id == CSS_VAL_AUTO ?
2078                     new CSSPrimitiveValue(CSS_VAL_AUTO) :
2079                     new CSSPrimitiveValue(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit);
2080                     
2081                 if (i == 0)
2082                     region->setTop(amount);
2083                 else if (i == 1)
2084                     region->setRight(amount);
2085                 else if (i == 2)
2086                     region->setBottom(amount);
2087                 else
2088                     region->setLeft(amount);
2089             }
2090         }
2091
2092         value = valueList->next();
2093     }
2094
2095     if (valid)
2096         addProperty(propId, new CSSPrimitiveValue(firstRegion.release()), important);
2097         
2098     return valid;
2099 }
2100 #endif
2101
2102 PassRefPtr<CSSValue> CSSParser::parseCounterContent(ValueList* args, bool counters)
2103 {
2104     unsigned numArgs = args->size();
2105     if (counters && numArgs != 3 && numArgs != 5)
2106         return 0;
2107     if (!counters && numArgs != 1 && numArgs != 3)
2108         return 0;
2109     
2110     Value* i = args->current();
2111     RefPtr<CSSPrimitiveValue> identifier = new CSSPrimitiveValue(domString(i->string),
2112         CSSPrimitiveValue::CSS_STRING);
2113
2114     RefPtr<CSSPrimitiveValue> separator;
2115     if (!counters)
2116         separator = new CSSPrimitiveValue(String(), CSSPrimitiveValue::CSS_STRING);
2117     else {
2118         i = args->next();
2119         if (i->unit != Value::Operator || i->iValue != ',')
2120             return 0;
2121         
2122         i = args->next();
2123         if (i->unit != CSSPrimitiveValue::CSS_STRING)
2124             return 0;
2125         
2126         separator = new CSSPrimitiveValue(domString(i->string), (CSSPrimitiveValue::UnitTypes) i->unit);
2127     }
2128
2129     RefPtr<CSSPrimitiveValue> listStyle;
2130     i = args->next();
2131     if (!i) // Make the list style default decimal
2132         listStyle = new CSSPrimitiveValue(CSS_VAL_DECIMAL - CSS_VAL_DISC, CSSPrimitiveValue::CSS_NUMBER);
2133     else {
2134         if (i->unit != Value::Operator || i->iValue != ',')
2135             return 0;
2136         
2137         i = args->next();
2138         if (i->unit != CSSPrimitiveValue::CSS_IDENT)
2139             return 0;
2140         
2141         short ls = 0;
2142         if (i->id == CSS_VAL_NONE)
2143             ls = CSS_VAL_KATAKANA_IROHA - CSS_VAL_DISC + 1;
2144         else if (i->id >= CSS_VAL_DISC && i->id <= CSS_VAL_KATAKANA_IROHA)
2145             ls = i->id - CSS_VAL_DISC;
2146         else
2147             return 0;
2148
2149         listStyle = new CSSPrimitiveValue(ls, (CSSPrimitiveValue::UnitTypes) i->unit);
2150     }
2151
2152     return new CSSPrimitiveValue(new Counter(identifier.release(), listStyle.release(), separator.release()));
2153 }
2154
2155 bool CSSParser::parseShape(int propId, bool important)
2156 {
2157     Value *value = valueList->current();
2158     ValueList *args = value->function->args;
2159     String fname = domString(value->function->name).lower();
2160     if (fname != "rect(" || !args)
2161         return false;
2162
2163     // rect(t, r, b, l) || rect(t r b l)
2164     if (args->size() != 4 && args->size() != 7)
2165         return false;
2166     RectImpl *rect = new RectImpl();
2167     bool valid = true;
2168     int i = 0;
2169     Value *a = args->current();
2170     while (a) {
2171         valid = a->id == CSS_VAL_AUTO || validUnit(a, FLength, strict);
2172         if (!valid)
2173             break;
2174         CSSPrimitiveValue *length = a->id == CSS_VAL_AUTO ?
2175             new CSSPrimitiveValue(CSS_VAL_AUTO) :
2176             new CSSPrimitiveValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
2177         if (i == 0)
2178             rect->setTop(length);
2179         else if (i == 1)
2180             rect->setRight(length);
2181         else if (i == 2)
2182             rect->setBottom(length);
2183         else
2184             rect->setLeft(length);
2185         a = args->next();
2186         if (a && args->size() == 7) {
2187             if (a->unit == Value::Operator && a->iValue == ',') {
2188                 a = args->next();
2189             } else {
2190                 valid = false;
2191                 break;
2192             }
2193         }
2194         i++;
2195     }
2196     if (valid) {
2197         addProperty(propId, new CSSPrimitiveValue(rect), important);
2198         valueList->next();
2199         return true;
2200     }
2201     delete rect;
2202     return false;
2203 }
2204
2205 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
2206 bool CSSParser::parseFont(bool important)
2207 {
2208     bool valid = true;
2209     Value *value = valueList->current();
2210     FontValue *font = new FontValue;
2211     // optional font-style, font-variant and font-weight
2212     while (value) {
2213         int id = value->id;
2214         if (id) {
2215             if (id == CSS_VAL_NORMAL) {
2216                 // do nothing, it's the inital value for all three
2217             } else if (id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE) {
2218                 if (font->style)
2219                     goto invalid;
2220                 font->style = new CSSPrimitiveValue(id);
2221             } else if (id == CSS_VAL_SMALL_CAPS) {
2222                 if (font->variant)
2223                     goto invalid;
2224                 font->variant = new CSSPrimitiveValue(id);
2225             } else if (id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER) {
2226                 if (font->weight)
2227                     goto invalid;
2228                 font->weight = new CSSPrimitiveValue(id);
2229             } else {
2230                 valid = false;
2231             }
2232         } else if (!font->weight && validUnit(value, FInteger|FNonNeg, true)) {
2233             int weight = (int)value->fValue;
2234             int val = 0;
2235             if (weight == 100)
2236                 val = CSS_VAL_100;
2237             else if (weight == 200)
2238                 val = CSS_VAL_200;
2239             else if (weight == 300)
2240                 val = CSS_VAL_300;
2241             else if (weight == 400)
2242                 val = CSS_VAL_400;
2243             else if (weight == 500)
2244                 val = CSS_VAL_500;
2245             else if (weight == 600)
2246                 val = CSS_VAL_600;
2247             else if (weight == 700)
2248                 val = CSS_VAL_700;
2249             else if (weight == 800)
2250                 val = CSS_VAL_800;
2251             else if (weight == 900)
2252                 val = CSS_VAL_900;
2253
2254             if (val)
2255                 font->weight = new CSSPrimitiveValue(val);
2256             else
2257                 valid = false;
2258         } else {
2259             valid = false;
2260         }
2261         if (!valid)
2262             break;
2263         value = valueList->next();
2264     }
2265     if (!value)
2266         goto invalid;
2267
2268     // set undefined values to default
2269     if (!font->style)
2270         font->style = new CSSPrimitiveValue(CSS_VAL_NORMAL);
2271     if (!font->variant)
2272         font->variant = new CSSPrimitiveValue(CSS_VAL_NORMAL);
2273     if (!font->weight)
2274         font->weight = new CSSPrimitiveValue(CSS_VAL_NORMAL);
2275
2276     // now a font size _must_ come
2277     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
2278     if (value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER)
2279         font->size = new CSSPrimitiveValue(value->id);
2280     else if (validUnit(value, FLength|FPercent, strict))
2281         font->size = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
2282     value = valueList->next();
2283     if (!font->size || !value)
2284         goto invalid;
2285
2286     if (value->unit == Value::Operator && value->iValue == '/') {
2287         // line-height
2288         value = valueList->next();
2289         if (!value)
2290             goto invalid;
2291         if (value->id == CSS_VAL_NORMAL) {
2292             // default value, nothing to do
2293         } else if (validUnit(value, FNumber|FLength|FPercent, strict))
2294             font->lineHeight = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
2295         else
2296             goto invalid;
2297         value = valueList->next();
2298         if (!value)
2299             goto invalid;
2300     }
2301     
2302     if (!font->lineHeight)
2303         font->lineHeight = new CSSPrimitiveValue(CSS_VAL_NORMAL);
2304
2305     // font family must come now
2306     font->family = parseFontFamily();
2307
2308     if (valueList->current() || !font->family)
2309         goto invalid;
2310
2311     addProperty(CSS_PROP_FONT, font, important);
2312     return true;
2313
2314  invalid:
2315     delete font;
2316     return false;
2317 }
2318
2319 CSSValueList* CSSParser::parseFontFamily()
2320 {
2321     CSSValueList* list = new CSSValueList;
2322     Value* value = valueList->current();
2323     FontFamilyValue* currFamily = 0;
2324     while (value) {
2325         Value* nextValue = valueList->next();
2326         bool nextValBreaksFont = !nextValue ||
2327                                  (nextValue->unit == Value::Operator && nextValue->iValue == ',');
2328         bool nextValIsFontName = nextValue &&
2329             ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL__WEBKIT_BODY) ||
2330             (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
2331
2332         if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL__WEBKIT_BODY) {
2333             if (currFamily) {
2334                 currFamily->parsedFontName += ' ';
2335                 currFamily->parsedFontName += deprecatedString(value->string);
2336             }
2337             else if (nextValBreaksFont || !nextValIsFontName)
2338                 list->append(new CSSPrimitiveValue(value->id));
2339             else
2340                 list->append(currFamily = new FontFamilyValue(deprecatedString(value->string)));
2341         }
2342         else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
2343             // Strings never share in a family name.
2344             currFamily = 0;
2345             list->append(new FontFamilyValue(deprecatedString(value->string)));
2346         }
2347         else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
2348             if (currFamily) {
2349                 currFamily->parsedFontName += ' ';
2350                 currFamily->parsedFontName += deprecatedString(value->string);
2351             }
2352             else if (nextValBreaksFont || !nextValIsFontName)
2353                 list->append(new FontFamilyValue(deprecatedString(value->string)));
2354             else
2355                 list->append(currFamily = new FontFamilyValue(deprecatedString(value->string)));
2356         }
2357         else {
2358             break;
2359         }
2360         
2361         if (!nextValue)
2362             break;
2363
2364         if (nextValBreaksFont) {
2365             value = valueList->next();
2366             currFamily = 0;
2367         }
2368         else if (nextValIsFontName)
2369             value = nextValue;
2370         else
2371             break;
2372     }
2373     if (!list->length()) {
2374         delete list;
2375         list = 0;
2376     }
2377     return list;
2378 }
2379
2380 bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict)
2381 {
2382     if (!strict && Color::parseHexColor(name, rgb))
2383         return true;
2384
2385     // try a little harder
2386     Color tc;
2387     tc.setNamedColor(name.lower());
2388     if (tc.isValid()) {
2389         rgb = tc.rgb();
2390         return true;
2391     }
2392
2393     return false;
2394 }
2395
2396 bool CSSParser::parseColorParameters(Value* value, int* colorArray, bool parseAlpha)
2397 {
2398     ValueList* args = value->function->args;
2399     Value* v = args->current();
2400     // Get the first value
2401     if (!validUnit(v, FInteger | FPercent, true))
2402         return false;
2403     colorArray[0] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
2404     for (int i = 1; i < 3; i++) {
2405         v = args->next();
2406         if (v->unit != Value::Operator && v->iValue != ',')
2407             return false;
2408         v = args->next();
2409         if (!validUnit(v, FInteger | FPercent, true))
2410             return false;
2411         colorArray[i] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
2412     }
2413     if (parseAlpha) {
2414         v = args->next();
2415         if (v->unit != Value::Operator && v->iValue != ',')
2416             return false;
2417         v = args->next();
2418         if (!validUnit(v, FNumber, true))
2419             return false;
2420         colorArray[3] = static_cast<int>(max(0.0, min(1.0, v->fValue)) * 255);
2421     }
2422     return true;
2423 }
2424
2425 // CSS3 sepcification defines the format of a HSL color as
2426 // hsl(<number>, <percent>, <percent>)
2427 // and with alpha, the format is
2428 // hsla(<number>, <percent>, <percent>, <number>)
2429 // The first value, HUE, is in an angle with a value between 0 and 360
2430 bool CSSParser::parseHSLParameters(Value* value, double* colorArray, bool parseAlpha)
2431 {
2432     ValueList* args = value->function->args;
2433     Value* v = args->current();
2434     // Get the first value
2435     if (!validUnit(v, FInteger, true))
2436         return false;
2437     // normalize the Hue value and change it to be between 0 and 1.0
2438     colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
2439     for (int i = 1; i < 3; i++) {
2440         v = args->next();
2441         if (v->unit != Value::Operator && v->iValue != ',')
2442             return false;
2443         v = args->next();
2444         if (!validUnit(v, FPercent, true))
2445             return false;
2446         colorArray[i] = max(0.0, min(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0
2447     }
2448     if (parseAlpha) {
2449         v = args->next();
2450         if (v->unit != Value::Operator && v->iValue != ',')
2451             return false;
2452         v = args->next();
2453         if (!validUnit(v, FNumber, true))
2454             return false;
2455         colorArray[3] = max(0.0, min(1.0, v->fValue));
2456     }
2457     return true;
2458 }
2459
2460 CSSPrimitiveValue *CSSParser::parseColor(Value* value)
2461 {
2462     RGBA32 c = Color::transparent;
2463     if (!parseColorFromValue(value ? value : valueList->current(), c))
2464         return 0;
2465     return new CSSPrimitiveValue(c);
2466 }
2467
2468 bool CSSParser::parseColorFromValue(Value* value, RGBA32& c, bool svg)
2469 {
2470     if (!strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
2471         value->fValue >= 0. && value->fValue < 1000000.) {
2472         String str = String::format("%06d", (int)(value->fValue+.5));
2473         if (!CSSParser::parseColor(str, c, strict))
2474             return false;
2475     } else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
2476                 value->unit == CSSPrimitiveValue::CSS_IDENT ||
2477                 (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
2478         if (!CSSParser::parseColor(domString(value->string), c, strict && value->unit == CSSPrimitiveValue::CSS_IDENT))
2479             return false;
2480     } else if (value->unit == Value::Function &&
2481                 value->function->args != 0 &&
2482                 value->function->args->size() == 5 /* rgb + two commas */ &&
2483                 domString(value->function->name).lower() == "rgb(") {
2484         int colorValues[3];
2485         if (!parseColorParameters(value, colorValues, false))
2486             return false;
2487         c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
2488     } else if (!svg) {
2489         if (value->unit == Value::Function &&
2490                 value->function->args != 0 &&
2491                 value->function->args->size() == 7 /* rgba + three commas */ &&
2492                 domString(value->function->name).lower() == "rgba(") {
2493             int colorValues[4];
2494             if (!parseColorParameters(value, colorValues, true))
2495                 return false;
2496             c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
2497         } else if (value->unit == Value::Function &&
2498                     value->function->args != 0 &&
2499                     value->function->args->size() == 5 /* hsl + two commas */ &&
2500                     domString(value->function->name).lower() == "hsl(") {
2501             double colorValues[3];
2502             if (!parseHSLParameters(value, colorValues, false))
2503                 return false;
2504             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
2505         } else if (value->unit == Value::Function &&
2506                     value->function->args != 0 &&
2507                     value->function->args->size() == 7 /* hsla + three commas */ &&
2508                     domString(value->function->name).lower() == "hsla(") {
2509             double colorValues[4];
2510             if (!parseHSLParameters(value, colorValues, true))
2511                 return false;
2512             c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
2513         } else
2514             return false;
2515     } else
2516         return false;
2517
2518     return true;
2519 }
2520
2521 // This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
2522 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
2523 struct ShadowParseContext {
2524     ShadowParseContext()
2525     :values(0), x(0), y(0), blur(0), color(0),
2526      allowX(true), allowY(false), allowBlur(false), allowColor(true),
2527      allowBreak(true)
2528     {}
2529
2530     ~ShadowParseContext() {
2531         if (!allowBreak) {
2532             delete values;
2533             delete x;
2534             delete y;
2535             delete blur;
2536             delete color;
2537         }
2538     }
2539
2540     bool allowLength() { return allowX || allowY || allowBlur; }
2541
2542     bool failed() { return allowBreak = false; }
2543     
2544     void commitValue() {
2545         // Handle the ,, case gracefully by doing nothing.
2546         if (x || y || blur || color) {
2547             if (!values)
2548                 values = new CSSValueList();
2549             
2550             // Construct the current shadow value and add it to the list.
2551             values->append(new ShadowValue(x, y, blur, color));
2552         }
2553         
2554         // Now reset for the next shadow value.
2555         x = y = blur = color = 0;
2556         allowX = allowColor = allowBreak = true;
2557         allowY = allowBlur = false;  
2558     }
2559
2560     void commitLength(Value* v) {
2561         CSSPrimitiveValue* val = new CSSPrimitiveValue(v->fValue,
2562                                                                (CSSPrimitiveValue::UnitTypes)v->unit);
2563         if (allowX) {
2564             x = val;
2565             allowX = false; allowY = true; allowColor = false; allowBreak = false;
2566         }
2567         else if (allowY) {
2568             y = val;
2569             allowY = false; allowBlur = true; allowColor = true; allowBreak = true;
2570         }
2571         else if (allowBlur) {
2572             blur = val;
2573             allowBlur = false;
2574         }
2575     }
2576
2577     void commitColor(CSSPrimitiveValue* val) {
2578         color = val;
2579         allowColor = false;
2580         if (allowX)
2581             allowBreak = false;
2582         else
2583             allowBlur = false;
2584     }
2585     
2586     CSSValueList* values;
2587     CSSPrimitiveValue* x;
2588     CSSPrimitiveValue* y;
2589     CSSPrimitiveValue* blur;
2590     CSSPrimitiveValue* color;
2591
2592     bool allowX;
2593     bool allowY;
2594     bool allowBlur;
2595     bool allowColor;
2596     bool allowBreak;
2597 };
2598
2599 bool CSSParser::parseShadow(int propId, bool important)
2600 {
2601     ShadowParseContext context;
2602     Value* val;
2603     while ((val = valueList->current())) {
2604         // Check for a comma break first.
2605         if (val->unit == Value::Operator) {
2606             if (val->iValue != ',' || !context.allowBreak)
2607                 // Other operators aren't legal or we aren't done with the current shadow
2608                 // value.  Treat as invalid.
2609                 return context.failed();
2610             
2611             // The value is good.  Commit it.
2612             context.commitValue();
2613         }
2614         // Check to see if we're a length.
2615         else if (validUnit(val, FLength, true)) {
2616             // We required a length and didn't get one. Invalid.
2617             if (!context.allowLength())
2618                 return context.failed();
2619
2620             // A length is allowed here.  Construct the value and add it.
2621             context.commitLength(val);
2622         }
2623         else {
2624             // The only other type of value that's ok is a color value.
2625             CSSPrimitiveValue* parsedColor = 0;
2626             bool isColor = (val->id >= CSS_VAL_AQUA && val->id <= CSS_VAL_WINDOWTEXT || val->id == CSS_VAL_MENU ||
2627                             (val->id >= CSS_VAL__WEBKIT_FOCUS_RING_COLOR && val->id <= CSS_VAL__WEBKIT_TEXT && !strict));
2628             if (isColor) {
2629                 if (!context.allowColor)
2630                     return context.failed();
2631                 parsedColor = new CSSPrimitiveValue(val->id);
2632             }
2633
2634             if (!parsedColor)
2635                 // It's not built-in. Try to parse it as a color.
2636                 parsedColor = parseColor(val);
2637
2638             if (!parsedColor || !context.allowColor)
2639                 return context.failed(); // This value is not a color or length and is invalid or
2640                                          // it is a color, but a color isn't allowed at this point.
2641             
2642             context.commitColor(parsedColor);
2643         }
2644         
2645         valueList->next();
2646     }
2647
2648     if (context.allowBreak) {
2649         context.commitValue();
2650         if (context.values->length()) {
2651             addProperty(propId, context.values, important);
2652             valueList->next();
2653             return true;
2654         }
2655     }
2656     
2657     return context.failed();
2658 }
2659
2660 struct BorderImageParseContext
2661 {
2662     BorderImageParseContext()
2663     :m_allowBreak(false), m_allowNumber(false), m_allowSlash(false), m_allowWidth(false),
2664      m_allowRule(false), m_image(0), m_top(0), m_right(0), m_bottom(0), m_left(0), m_borderTop(0), m_borderRight(0), m_borderBottom(0),
2665      m_borderLeft(0), m_horizontalRule(0), m_verticalRule(0)
2666     {}
2667     
2668     ~BorderImageParseContext() {
2669         if (!m_allowBreak) {
2670             delete m_image;
2671             delete m_top; delete m_right; delete m_bottom; delete m_left;
2672             delete m_borderTop; delete m_borderRight; delete m_borderBottom; delete m_borderLeft;
2673         }
2674     }
2675
2676     bool failed() { return m_allowBreak = false; }
2677     bool allowBreak() const { return m_allowBreak; }
2678     bool allowNumber() const { return m_allowNumber; }
2679     bool allowSlash() const { return m_allowSlash; }
2680     bool allowWidth() const { return m_allowWidth; }
2681     bool allowRule() const { return m_allowRule; }
2682
2683     void commitImage(CSSImageValue* image) { m_image = image; m_allowNumber = true; }
2684     void commitNumber(Value* v) {
2685         CSSPrimitiveValue* val = new CSSPrimitiveValue(v->fValue,
2686                                                                (CSSPrimitiveValue::UnitTypes)v->unit);
2687         if (!m_top)
2688             m_top = val;
2689         else if (!m_right)
2690             m_right = val;
2691         else if (!m_bottom)
2692             m_bottom = val;
2693         else {
2694             assert(!m_left);
2695             m_left = val;
2696         }
2697         
2698         m_allowBreak = m_allowSlash = m_allowRule = true;
2699         m_allowNumber = !m_left;
2700     }
2701     void commitSlash() { m_allowBreak = m_allowSlash = m_allowNumber = false; m_allowWidth = true; }
2702     void commitWidth(Value* val) {
2703         if (!m_borderTop)
2704             m_borderTop = val;
2705         else if (!m_borderRight)
2706             m_borderRight = val;
2707         else if (!m_borderBottom)
2708             m_borderBottom = val;
2709         else {
2710             assert(!m_borderLeft);
2711             m_borderLeft = val;
2712         }
2713
2714         m_allowBreak = m_allowRule = true;
2715         m_allowWidth = !m_borderLeft;
2716     }
2717     void commitRule(int keyword) {
2718         if (!m_horizontalRule)
2719             m_horizontalRule = keyword;
2720         else if (!m_verticalRule)
2721             m_verticalRule = keyword;
2722         m_allowRule = !m_verticalRule;
2723     }
2724     void commitBorderImage(CSSParser* p, int propId, bool important) {
2725         // We need to clone and repeat values for any omissions.
2726         if (!m_right) {
2727             m_right = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2728             m_bottom = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2729             m_left = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2730         }
2731         if (!m_bottom) {
2732             m_bottom = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2733             m_left = new CSSPrimitiveValue(m_right->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
2734         }
2735         if (!m_left)
2736              m_left = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2737              
2738         // Now build a rect value to hold all four of our primitive values.
2739         RectImpl* rect = new RectImpl;
2740         rect->setTop(m_top); rect->setRight(m_right); rect->setBottom(m_bottom); rect->setLeft(m_left);
2741
2742         // Fill in STRETCH as the default if it wasn't specified.
2743         if (!m_horizontalRule)
2744             m_horizontalRule = CSS_VAL_STRETCH;
2745         if (!m_verticalRule)
2746             m_verticalRule = CSS_VAL_STRETCH;
2747
2748         // Make our new border image value now and add it as the result.
2749         CSSBorderImageValue* borderImage = new CSSBorderImageValue(m_image, rect, m_horizontalRule, m_verticalRule);
2750         p->addProperty(propId, borderImage, important);
2751             
2752         // 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
2753         // list and then make our parsing machinery do the parsing.
2754         if (m_borderTop) {
2755             ValueList newList;
2756             newList.addValue(*m_borderTop);
2757             if (m_borderRight)
2758                 newList.addValue(*m_borderRight);
2759             if (m_borderBottom)
2760                 newList.addValue(*m_borderBottom);
2761             if (m_borderLeft)
2762                 newList.addValue(*m_borderLeft);
2763             p->valueList = &newList;
2764             p->parseValue(CSS_PROP_BORDER_WIDTH, important);
2765             p->valueList = 0;
2766         }
2767     }
2768     
2769     bool m_allowBreak;
2770     bool m_allowNumber;
2771     bool m_allowSlash;
2772     bool m_allowWidth;
2773     bool m_allowRule;
2774     
2775     CSSImageValue* m_image;
2776     
2777     CSSPrimitiveValue* m_top;
2778     CSSPrimitiveValue* m_right;
2779     CSSPrimitiveValue* m_bottom;
2780     CSSPrimitiveValue* m_left;
2781     
2782     Value* m_borderTop;
2783     Value* m_borderRight;
2784     Value* m_borderBottom;
2785     Value* m_borderLeft;
2786     
2787     int m_horizontalRule;
2788     int m_verticalRule;
2789 };
2790
2791 bool CSSParser::parseBorderImage(int propId, bool important)
2792 {
2793     // Look for an image initially.  If the first value is not a URI, then we're done.
2794     BorderImageParseContext context;
2795     Value* val = valueList->current();
2796     if (val->unit != CSSPrimitiveValue::CSS_URI)
2797         return context.failed();
2798         
2799     String uri = parseURL(domString(val->string));
2800     if (uri.isEmpty())
2801         return context.failed();
2802     
2803     context.commitImage(new CSSImageValue(String(KURL(styleElement->baseURL().deprecatedString(), uri.deprecatedString()).url()),
2804                                                              styleElement));
2805     while ((val = valueList->next())) {
2806         if (context.allowNumber() && validUnit(val, FInteger|FNonNeg|FPercent, true)) {
2807             context.commitNumber(val);
2808         } else if (context.allowSlash() && val->unit == Value::Operator && val->iValue == '/') {
2809             context.commitSlash();
2810         } else if (context.allowWidth() &&
2811             (val->id == CSS_VAL_THIN || val->id == CSS_VAL_MEDIUM || val->id == CSS_VAL_THICK || validUnit(val, FLength, strict))) {
2812             context.commitWidth(val);
2813         } else if (context.allowRule() &&
2814             (val->id == CSS_VAL_STRETCH || val->id == CSS_VAL_ROUND || val->id == CSS_VAL_REPEAT)) {
2815             context.commitRule(val->id);
2816         } else {
2817             // Something invalid was encountered.
2818             return context.failed();
2819         }
2820     }
2821     
2822     if (context.allowBreak()) {
2823         // Need to fully commit as a single value.
2824         context.commitBorderImage(this, propId, important);
2825         return true;
2826     }
2827     
2828     return context.failed();
2829 }
2830
2831 bool CSSParser::parseCounter(int propId, int defaultValue, bool important)
2832 {
2833     enum { ID, VAL } state = ID;
2834
2835     RefPtr<CSSValueList> list = new CSSValueList;
2836     RefPtr<CSSPrimitiveValue> counterName;
2837     
2838     while (true) {
2839         Value* val = valueList->current();
2840         switch (state) {
2841             case ID:
2842                 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
2843                     counterName = new CSSPrimitiveValue(domString(val->string), CSSPrimitiveValue::CSS_STRING);
2844                     state = VAL;
2845                     valueList->next();
2846                     continue;
2847                 }
2848                 break;
2849             case VAL: {
2850                 int i = defaultValue;
2851                 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
2852                     i = (int)val->fValue;
2853                     valueList->next();
2854                 }
2855
2856                 list->append(new CSSPrimitiveValue(new Pair(counterName.release(),
2857                     new CSSPrimitiveValue(i, CSSPrimitiveValue::CSS_NUMBER))));
2858                 state = ID;
2859                 continue;
2860             }
2861         }
2862         break;
2863     }
2864     
2865     if (list->length() > 0) {
2866         addProperty(propId, list.release(), important);
2867         return true;
2868     }
2869
2870     return false;
2871 }
2872
2873 #ifdef CSS_DEBUG
2874
2875 static inline int yyerror(const char *str)
2876 {
2877     kdDebug(6080) << "CSS parse error " << str << endl;
2878     return 1;
2879 }
2880
2881 #else
2882
2883 static inline int yyerror(const char*) { return 1; }
2884
2885 #endif
2886
2887 #define END_TOKEN 0
2888
2889 #include "CSSGrammar.h"
2890
2891 int CSSParser::lex(void* yylvalWithoutType)
2892 {
2893     YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
2894     int token = lex();
2895     int length;
2896     UChar* t = text(&length);
2897
2898     switch(token) {
2899     case WHITESPACE:
2900     case SGML_CD:
2901     case INCLUDES:
2902     case DASHMATCH:
2903         break;
2904
2905     case URI:
2906     case STRING:
2907     case IDENT:
2908     case HASH:
2909     case DIMEN:
2910     case UNICODERANGE:
2911     case FUNCTION:
2912     case NOTFUNCTION:
2913         yylval->string.characters = t;
2914         yylval->string.length = length;
2915         break;
2916
2917     case IMPORT_SYM:
2918     case PAGE_SYM:
2919     case MEDIA_SYM:
2920     case FONT_FACE_SYM:
2921     case CHARSET_SYM:
2922     case NAMESPACE_SYM:
2923
2924     case IMPORTANT_SYM:
2925         break;
2926
2927     case QEMS:
2928         length--;
2929     case GRADS:
2930         length--;
2931     case DEGS:
2932     case RADS:
2933     case KHERZ:
2934         length--;
2935     case MSECS:
2936     case HERZ:
2937     case EMS:
2938     case EXS:
2939     case PXS:
2940     case CMS:
2941     case MMS:
2942     case INS:
2943     case PTS:
2944     case PCS:
2945         length--;
2946     case SECS:
2947     case PERCENTAGE:
2948         length--;
2949     case FLOAT:
2950     case INTEGER:
2951         yylval->val = DeprecatedString((DeprecatedChar *)t, length).toDouble();
2952         break;
2953
2954     default:
2955         break;
2956     }
2957
2958     return token;
2959 }
2960
2961 static inline int toHex(char c)
2962 {
2963     if ('0' <= c && c <= '9')
2964         return c - '0';
2965     if ('a' <= c && c <= 'f')
2966         return c - 'a' + 10;
2967     if ('A' <= c && c<= 'F')
2968         return c - 'A' + 10;
2969     return 0;
2970 }
2971
2972 UChar* CSSParser::text(int *length)
2973 {
2974     UChar* start = yytext;
2975     int l = yyleng;
2976     switch(yyTok) {
2977     case STRING:
2978         l--;
2979         /* nobreak */
2980     case HASH:
2981         start++;
2982         l--;
2983         break;
2984     case URI:
2985         // "url("{w}{string}{w}")"
2986         // "url("{w}{url}{w}")"
2987
2988         // strip "url(" and ")"
2989         start += 4;
2990         l -= 5;
2991         // strip {w}
2992         while (l &&
2993                 (*start == ' ' || *start == '\t' || *start == '\r' ||
2994                  *start == '\n' || *start == '\f')) {
2995             start++; l--;
2996         }
2997         if (*start == '"' || *start == '\'') {
2998             start++; l--;
2999         }
3000         while (l &&
3001                 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
3002                  start[l-1] == '\n' || start[l-1] == '\f')) {
3003             l--;
3004         }
3005         if (l && (start[l-1] == '\"' || start[l-1] == '\''))
3006              l--;
3007
3008     default:
3009         break;
3010     }
3011
3012     // process escapes
3013     UChar* out = start;
3014     UChar* escape = 0;
3015
3016     for (int i = 0; i < l; i++) {
3017         UChar* current = start + i;
3018         if (escape == current - 1) {
3019             if ((*current >= '0' && *current <= '9') ||
3020                  (*current >= 'a' && *current <= 'f') ||
3021                  (*current >= 'A' && *current <= 'F'))
3022                 continue;
3023             if (yyTok == STRING &&
3024                  (*current == '\n' || *current == '\r' || *current == '\f')) {
3025                 // ### handle \r\n case
3026                 if (*current != '\r')
3027                     escape = 0;
3028                 continue;
3029             }
3030             // in all other cases copy the char to output
3031             // ###
3032             *out++ = *current;
3033             escape = 0;
3034             continue;
3035         }
3036         if (escape == current - 2 && yyTok == STRING &&
3037              *(current-1) == '\r' && *current == '\n') {
3038             escape = 0;
3039             continue;
3040         }
3041         if (escape > current - 7 &&
3042              ((*current >= '0' && *current <= '9') ||
3043                (*current >= 'a' && *current <= 'f') ||
3044                (*current >= 'A' && *current <= 'F')))
3045             continue;
3046         if (escape) {
3047             // add escaped char
3048             unsigned uc = 0;
3049             escape++;
3050             while (escape < current) {
3051                 uc *= 16;
3052                 uc += toHex(*escape);
3053                 escape++;
3054             }
3055             // can't handle chars outside ucs2
3056             if (uc > 0xffff)
3057                 uc = 0xfffd;
3058             *out++ = uc;
3059             escape = 0;
3060             if (*current == ' ' ||
3061                  *current == '\t' ||
3062                  *current == '\r' ||
3063                  *current == '\n' ||
3064                  *current == '\f')
3065                 continue;
3066         }
3067         if (!escape && *current == '\\') {
3068             escape = current;
3069             continue;
3070         }
3071         *out++ = *current;
3072     }
3073     if (escape) {
3074         // add escaped char
3075         unsigned uc = 0;
3076         escape++;
3077         while (escape < start+l) {
3078             uc *= 16;
3079             uc += toHex(*escape);
3080             escape++;
3081         }
3082         // can't handle chars outside ucs2
3083         if (uc > 0xffff)
3084             uc = 0xfffd;
3085         *out++ = uc;
3086     }
3087     
3088     *length = out - start;
3089     return start;
3090 }
3091
3092 CSSSelector* CSSParser::createFloatingSelector()
3093 {
3094     CSSSelector* selector = new CSSSelector;
3095     m_floatingSelectors.add(selector);
3096     return selector;
3097 }
3098
3099 CSSSelector* CSSParser::sinkFloatingSelector(CSSSelector* selector)
3100 {
3101     if (selector) {
3102         ASSERT(m_floatingSelectors.contains(selector));
3103         m_floatingSelectors.remove(selector);
3104     }
3105     return selector;
3106 }
3107
3108 ValueList* CSSParser::createFloatingValueList()
3109 {
3110     ValueList* list = new ValueList;
3111     m_floatingValueLists.add(list);
3112     return list;
3113 }
3114
3115 ValueList* CSSParser::sinkFloatingValueList(ValueList* list)
3116 {
3117     if (list) {
3118         ASSERT(m_floatingValueLists.contains(list));
3119         m_floatingValueLists.remove(list);
3120     }
3121     return list;
3122 }
3123
3124 Function* CSSParser::createFloatingFunction()
3125 {
3126     Function* function = new Function;
3127     m_floatingFunctions.add(function);
3128     return function;
3129 }
3130
3131 Function* CSSParser::sinkFloatingFunction(Function* function)
3132 {
3133     if (function) {
3134         ASSERT(m_floatingFunctions.contains(function));
3135         m_floatingFunctions.remove(function);
3136     }
3137     return function;
3138 }
3139
3140 Value& CSSParser::sinkFloatingValue(Value& value)
3141 {
3142     if (value.unit == Value::Function) {
3143         ASSERT(m_floatingFunctions.contains(value.function));
3144         m_floatingFunctions.remove(value.function);
3145     }
3146     return value;
3147 }
3148
3149 MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, ValueList* values)
3150 {
3151     delete m_floatingMediaQueryExp;
3152     m_floatingMediaQueryExp = new MediaQueryExp(mediaFeature, values);
3153     return m_floatingMediaQueryExp;
3154 }
3155
3156 MediaQueryExp* CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* e)
3157 {
3158     ASSERT(e == m_floatingMediaQueryExp);
3159     m_floatingMediaQueryExp = 0;
3160     return e;
3161 }
3162
3163 Vector<MediaQueryExp*>* CSSParser::createFloatingMediaQueryExpList()
3164 {
3165     if (m_floatingMediaQueryExpList) {
3166         deleteAllValues(*m_floatingMediaQueryExpList);
3167         delete m_floatingMediaQueryExpList;
3168     }
3169     m_floatingMediaQueryExpList = new Vector<MediaQueryExp*>;
3170     return m_floatingMediaQueryExpList;
3171 }
3172
3173 Vector<MediaQueryExp*>* CSSParser::sinkFloatingMediaQueryExpList(Vector<MediaQueryExp*>* l)
3174 {
3175     ASSERT(l == m_floatingMediaQueryExpList);
3176     m_floatingMediaQueryExpList = 0;
3177     return l;
3178 }
3179
3180 MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor r, const String& mediaType, Vector<MediaQueryExp*>* exprs)
3181 {
3182     delete m_floatingMediaQuery;
3183     m_floatingMediaQuery = new MediaQuery(r, mediaType, exprs);
3184     return m_floatingMediaQuery;
3185 }
3186
3187 MediaQuery* CSSParser::sinkFloatingMediaQuery(MediaQuery* mq)
3188 {
3189     ASSERT(mq == m_floatingMediaQuery);
3190     m_floatingMediaQuery = 0;
3191     return mq;
3192 }
3193
3194 MediaList* CSSParser::createMediaList()
3195 {
3196     MediaList* list = new MediaList;
3197     m_parsedStyleObjects.append(list);
3198     return list;
3199 }
3200
3201 CSSRule* CSSParser::createCharsetRule(const ParseString& charset)
3202 {
3203     if (!styleElement)
3204         return 0;
3205     if (!styleElement->isCSSStyleSheet())
3206         return 0;
3207     CSSCharsetRule* rule = new CSSCharsetRule(styleElement, domString(charset));
3208     m_parsedStyleObjects.append(rule);
3209     return rule;
3210 }
3211
3212 CSSRule* CSSParser::createImportRule(const ParseString& URL, MediaList* media)
3213 {
3214     if (!media)
3215         return 0;
3216     if (!styleElement)
3217         return 0;
3218     if (!styleElement->isCSSStyleSheet())
3219         return 0;
3220     CSSImportRule* rule = new CSSImportRule(styleElement, domString(URL), media);
3221     m_parsedStyleObjects.append(rule);
3222     return rule;
3223 }
3224
3225 CSSRule* CSSParser::createMediaRule(MediaList* media, CSSRuleList* rules)
3226 {
3227     if (!media)
3228         return 0;
3229     if (!rules)
3230         return 0;
3231     if (!styleElement)
3232         return 0;
3233     if (!styleElement->isCSSStyleSheet())
3234         return 0;
3235     CSSMediaRule* rule = new CSSMediaRule(styleElement, media, rules);
3236     m_parsedStyleObjects.append(rule);
3237     return rule;
3238 }
3239
3240 CSSRuleList* CSSParser::createRuleList()
3241 {
3242     CSSRuleList* list = new CSSRuleList;
3243     m_parsedRuleLists.append(list);
3244     return list;
3245 }
3246
3247 CSSRule* CSSParser::createStyleRule(CSSSelector* selector)
3248 {
3249     CSSStyleRule* rule = 0;
3250     if (selector) {
3251         rule = new CSSStyleRule(styleElement);
3252         m_parsedStyleObjects.append(rule);
3253         rule->setSelector(sinkFloatingSelector(selector));
3254         rule->setDeclaration(new CSSMutableStyleDeclaration(rule, parsedProperties, numParsedProperties));
3255     }
3256     clearProperties();
3257     return rule;
3258 }
3259
3260 DeprecatedString deprecatedString(const ParseString& ps)
3261 {
3262     return DeprecatedString(reinterpret_cast<const DeprecatedChar*>(ps.characters), ps.length);
3263 }
3264
3265 #define YY_DECL int CSSParser::lex()
3266 #define yyconst const
3267 typedef int yy_state_type;
3268 typedef unsigned YY_CHAR;
3269 // this line makes sure we treat all Unicode chars correctly.
3270 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
3271 #define YY_DO_BEFORE_ACTION \
3272         yytext = yy_bp; \
3273         yyleng = (int) (yy_cp - yy_bp); \
3274         yy_hold_char = *yy_cp; \
3275         *yy_cp = 0; \
3276         yy_c_buf_p = yy_cp;
3277 #define YY_BREAK break;
3278 #define ECHO
3279 #define YY_RULE_SETUP
3280 #define INITIAL 0
3281 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
3282 #define yyterminate() yyTok = END_TOKEN; return yyTok
3283 #define YY_FATAL_ERROR(a)
3284 // The line below is needed to build the tokenizer with conditon stack.
3285 // The macro is used in the tokenizer grammar with lines containing
3286 // BEGIN(mediaqueries) and BEGIN(initial). yy_start acts as index to
3287 // tokenizer transition table, and 'mediaqueries' and 'initial' are
3288 // offset multipliers that specify which transitions are active
3289 // in the tokenizer during in each condition (tokenizer state)
3290 #define BEGIN yy_start = 1 + 2 *
3291
3292 #include "tokenizer.cpp"
3293
3294 }