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