More dashboard region work.
[WebKit-https.git] / WebCore / khtml / 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  *
6  * $Id$
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 //#define CSS_DEBUG
25 // #define TOKEN_DEBUG
26 #define YYDEBUG 0
27
28 #include <kdebug.h>
29 #include <kurl.h>
30
31 #include "cssparser.h"
32 #include "css_valueimpl.h"
33 #include "css_ruleimpl.h"
34 #include "css_stylesheetimpl.h"
35 #include "cssproperties.h"
36 #include "cssvalues.h"
37 #include "misc/helper.h"
38 #include "xml/dom_docimpl.h"
39 #include "csshelper.h"
40 using namespace DOM;
41
42 #include <stdlib.h>
43
44 #if APPLE_CHANGES
45 void qFatal ( const char * msg ) {}
46 #endif
47
48 ValueList::ValueList()
49 {
50     values = (Value *) malloc( 16 * sizeof ( Value ) );
51     numValues = 0;
52     currentValue = 0;
53     maxValues = 16;
54 }
55
56 ValueList::~ValueList()
57 {
58     for ( int i = 0; i < numValues; i++ ) {
59 #ifdef CSS_DEBUG
60         kdDebug( 6080 ) << "       value: (unit=" << values[i].unit <<")"<< endl;
61 #endif
62         if ( values[i].unit == Value::Function )
63             delete values[i].function;
64     }
65     free( values );
66 }
67
68 void ValueList::addValue( const Value &val )
69 {
70     if ( numValues >= maxValues ) {
71         maxValues += 16;
72         values = (Value *) realloc( values, maxValues*sizeof( Value ) );
73     }
74     values[numValues++] = val;
75 }
76
77
78 using namespace DOM;
79
80 #if YYDEBUG > 0
81 extern int cssyydebug;
82 #endif
83
84 extern int cssyyparse( void * parser );
85
86 CSSParser *CSSParser::currentParser = 0;
87
88 CSSParser::CSSParser( bool strictParsing )
89 {
90 #ifdef CSS_DEBUG
91     kdDebug( 6080 ) << "CSSParser::CSSParser this=" << this << endl;
92 #endif
93     strict = strictParsing;
94
95     parsedProperties = (CSSProperty **) malloc( 32 * sizeof( CSSProperty * ) );
96     numParsedProperties = 0;
97     maxParsedProperties = 32;
98
99     data = 0;
100     valueList = 0;
101     rule = 0;
102     id = 0;
103     important = false;
104     inParseShortHand = false;
105     
106     defaultNamespace = anyNamespace;
107     
108     yy_start = 1;
109
110 #if YYDEBUG > 0
111     cssyydebug = 1;
112 #endif
113
114 }
115
116 CSSParser::~CSSParser()
117 {
118     if ( numParsedProperties )
119         clearProperties();
120     free( parsedProperties );
121
122     delete valueList;
123
124 #ifdef CSS_DEBUG
125     kdDebug( 6080 ) << "CSSParser::~CSSParser this=" << this << endl;
126 #endif
127
128     free( data );
129
130 }
131
132 void ParseString::lower()
133 {
134     for (int i = 0; i < length; i++)
135         string[i] = QChar(string[i]).lower().unicode();
136 }
137
138 void CSSParser::setupParser(const char *prefix, const DOMString &string, const char *suffix)
139 {
140     int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
141     
142     data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
143     for ( unsigned int i = 0; i < strlen(prefix); i++ )
144         data[i] = prefix[i];
145     
146     memcpy( data + strlen( prefix ), string.unicode(), string.length()*sizeof( unsigned short) );
147
148     unsigned int start = strlen( prefix ) + string.length();
149     unsigned int end = start + strlen(suffix);
150     for ( unsigned int i = start; i < end; i++ )
151         data[i] = suffix[i-start];
152
153     data[length-1] = 0;
154     data[length-2] = 0;
155
156     yy_hold_char = 0;
157     yyleng = 0;
158     yytext = yy_c_buf_p = data;
159     yy_hold_char = *yy_c_buf_p;
160 }
161
162 void CSSParser::parseSheet( CSSStyleSheetImpl *sheet, const DOMString &string )
163 {
164     styleElement = sheet;
165     defaultNamespace = anyNamespace; // Reset the default namespace.
166     
167     setupParser ("", string, "");
168
169 #ifdef CSS_DEBUG
170     kdDebug( 6080 ) << ">>>>>>> start parsing style sheet" << endl;
171 #endif
172     CSSParser *old = currentParser;
173     currentParser = this;
174     cssyyparse( this );
175     currentParser = old;
176 #ifdef CSS_DEBUG
177     kdDebug( 6080 ) << "<<<<<<< done parsing style sheet" << endl;
178 #endif
179
180     delete rule;
181     rule = 0;
182 }
183
184 CSSRuleImpl *CSSParser::parseRule( DOM::CSSStyleSheetImpl *sheet, const DOM::DOMString &string )
185 {
186     styleElement = sheet;
187     
188     setupParser ("@-khtml-rule{", string, "} ");
189
190     CSSParser *old = currentParser;
191     currentParser = this;
192     cssyyparse( this );
193     currentParser = old;
194
195     CSSRuleImpl *result = rule;
196     rule = 0;
197     
198     return result;
199 }
200
201 bool CSSParser::parseValue( DOM::CSSStyleDeclarationImpl *declaration, int _id, const DOM::DOMString &string,
202                             bool _important)
203 {
204 #ifdef CSS_DEBUG
205     kdDebug( 6080 ) << "CSSParser::parseValue: id=" << _id << " important=" << _important
206                     << " value='" << string.string() << "'" << endl;
207 #endif
208
209     styleElement = declaration->stylesheet();
210
211     setupParser ("@-khtml-value{", string, "} ");
212
213     id = _id;
214     important = _important;
215     
216     CSSParser *old = currentParser;
217     currentParser = this;
218     cssyyparse( this );
219     currentParser = old;
220     
221     delete rule;
222     rule = 0;
223
224     bool ok = false;
225     if ( numParsedProperties ) {
226         ok = true;
227         for ( int i = 0; i < numParsedProperties; i++ ) {
228             declaration->removeProperty(parsedProperties[i]->m_id);
229             declaration->values()->append( parsedProperties[i] );
230         }
231         numParsedProperties = 0;
232     }
233
234     return ok;
235 }
236
237 QRgb CSSParser::parseColor( const DOM::DOMString &string )
238 {
239     QRgb color = 0;
240     DOM::CSSStyleDeclarationImpl *dummyStyleDeclaration = new DOM::CSSStyleDeclarationImpl(0);
241     
242     dummyStyleDeclaration->ref();
243
244     DOM::CSSParser parser(true);
245
246     // First try creating a color specified by name or the "#" syntax.
247     if (!parser.parseColor(string.string(), color)) {
248     
249         // Now try to create a color from the rgb() or rgba() syntax.
250         bool ok = parser.parseColor(dummyStyleDeclaration, string);
251         if ( ok ) {
252             CSSValueImpl *value = parser.parsedProperties[0]->value();
253             if (value->cssValueType() == DOM::CSSValue::CSS_PRIMITIVE_VALUE) {
254                 DOM::CSSPrimitiveValueImpl *primitiveValue = static_cast<DOM::CSSPrimitiveValueImpl *>(value);
255                 color = primitiveValue->getRGBColorValue();
256             }
257         }
258     
259     }
260     
261     dummyStyleDeclaration->deref();
262     
263     return color;
264 }
265
266 bool CSSParser::parseColor( DOM::CSSStyleDeclarationImpl *declaration, const DOM::DOMString &string )
267 {
268     styleElement = declaration->stylesheet();
269
270     setupParser ( "@-khtml-decls{color:", string, "} ");
271
272     CSSParser *old = currentParser;
273     currentParser = this;
274     cssyyparse( this );
275     currentParser = old;
276
277     delete rule;
278     rule = 0;
279
280     bool ok = false;
281     if ( numParsedProperties && parsedProperties[0]->m_id == CSS_PROP_COLOR) {
282         ok = true;
283     }
284
285     return ok;
286 }
287
288 bool CSSParser::parseDeclaration( DOM::CSSStyleDeclarationImpl *declaration, const DOM::DOMString &string )
289 {
290 #ifdef CSS_DEBUG
291     kdDebug( 6080 ) << "CSSParser::parseDeclaration:value='" << string.string() << "'" << endl;
292 #endif
293
294     styleElement = declaration->stylesheet();
295
296     setupParser ( "@-khtml-decls{", string, "} ");
297
298     CSSParser *old = currentParser;
299     currentParser = this;
300     cssyyparse( this );
301     currentParser = old;
302
303     delete rule;
304     rule = 0;
305
306     bool ok = false;
307     if ( numParsedProperties ) {
308         ok = true;
309         for ( int i = 0; i < numParsedProperties; i++ ) {
310             declaration->removeProperty(parsedProperties[i]->m_id);
311             declaration->values()->append( parsedProperties[i] );
312         }
313         numParsedProperties = 0;
314     }
315
316     return ok;
317 }
318
319
320 void CSSParser::addProperty( int propId, CSSValueImpl *value, bool important )
321 {
322     CSSProperty *prop = new CSSProperty;
323     prop->m_id = propId;
324     prop->setValue( value );
325     prop->m_bImportant = important;
326
327     if ( numParsedProperties >= maxParsedProperties ) {
328         maxParsedProperties += 32;
329         parsedProperties = (CSSProperty **) realloc( parsedProperties,
330                                                     maxParsedProperties*sizeof( CSSProperty * ) );
331     }
332     parsedProperties[numParsedProperties++] = prop;
333 }
334
335 CSSStyleDeclarationImpl *CSSParser::createStyleDeclaration( CSSStyleRuleImpl *rule )
336 {
337     QPtrList<CSSProperty> *propList = new QPtrList<CSSProperty>;
338     propList->setAutoDelete( true );
339     for ( int i = 0; i < numParsedProperties; i++ )
340         propList->append( parsedProperties[i] );
341
342     numParsedProperties = 0;
343     return new CSSStyleDeclarationImpl(rule, propList);
344 }
345
346 void CSSParser::clearProperties()
347 {
348     for ( int i = 0; i < numParsedProperties; i++ )
349         delete parsedProperties[i];
350     numParsedProperties = 0;
351 }
352
353 DOM::DocumentImpl *CSSParser::document() const
354 {
355     StyleBaseImpl *root = styleElement;
356     DocumentImpl *doc = 0;
357     while (root->parent())
358         root = root->parent();
359     if (root->isCSSStyleSheet())
360         doc = static_cast<CSSStyleSheetImpl*>(root)->doc();
361     return doc;
362 }
363
364
365 // defines units allowed for a certain property, used in parseUnit
366 enum Units
367 {
368     FUnknown   = 0x0000,
369     FInteger   = 0x0001,
370     FNumber    = 0x0002,  // Real Numbers
371     FPercent   = 0x0004,
372     FLength    = 0x0008,
373     FAngle     = 0x0010,
374     FTime      = 0x0020,
375     FFrequency = 0x0040,
376     FRelative  = 0x0100,
377     FNonNeg    = 0x0200
378 };
379
380 static bool validUnit( Value *value, int unitflags, bool strict )
381 {
382     if ( unitflags & FNonNeg && value->fValue < 0 )
383         return false;
384
385     bool b = false;
386     switch( value->unit ) {
387     case CSSPrimitiveValue::CSS_NUMBER:
388         b = (unitflags & FNumber);
389         if ( !b && ( (unitflags & FLength) && (value->fValue == 0 || !strict ) ) ) {
390             value->unit = CSSPrimitiveValue::CSS_PX;
391             b = true;
392         }
393         if ( !b && ( unitflags & FInteger ) &&
394              (value->fValue - (int)value->fValue) < 0.001 )
395             b = true;
396         break;
397     case CSSPrimitiveValue::CSS_PERCENTAGE:
398         b = (unitflags & FPercent);
399         break;
400     case Value::Q_EMS:
401     case CSSPrimitiveValue::CSS_EMS:
402     case CSSPrimitiveValue::CSS_EXS:
403     case CSSPrimitiveValue::CSS_PX:
404     case CSSPrimitiveValue::CSS_CM:
405     case CSSPrimitiveValue::CSS_MM:
406     case CSSPrimitiveValue::CSS_IN:
407     case CSSPrimitiveValue::CSS_PT:
408     case CSSPrimitiveValue::CSS_PC:
409         b = (unitflags & FLength);
410         break;
411     case CSSPrimitiveValue::CSS_MS:
412     case CSSPrimitiveValue::CSS_S:
413         b = (unitflags & FTime);
414         break;
415     case CSSPrimitiveValue::CSS_DEG:
416     case CSSPrimitiveValue::CSS_RAD:
417     case CSSPrimitiveValue::CSS_GRAD:
418     case CSSPrimitiveValue::CSS_HZ:
419     case CSSPrimitiveValue::CSS_KHZ:
420     case CSSPrimitiveValue::CSS_DIMENSION:
421     default:
422         break;
423     }
424     return b;
425 }
426
427 bool CSSParser::parseValue( int propId, bool important )
428 {
429     if ( !valueList ) return false;
430
431     Value *value = valueList->current();
432
433     if ( !value )
434         return false;
435
436     int id = 0;
437     id = value->id;
438
439     if (id == CSS_VAL_INHERIT) {
440         addProperty(propId, new CSSInheritedValueImpl(), important);
441         return true;
442     }
443     else if (id == CSS_VAL_INITIAL) {
444         addProperty(propId, new CSSInitialValueImpl(), important);
445         return true;
446     }
447
448     bool valid_primitive = false;
449     CSSValueImpl *parsedValue = 0;
450
451     switch(propId) {
452         /* The comment to the left defines all valid value of this properties as defined
453          * in CSS 2, Appendix F. Property index
454          */
455
456         /* All the CSS properties are not supported by the renderer at the moment.
457          * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
458          * (see parseAuralValues). As we don't support them at all this seems reasonable.
459          */
460
461     case CSS_PROP_SIZE:                 // <length>{1,2} | auto | portrait | landscape | inherit
462     case CSS_PROP_QUOTES:               // [<string> <string>]+ | none | inherit
463 //     case CSS_PROP_PAGE:                 // <identifier> | auto // ### CHECK
464         // ### To be done
465         if (id)
466             valid_primitive = true;
467         break;
468     case CSS_PROP_UNICODE_BIDI:         // normal | embed | bidi-override | inherit
469         if ( id == CSS_VAL_NORMAL ||
470              id == CSS_VAL_EMBED ||
471              id == CSS_VAL_BIDI_OVERRIDE )
472             valid_primitive = true;
473         break;
474
475     case CSS_PROP_POSITION:             // static | relative | absolute | fixed | inherit
476         if ( id == CSS_VAL_STATIC ||
477              id == CSS_VAL_RELATIVE ||
478              id == CSS_VAL_ABSOLUTE ||
479              id == CSS_VAL_FIXED )
480             valid_primitive = true;
481         break;
482
483     case CSS_PROP_PAGE_BREAK_AFTER:     // auto | always | avoid | left | right | inherit
484     case CSS_PROP_PAGE_BREAK_BEFORE:    // auto | always | avoid | left | right | inherit
485         if ( id == CSS_VAL_AUTO ||
486              id == CSS_VAL_ALWAYS ||
487              id == CSS_VAL_AVOID ||
488              id == CSS_VAL_LEFT ||
489              id == CSS_VAL_RIGHT )
490             valid_primitive = true;
491         break;
492
493     case CSS_PROP_PAGE_BREAK_INSIDE:    // avoid | auto | inherit
494         if ( id == CSS_VAL_AUTO ||
495              id == CSS_VAL_AVOID )
496             valid_primitive = true;
497         break;
498
499     case CSS_PROP_EMPTY_CELLS:          // show | hide | inherit
500         if ( id == CSS_VAL_SHOW ||
501              id == CSS_VAL_HIDE )
502             valid_primitive = true;
503         break;
504
505     case CSS_PROP_CONTENT:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
506         // close-quote | no-open-quote | no-close-quote ]+ | inherit
507         return parseContent( propId, important );
508         break;
509
510     case CSS_PROP_WHITE_SPACE:          // normal | pre | nowrap | inherit
511         if ( id == CSS_VAL_NORMAL ||
512              id == CSS_VAL_PRE ||
513              id == CSS_VAL_NOWRAP )
514             valid_primitive = true;
515         break;
516
517     case CSS_PROP_CLIP:                 // <shape> | auto | inherit
518         if ( id == CSS_VAL_AUTO )
519             valid_primitive = true;
520         else if ( value->unit == Value::Function )
521             return parseShape( propId, important );
522         break;
523
524 #if APPLE_CHANGES
525     case CSS_PROP__APPLE_DASHBOARD_REGION:                 // <dashboard-region-circle> | <dashboard-region-rectangle> 
526         if ( value->unit == Value::Function )
527             return parseDashboardRegions( propId, important );
528         break;
529 #endif
530
531     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
532      * correctly and allows optimization in khtml::applyRule(..)
533      */
534     case CSS_PROP_CAPTION_SIDE:         // top | bottom | left | right | inherit
535         if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
536             id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM)
537             valid_primitive = true;
538         break;
539
540     case CSS_PROP_BORDER_COLLAPSE:      // collapse | separate | inherit
541         if ( id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE )
542             valid_primitive = true;
543         break;
544
545     case CSS_PROP_VISIBILITY:           // visible | hidden | collapse | inherit
546         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE)
547             valid_primitive = true;
548         break;
549
550     case CSS_PROP_OVERFLOW:             // visible | hidden | scroll | auto | marquee | overlay | inherit
551         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ||
552             id == CSS_VAL_MARQUEE || id == CSS_VAL_OVERLAY)
553             valid_primitive = true;
554         break;
555
556     case CSS_PROP_LIST_STYLE_POSITION:  // inside | outside | inherit
557         if ( id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE )
558             valid_primitive = true;
559         break;
560
561     case CSS_PROP_LIST_STYLE_TYPE:
562         // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
563         // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
564         // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
565         // katakana | hiragana-iroha | katakana-iroha | none | inherit
566         if ((id >= CSS_VAL_DISC && id <= CSS_VAL_KATAKANA_IROHA) || id == CSS_VAL_NONE)
567             valid_primitive = true;
568         break;
569
570     case CSS_PROP_DISPLAY:
571         // inline | block | list-item | run-in | inline-block | table |
572         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
573         // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
574         if ((id >= CSS_VAL_INLINE && id <= CSS_VAL__KHTML_INLINE_BOX) || id == CSS_VAL_NONE)
575             valid_primitive = true;
576         break;
577
578     case CSS_PROP_DIRECTION:            // ltr | rtl | inherit
579         if ( id == CSS_VAL_LTR || id == CSS_VAL_RTL )
580             valid_primitive = true;
581         break;
582
583     case CSS_PROP_TEXT_TRANSFORM:       // capitalize | uppercase | lowercase | none | inherit
584         if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE)
585             valid_primitive = true;
586         break;
587
588     case CSS_PROP_FLOAT:                // left | right | none | inherit + center for buggy CSS
589         if ( id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
590              id == CSS_VAL_NONE || id == CSS_VAL_CENTER)
591             valid_primitive = true;
592         break;
593
594     case CSS_PROP_CLEAR:                // none | left | right | both | inherit
595         if ( id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
596              id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH)
597             valid_primitive = true;
598         break;
599
600     case CSS_PROP_TEXT_ALIGN:
601         // left | right | center | justify | khtml_left | khtml_right | khtml_center | <string> | inherit
602         if ( ( id >= CSS_VAL__KHTML_AUTO && id <= CSS_VAL__KHTML_CENTER ) ||
603              value->unit == CSSPrimitiveValue::CSS_STRING )
604             valid_primitive = true;
605         break;
606
607     case CSS_PROP_OUTLINE_STYLE:        // <border-style> | auto | inherit
608         if (id == CSS_VAL_AUTO) {
609             valid_primitive = true;
610             break;
611         } // Fall through!
612     case CSS_PROP_BORDER_TOP_STYLE:     //// <border-style> | inherit
613     case CSS_PROP_BORDER_RIGHT_STYLE:   //   Defined as:    none | hidden | dotted | dashed |
614     case CSS_PROP_BORDER_BOTTOM_STYLE:  //   solid | double | groove | ridge | inset | outset
615     case CSS_PROP_BORDER_LEFT_STYLE:    ////
616         if (id >= CSS_VAL_NONE && id <= CSS_VAL_DOUBLE)
617             valid_primitive = true;
618         break;
619
620     case CSS_PROP_FONT_WEIGHT:  // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 |
621         // 500 | 600 | 700 | 800 | 900 | inherit
622         if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) {
623             // Allready correct id
624             valid_primitive = true;
625         } else if ( validUnit( value, FInteger|FNonNeg, false ) ) {
626             int weight = (int)value->fValue;
627             if ( (weight % 100) )
628                 break;
629             weight /= 100;
630             if ( weight >= 1 && weight <= 9 ) {
631                 id = CSS_VAL_100 + weight - 1;
632                 valid_primitive = true;
633             }
634         }
635         break;
636
637     case CSS_PROP_BACKGROUND_REPEAT:    // repeat | repeat-x | repeat-y | no-repeat | inherit
638         if ( id >= CSS_VAL_REPEAT && id <= CSS_VAL_NO_REPEAT )
639             valid_primitive = true;
640         break;
641
642     case CSS_PROP_BACKGROUND_ATTACHMENT: // scroll | fixed
643         if ( id == CSS_VAL_SCROLL || id == CSS_VAL_FIXED )
644             valid_primitive = true;
645         break;
646
647     case CSS_PROP_BACKGROUND_POSITION:
648         if ( id ) {
649             /* Problem: center is ambigous
650              * In case of 'center' center defines X and Y coords
651              * In case of 'center top', center defines the Y coord
652              * in case of 'center left', center defines the X coord
653              */
654             int pos[2];
655             pos[0] = -1;
656             pos[1] = -1;
657             bool invalid = false;
658             switch( id ) {
659             case CSS_VAL_TOP:
660                 pos[1] = 0;
661                 break;
662             case CSS_VAL_BOTTOM:
663                 pos[1] = 100;
664                 break;
665             case CSS_VAL_LEFT:
666                 pos[0] = 0;
667                 break;
668             case CSS_VAL_RIGHT:
669                 pos[0] = 100;
670                 break;
671             case  CSS_VAL_CENTER:
672                 break;
673             default:
674                 invalid = true;
675             }
676             if ( invalid )
677                 break;
678             value = valueList->next();
679             if ( value ) {
680                 id = value->id;
681                 switch( id ) {
682                 case CSS_VAL_TOP:
683                     if ( pos[1] != -1 )
684                         invalid = true;
685                     pos[1] = 0;
686                     break;
687                 case CSS_VAL_BOTTOM:
688                     if ( pos[1] != -1 )
689                         invalid = true;
690                     pos[1] = 100;
691                     break;
692                 case CSS_VAL_LEFT:
693                     if ( pos[0] != -1 )
694                         invalid = true;
695                     pos[0] = 0;
696                     break;
697                 case CSS_VAL_RIGHT:
698                     if ( pos[0] != -1 )
699                         invalid = true;
700                     pos[0] = 100;
701                     break;
702                 case  CSS_VAL_CENTER:
703                     break;
704                 default:
705                     invalid = true;
706                 }
707                 if ( !invalid )
708                     value = valueList->next();
709             }
710             if ( pos[0] == -1 )
711                 pos[0] = 50;
712             if ( pos[1] == -1 )
713                 pos[1] = 50;
714             addProperty( CSS_PROP_BACKGROUND_POSITION_X,
715                          new CSSPrimitiveValueImpl( pos[0], CSSPrimitiveValue::CSS_PERCENTAGE ),
716                          important );
717             addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
718                          new CSSPrimitiveValueImpl( pos[1], CSSPrimitiveValue::CSS_PERCENTAGE ),
719                          important );
720         } else {
721             bool ok = parseValue( CSS_PROP_BACKGROUND_POSITION_X, important );
722             if ( !ok )
723                 break;
724             value = valueList->current();
725             if ( value )
726                 ok = parseValue( CSS_PROP_BACKGROUND_POSITION_Y, important );
727             if ( !ok )
728                 addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
729                              new CSSPrimitiveValueImpl( 50, CSSPrimitiveValue::CSS_PERCENTAGE ),
730                              important );
731         }
732         return true;
733
734     case CSS_PROP_BACKGROUND_POSITION_X:
735     case CSS_PROP_BACKGROUND_POSITION_Y:
736         valid_primitive = validUnit( value, FPercent|FLength, strict );
737         break;
738
739     case CSS_PROP_BORDER_SPACING: {
740         const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING,
741                                     CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
742         int num = valueList->numValues;
743         if (num == 1) {
744             if (!parseValue(properties[0], important)) return false;
745             CSSValueImpl* value = parsedProperties[numParsedProperties-1]->value();
746             addProperty(properties[1], value, important);
747             return true;
748         }
749         else if (num == 2) {
750             if (!parseValue(properties[0], important)) return false;
751             if (!parseValue(properties[1], important)) return false;
752             return true;
753         }
754         return false;
755     }
756     case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING:
757     case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING:
758         valid_primitive = validUnit(value, FLength|FNonNeg, strict);
759         break;
760     case CSS_PROP_SCROLLBAR_FACE_COLOR:         // IE5.5
761     case CSS_PROP_SCROLLBAR_SHADOW_COLOR:       // IE5.5
762     case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:    // IE5.5
763     case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:      // IE5.5
764     case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:   // IE5.5
765     case CSS_PROP_SCROLLBAR_TRACK_COLOR:        // IE5.5
766     case CSS_PROP_SCROLLBAR_ARROW_COLOR:        // IE5.5
767         if ( strict )
768             break;
769         /* nobreak */
770     case CSS_PROP_OUTLINE_COLOR:        // <color> | invert | inherit
771         // outline has "invert" as additional keyword.
772         if ( propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT ) {
773             valid_primitive = true;
774             break;
775         }
776         /* nobreak */
777     case CSS_PROP_BACKGROUND_COLOR:     // <color> | transparent | inherit
778     case CSS_PROP_BORDER_TOP_COLOR:     // <color> | transparent | inherit
779     case CSS_PROP_BORDER_RIGHT_COLOR:   // <color> | transparent | inherit
780     case CSS_PROP_BORDER_BOTTOM_COLOR:  // <color> | transparent | inherit
781     case CSS_PROP_BORDER_LEFT_COLOR:    // <color> | transparent | inherit
782     case CSS_PROP_COLOR:                // <color> | inherit
783     case CSS_PROP_TEXT_LINE_THROUGH_COLOR: // CSS3 text decoration colors
784     case CSS_PROP_TEXT_UNDERLINE_COLOR:
785     case CSS_PROP_TEXT_OVERLINE_COLOR:
786         if (id == CSS_VAL__KHTML_TEXT)
787             valid_primitive = true; // Always allow this, even when strict parsing is on,
788                                     // since we use this in our UA sheets.
789         else if ( id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT || id == CSS_VAL_MENU ||
790              (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict) ) {
791             valid_primitive = true;
792         } else {
793             parsedValue = parseColor();
794             if ( parsedValue )
795                 valueList->next();
796         }
797         break;
798
799     case CSS_PROP_CURSOR:
800         //  [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
801         // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | text |
802         // wait | help ] ] | inherit
803     // MSIE 5 compatibility :/
804         if ( !strict && id == CSS_VAL_HAND ) {
805             id = CSS_VAL_POINTER;
806             valid_primitive = true;
807         } else if ( id >= CSS_VAL_AUTO && id <= CSS_VAL_HELP )
808             valid_primitive = true;
809         break;
810
811     case CSS_PROP_BACKGROUND_IMAGE:     // <uri> | none | inherit
812     case CSS_PROP_LIST_STYLE_IMAGE:     // <uri> | none | inherit
813
814         if ( id == CSS_VAL_NONE ) {
815             parsedValue = new CSSImageValueImpl();
816             valueList->next();
817 #ifdef CSS_DEBUG
818             kdDebug( 6080 ) << "empty image " << endl;
819 #endif
820         } else if ( value->unit == CSSPrimitiveValue::CSS_URI ) {
821             // ### allow string in non strict mode?
822             DOMString uri = khtml::parseURL( domString( value->string ) );
823             if ( !uri.isEmpty() ) {
824                 parsedValue = new CSSImageValueImpl(
825                     DOMString(KURL( styleElement->baseURL().string(), uri.string()).url()),
826                     styleElement );
827                 valueList->next();
828 #ifdef CSS_DEBUG
829                 kdDebug( 6080 ) << "image, url=" << uri.string() << " base=" << styleElement->baseURL().string() << endl;
830 #endif
831             }
832         }
833         break;
834
835     case CSS_PROP_OUTLINE_WIDTH:        // <border-width> | inherit
836     case CSS_PROP_BORDER_TOP_WIDTH:     //// <border-width> | inherit
837     case CSS_PROP_BORDER_RIGHT_WIDTH:   //   Which is defined as
838     case CSS_PROP_BORDER_BOTTOM_WIDTH:  //   thin | medium | thick | <length>
839     case CSS_PROP_BORDER_LEFT_WIDTH:    ////
840         if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
841             valid_primitive = true;
842         else
843             valid_primitive = ( validUnit( value, FLength, strict ) );
844         break;
845
846     case CSS_PROP_LETTER_SPACING:       // normal | <length> | inherit
847     case CSS_PROP_WORD_SPACING:         // normal | <length> | inherit
848         if ( id == CSS_VAL_NORMAL )
849             valid_primitive = true;
850         else
851             valid_primitive = validUnit( value, FLength, strict );
852         break;
853
854     case CSS_PROP_TEXT_INDENT:          // <length> | <percentage> | inherit
855     case CSS_PROP_PADDING_TOP:          //// <padding-width> | inherit
856     case CSS_PROP_PADDING_RIGHT:        //   Which is defined as
857     case CSS_PROP_PADDING_BOTTOM:       //   <length> | <percentage>
858     case CSS_PROP_PADDING_LEFT:         ////
859         valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict ) );
860         break;
861
862     case CSS_PROP_MAX_HEIGHT:           // <length> | <percentage> | none | inherit
863     case CSS_PROP_MAX_WIDTH:            // <length> | <percentage> | none | inherit
864         if (id == CSS_VAL_NONE || id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC) {
865             valid_primitive = true;
866             break;
867         }
868         /* nobreak */
869     case CSS_PROP_MIN_HEIGHT:           // <length> | <percentage> | inherit
870     case CSS_PROP_MIN_WIDTH:            // <length> | <percentage> | inherit
871         if (id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC)
872             valid_primitive = true;
873         else
874             valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict ) );
875         break;
876
877     case CSS_PROP_FONT_SIZE:
878         // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
879         if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER)
880             valid_primitive = true;
881         else
882             valid_primitive = ( validUnit( value, FLength|FPercent, strict ) );
883         break;
884
885     case CSS_PROP_FONT_STYLE:           // normal | italic | oblique | inherit
886         if ( id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE)
887             valid_primitive = true;
888         break;
889
890     case CSS_PROP_FONT_VARIANT:         // normal | small-caps | inherit
891         if ( id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS)
892             valid_primitive = true;
893         break;
894
895     case CSS_PROP_VERTICAL_ALIGN:
896         // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
897         // <percentage> | <length> | inherit
898
899         if ( id >= CSS_VAL_BASELINE && id <= CSS_VAL__KHTML_BASELINE_MIDDLE )
900             valid_primitive = true;
901         else
902             valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict ) );
903         break;
904
905     case CSS_PROP_HEIGHT:               // <length> | <percentage> | auto | inherit
906     case CSS_PROP_WIDTH:                // <length> | <percentage> | auto | inherit
907         if (id == CSS_VAL_AUTO || id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC)
908             valid_primitive = true;
909         else
910             // ### handle multilength case where we allow relative units
911             valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict ) );
912         break;
913
914     case CSS_PROP_BOTTOM:               // <length> | <percentage> | auto | inherit
915     case CSS_PROP_LEFT:                 // <length> | <percentage> | auto | inherit
916     case CSS_PROP_RIGHT:                // <length> | <percentage> | auto | inherit
917     case CSS_PROP_TOP:                  // <length> | <percentage> | auto | inherit
918     case CSS_PROP_MARGIN_TOP:           //// <margin-width> | inherit
919     case CSS_PROP_MARGIN_RIGHT:         //   Which is defined as
920     case CSS_PROP_MARGIN_BOTTOM:        //   <length> | <percentage> | auto | inherit
921     case CSS_PROP_MARGIN_LEFT:          ////
922         if ( id == CSS_VAL_AUTO )
923             valid_primitive = true;
924         else
925             valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict ) );
926         break;
927
928     case CSS_PROP_Z_INDEX:              // auto | <integer> | inherit
929         // qDebug("parsing z-index: id=%d, fValue=%f", id, value->fValue );
930         if ( id == CSS_VAL_AUTO ) {
931             valid_primitive = true;
932             break;
933         }
934         /* nobreak */
935     case CSS_PROP_ORPHANS:              // <integer> | inherit
936     case CSS_PROP_WIDOWS:               // <integer> | inherit
937         // ### not supported later on
938         valid_primitive = ( !id && validUnit( value, FInteger, false ) );
939         break;
940
941     case CSS_PROP_LINE_HEIGHT:          // normal | <number> | <length> | <percentage> | inherit
942         if ( id == CSS_VAL_NORMAL )
943             valid_primitive = true;
944         else
945             valid_primitive = ( !id && validUnit( value, FNumber|FLength|FPercent, strict ) );
946         break;
947 #if 0
948         // removed from CSS 2.1
949     case CSS_PROP_COUNTER_INCREMENT:    // [ <identifier> <integer>? ]+ | none | inherit
950     case CSS_PROP_COUNTER_RESET:        // [ <identifier> <integer>? ]+ | none | inherit
951         if ( id == CSS_VAL_NONE )
952             valid_primitive = true;
953         else {
954             CSSValueListImpl *list = new CSSValueListImpl;
955             int pos=0, pos2;
956             while( 1 )
957             {
958                 pos2 = value.find(',', pos);
959                 QString face = value.mid(pos, pos2-pos);
960                 face = face.stripWhiteSpace();
961                 if(face.length() == 0) break;
962                 // ### single quoted is missing...
963                 if(face[0] == '\"') face.remove(0, 1);
964                 if(face[face.length()-1] == '\"') face = face.left(face.length()-1);
965                 //kdDebug( 6080 ) << "found face '" << face << "'" << endl;
966                 list->append(new CSSPrimitiveValueImpl(DOMString(face), CSSPrimitiveValue::CSS_STRING));
967                 pos = pos2 + 1;
968                 if(pos2 == -1) break;
969             }
970             //kdDebug( 6080 ) << "got " << list->length() << " faces" << endl;
971             if(list->length()) {
972                 parsedValue = list;
973                 valueList->next();
974             } else
975                 delete list;
976             break;
977         }
978 #endif
979     case CSS_PROP_FONT_FAMILY:
980         // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
981     {
982         parsedValue = parseFontFamily();
983         break;
984     }
985
986     case CSS_PROP_TEXT_DECORATION:
987         // none | [ underline || overline || line-through || blink ] | inherit
988         if (id == CSS_VAL_NONE) {
989             valid_primitive = true;
990         } else {
991             CSSValueListImpl *list = new CSSValueListImpl;
992             bool is_valid = true;
993             while( is_valid && value ) {
994                 switch ( value->id ) {
995                 case CSS_VAL_BLINK:
996                     break;
997                 case CSS_VAL_UNDERLINE:
998                 case CSS_VAL_OVERLINE:
999                 case CSS_VAL_LINE_THROUGH:
1000                     list->append( new CSSPrimitiveValueImpl( value->id ) );
1001                     break;
1002                 default:
1003                     is_valid = false;
1004                 }
1005                 value = valueList->next();
1006             }
1007             //kdDebug( 6080 ) << "got " << list->length() << "d decorations" << endl;
1008             if(list->length() && is_valid) {
1009                 parsedValue = list;
1010                 valueList->next();
1011             } else {
1012                 delete list;
1013             }
1014         }
1015         break;
1016
1017     case CSS_PROP_TABLE_LAYOUT:         // auto | fixed | inherit
1018         if ( id == CSS_VAL_AUTO || id == CSS_VAL_FIXED )
1019             valid_primitive = true;
1020         break;
1021
1022     /* CSS3 properties */
1023     case CSS_PROP__KHTML_BINDING:
1024 #ifndef KHTML_NO_XBL
1025         if (id == CSS_VAL_NONE)
1026             valid_primitive = true;
1027         else {
1028             CSSValueListImpl* values = new CSSValueListImpl();
1029             Value* val;
1030             CSSValueImpl* parsedValue = 0;
1031             while ((val = valueList->current())) {
1032                 if (val->unit == CSSPrimitiveValue::CSS_URI) {
1033                     DOMString value = khtml::parseURL(domString(val->string));
1034                     parsedValue = new CSSPrimitiveValueImpl(
1035                                     DOMString(KURL(styleElement->baseURL().string(), value.string()).url()), 
1036                                     CSSPrimitiveValue::CSS_URI);
1037                 } 
1038                 
1039                 if (parsedValue)
1040                     values->append(parsedValue);
1041                 else
1042                     break;
1043                 valueList->next();
1044             }
1045             if ( values->length() ) {
1046                 addProperty( propId, values, important );
1047                 valueList->next();
1048                 return true;
1049             }
1050             delete values;
1051             return false;
1052         }
1053 #endif
1054         break;
1055     case CSS_PROP_OUTLINE_OFFSET:
1056         valid_primitive = validUnit(value, FLength, strict);
1057         break;
1058     case CSS_PROP_TEXT_SHADOW: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
1059         if (id == CSS_VAL_NONE)
1060             valid_primitive = true;
1061         else
1062             return parseShadow(propId, important);
1063         break;
1064     case CSS_PROP_OPACITY:
1065         valid_primitive = validUnit(value, FNumber, strict);
1066         break;
1067     case CSS_PROP__KHTML_BOX_ALIGN:
1068         if (id == CSS_VAL_STRETCH || id == CSS_VAL_START || id == CSS_VAL_END ||
1069             id == CSS_VAL_CENTER || id == CSS_VAL_BASELINE)
1070             valid_primitive = true;
1071         break;
1072     case CSS_PROP__KHTML_BOX_DIRECTION:
1073         if (id == CSS_VAL_NORMAL || id == CSS_VAL_REVERSE)
1074             valid_primitive = true;
1075         break;
1076     case CSS_PROP__KHTML_BOX_LINES:
1077         if (id == CSS_VAL_SINGLE || id == CSS_VAL_MULTIPLE)
1078             valid_primitive = true;
1079         break;
1080     case CSS_PROP__KHTML_BOX_ORIENT:
1081         if (id == CSS_VAL_HORIZONTAL || id == CSS_VAL_VERTICAL ||
1082             id == CSS_VAL_INLINE_AXIS || id == CSS_VAL_BLOCK_AXIS)
1083             valid_primitive = true;
1084         break;
1085     case CSS_PROP__KHTML_BOX_PACK:
1086         if (id == CSS_VAL_START || id == CSS_VAL_END ||
1087             id == CSS_VAL_CENTER || id == CSS_VAL_JUSTIFY)
1088             valid_primitive = true;
1089         break;
1090     case CSS_PROP__KHTML_BOX_FLEX:
1091         valid_primitive = validUnit(value, FNumber, strict);
1092         break;
1093     case CSS_PROP__KHTML_BOX_FLEX_GROUP:
1094     case CSS_PROP__KHTML_BOX_ORDINAL_GROUP:
1095         valid_primitive = validUnit(value, FInteger|FNonNeg, true);
1096         break;
1097     case CSS_PROP__KHTML_MARQUEE: {
1098         const int properties[5] = { CSS_PROP__KHTML_MARQUEE_DIRECTION, CSS_PROP__KHTML_MARQUEE_INCREMENT,
1099                                     CSS_PROP__KHTML_MARQUEE_REPETITION,
1100                                     CSS_PROP__KHTML_MARQUEE_STYLE, CSS_PROP__KHTML_MARQUEE_SPEED };
1101         return parseShortHand(properties, 5, important);
1102     }
1103     case CSS_PROP__KHTML_MARQUEE_DIRECTION:
1104         if (id == CSS_VAL_FORWARDS || id == CSS_VAL_BACKWARDS || id == CSS_VAL_AHEAD ||
1105             id == CSS_VAL_REVERSE || id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_DOWN ||
1106             id == CSS_VAL_UP || id == CSS_VAL_AUTO)
1107             valid_primitive = true;
1108         break;
1109     case CSS_PROP__KHTML_MARQUEE_INCREMENT:
1110         if (id == CSS_VAL_SMALL || id == CSS_VAL_LARGE || id == CSS_VAL_MEDIUM)
1111             valid_primitive = true;
1112         else
1113             valid_primitive = validUnit(value, FLength|FPercent, strict);
1114         break;
1115     case CSS_PROP__KHTML_MARQUEE_STYLE:
1116         if (id == CSS_VAL_NONE || id == CSS_VAL_SLIDE || id == CSS_VAL_SCROLL || id == CSS_VAL_ALTERNATE ||
1117             id == CSS_VAL_UNFURL)
1118             valid_primitive = true;
1119         break;
1120     case CSS_PROP__KHTML_MARQUEE_REPETITION:
1121         if (id == CSS_VAL_INFINITE)
1122             valid_primitive = true;
1123         else
1124             valid_primitive = validUnit(value, FInteger|FNonNeg, strict);
1125         break;
1126     case CSS_PROP__KHTML_MARQUEE_SPEED:
1127         if (id == CSS_VAL_NORMAL || id == CSS_VAL_SLOW || id == CSS_VAL_FAST)
1128             valid_primitive = true;
1129         else
1130             valid_primitive = validUnit(value, FTime|FInteger|FNonNeg, strict);
1131         break;
1132     case CSS_PROP__KHTML_USER_DRAG: // auto | none | element
1133         if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE || id == CSS_VAL_ELEMENT)
1134             valid_primitive = true;
1135         break;
1136     case CSS_PROP__KHTML_USER_MODIFY:   // read-only | read-write
1137         if (id == CSS_VAL_READ_ONLY || id == CSS_VAL_READ_WRITE)
1138             valid_primitive = true;
1139         break;
1140     case CSS_PROP__KHTML_USER_SELECT: // auto | none | text
1141         if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE || id == CSS_VAL_TEXT)
1142             valid_primitive = true;
1143         break;
1144     case CSS_PROP_TEXT_OVERFLOW: // clip | ellipsis
1145         if (id == CSS_VAL_CLIP || id == CSS_VAL_ELLIPSIS)
1146             valid_primitive = true;
1147         break;
1148     case CSS_PROP__KHTML_MARGIN_COLLAPSE: {
1149         const int properties[2] = { CSS_PROP__KHTML_MARGIN_TOP_COLLAPSE,
1150             CSS_PROP__KHTML_MARGIN_BOTTOM_COLLAPSE };
1151         int num = valueList->numValues;
1152         if (num == 1) {
1153             if (!parseValue(properties[0], important)) return false;
1154             CSSValueImpl* value = parsedProperties[numParsedProperties-1]->value();
1155             addProperty(properties[1], value, important);
1156             return true;
1157         }
1158         else if (num == 2) {
1159             if (!parseValue(properties[0], important)) return false;
1160             if (!parseValue(properties[1], important)) return false;
1161             return true;
1162         }
1163         return false;
1164     }
1165     case CSS_PROP__KHTML_MARGIN_TOP_COLLAPSE:
1166     case CSS_PROP__KHTML_MARGIN_BOTTOM_COLLAPSE:
1167         if (id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE || id == CSS_VAL_DISCARD)
1168             valid_primitive = true;
1169         break;
1170     case CSS_PROP_TEXT_LINE_THROUGH_MODE:
1171     case CSS_PROP_TEXT_OVERLINE_MODE:
1172     case CSS_PROP_TEXT_UNDERLINE_MODE:
1173         if (id == CSS_VAL_CONTINUOUS || id == CSS_VAL_SKIP_WHITE_SPACE)
1174             valid_primitive = true;
1175         break;
1176     case CSS_PROP_TEXT_LINE_THROUGH_STYLE:
1177     case CSS_PROP_TEXT_OVERLINE_STYLE:
1178     case CSS_PROP_TEXT_UNDERLINE_STYLE:
1179         if (id == CSS_VAL_NONE || id == CSS_VAL_SOLID || id == CSS_VAL_DOUBLE ||
1180             id == CSS_VAL_DASHED || id == CSS_VAL_DOT_DASH || id == CSS_VAL_DOT_DOT_DASH ||
1181             id == CSS_VAL_WAVE)
1182             valid_primitive = true;
1183         break;
1184     case CSS_PROP_TEXT_LINE_THROUGH_WIDTH:
1185     case CSS_PROP_TEXT_OVERLINE_WIDTH:
1186     case CSS_PROP_TEXT_UNDERLINE_WIDTH:
1187         if (id == CSS_VAL_AUTO || id == CSS_VAL_NORMAL || id == CSS_VAL_THIN ||
1188             id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
1189             valid_primitive = true;
1190         else
1191             valid_primitive = !id && validUnit(value, FNumber|FLength|FPercent, strict);
1192         break;
1193     
1194     // End of CSS3 properties
1195
1196 #if APPLE_CHANGES
1197     // Apple specific properties.  These will never be standardized and are purely to
1198     // support custom WebKit-based Apple applications.
1199     case CSS_PROP__APPLE_LINE_CLAMP:
1200         valid_primitive = (!id && validUnit(value, FPercent, false));
1201         break;
1202     case CSS_PROP__APPLE_TEXT_SIZE_ADJUST:
1203         if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE)
1204             valid_primitive = true;
1205         break;
1206 #endif
1207
1208         /* shorthand properties */
1209     case CSS_PROP_BACKGROUND:
1210         // ['background-color' || 'background-image' ||'background-repeat' ||
1211         // 'background-attachment' || 'background-position'] | inherit
1212     {
1213 #ifdef CSS_DEBUG_BCKGR
1214         kdDebug(6080) << "CSS_PROP_BACKGROUND" << endl;
1215 #endif
1216         const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
1217                                     CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,
1218                                     CSS_PROP_BACKGROUND_COLOR };
1219         return parseShortHand(properties, 5, important);
1220     }
1221     case CSS_PROP_BORDER:
1222         // [ 'border-width' || 'border-style' || <color> ] | inherit
1223     {
1224         const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
1225                                     CSS_PROP_BORDER_COLOR };
1226         return parseShortHand(properties, 3, important);
1227     }
1228     case CSS_PROP_BORDER_TOP:
1229         // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1230     {
1231         const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
1232                                     CSS_PROP_BORDER_TOP_COLOR};
1233         return parseShortHand(properties, 3, important);
1234     }
1235     case CSS_PROP_BORDER_RIGHT:
1236         // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1237     {
1238         const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
1239                                     CSS_PROP_BORDER_RIGHT_COLOR };
1240         return parseShortHand(properties, 3, important);
1241     }
1242     case CSS_PROP_BORDER_BOTTOM:
1243         // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1244     {
1245         const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
1246                                     CSS_PROP_BORDER_BOTTOM_COLOR };
1247         return parseShortHand(properties, 3, important);
1248     }
1249     case CSS_PROP_BORDER_LEFT:
1250         // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1251     {
1252         const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
1253                                     CSS_PROP_BORDER_LEFT_COLOR };
1254         return parseShortHand(properties, 3, important);
1255     }
1256     case CSS_PROP_OUTLINE:
1257         // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1258     {
1259         const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
1260                                     CSS_PROP_OUTLINE_COLOR };
1261         return parseShortHand(properties, 3, important);
1262     }
1263     case CSS_PROP_BORDER_COLOR:
1264         // <color>{1,4} | transparent | inherit
1265     {
1266         const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
1267                                     CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
1268         return parse4Values(properties, important);
1269     }
1270     case CSS_PROP_BORDER_WIDTH:
1271         // <border-width>{1,4} | inherit
1272     {
1273         const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
1274                                     CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
1275         return parse4Values(properties, important);
1276     }
1277     case CSS_PROP_BORDER_STYLE:
1278         // <border-style>{1,4} | inherit
1279     {
1280         const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
1281                                     CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
1282         return parse4Values(properties, important);
1283     }
1284     case CSS_PROP_MARGIN:
1285         // <margin-width>{1,4} | inherit
1286     {
1287         const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
1288                                     CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
1289         return parse4Values(properties, important);
1290     }
1291     case CSS_PROP_PADDING:
1292         // <padding-width>{1,4} | inherit
1293     {
1294         const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
1295                                     CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
1296         return parse4Values(properties, important);
1297     }
1298     case CSS_PROP_FONT:
1299         // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1300         // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1301         if ( id >= CSS_VAL_CAPTION && id <= CSS_VAL_STATUS_BAR )
1302             valid_primitive = true;
1303         else
1304             return parseFont(important);
1305
1306     case CSS_PROP_LIST_STYLE:
1307     {
1308         const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
1309                                     CSS_PROP_LIST_STYLE_IMAGE };
1310         return parseShortHand(properties, 3, important);
1311     }
1312     default:
1313 // #ifdef CSS_DEBUG
1314 //      kdDebug( 6080 ) << "illegal or CSS2 Aural property: " << val << endl;
1315 // #endif
1316         break;
1317     }
1318
1319     if ( valid_primitive ) {
1320         if ( id != 0 ) {
1321             // qDebug(" new value: id=%d", id );
1322             parsedValue = new CSSPrimitiveValueImpl( id );
1323         } else if ( value->unit == CSSPrimitiveValue::CSS_STRING )
1324             parsedValue = new CSSPrimitiveValueImpl( domString( value->string ),
1325                                                      (CSSPrimitiveValue::UnitTypes) value->unit );
1326         else if ( value->unit >= CSSPrimitiveValue::CSS_NUMBER &&
1327                   value->unit <= CSSPrimitiveValue::CSS_KHZ ) {
1328             // qDebug(" new value: value=%.2f, unit=%d", value->fValue, value->unit );
1329             parsedValue = new CSSPrimitiveValueImpl( value->fValue,
1330                                                      (CSSPrimitiveValue::UnitTypes) value->unit );
1331         } else if ( value->unit >= Value::Q_EMS ) {
1332             // qDebug(" new quirks value: value=%.2f, unit=%d", value->fValue, value->unit );
1333             parsedValue = new CSSQuirkPrimitiveValueImpl( value->fValue, CSSPrimitiveValue::CSS_EMS );
1334         }
1335         valueList->next();
1336     }
1337     if ( parsedValue ) {
1338         addProperty( propId, parsedValue, important );
1339         return true;
1340     }
1341     return false;
1342 }
1343
1344 bool CSSParser::parseShortHand( const int *properties, int numProperties, bool important )
1345 {
1346     /* We try to match as many properties as possible
1347      * We setup an array of booleans to mark which property has been found,
1348      * and we try to search for properties until it makes no longer any sense
1349      */
1350     inParseShortHand = true;
1351
1352     bool found = false;
1353     bool fnd[6]; //Trust me ;)
1354     for( int i = 0; i < numProperties; i++ )
1355         fnd[i] = false;
1356
1357 #ifdef CSS_DEBUG
1358     kdDebug(6080) << "PSH: numProperties=" << numProperties << endl;
1359 #endif
1360
1361     while ( valueList->current() ) {
1362         found = false;
1363         // qDebug("outer loop" );
1364         for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
1365             if (!fnd[propIndex]) {
1366 #ifdef CSS_DEBUG
1367                 kdDebug(6080) << "LOOKING FOR: " << getPropertyName(properties[propIndex]).string() << endl;
1368 #endif
1369                 if ( parseValue( properties[propIndex], important ) ) {
1370                     fnd[propIndex] = found = true;
1371 #ifdef CSS_DEBUG
1372                     kdDebug(6080) << "FOUND: " << getPropertyName(properties[propIndex]).string() << endl;
1373 #endif
1374                 }
1375             }
1376         }
1377         // if we didn't find at least one match, this is an
1378         // invalid shorthand and we have to ignore it
1379         if (!found) {
1380 #ifdef CSS_DEBUG
1381             qDebug("didn't find anything" );
1382 #endif
1383             inParseShortHand = false;
1384             return false;
1385         }
1386     }
1387     
1388     // Fill in any remaining properties with the initial value.
1389     for (int i = 0; i < numProperties; ++i) {
1390         if (!fnd[i])
1391             addProperty(properties[i], new CSSInitialValueImpl(), important);
1392     }
1393     
1394     inParseShortHand = false;
1395 #ifdef CSS_DEBUG
1396     kdDebug( 6080 ) << "parsed shorthand" << endl;
1397 #endif
1398     return true;
1399 }
1400
1401 bool CSSParser::parse4Values( const int *properties,  bool important )
1402 {
1403     /* From the CSS 2 specs, 8.3
1404      * If there is only one value, it applies to all sides. If there are two values, the top and
1405      * bottom margins are set to the first value and the right and left margins are set to the second.
1406      * If there are three values, the top is set to the first value, the left and right are set to the
1407      * second, and the bottom is set to the third. If there are four values, they apply to the top,
1408      * right, bottom, and left, respectively.
1409      */
1410
1411     int num = inParseShortHand ? 1 : valueList->numValues;
1412     // qDebug("parse4Values: num=%d", num );
1413
1414     // the order is top, right, bottom, left
1415     switch( num ) {
1416     case 1: {
1417         if( !parseValue( properties[0], important ) ) return false;
1418         CSSValueImpl *value = parsedProperties[numParsedProperties-1]->value();
1419         addProperty( properties[1], value, important );
1420         addProperty( properties[2], value, important );
1421         addProperty( properties[3], value, important );
1422         return true;
1423     }
1424     case 2: {
1425
1426         if( !parseValue( properties[0], important ) ) return false;
1427         if( !parseValue( properties[1], important ) ) return false;
1428         CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
1429         addProperty( properties[2], value, important );
1430         value = parsedProperties[numParsedProperties-2]->value();
1431         addProperty( properties[3], value, important );
1432         return true;
1433     }
1434     case 3: {
1435         if( !parseValue( properties[0], important ) ) return false;
1436         if( !parseValue( properties[1], important ) ) return false;
1437         if( !parseValue( properties[2], important ) ) return false;
1438         CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
1439         addProperty( properties[3], value, important );
1440         return true;
1441     }
1442     case 4: {
1443         if( !parseValue( properties[0], important ) ) return false;
1444         if( !parseValue( properties[1], important ) ) return false;
1445         if( !parseValue( properties[2], important ) ) return false;
1446         if( !parseValue( properties[3], important ) ) return false;
1447         return true;
1448     }
1449     default:
1450         return false;
1451     }
1452 }
1453
1454 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1455 // in CSS 2.1 this got somewhat reduced:
1456 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1457 bool CSSParser::parseContent( int propId, bool important )
1458 {
1459     CSSValueListImpl* values = new CSSValueListImpl();
1460
1461     Value *val;
1462     CSSValueImpl *parsedValue = 0;
1463     while ( (val = valueList->current()) ) {
1464         if ( val->unit == CSSPrimitiveValue::CSS_URI ) {
1465             // url
1466             DOMString value = khtml::parseURL(domString(val->string));
1467             parsedValue = new CSSImageValueImpl(
1468                 DOMString(KURL( styleElement->baseURL().string(), value.string()).url() ), styleElement );
1469 #ifdef CSS_DEBUG
1470             kdDebug( 6080 ) << "content, url=" << value.string() << " base=" << styleElement->baseURL().string() << endl;
1471 #endif
1472         } else if ( val->unit == Value::Function ) {
1473             // attr( X )
1474             ValueList *args = val->function->args;
1475             QString fname = qString( val->function->name ).lower();
1476             if ( fname != "attr(" || !args )
1477                 return false;
1478             if ( args->numValues != 1)
1479                 return false;
1480             Value *a = args->current();
1481             parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR);
1482         } else if ( val->unit == CSSPrimitiveValue::CSS_IDENT ) {
1483             // open-quote
1484             // close-quote
1485             // no-open-quote
1486             // no-close-quote
1487         } else if ( val->unit == CSSPrimitiveValue::CSS_STRING ) {
1488             parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING);
1489         }
1490         if (parsedValue)
1491             values->append(parsedValue);
1492         else
1493             break;
1494         valueList->next();
1495     }
1496     if ( values->length() ) {
1497         addProperty( propId, values, important );
1498         valueList->next();
1499         return true;
1500     }
1501     delete values;
1502     return false;
1503 }
1504
1505 static Value *skipCommaInDashboardRegion (ValueList *args)
1506 {
1507     if ( args->numValues == 9 ) {
1508         Value *current = args->current();
1509         if (current->unit == Value::Operator && current->iValue == ',' )
1510             return args->next();
1511     }
1512     return args->current();
1513 }
1514
1515 #if APPLE_CHANGES
1516 bool CSSParser::parseDashboardRegions( int propId, bool important )
1517 {
1518     bool valid = true;
1519     
1520     DashboardRegionImpl *firstRegion = new DashboardRegionImpl(), *region = 0;
1521
1522     Value *value = valueList->current();
1523     while (value) {
1524         if (region == 0) {
1525             region = firstRegion;
1526         }
1527         else {
1528             DashboardRegionImpl *nextRegion = new DashboardRegionImpl();
1529             region->setNext (nextRegion);
1530             region = nextRegion;
1531         }
1532         
1533         if ( value->unit != Value::Function) {
1534             valid = false;
1535             break;
1536         }
1537             
1538         // Commas count as values, so allow:
1539         // dashbaord-region-rectangle( label, t, r, b, l ) or dashbaord-region-rectangle( label t r b l )
1540         // dashbaord-region-circle( label, t, r, b, l ) or dashbaord-region-circle( label t r b l )
1541         ValueList *args = value->function->args;
1542         int numArgs = value->function->args->numValues;
1543         if (numArgs != 5 && numArgs != 9) {
1544             valid = false;
1545             break;
1546         }
1547         
1548         QString fname = qString( value->function->name ).lower();
1549         if (fname == "dashboard-region-rectangle(" ) {
1550             region->m_isRectangle = true;
1551         }    
1552         else if (fname == "dashboard-region-circle(" ) {
1553             region->m_isCircle = true;
1554         }
1555         else {
1556             valid = false;
1557             break;
1558         }
1559             
1560         // First arg should be a label.
1561         Value *arg = args->current();
1562         if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
1563             valid = false;
1564             break;
1565         }
1566             
1567         region->m_label = qString(arg->string);
1568
1569         // Next four arguments must be offset numbers
1570         int i;
1571         for (i = 0; i < 4; i++) {
1572             arg = args->next();
1573             arg = skipCommaInDashboardRegion (args);
1574
1575             valid = arg->id == CSS_VAL_AUTO || validUnit( arg, FLength, strict );
1576             if ( !valid )
1577                 break;
1578                 
1579             CSSPrimitiveValueImpl *amount = arg->id == CSS_VAL_AUTO ?
1580                 new CSSPrimitiveValueImpl(CSS_VAL_AUTO) :
1581                 new CSSPrimitiveValueImpl(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit );
1582                 
1583             if ( i == 0 )
1584                 region->setTop( amount );
1585             else if ( i == 1 )
1586                 region->setRight( amount );
1587             else if ( i == 2 )
1588                 region->setBottom( amount );
1589             else
1590                 region->setLeft( amount );
1591         }
1592
1593         value = valueList->next();
1594     }
1595
1596     if (valid)
1597         addProperty( propId, new CSSPrimitiveValueImpl( firstRegion ), important );
1598     else
1599         delete firstRegion;
1600         
1601     return valid;
1602 }
1603 #endif
1604
1605 bool CSSParser::parseShape( int propId, bool important )
1606 {
1607     Value *value = valueList->current();
1608     ValueList *args = value->function->args;
1609     QString fname = qString( value->function->name ).lower();
1610     if ( fname != "rect(" || !args )
1611         return false;
1612
1613     // rect( t, r, b, l ) || rect( t r b l )
1614     if ( args->numValues != 4 && args->numValues != 7 )
1615         return false;
1616     RectImpl *rect = new RectImpl();
1617     bool valid = true;
1618     int i = 0;
1619     Value *a = args->current();
1620     while ( a ) {
1621         valid = a->id == CSS_VAL_AUTO || validUnit( a, FLength, strict );
1622         if ( !valid )
1623             break;
1624         CSSPrimitiveValueImpl *length = a->id == CSS_VAL_AUTO ?
1625             new CSSPrimitiveValueImpl(CSS_VAL_AUTO) :
1626             new CSSPrimitiveValueImpl( a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit );
1627         if ( i == 0 )
1628             rect->setTop( length );
1629         else if ( i == 1 )
1630             rect->setRight( length );
1631         else if ( i == 2 )
1632             rect->setBottom( length );
1633         else
1634             rect->setLeft( length );
1635         a = args->next();
1636         if ( a && args->numValues == 7 ) {
1637             if ( a->unit == Value::Operator && a->iValue == ',' ) {
1638                 a = args->next();
1639             } else {
1640                 valid = false;
1641                 break;
1642             }
1643         }
1644         i++;
1645     }
1646     if ( valid ) {
1647         addProperty( propId, new CSSPrimitiveValueImpl( rect ), important );
1648         valueList->next();
1649         return true;
1650     }
1651     delete rect;
1652     return false;
1653 }
1654
1655 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
1656 bool CSSParser::parseFont( bool important )
1657 {
1658 //     kdDebug(6080) << "parsing font property current=" << valueList->currentValue << endl;
1659     bool valid = true;
1660     Value *value = valueList->current();
1661     FontValueImpl *font = new FontValueImpl;
1662     // optional font-style, font-variant and font-weight
1663     while ( value ) {
1664 //      kdDebug( 6080 ) << "got value " << value->id << " / " << (value->unit == CSSPrimitiveValue::CSS_STRING ||
1665         //                                 value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
1666 //                      << endl;
1667         int id = value->id;
1668         if ( id ) {
1669             if ( id == CSS_VAL_NORMAL ) {
1670                 // do nothing, it's the inital value for all three
1671             }
1672             /*
1673               else if ( id == CSS_VAL_INHERIT ) {
1674               // set all non set ones to inherit
1675               // This is not that simple as the inherit could also apply to the following font-size.
1676               // very ahrd to tell without looking ahead.
1677               inherit = true;
1678                 } */
1679             else if ( id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE ) {
1680                 if ( font->style )
1681                     goto invalid;
1682                 font->style = new CSSPrimitiveValueImpl( id );
1683             } else if ( id == CSS_VAL_SMALL_CAPS ) {
1684                 if ( font->variant )
1685                     goto invalid;
1686                 font->variant = new CSSPrimitiveValueImpl( id );
1687             } else if ( id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER ) {
1688                 if ( font->weight )
1689                     goto invalid;
1690                 font->weight = new CSSPrimitiveValueImpl( id );
1691             } else {
1692                 valid = false;
1693             }
1694         } else if ( !font->weight && validUnit( value, FInteger|FNonNeg, true ) ) {
1695             int weight = (int)value->fValue;
1696             int val = 0;
1697             if ( weight == 100 )
1698                 val = CSS_VAL_100;
1699             else if ( weight == 200 )
1700                 val = CSS_VAL_200;
1701             else if ( weight == 300 )
1702                 val = CSS_VAL_300;
1703             else if ( weight == 400 )
1704                 val = CSS_VAL_400;
1705             else if ( weight == 500 )
1706                 val = CSS_VAL_500;
1707             else if ( weight == 600 )
1708                 val = CSS_VAL_600;
1709             else if ( weight == 700 )
1710                 val = CSS_VAL_700;
1711             else if ( weight == 800 )
1712                 val = CSS_VAL_800;
1713             else if ( weight == 900 )
1714                 val = CSS_VAL_900;
1715
1716             if ( val )
1717                 font->weight = new CSSPrimitiveValueImpl( val );
1718             else
1719                 valid = false;
1720         } else {
1721             valid = false;
1722         }
1723         if ( !valid )
1724             break;
1725         value = valueList->next();
1726     }
1727     if ( !value )
1728         goto invalid;
1729
1730     // set undefined values to default
1731     if ( !font->style )
1732         font->style = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
1733     if ( !font->variant )
1734         font->variant = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
1735     if ( !font->weight )
1736         font->weight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
1737
1738 //     kdDebug( 6080 ) << "  got style, variant and weight current=" << valueList->currentValue << endl;
1739
1740     // now a font size _must_ come
1741     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
1742     if ( value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER )
1743         font->size = new CSSPrimitiveValueImpl( value->id );
1744     else if ( validUnit( value, FLength|FPercent, strict ) ) {
1745         font->size = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
1746     }
1747     value = valueList->next();
1748     if ( !font->size || !value )
1749         goto invalid;
1750
1751     // kdDebug( 6080 ) << "  got size" << endl;
1752
1753     if ( value->unit == Value::Operator && value->iValue == '/' ) {
1754         // line-height
1755         value = valueList->next();
1756         if ( !value )
1757             goto invalid;
1758         if ( value->id == CSS_VAL_NORMAL ) {
1759             // default value, nothing to do
1760         } else if ( validUnit( value, FNumber|FLength|FPercent, strict ) ) {
1761             font->lineHeight = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
1762         } else {
1763             goto invalid;
1764         }
1765         value = valueList->next();
1766         if ( !value )
1767             goto invalid;
1768     }
1769     
1770     if (!font->lineHeight)
1771         font->lineHeight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
1772
1773 //     kdDebug( 6080 ) << "  got line height current=" << valueList->currentValue << endl;
1774     // font family must come now
1775     font->family = parseFontFamily();
1776
1777     if ( valueList->current() || !font->family )
1778         goto invalid;
1779 //     kdDebug( 6080 ) << "  got family, parsing ok!" << endl;
1780
1781     addProperty( CSS_PROP_FONT, font, important );
1782     return true;
1783
1784  invalid:
1785 //     kdDebug(6080) << "   -> invalid" << endl;
1786     delete font;
1787     return false;
1788 }
1789
1790 CSSValueListImpl *CSSParser::parseFontFamily()
1791 {
1792 //     kdDebug( 6080 ) << "CSSParser::parseFontFamily current=" << valueList->currentValue << endl;
1793     CSSValueListImpl *list = new CSSValueListImpl;
1794     Value *value = valueList->current();
1795     FontFamilyValueImpl* currFamily = 0;
1796     while ( value ) {
1797 //      kdDebug( 6080 ) << "got value " << value->id << " / "
1798 //                      << (value->unit == CSSPrimitiveValue::CSS_STRING ||
1799 //                          value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
1800 //                      << endl;
1801         Value* nextValue = valueList->next();
1802         bool nextValBreaksFont = !nextValue ||
1803                                  (nextValue->unit == Value::Operator && nextValue->iValue == ',');
1804         bool nextValIsFontName = nextValue &&
1805             ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL__KHTML_BODY) ||
1806             (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
1807
1808         if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL__KHTML_BODY) {
1809             if (currFamily) {
1810                 currFamily->parsedFontName += ' ';
1811                 currFamily->parsedFontName += qString(value->string);
1812             }
1813             else if (nextValBreaksFont || !nextValIsFontName)
1814                 list->append(new CSSPrimitiveValueImpl(value->id));
1815             else
1816                 list->append(currFamily = new FontFamilyValueImpl(qString(value->string)));
1817         }
1818         else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
1819             // Strings never share in a family name.
1820             currFamily = 0;
1821             list->append(new FontFamilyValueImpl(qString( value->string)));
1822         }
1823         else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
1824             if (currFamily) {
1825                 currFamily->parsedFontName += ' ';
1826                 currFamily->parsedFontName += qString(value->string);
1827             }
1828             else if (nextValBreaksFont || !nextValIsFontName)
1829                 list->append(new FontFamilyValueImpl(qString( value->string)));
1830             else
1831                 list->append(currFamily = new FontFamilyValueImpl(qString(value->string)));
1832         }
1833         else {
1834 //          kdDebug( 6080 ) << "invalid family part" << endl;
1835             break;
1836         }
1837         
1838         if (!nextValue)
1839             break;
1840
1841         if (nextValBreaksFont) {
1842             value = valueList->next();
1843             currFamily = 0;
1844         }
1845         else if (nextValIsFontName)
1846             value = nextValue;
1847         else
1848             break;
1849     }
1850     if ( !list->length() ) {
1851         delete list;
1852         list = 0;
1853     }
1854     return list;
1855 }
1856
1857
1858 bool CSSParser::parseColor(const QString &name, QRgb& rgb)
1859 {
1860     int len = name.length();
1861
1862     if ( !len )
1863         return false;
1864
1865
1866     bool ok;
1867
1868     if ( len == 3 || len == 6 ) {
1869         int val = name.toInt(&ok, 16);
1870         if ( ok ) {
1871             if (len == 6) {
1872                 rgb =  (0xff << 24) | val;
1873                 return true;
1874             }
1875             else if ( len == 3 ) {
1876                 // #abc converts to #aabbcc according to the specs
1877                 rgb = (0xff << 24) |
1878                     (val&0xf00)<<12 | (val&0xf00)<<8 |
1879                     (val&0xf0)<<8 | (val&0xf0)<<4 |
1880                     (val&0xf)<<4 | (val&0xf);
1881                 return true;
1882             }
1883         }
1884     }
1885
1886     // try a little harder
1887     QColor tc;
1888     tc.setNamedColor(name.lower());
1889     if (tc.isValid()) {
1890         rgb = tc.rgb();
1891         return true;
1892     }
1893
1894     return false;
1895 }
1896
1897
1898 CSSPrimitiveValueImpl *CSSParser::parseColor()
1899 {
1900     return parseColorFromValue(valueList->current());
1901 }
1902
1903 CSSPrimitiveValueImpl *CSSParser::parseColorFromValue(Value* value)
1904 {
1905     QRgb c = khtml::transparentColor;
1906     if ( !strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
1907         value->fValue >= 0. && value->fValue < 1000000. ) {
1908         QString str;
1909         str.sprintf( "%06d", (int)(value->fValue+.5) );
1910         if (!CSSParser::parseColor( str, c ))
1911             return 0;
1912     } else if ( value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
1913                 value->unit == CSSPrimitiveValue::CSS_IDENT ||
1914                 value->unit == CSSPrimitiveValue::CSS_DIMENSION ) {
1915         if (!CSSParser::parseColor( qString( value->string ), c))
1916             return 0;
1917     }
1918     else if ( value->unit == Value::Function &&
1919                 value->function->args != 0 &&
1920                 value->function->args->numValues == 5 /* rgb + two commas */ &&
1921                 qString( value->function->name ).lower() == "rgb(" ) {
1922         ValueList *args = value->function->args;
1923         Value *v = args->current();
1924         if ( !validUnit( v, FInteger|FPercent, true ) )
1925             return 0;
1926         int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
1927         v = args->next();
1928         if ( v->unit != Value::Operator && v->iValue != ',' )
1929             return 0;
1930         v = args->next();
1931         if ( !validUnit( v, FInteger|FPercent, true ) )
1932             return 0;
1933         int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
1934         v = args->next();
1935         if ( v->unit != Value::Operator && v->iValue != ',' )
1936             return 0;
1937         v = args->next();
1938         if ( !validUnit( v, FInteger|FPercent, true ) )
1939             return 0;
1940         int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
1941         r = QMAX( 0, QMIN( 255, r ) );
1942         g = QMAX( 0, QMIN( 255, g ) );
1943         b = QMAX( 0, QMIN( 255, b ) );
1944         c = qRgb( r, g, b );
1945     }
1946     else if ( value->unit == Value::Function &&
1947               value->function->args != 0 &&
1948               value->function->args->numValues == 7 /* rgba + three commas */ &&
1949               qString( value->function->name ).lower() == "rgba(" ) {
1950         ValueList *args = value->function->args;
1951         Value *v = args->current();
1952         if ( !validUnit( v, FInteger|FPercent, true ) )
1953             return 0;
1954         int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
1955         v = args->next();
1956         if ( v->unit != Value::Operator && v->iValue != ',' )
1957             return 0;
1958         v = args->next();
1959         if ( !validUnit( v, FInteger|FPercent, true ) )
1960             return 0;
1961         int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
1962         v = args->next();
1963         if ( v->unit != Value::Operator && v->iValue != ',' )
1964             return 0;
1965         v = args->next();
1966         if ( !validUnit( v, FInteger|FPercent, true ) )
1967             return 0;
1968         int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
1969         v = args->next();
1970         if ( v->unit != Value::Operator && v->iValue != ',' )
1971             return 0;
1972         v = args->next();
1973         if ( !validUnit( v, FNumber, true ) )
1974             return 0;
1975         r = QMAX( 0, QMIN( 255, r ) );
1976         g = QMAX( 0, QMIN( 255, g ) );
1977         b = QMAX( 0, QMIN( 255, b ) );
1978         int a = (int)(QMAX( 0, QMIN( 1.0f, v->fValue ) ) * 255);
1979         c = qRgba( r, g, b, a );
1980     }
1981     else
1982         return 0;
1983
1984     return new CSSPrimitiveValueImpl(c);
1985 }
1986
1987 // This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
1988 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
1989 struct ShadowParseContext {
1990     ShadowParseContext()
1991     :values(0), x(0), y(0), blur(0), color(0),
1992      allowX(true), allowY(false), allowBlur(false), allowColor(true),
1993      allowBreak(true)
1994     {}
1995
1996     ~ShadowParseContext() {
1997         if (!allowBreak) {
1998             delete values;
1999             delete x;
2000             delete y;
2001             delete blur;
2002             delete color;
2003         }
2004     }
2005
2006     bool allowLength() { return allowX || allowY || allowBlur; }
2007
2008     bool failed() { return allowBreak = false; }
2009     
2010     void commitValue() {
2011         // Handle the ,, case gracefully by doing nothing.
2012         if (x || y || blur || color) {
2013             if (!values)
2014                 values = new CSSValueListImpl();
2015             
2016             // Construct the current shadow value and add it to the list.
2017             values->append(new ShadowValueImpl(x, y, blur, color));
2018         }
2019         
2020         // Now reset for the next shadow value.
2021         x = y = blur = color = 0;
2022         allowX = allowColor = allowBreak = true;
2023         allowY = allowBlur = false;  
2024     }
2025
2026     void commitLength(Value* v) {
2027         CSSPrimitiveValueImpl* val = new CSSPrimitiveValueImpl(v->fValue,
2028                                                                (CSSPrimitiveValue::UnitTypes)v->unit);
2029         if (allowX) {
2030             x = val;
2031             allowX = false; allowY = true; allowColor = false; allowBreak = false;
2032         }
2033         else if (allowY) {
2034             y = val;
2035             allowY = false; allowBlur = true; allowColor = true; allowBreak = true;
2036         }
2037         else if (allowBlur) {
2038             blur = val;
2039             allowBlur = false;
2040         }
2041     }
2042
2043     void commitColor(CSSPrimitiveValueImpl* val) {
2044         color = val;
2045         allowColor = false;
2046         if (allowX)
2047             allowBreak = false;
2048         else
2049             allowBlur = false;
2050     }
2051     
2052     CSSValueListImpl* values;
2053     CSSPrimitiveValueImpl* x;
2054     CSSPrimitiveValueImpl* y;
2055     CSSPrimitiveValueImpl* blur;
2056     CSSPrimitiveValueImpl* color;
2057
2058     bool allowX;
2059     bool allowY;
2060     bool allowBlur;
2061     bool allowColor;
2062     bool allowBreak;
2063 };
2064
2065 bool CSSParser::parseShadow(int propId, bool important)
2066 {
2067     ShadowParseContext context;
2068     Value* val;
2069     while ((val = valueList->current())) {
2070         // Check for a comma break first.
2071         if (val->unit == Value::Operator) {
2072             if (val->iValue != ',' || !context.allowBreak)
2073                 // Other operators aren't legal or we aren't done with the current shadow
2074                 // value.  Treat as invalid.
2075                 return context.failed();
2076             
2077             // The value is good.  Commit it.
2078             context.commitValue();
2079         }
2080         // Check to see if we're a length.
2081         else if (validUnit(val, FLength, true)) {
2082             // We required a length and didn't get one. Invalid.
2083             if (!context.allowLength())
2084                 return context.failed();
2085
2086             // A length is allowed here.  Construct the value and add it.
2087             context.commitLength(val);
2088         }
2089         else {
2090             // The only other type of value that's ok is a color value.
2091             CSSPrimitiveValueImpl* parsedColor = 0;
2092             bool isColor = (val->id >= CSS_VAL_AQUA && val->id <= CSS_VAL_WINDOWTEXT || val->id == CSS_VAL_MENU ||
2093                             (val->id >= CSS_VAL_GREY && val->id <= CSS_VAL__KHTML_TEXT && !strict));
2094             if (isColor) {
2095                 if (!context.allowColor)
2096                     return context.failed();
2097                 parsedColor = new CSSPrimitiveValueImpl(val->id);
2098             }
2099
2100             if (!parsedColor)
2101                 // It's not built-in. Try to parse it as a color.
2102                 parsedColor = parseColorFromValue(val);
2103
2104             if (!parsedColor || !context.allowColor)
2105                 return context.failed(); // This value is not a color or length and is invalid or
2106                                          // it is a color, but a color isn't allowed at this point.
2107             
2108             context.commitColor(parsedColor);
2109         }
2110         
2111         valueList->next();
2112     }
2113
2114     if (context.allowBreak) {
2115         context.commitValue();
2116         if (context.values->length()) {
2117             addProperty(propId, context.values, important);
2118             valueList->next();
2119             return true;
2120         }
2121     }
2122     
2123     return context.failed();
2124 }
2125
2126 static inline int yyerror( const char *str ) {
2127 #ifdef CSS_DEBUG
2128     kdDebug( 6080 ) << "CSS parse error " << str << endl;
2129 #else
2130     Q_UNUSED( str );
2131 #endif
2132     return 1;
2133 }
2134
2135 #define END 0
2136
2137 #include "parser.h"
2138
2139 int DOM::CSSParser::lex( void *_yylval ) {
2140     YYSTYPE *yylval = (YYSTYPE *)_yylval;
2141     int token = lex();
2142     int length;
2143     unsigned short *t = text( &length );
2144
2145 #ifdef TOKEN_DEBUG
2146     qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString( (QChar *)t, length ).latin1() );
2147 #endif
2148     switch( token ) {
2149     case WHITESPACE:
2150     case SGML_CD:
2151     case INCLUDES:
2152     case DASHMATCH:
2153         break;
2154
2155     case URI:
2156     case STRING:
2157     case IDENT:
2158     case HASH:
2159     case DIMEN:
2160     case UNICODERANGE:
2161     case FUNCTION:
2162         yylval->string.string = t;
2163         yylval->string.length = length;
2164         break;
2165
2166     case IMPORT_SYM:
2167     case PAGE_SYM:
2168     case MEDIA_SYM:
2169     case FONT_FACE_SYM:
2170     case CHARSET_SYM:
2171     case NAMESPACE_SYM:
2172
2173     case IMPORTANT_SYM:
2174         break;
2175
2176     case QEMS:
2177         length--;
2178     case GRADS:
2179         length--;
2180     case DEGS:
2181     case RADS:
2182     case KHERZ:
2183         length--;
2184     case MSECS:
2185     case HERZ:
2186     case EMS:
2187     case EXS:
2188     case PXS:
2189     case CMS:
2190     case MMS:
2191     case INS:
2192     case PTS:
2193     case PCS:
2194         length--;
2195     case SECS:
2196     case PERCENTAGE:
2197         length--;
2198     case NUMBER:
2199         yylval->val = QString( (QChar *)t, length ).toDouble();
2200         //qDebug("value = %s, converted=%.2f", QString( (QChar *)t, length ).latin1(), yylval->val );
2201         break;
2202
2203     default:
2204         break;
2205     }
2206
2207     return token;
2208 }
2209
2210 static inline int toHex( char c ) {
2211     if ( '0' <= c && c <= '9' )
2212         return c - '0';
2213     if ( 'a' <= c && c <= 'f' )
2214         return c - 'a' + 10;
2215     if ( 'A' <= c && c<= 'F' )
2216         return c - 'A' + 10;
2217     return 0;
2218 }
2219
2220 unsigned short *DOM::CSSParser::text(int *length)
2221 {
2222     unsigned short *start = yytext;
2223     int l = yyleng;
2224     switch( yyTok ) {
2225     case STRING:
2226         l--;
2227         /* nobreak */
2228     case HASH:
2229         start++;
2230         l--;
2231         break;
2232     case URI:
2233         // "url("{w}{string}{w}")"
2234         // "url("{w}{url}{w}")"
2235
2236         // strip "url(" and ")"
2237         start += 4;
2238         l -= 5;
2239         // strip {w}
2240         while ( l &&
2241                 (*start == ' ' || *start == '\t' || *start == '\r' ||
2242                  *start == '\n' || *start == '\f' ) ) {
2243             start++; l--;
2244         }
2245         if ( *start == '"' || *start == '\'' ) {
2246             start++; l--;
2247         }
2248         while ( l &&
2249                 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
2250                  start[l-1] == '\n' || start[l-1] == '\f' ) ) {
2251             l--;
2252         }
2253         if ( l && (start[l-1] == '\"' || start[l-1] == '\'' ) )
2254              l--;
2255
2256     default:
2257         break;
2258     }
2259
2260     // process escapes
2261     unsigned short *out = start;
2262     unsigned short *escape = 0;
2263
2264     for ( int i = 0; i < l; i++ ) {
2265         unsigned short *current = start+i;
2266         if ( escape == current - 1 ) {
2267             if ( ( *current >= '0' && *current <= '9' ) ||
2268                  ( *current >= 'a' && *current <= 'f' ) ||
2269                  ( *current >= 'A' && *current <= 'F' ) )
2270                 continue;
2271             if ( yyTok == STRING &&
2272                  ( *current == '\n' || *current == '\r' || *current == '\f' ) ) {
2273                 // ### handle \r\n case
2274                 if ( *current != '\r' )
2275                     escape = 0;
2276                 continue;
2277             }
2278             // in all other cases copy the char to output
2279             // ###
2280             *out++ = *current;
2281             escape = 0;
2282             continue;
2283         }
2284         if ( escape == current - 2 && yyTok == STRING &&
2285              *(current-1) == '\r' && *current == '\n' ) {
2286             escape = 0;
2287             continue;
2288         }
2289         if ( escape > current - 7 &&
2290              ( ( *current >= '0' && *current <= '9' ) ||
2291                ( *current >= 'a' && *current <= 'f' ) ||
2292                ( *current >= 'A' && *current <= 'F' ) ) )
2293             continue;
2294         if ( escape ) {
2295             // add escaped char
2296             int uc = 0;
2297             escape++;
2298             while ( escape < current ) {
2299                 //              qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
2300                 uc *= 16;
2301                 uc += toHex( *escape );
2302                 escape++;
2303             }
2304             //      qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
2305             // can't handle chars outside ucs2
2306             if ( uc > 0xffff )
2307                 uc = 0xfffd;
2308             *(out++) = (unsigned short)uc;
2309             escape = 0;
2310             if ( *current == ' ' ||
2311                  *current == '\t' ||
2312                  *current == '\r' ||
2313                  *current == '\n' ||
2314                  *current == '\f' )
2315                 continue;
2316         }
2317         if ( !escape && *current == '\\' ) {
2318             escape = current;
2319             continue;
2320         }
2321         *(out++) = *current;
2322     }
2323     if ( escape ) {
2324         // add escaped char
2325         int uc = 0;
2326         escape++;
2327         while ( escape < start+l ) {
2328             //          qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
2329             uc *= 16;
2330             uc += toHex( *escape );
2331             escape++;
2332         }
2333         //          qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
2334         // can't handle chars outside ucs2
2335         if ( uc > 0xffff )
2336             uc = 0xfffd;
2337         *(out++) = (unsigned short)uc;
2338     }
2339     
2340     *length = out - start;
2341     return start;
2342 }
2343
2344
2345 #define YY_DECL int DOM::CSSParser::lex()
2346 #define yyconst const
2347 typedef int yy_state_type;
2348 typedef unsigned int YY_CHAR;
2349 // this line makes sure we treat all Unicode chars correctly.
2350 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
2351 #define YY_DO_BEFORE_ACTION \
2352         yytext = yy_bp; \
2353         yyleng = (int) (yy_cp - yy_bp); \
2354         yy_hold_char = *yy_cp; \
2355         *yy_cp = 0; \
2356         yy_c_buf_p = yy_cp;
2357 #define YY_BREAK break;
2358 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).latin1() )
2359 #define YY_RULE_SETUP
2360 #define INITIAL 0
2361 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
2362 #define yyterminate() yyTok = END; return yyTok
2363 #define YY_FATAL_ERROR(a) qFatal(a)
2364 #define BEGIN yy_start = 1 + 2 *
2365 #define COMMENT 1
2366
2367 #include "tokenizer.cpp"