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