cssparser.cpp

00001 /*
00002  * This file is part of the DOM implementation for KDE.
00003  *
00004  * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
00005  * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
00006  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Library General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Library General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Library General Public License
00019  * along with this library; see the file COPYING.LIB.  If not, write to
00020  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021  * Boston, MA 02110-1301, USA.
00022  */
00023 
00024 // #define CSS_DEBUG
00025 // #define TOKEN_DEBUG
00026 #define YYDEBUG 0
00027 
00028 #include <kdebug.h>
00029 #include <kglobal.h>
00030 #include <kurl.h>
00031 
00032 #include "cssparser.h"
00033 #include "css_valueimpl.h"
00034 #include "css_ruleimpl.h"
00035 #include "css_stylesheetimpl.h"
00036 #include "cssproperties.h"
00037 #include "cssvalues.h"
00038 #include "misc/helper.h"
00039 #include "csshelper.h"
00040 using namespace DOM;
00041 
00042 #include <stdlib.h>
00043 #include <assert.h>
00044 
00045 // used to promote background: left to left center
00046 #define BACKGROUND_SKIP_CENTER( num ) \
00047     if ( !pos_ok[ num ] && expected != 1 ) {    \
00048         pos_ok[num] = true; \
00049         pos[num] = 0; \
00050         skip_next = false; \
00051     }
00052 
00053 ValueList::~ValueList()
00054 {
00055      unsigned numValues = m_values.size();
00056      for (unsigned i = 0; i < numValues; i++)
00057          if (m_values[i].unit == Value::Function)
00058              delete m_values[i].function;
00059 }
00060 
00061 namespace {
00062     class ShorthandScope {
00063     public:
00064         ShorthandScope(CSSParser* parser, int propId) : m_parser(parser)
00065         {
00066             if (!(m_parser->m_inParseShorthand++))
00067                 m_parser->m_currentShorthand = propId;
00068         }
00069         ~ShorthandScope()
00070         {
00071             if (!(--m_parser->m_inParseShorthand))
00072                 m_parser->m_currentShorthand = 0;
00073         }
00074 
00075     private:
00076         CSSParser* m_parser;
00077     };
00078 }
00079 
00080 using namespace DOM;
00081 
00082 #if YYDEBUG > 0
00083 extern int cssyydebug;
00084 #endif
00085 
00086 extern int cssyyparse( void * parser );
00087 
00088 CSSParser *CSSParser::currentParser = 0;
00089 
00090 CSSParser::CSSParser( bool strictParsing )
00091 {
00092 #ifdef CSS_DEBUG
00093     kdDebug( 6080 ) << "CSSParser::CSSParser this=" << this << endl;
00094 #endif
00095     strict = strictParsing;
00096 
00097     parsedProperties = (CSSProperty **) malloc( 32 * sizeof( CSSProperty * ) );
00098     numParsedProperties = 0;
00099     maxParsedProperties = 32;
00100 
00101     data = 0;
00102     valueList = 0;
00103     rule = 0;
00104     id = 0;
00105     important = false;
00106     nonCSSHint = false;
00107 
00108     m_inParseShorthand = 0;
00109     m_currentShorthand = 0;
00110     m_implicitShorthand = false;
00111 
00112     yy_start = 1;
00113 
00114 #if YYDEBUG > 0
00115     cssyydebug = 1;
00116 #endif
00117 
00118 }
00119 
00120 CSSParser::~CSSParser()
00121 {
00122     if ( numParsedProperties )
00123         clearProperties();
00124     free( parsedProperties );
00125 
00126     delete valueList;
00127 
00128 #ifdef CSS_DEBUG
00129     kdDebug( 6080 ) << "CSSParser::~CSSParser this=" << this << endl;
00130 #endif
00131 
00132     free( data );
00133 
00134 }
00135 
00136 unsigned int CSSParser::defaultNamespace()
00137 {
00138     if (styleElement && styleElement->isCSSStyleSheet())
00139         return static_cast<CSSStyleSheetImpl*>(styleElement)->defaultNamespace();
00140     else
00141         return anyNamespace;
00142 }
00143 
00144 void CSSParser::runParser(int length)
00145 {
00146     data[length-1] = 0;
00147     data[length-2] = 0;
00148     data[length-3] = ' ';
00149 
00150     yyTok = -1;
00151     block_nesting = 0;
00152     yy_hold_char = 0;
00153     yyleng = 0;
00154     yytext = yy_c_buf_p = data;
00155     yy_hold_char = *yy_c_buf_p;
00156 
00157     CSSParser *old = currentParser;
00158     currentParser = this;
00159     cssyyparse( this );
00160     currentParser = old;
00161 }
00162 
00163 void CSSParser::parseSheet( CSSStyleSheetImpl *sheet, const DOMString &string )
00164 {
00165     styleElement = sheet;
00166 
00167     int length = string.length() + 3;
00168     data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00169     memcpy( data, string.unicode(), string.length()*sizeof( unsigned short) );
00170 
00171 #ifdef CSS_DEBUG
00172     kdDebug( 6080 ) << ">>>>>>> start parsing style sheet" << endl;
00173 #endif
00174     runParser(length);
00175 #ifdef CSS_DEBUG
00176     kdDebug( 6080 ) << "<<<<<<< done parsing style sheet" << endl;
00177 #endif
00178 
00179     delete rule;
00180     rule = 0;
00181 }
00182 
00183 CSSRuleImpl *CSSParser::parseRule( DOM::CSSStyleSheetImpl *sheet, const DOM::DOMString &string )
00184 {
00185     styleElement = sheet;
00186 
00187     const char khtml_rule[] = "@-khtml-rule{";
00188     int length = string.length() + 4 + strlen(khtml_rule);
00189     assert( !data );
00190     data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00191     for ( unsigned int i = 0; i < strlen(khtml_rule); i++ )
00192         data[i] = khtml_rule[i];
00193     memcpy( data + strlen( khtml_rule ), string.unicode(), string.length()*sizeof( unsigned short) );
00194     // qDebug("parse string = '%s'", QConstString( (const QChar *)data, length ).string().latin1() );
00195     data[length-4] = '}';
00196 
00197     runParser(length);
00198 
00199     CSSRuleImpl *result = rule;
00200     rule = 0;
00201 
00202     return result;
00203 }
00204 
00205 bool CSSParser::parseValue( DOM::CSSStyleDeclarationImpl *declaration, int _id, const DOM::DOMString &string,
00206                             bool _important, bool _nonCSSHint )
00207 {
00208 #ifdef CSS_DEBUG
00209     kdDebug( 6080 ) << "CSSParser::parseValue: id=" << _id << " important=" << _important
00210                     << " nonCSSHint=" << _nonCSSHint << " value='" << string.string() << "'" << endl;
00211 #endif
00212 
00213     styleElement = declaration->stylesheet();
00214 
00215     const char khtml_value[] = "@-khtml-value{";
00216     int length = string.length() + 4 + strlen(khtml_value);
00217     assert( !data );
00218     data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00219     for ( unsigned int i = 0; i < strlen(khtml_value); i++ )
00220         data[i] = khtml_value[i];
00221     memcpy( data + strlen( khtml_value ), string.unicode(), string.length()*sizeof( unsigned short) );
00222     data[length-4] = '}';
00223     // qDebug("parse string = '%s'", QConstString( (const QChar *)data, length ).string().latin1() );
00224 
00225     id = _id;
00226     important = _important;
00227     nonCSSHint = _nonCSSHint;
00228 
00229     runParser(length);
00230 
00231     delete rule;
00232     rule = 0;
00233 
00234     bool ok = false;
00235     if ( numParsedProperties ) {
00236         ok = true;
00237         for ( int i = 0; i < numParsedProperties; i++ ) {
00238             declaration->removeProperty(parsedProperties[i]->m_id, nonCSSHint);
00239             declaration->values()->append( parsedProperties[i] );
00240         }
00241         numParsedProperties = 0;
00242     }
00243 
00244     return ok;
00245 }
00246 
00247 bool CSSParser::parseDeclaration( DOM::CSSStyleDeclarationImpl *declaration, const DOM::DOMString &string,
00248                                   bool _nonCSSHint )
00249 {
00250 #ifdef CSS_DEBUG
00251     kdDebug( 6080 ) << "CSSParser::parseDeclaration: nonCSSHint=" << nonCSSHint
00252                     << " value='" << string.string() << "'" << endl;
00253 #endif
00254 
00255     styleElement = declaration->stylesheet();
00256 
00257     const char khtml_decls[] = "@-khtml-decls{";
00258     int length = string.length() + 4 + strlen(khtml_decls);
00259     assert( !data );
00260     data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00261     for ( unsigned int i = 0; i < strlen(khtml_decls); i++ )
00262         data[i] = khtml_decls[i];
00263     memcpy( data + strlen( khtml_decls ), string.unicode(), string.length()*sizeof( unsigned short) );
00264     data[length-4] = '}';
00265 
00266     nonCSSHint = _nonCSSHint;
00267 
00268     runParser(length);
00269 
00270     delete rule;
00271     rule = 0;
00272 
00273     bool ok = false;
00274     if ( numParsedProperties ) {
00275         ok = true;
00276         for ( int i = 0; i < numParsedProperties; i++ ) {
00277             declaration->removeProperty(parsedProperties[i]->m_id, false);
00278             declaration->values()->append( parsedProperties[i] );
00279         }
00280         numParsedProperties = 0;
00281     }
00282 
00283     return ok;
00284 }
00285 
00286 void CSSParser::addProperty( int propId, CSSValueImpl *value, bool important )
00287 {
00288     CSSProperty *prop = new CSSProperty;
00289     prop->m_id = propId;
00290     prop->setValue( value );
00291     prop->m_important = important;
00292     prop->nonCSSHint = nonCSSHint;
00293 
00294     if ( numParsedProperties >= maxParsedProperties ) {
00295         maxParsedProperties += 32;
00296         parsedProperties = (CSSProperty **) realloc( parsedProperties,
00297                                                     maxParsedProperties*sizeof( CSSProperty * ) );
00298     }
00299     parsedProperties[numParsedProperties++] = prop;
00300 }
00301 
00302 CSSStyleDeclarationImpl *CSSParser::createStyleDeclaration( CSSStyleRuleImpl *rule )
00303 {
00304     QPtrList<CSSProperty> *propList = new QPtrList<CSSProperty>;
00305     propList->setAutoDelete( true );
00306     for ( int i = 0; i < numParsedProperties; i++ )
00307         propList->append( parsedProperties[i] );
00308 
00309     numParsedProperties = 0;
00310     return new CSSStyleDeclarationImpl(rule, propList);
00311 }
00312 
00313 void CSSParser::clearProperties()
00314 {
00315     for ( int i = 0; i < numParsedProperties; i++ )
00316         delete parsedProperties[i];
00317     numParsedProperties = 0;
00318 }
00319 
00320 DOM::DocumentImpl *CSSParser::document() const
00321 {
00322     const StyleBaseImpl* root = styleElement;
00323     DocumentImpl *doc = 0;
00324     while (root->parent())
00325         root = root->parent();
00326     if (root->isCSSStyleSheet())
00327         doc = static_cast<const CSSStyleSheetImpl*>(root)->doc();
00328     return doc;
00329 }
00330 
00331 
00332 // defines units allowed for a certain property, used in parseUnit
00333 enum Units
00334 {
00335     FUnknown   = 0x0000,
00336     FInteger   = 0x0001,
00337     FNumber    = 0x0002,  // Real Numbers
00338     FPercent   = 0x0004,
00339     FLength    = 0x0008,
00340     FAngle     = 0x0010,
00341     FTime      = 0x0020,
00342     FFrequency = 0x0040,
00343     FRelative  = 0x0100,
00344     FNonNeg    = 0x0200
00345 };
00346 
00347 static bool validUnit( Value *value, int unitflags, bool strict )
00348 {
00349     if ( unitflags & FNonNeg && value->fValue < 0 )
00350         return false;
00351 
00352     bool b = false;
00353     switch( value->unit ) {
00354     case CSSPrimitiveValue::CSS_NUMBER:
00355         b = (unitflags & FNumber);
00356         if ( !b && ( (unitflags & FLength) && (value->fValue == 0 || !strict ) ) ) {
00357             value->unit = CSSPrimitiveValue::CSS_PX;
00358             b = true;
00359         }
00360         if (!b && (unitflags & FInteger) && value->isInt)
00361             b = true;
00362         break;
00363     case CSSPrimitiveValue::CSS_PERCENTAGE:
00364         b = (unitflags & FPercent);
00365         break;
00366     case Value::Q_EMS:
00367     case CSSPrimitiveValue::CSS_EMS:
00368     case CSSPrimitiveValue::CSS_EXS:
00369     case CSSPrimitiveValue::CSS_PX:
00370     case CSSPrimitiveValue::CSS_CM:
00371     case CSSPrimitiveValue::CSS_MM:
00372     case CSSPrimitiveValue::CSS_IN:
00373     case CSSPrimitiveValue::CSS_PT:
00374     case CSSPrimitiveValue::CSS_PC:
00375         b = (unitflags & FLength);
00376         break;
00377     case CSSPrimitiveValue::CSS_MS:
00378     case CSSPrimitiveValue::CSS_S:
00379         b = (unitflags & FTime);
00380         break;
00381     case CSSPrimitiveValue::CSS_DEG:
00382     case CSSPrimitiveValue::CSS_RAD:
00383     case CSSPrimitiveValue::CSS_GRAD:
00384     case CSSPrimitiveValue::CSS_HZ:
00385     case CSSPrimitiveValue::CSS_KHZ:
00386     case CSSPrimitiveValue::CSS_DIMENSION:
00387     default:
00388         break;
00389     }
00390     return b;
00391 }
00392 
00393 bool CSSParser::parseValue( int propId, bool important )
00394 {
00395     if ( !valueList ) return false;
00396 
00397     Value *value = valueList->current();
00398 
00399     if ( !value )
00400         return false;
00401 
00402     int id = value->id;
00403 
00404     int num = inShorthand() ? 1 : valueList->size();
00405 
00406     if ( id == CSS_VAL_INHERIT ) {
00407         if (num != 1)
00408             return false;
00409         addProperty( propId, new CSSInheritedValueImpl(), important );
00410         return true;
00411     } else if (id == CSS_VAL_INITIAL ) {
00412         if (num != 1)
00413             return false;
00414         addProperty(propId, new CSSInitialValueImpl(), important);
00415         return true;
00416     }
00417 
00418     bool valid_primitive = false;
00419     CSSValueImpl *parsedValue = 0;
00420 
00421     switch(propId) {
00422         /* The comment to the left defines all valid value of this properties as defined
00423          * in CSS 2, Appendix F. Property index
00424          */
00425 
00426         /* All the CSS properties are not supported by the renderer at the moment.
00427          * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
00428          * (see parseAuralValues). As we don't support them at all this seems reasonable.
00429          */
00430 
00431     case CSS_PROP_SIZE:                 // <length>{1,2} | auto | portrait | landscape | inherit
00432 //     case CSS_PROP_PAGE:                 // <identifier> | auto // ### CHECK
00433         // ### To be done
00434         if (id)
00435             valid_primitive = true;
00436         break;
00437     case CSS_PROP_UNICODE_BIDI:         // normal | embed | bidi-override | inherit
00438         if ( id == CSS_VAL_NORMAL ||
00439              id == CSS_VAL_EMBED ||
00440              id == CSS_VAL_BIDI_OVERRIDE )
00441             valid_primitive = true;
00442         break;
00443 
00444     case CSS_PROP_POSITION:             // static | relative | absolute | fixed | inherit
00445         if ( id == CSS_VAL_STATIC ||
00446              id == CSS_VAL_RELATIVE ||
00447              id == CSS_VAL_ABSOLUTE ||
00448               id == CSS_VAL_FIXED )
00449             valid_primitive = true;
00450         break;
00451 
00452     case CSS_PROP_PAGE_BREAK_AFTER:     // auto | always | avoid | left | right | inherit
00453     case CSS_PROP_PAGE_BREAK_BEFORE:    // auto | always | avoid | left | right | inherit
00454         if ( id == CSS_VAL_AUTO ||
00455              id == CSS_VAL_ALWAYS ||
00456              id == CSS_VAL_AVOID ||
00457               id == CSS_VAL_LEFT ||
00458               id == CSS_VAL_RIGHT )
00459             valid_primitive = true;
00460         break;
00461 
00462     case CSS_PROP_PAGE_BREAK_INSIDE:    // avoid | auto | inherit
00463         if ( id == CSS_VAL_AUTO ||
00464              id == CSS_VAL_AVOID )
00465             valid_primitive = true;
00466         break;
00467 
00468     case CSS_PROP_EMPTY_CELLS:          // show | hide | inherit
00469         if ( id == CSS_VAL_SHOW ||
00470              id == CSS_VAL_HIDE )
00471             valid_primitive = true;
00472         break;
00473 
00474     case CSS_PROP_QUOTES:               // [<string> <string>]+ | none | inherit
00475         if (id == CSS_VAL_NONE) {
00476             valid_primitive = true;
00477         } else {
00478             QuotesValueImpl *quotes = new QuotesValueImpl;
00479             bool is_valid = true;
00480             QString open, close;
00481             Value *val=valueList->current();
00482             while (val) {
00483                 if (val->unit == CSSPrimitiveValue::CSS_STRING)
00484                     open = qString(val->string);
00485                 else {
00486                     is_valid = false;
00487                     break;
00488                 }
00489                 valueList->next();
00490                 val=valueList->current();
00491                 if (val && val->unit == CSSPrimitiveValue::CSS_STRING)
00492                     close = qString(val->string);
00493                 else {
00494                     is_valid = false;
00495                     break;
00496                 }
00497                 quotes->addLevel(open, close);
00498                 valueList->next();
00499                 val=valueList->current();
00500             }
00501             if (is_valid)
00502                 parsedValue = quotes;
00503             else
00504                 delete quotes;
00505         }
00506         break;
00507 
00508     case CSS_PROP_CONTENT:     //  normal | none | inherit |
00509         // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+
00510         if ( id == CSS_VAL_NORMAL || id == CSS_VAL_NONE)
00511             valid_primitive = true;
00512         else
00513             return parseContent( propId, important );
00514         break;
00515 
00516     case CSS_PROP_WHITE_SPACE:          // normal | pre | nowrap | pre-wrap | pre-line | inherit
00517         if ( id == CSS_VAL_NORMAL ||
00518              id == CSS_VAL_PRE ||
00519              id == CSS_VAL_PRE_WRAP ||
00520              id == CSS_VAL_PRE_LINE ||
00521              id == CSS_VAL_NOWRAP )
00522             valid_primitive = true;
00523         break;
00524 
00525     case CSS_PROP_CLIP:                 // <shape> | auto | inherit
00526         if ( id == CSS_VAL_AUTO )
00527             valid_primitive = true;
00528         else if ( value->unit == Value::Function )
00529             return parseShape( propId, important );
00530         break;
00531 
00532     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
00533      * correctly and allows optimization in khtml::applyRule(..)
00534      */
00535     case CSS_PROP_CAPTION_SIDE:         // top | bottom | left | right | inherit
00536         // Left and right were deprecated in CSS 2.1 and never supported by KHTML
00537         if ( /* id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || */
00538             id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM)
00539             valid_primitive = true;
00540         break;
00541 
00542     case CSS_PROP_BORDER_COLLAPSE:      // collapse | separate | inherit
00543         if ( id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE )
00544             valid_primitive = true;
00545         break;
00546 
00547     case CSS_PROP_VISIBILITY:           // visible | hidden | collapse | inherit
00548         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE)
00549             valid_primitive = true;
00550         break;
00551 
00552     case CSS_PROP_OVERFLOW:             // visible | hidden | scroll | auto | marquee | inherit
00553         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ||
00554             id == CSS_VAL_MARQUEE)
00555             valid_primitive = true;
00556         break;
00557 
00558     case CSS_PROP_LIST_STYLE_POSITION:  // inside | outside | inherit
00559         if ( id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE )
00560             valid_primitive = true;
00561         break;
00562 
00563     case CSS_PROP_LIST_STYLE_TYPE:
00564         // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
00565         // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
00566         // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
00567         // katakana | hiragana-iroha | katakana-iroha | none | inherit
00568         if ((id >= CSS_VAL_DISC && id <= CSS_VAL__KHTML_CLOSE_QUOTE) || id == CSS_VAL_NONE)
00569             valid_primitive = true;
00570         break;
00571 
00572     case CSS_PROP_DISPLAY:
00573         // inline | block | list-item | run-in | inline-block | -khtml-ruler | table |
00574         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
00575         // table-column-group | table-column | table-cell | table-caption | none | inherit
00576         if ((id >= CSS_VAL_INLINE && id <= CSS_VAL_TABLE_CAPTION) || id == CSS_VAL_NONE)
00577             valid_primitive = true;
00578         break;
00579 
00580     case CSS_PROP_DIRECTION:            // ltr | rtl | inherit
00581         if ( id == CSS_VAL_LTR || id == CSS_VAL_RTL )
00582             valid_primitive = true;
00583         break;
00584 
00585     case CSS_PROP_TEXT_TRANSFORM:       // capitalize | uppercase | lowercase | none | inherit
00586         if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE)
00587             valid_primitive = true;
00588         break;
00589 
00590     case CSS_PROP_FLOAT:                // left | right | none | khtml_left | khtml_right | inherit + center for buggy CSS
00591         if ( id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL__KHTML_LEFT ||
00592              id == CSS_VAL__KHTML_RIGHT ||id == CSS_VAL_NONE || id == CSS_VAL_CENTER)
00593             valid_primitive = true;
00594         break;
00595 
00596     case CSS_PROP_CLEAR:                // none | left | right | both | inherit
00597         if ( id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
00598              id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH)
00599             valid_primitive = true;
00600         break;
00601 
00602     case CSS_PROP_TEXT_ALIGN:
00603         // left | right | center | justify | khtml_left | khtml_right | khtml_center | <string> | inherit
00604         if ( ( id >= CSS_VAL__KHTML_AUTO && id <= CSS_VAL__KHTML_CENTER ) ||
00605              value->unit == CSSPrimitiveValue::CSS_STRING )
00606             valid_primitive = true;
00607         break;
00608 
00609     case CSS_PROP_OUTLINE_STYLE:        // <border-style> | inherit
00610     case CSS_PROP_BORDER_TOP_STYLE:     
00611     case CSS_PROP_BORDER_RIGHT_STYLE:   //   Defined as:    none | hidden | dotted | dashed |
00612     case CSS_PROP_BORDER_BOTTOM_STYLE:  //   solid | double | groove | ridge | inset | outset | -khtml-native
00613     case CSS_PROP_BORDER_LEFT_STYLE:    
00614         if (id >= CSS_VAL__KHTML_NATIVE && id <= CSS_VAL_DOUBLE)
00615             valid_primitive = true;
00616         break;
00617 
00618     case CSS_PROP_FONT_WEIGHT:  // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 |
00619         // 500 | 600 | 700 | 800 | 900 | inherit
00620         if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) {
00621             // Allready correct id
00622             valid_primitive = true;
00623         } else if ( validUnit( value, FInteger|FNonNeg, false ) ) {
00624             int weight = (int)value->fValue;
00625             if ( (weight % 100) )
00626                 break;
00627             weight /= 100;
00628             if ( weight >= 1 && weight <= 9 ) {
00629                 id = CSS_VAL_100 + weight - 1;
00630                 valid_primitive = true;
00631             }
00632         }
00633         break;
00634 
00635     case CSS_PROP_BORDER_SPACING:
00636     {
00637         const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING,
00638                                     CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
00639         if (num == 1) {
00640             ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
00641             if (!parseValue(properties[0], important)) return false;
00642             CSSValueImpl* value = parsedProperties[numParsedProperties-1]->value();
00643             addProperty(properties[1], value, important);
00644             return true;
00645         }
00646         else if (num == 2) {
00647             ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
00648             if (!parseValue(properties[0], important)) return false;
00649             if (!parseValue(properties[1], important)) return false;
00650             return true;
00651         }
00652         return false;
00653     }
00654     case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING:
00655     case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING:
00656         valid_primitive = validUnit(value, FLength|FNonNeg, strict&(!nonCSSHint));
00657         break;
00658 
00659     case CSS_PROP_SCROLLBAR_FACE_COLOR:         // IE5.5
00660     case CSS_PROP_SCROLLBAR_SHADOW_COLOR:       // IE5.5
00661     case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:    // IE5.5
00662     case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:      // IE5.5
00663     case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:   // IE5.5
00664     case CSS_PROP_SCROLLBAR_TRACK_COLOR:        // IE5.5
00665     case CSS_PROP_SCROLLBAR_ARROW_COLOR:        // IE5.5
00666     case CSS_PROP_SCROLLBAR_BASE_COLOR:         // IE5.5
00667         if ( strict )
00668             break;
00669         /* nobreak */
00670     case CSS_PROP_OUTLINE_COLOR:        // <color> | invert | inherit
00671         // outline has "invert" as additional keyword.
00672         if ( propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT ) {
00673             valid_primitive = true;
00674             break;
00675         }
00676         /* nobreak */
00677     case CSS_PROP_BACKGROUND_COLOR:     // <color> | inherit
00678     case CSS_PROP_BORDER_TOP_COLOR:     // <color> | inherit
00679     case CSS_PROP_BORDER_RIGHT_COLOR:   // <color> | inherit
00680     case CSS_PROP_BORDER_BOTTOM_COLOR:  // <color> | inherit
00681     case CSS_PROP_BORDER_LEFT_COLOR:    // <color> | inherit
00682     case CSS_PROP_COLOR:                // <color> | inherit
00683         if ( id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_MENU ||
00684              (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT ) ||
00685              id == CSS_VAL_TRANSPARENT ||
00686              (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && (nonCSSHint|!strict) ) ) {
00687             valid_primitive = true;
00688         } else {
00689             parsedValue = parseColor();
00690             if ( parsedValue )
00691                 valueList->next();
00692         }
00693         break;
00694 
00695     case CSS_PROP_CURSOR:
00696         //  [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
00697         // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | text |
00698         // wait | help ] ] | inherit
00699     // MSIE 5 compatibility :/
00700         if ( !strict && id == CSS_VAL_HAND ) {
00701             id = CSS_VAL_POINTER;
00702             valid_primitive = true;
00703         } else if ( id >= CSS_VAL_AUTO && id <= CSS_VAL_HELP )
00704             valid_primitive = true;
00705         break;
00706 
00707     case CSS_PROP_BACKGROUND_ATTACHMENT:
00708     case CSS_PROP__KHTML_BACKGROUND_CLIP:
00709     case CSS_PROP_BACKGROUND_IMAGE:
00710     case CSS_PROP__KHTML_BACKGROUND_ORIGIN:
00711     case CSS_PROP_BACKGROUND_POSITION:
00712     case CSS_PROP_BACKGROUND_POSITION_X:
00713     case CSS_PROP_BACKGROUND_POSITION_Y:
00714     case CSS_PROP__KHTML_BACKGROUND_SIZE:
00715     case CSS_PROP_BACKGROUND_REPEAT: {
00716         CSSValueImpl *val1 = 0, *val2 = 0;
00717         int propId1, propId2;
00718         if (parseBackgroundProperty(propId, propId1, propId2, val1, val2)) {
00719             addProperty(propId1, val1, important);
00720             if (val2)
00721                 addProperty(propId2, val2, important);
00722             return true;
00723         }
00724         return false;
00725     }
00726     case CSS_PROP_LIST_STYLE_IMAGE:     // <uri> | none | inherit
00727         if (id == CSS_VAL_NONE) {
00728             parsedValue = new CSSImageValueImpl();
00729             valueList->next();
00730         }
00731         else if (value->unit == CSSPrimitiveValue::CSS_URI ) {
00732             // ### allow string in non strict mode?
00733             DOMString uri = khtml::parseURL( domString( value->string ) );
00734             if (!uri.isEmpty()) {
00735                 parsedValue = new CSSImageValueImpl(
00736                     DOMString(KURL( styleElement->baseURL(), uri.string()).url()),
00737                     styleElement );
00738                 valueList->next();
00739             }
00740         }
00741         break;
00742 
00743     case CSS_PROP_OUTLINE_WIDTH:        // <border-width> | inherit
00744     case CSS_PROP_BORDER_TOP_WIDTH:     
00745     case CSS_PROP_BORDER_RIGHT_WIDTH:   //   Which is defined as
00746     case CSS_PROP_BORDER_BOTTOM_WIDTH:  //   thin | medium | thick | <length>
00747     case CSS_PROP_BORDER_LEFT_WIDTH:    
00748         if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
00749             valid_primitive = true;
00750         else
00751             valid_primitive = ( validUnit( value, FLength, strict&(!nonCSSHint) ) );
00752         break;
00753 
00754     case CSS_PROP_LETTER_SPACING:       // normal | <length> | inherit
00755     case CSS_PROP_WORD_SPACING:         // normal | <length> | inherit
00756         if ( id == CSS_VAL_NORMAL )
00757             valid_primitive = true;
00758         else
00759             valid_primitive = validUnit( value, FLength, strict&(!nonCSSHint) );
00760         break;
00761 
00762     case CSS_PROP_TEXT_INDENT:          //  <length> | <percentage> | inherit
00763         valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00764         break;
00765 
00766     case CSS_PROP_PADDING_TOP:          //  <length> | <percentage> | inherit
00767     case CSS_PROP_PADDING_RIGHT:        //  <padding-width> | inherit
00768     case CSS_PROP_PADDING_BOTTOM:       //   Which is defined as
00769     case CSS_PROP_PADDING_LEFT:         //   <length> | <percentage>
00770     case CSS_PROP__KHTML_PADDING_START:
00771         valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00772         break;
00773 
00774     case CSS_PROP_MAX_HEIGHT:           // <length> | <percentage> | none | inherit
00775     case CSS_PROP_MAX_WIDTH:            // <length> | <percentage> | none | inherit
00776         if ( id == CSS_VAL_NONE ) {
00777             valid_primitive = true;
00778             break;
00779         }
00780         /* nobreak */
00781     case CSS_PROP_MIN_HEIGHT:           // <length> | <percentage> | inherit
00782     case CSS_PROP_MIN_WIDTH:            // <length> | <percentage> | inherit
00783             valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00784         break;
00785 
00786     case CSS_PROP_FONT_SIZE:
00787             // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
00788         if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER)
00789             valid_primitive = true;
00790         else
00791             valid_primitive = ( validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00792         break;
00793 
00794     case CSS_PROP_FONT_STYLE:           // normal | italic | oblique | inherit
00795         if ( id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE)
00796             valid_primitive = true;
00797         break;
00798 
00799     case CSS_PROP_FONT_VARIANT:         // normal | small-caps | inherit
00800         if ( id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS)
00801             valid_primitive = true;
00802         break;
00803 
00804     case CSS_PROP_VERTICAL_ALIGN:
00805             // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
00806         // <percentage> | <length> | inherit
00807 
00808         if ( id >= CSS_VAL_BASELINE && id <= CSS_VAL__KHTML_BASELINE_MIDDLE )
00809             valid_primitive = true;
00810         else
00811             valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00812         break;
00813 
00814     case CSS_PROP_HEIGHT:               // <length> | <percentage> | auto | inherit
00815     case CSS_PROP_WIDTH:                // <length> | <percentage> | auto | inherit
00816         if ( id == CSS_VAL_AUTO )
00817             valid_primitive = true;
00818         else
00819             // ### handle multilength case where we allow relative units
00820             valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00821         break;
00822 
00823     case CSS_PROP_BOTTOM:               // <length> | <percentage> | auto | inherit
00824     case CSS_PROP_LEFT:                 // <length> | <percentage> | auto | inherit
00825     case CSS_PROP_RIGHT:                // <length> | <percentage> | auto | inherit
00826     case CSS_PROP_TOP:                  // <length> | <percentage> | auto | inherit
00827     case CSS_PROP_MARGIN_TOP:           
00828     case CSS_PROP_MARGIN_RIGHT:         //   Which is defined as
00829     case CSS_PROP_MARGIN_BOTTOM:        //   <length> | <percentage> | auto | inherit
00830     case CSS_PROP_MARGIN_LEFT:          
00831     case CSS_PROP__KHTML_MARGIN_START:
00832         if ( id == CSS_VAL_AUTO )
00833             valid_primitive = true;
00834         else
00835             valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00836         break;
00837 
00838     case CSS_PROP_Z_INDEX:              // auto | <integer> | inherit
00839         // qDebug("parsing z-index: id=%d, fValue=%f", id, value->fValue );
00840         if ( id == CSS_VAL_AUTO ) {
00841             valid_primitive = true;
00842             break;
00843         }
00844         /* nobreak */
00845     case CSS_PROP_ORPHANS:              // <integer> | inherit
00846     case CSS_PROP_WIDOWS:               // <integer> | inherit
00847         // ### not supported later on
00848         valid_primitive = ( !id && validUnit( value, FInteger, false ) );
00849         break;
00850 
00851     case CSS_PROP_LINE_HEIGHT:          // normal | <number> | <length> | <percentage> | inherit
00852         if ( id == CSS_VAL_NORMAL )
00853             valid_primitive = true;
00854         else
00855             valid_primitive = ( !id && validUnit( value, FNumber|FLength|FPercent, strict&(!nonCSSHint) ) );
00856         break;
00857     case CSS_PROP_COUNTER_INCREMENT:    // [ <identifier> <integer>? ]+ | none | inherit
00858         if ( id == CSS_VAL_NONE )
00859             valid_primitive = true;
00860         else
00861             return parseCounter(propId, true, important);
00862         break;
00863     case CSS_PROP_COUNTER_RESET:        // [ <identifier> <integer>? ]+ | none | inherit
00864         if ( id == CSS_VAL_NONE )
00865             valid_primitive = true;
00866         else
00867             return parseCounter(propId, false, important);
00868             break;
00869 
00870     case CSS_PROP_FONT_FAMILY:
00871             // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
00872     {
00873         parsedValue = parseFontFamily();
00874         break;
00875     }
00876 
00877     case CSS_PROP_TEXT_DECORATION:
00878             // none | [ underline || overline || line-through || blink ] | inherit
00879         if (id == CSS_VAL_NONE) {
00880             valid_primitive = true;
00881         } else {
00882             CSSValueListImpl *list = new CSSValueListImpl;
00883             bool is_valid = true;
00884             while( is_valid && value ) {
00885                 switch ( value->id ) {
00886                 case CSS_VAL_BLINK:
00887                     break;
00888                 case CSS_VAL_UNDERLINE:
00889                 case CSS_VAL_OVERLINE:
00890                 case CSS_VAL_LINE_THROUGH:
00891                     list->append( new CSSPrimitiveValueImpl( value->id ) );
00892                     break;
00893                 default:
00894                     is_valid = false;
00895                 }
00896                 value = valueList->next();
00897             }
00898             //kdDebug( 6080 ) << "got " << list->length() << "d decorations" << endl;
00899             if(list->length() && is_valid) {
00900                 parsedValue = list;
00901                 valueList->next();
00902             } else {
00903                 delete list;
00904             }
00905         }
00906         break;
00907 
00908     case CSS_PROP_TABLE_LAYOUT:         // auto | fixed | inherit
00909         if ( id == CSS_VAL_AUTO || id == CSS_VAL_FIXED )
00910             valid_primitive = true;
00911         break;
00912 
00913     case CSS_PROP__KHTML_FLOW_MODE:
00914         if ( id == CSS_VAL__KHTML_NORMAL || id == CSS_VAL__KHTML_AROUND_FLOATS )
00915             valid_primitive = true;
00916         break;
00917 
00918     /* CSS3 properties */
00919     case CSS_PROP_BOX_SIZING:        // border-box | content-box | inherit
00920         if ( id == CSS_VAL_BORDER_BOX || id == CSS_VAL_CONTENT_BOX )
00921             valid_primitive = true;
00922         break;
00923     case CSS_PROP_OUTLINE_OFFSET:
00924         valid_primitive = validUnit(value, FLength, strict);
00925         break;
00926     case CSS_PROP_TEXT_SHADOW:  // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
00927         if (id == CSS_VAL_NONE)
00928             valid_primitive = true;
00929         else
00930             return parseShadow(propId, important);
00931         break;
00932     case CSS_PROP_OPACITY:
00933         valid_primitive = validUnit(value, FNumber, strict);
00934         break;
00935     case CSS_PROP__KHTML_USER_INPUT:        // none | enabled | disabled | inherit
00936         if ( id == CSS_VAL_NONE || id == CSS_VAL_ENABLED || id == CSS_VAL_DISABLED )
00937             valid_primitive = true;
00938 //        kdDebug(6080) << "CSS_PROP__KHTML_USER_INPUT: " << valid_primitive << endl;
00939         break;
00940     case CSS_PROP__KHTML_MARQUEE: {
00941         const int properties[5] = { CSS_PROP__KHTML_MARQUEE_DIRECTION, CSS_PROP__KHTML_MARQUEE_INCREMENT,
00942                                     CSS_PROP__KHTML_MARQUEE_REPETITION,
00943                                     CSS_PROP__KHTML_MARQUEE_STYLE, CSS_PROP__KHTML_MARQUEE_SPEED };
00944         return parseShortHand(propId, properties, 5, important);
00945     }
00946     case CSS_PROP__KHTML_MARQUEE_DIRECTION:
00947         if (id == CSS_VAL_FORWARDS || id == CSS_VAL_BACKWARDS || id == CSS_VAL_AHEAD ||
00948             id == CSS_VAL_REVERSE || id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_DOWN ||
00949             id == CSS_VAL_UP || id == CSS_VAL_AUTO)
00950             valid_primitive = true;
00951         break;
00952     case CSS_PROP__KHTML_MARQUEE_INCREMENT:
00953         if (id == CSS_VAL_SMALL || id == CSS_VAL_LARGE || id == CSS_VAL_MEDIUM)
00954             valid_primitive = true;
00955         else
00956             valid_primitive = validUnit(value, FLength|FPercent, strict&(!nonCSSHint));
00957         break;
00958     case CSS_PROP__KHTML_MARQUEE_STYLE:
00959         if (id == CSS_VAL_NONE || id == CSS_VAL_SLIDE || id == CSS_VAL_SCROLL || id == CSS_VAL_ALTERNATE ||
00960             id == CSS_VAL_UNFURL)
00961             valid_primitive = true;
00962         break;
00963     case CSS_PROP__KHTML_MARQUEE_REPETITION:
00964         if (id == CSS_VAL_INFINITE)
00965             valid_primitive = true;
00966         else
00967             valid_primitive = validUnit(value, FInteger|FNonNeg, strict&(!nonCSSHint));
00968         break;
00969     case CSS_PROP__KHTML_MARQUEE_SPEED:
00970         if (id == CSS_VAL_NORMAL || id == CSS_VAL_SLOW || id == CSS_VAL_FAST)
00971             valid_primitive = true;
00972         else
00973             valid_primitive = validUnit(value, FTime|FInteger|FNonNeg, strict&(!nonCSSHint));
00974         break;
00975     // End of CSS3 properties
00976 
00977         /* shorthand properties */
00978     case CSS_PROP_BACKGROUND:
00979             // ['background-color' || 'background-image' ||'background-repeat' ||
00980         // 'background-attachment' || 'background-position'] | inherit
00981     return parseBackgroundShorthand(important);
00982     case CSS_PROP_BORDER:
00983          // [ 'border-width' || 'border-style' || <color> ] | inherit
00984     {
00985         const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
00986                                     CSS_PROP_BORDER_COLOR };
00987         return parseShortHand(propId, properties, 3, important);
00988     }
00989     case CSS_PROP_BORDER_TOP:
00990             // [ 'border-top-width' || 'border-style' || <color> ] | inherit
00991     {
00992         const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
00993                                     CSS_PROP_BORDER_TOP_COLOR};
00994         return parseShortHand(propId, properties, 3, important);
00995     }
00996     case CSS_PROP_BORDER_RIGHT:
00997             // [ 'border-right-width' || 'border-style' || <color> ] | inherit
00998     {
00999         const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
01000                                     CSS_PROP_BORDER_RIGHT_COLOR };
01001         return parseShortHand(propId, properties, 3, important);
01002     }
01003     case CSS_PROP_BORDER_BOTTOM:
01004             // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
01005     {
01006         const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
01007                                     CSS_PROP_BORDER_BOTTOM_COLOR };
01008         return parseShortHand(propId, properties, 3, important);
01009     }
01010     case CSS_PROP_BORDER_LEFT:
01011             // [ 'border-left-width' || 'border-style' || <color> ] | inherit
01012     {
01013         const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
01014                                     CSS_PROP_BORDER_LEFT_COLOR };
01015         return parseShortHand(propId, properties, 3, important);
01016     }
01017     case CSS_PROP_OUTLINE:
01018             // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
01019     {
01020         const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
01021                                     CSS_PROP_OUTLINE_COLOR };
01022         return parseShortHand(propId, properties, 3, important);
01023     }
01024     case CSS_PROP_BORDER_COLOR:
01025             // <color>{1,4} | inherit
01026     {
01027         const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
01028                                     CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
01029         return parse4Values(propId, properties, important);
01030     }
01031     case CSS_PROP_BORDER_WIDTH:
01032             // <border-width>{1,4} | inherit
01033     {
01034         const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
01035                                     CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
01036         return parse4Values(propId, properties, important);
01037     }
01038     case CSS_PROP_BORDER_STYLE:
01039             // <border-style>{1,4} | inherit
01040     {
01041         const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
01042                                     CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
01043         return parse4Values(propId, properties, important);
01044     }
01045     case CSS_PROP_MARGIN:
01046             // <margin-width>{1,4} | inherit
01047     {
01048         const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
01049                                     CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
01050         return parse4Values(propId, properties, important);
01051     }
01052     case CSS_PROP_PADDING:
01053             // <padding-width>{1,4} | inherit
01054     {
01055         const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
01056                                     CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
01057         return parse4Values(propId, properties, important);
01058     }
01059     case CSS_PROP_FONT:
01060             // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
01061         // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
01062         if ( id >= CSS_VAL_CAPTION && id <= CSS_VAL_STATUS_BAR )
01063             valid_primitive = true;
01064         else
01065             return parseFont(important);
01066 
01067     case CSS_PROP_LIST_STYLE:
01068     {
01069         const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
01070                                     CSS_PROP_LIST_STYLE_IMAGE };
01071         return parseShortHand(propId, properties, 3, important);
01072     }
01073     default:
01074 // #ifdef CSS_DEBUG
01075 //         kdDebug( 6080 ) << "illegal or CSS2 Aural property: " << val << endl;
01076 // #endif
01077         break;
01078     }
01079 
01080     if ( valid_primitive ) {
01081 
01082         if ( id != 0 ) {
01083             parsedValue = new CSSPrimitiveValueImpl( id );
01084         } else if ( value->unit == CSSPrimitiveValue::CSS_STRING )
01085             parsedValue = new CSSPrimitiveValueImpl( domString( value->string ),
01086                                                      (CSSPrimitiveValue::UnitTypes) value->unit );
01087         else if ( value->unit >= CSSPrimitiveValue::CSS_NUMBER &&
01088                   value->unit <= CSSPrimitiveValue::CSS_KHZ ) {
01089             parsedValue = new CSSPrimitiveValueImpl( value->fValue,
01090                                                      (CSSPrimitiveValue::UnitTypes) value->unit );
01091         } else if ( value->unit >= Value::Q_EMS ) {
01092             parsedValue = new CSSQuirkPrimitiveValueImpl( value->fValue, CSSPrimitiveValue::CSS_EMS );
01093         }
01094         valueList->next();
01095     }
01096     if ( parsedValue ) {
01097         if (!valueList->current() || inShorthand()) {
01098             addProperty( propId, parsedValue, important );
01099             return true;
01100         }
01101         delete parsedValue;
01102     }
01103     return false;
01104 }
01105 
01106 void CSSParser::addBackgroundValue(CSSValueImpl*& lval, CSSValueImpl* rval)
01107 {
01108     if (lval) {
01109         if (lval->isValueList())
01110             static_cast<CSSValueListImpl*>(lval)->append(rval);
01111         else {
01112             CSSValueImpl* oldVal = lval;
01113             CSSValueListImpl* list = new CSSValueListImpl();
01114             lval = list;
01115             list->append(oldVal);
01116             list->append(rval);
01117         }
01118     }
01119     else
01120         lval = rval;
01121 }
01122 
01123 bool CSSParser::parseBackgroundShorthand(bool important)
01124 {
01125     // Position must come before color in this array because a plain old "0" is a legal color
01126     // in quirks mode but it's usually the X coordinate of a position.
01127     // FIXME: Add CSS_PROP__KHTML_BACKGROUND_SIZE to the shorthand.
01128     const int numProperties = 7;
01129     const int properties[numProperties] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
01130         CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,  CSS_PROP__KHTML_BACKGROUND_CLIP,
01131         CSS_PROP__KHTML_BACKGROUND_ORIGIN, CSS_PROP_BACKGROUND_COLOR };
01132 
01133     ShorthandScope scope(this, CSS_PROP_BACKGROUND);
01134 
01135     bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
01136     CSSValueImpl* values[numProperties] = { 0 }; // compiler will repeat 0 as necessary
01137     CSSValueImpl* positionYValue = 0;
01138     int i;
01139 
01140     while (valueList->current()) {
01141         Value* val = valueList->current();
01142         if (val->unit == Value::Operator && val->iValue == ',') {
01143             // We hit the end.  Fill in all remaining values with the initial value.
01144             valueList->next();
01145             for (i = 0; i < numProperties; ++i) {
01146                 if (properties[i] == CSS_PROP_BACKGROUND_COLOR && parsedProperty[i])
01147                     // Color is not allowed except as the last item in a list.  Reject the entire
01148                     // property.
01149                     goto fail;
01150 
01151                 if (!parsedProperty[i] && properties[i] != CSS_PROP_BACKGROUND_COLOR) {
01152                     addBackgroundValue(values[i], new CSSInitialValueImpl());
01153                     if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
01154                         addBackgroundValue(positionYValue, new CSSInitialValueImpl());
01155                 }
01156                 parsedProperty[i] = false;
01157             }
01158             if (!valueList->current())
01159                 break;
01160         }
01161 
01162         bool found = false;
01163         for (i = 0; !found && i < numProperties; ++i) {
01164             if (!parsedProperty[i]) {
01165                 CSSValueImpl *val1 = 0, *val2 = 0;
01166                 int propId1, propId2;
01167         if (parseBackgroundProperty(properties[i], propId1, propId2, val1, val2)) {
01168             parsedProperty[i] = found = true;
01169                     addBackgroundValue(values[i], val1);
01170                     if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
01171                         addBackgroundValue(positionYValue, val2);
01172         }
01173         }
01174     }
01175 
01176         // if we didn't find at least one match, this is an
01177         // invalid shorthand and we have to ignore it
01178         if (!found)
01179             goto fail;
01180     }
01181 
01182     // Fill in any remaining properties with the initial value.
01183     for (i = 0; i < numProperties; ++i) {
01184         if (!parsedProperty[i]) {
01185             addBackgroundValue(values[i], new CSSInitialValueImpl());
01186             if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
01187                 addBackgroundValue(positionYValue, new CSSInitialValueImpl());
01188         }
01189     }
01190 
01191     // Now add all of the properties we found.
01192     for (i = 0; i < numProperties; i++) {
01193         if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
01194             addProperty(CSS_PROP_BACKGROUND_POSITION_X, values[i], important);
01195             addProperty(CSS_PROP_BACKGROUND_POSITION_Y, positionYValue, important);
01196         }
01197         else
01198             addProperty(properties[i], values[i], important);
01199     }
01200 
01201     return true;
01202 
01203 fail:
01204     for (int k = 0; k < numProperties; k++)
01205         delete values[k];
01206     delete positionYValue;
01207     return false;
01208 }
01209 
01210 bool CSSParser::parseShortHand(int propId, const int *properties, int numProperties, bool important )
01211 {
01212     /* We try to match as many properties as possible
01213      * We setup an array of booleans to mark which property has been found,
01214      * and we try to search for properties until it makes no longer any sense
01215      */
01216     ShorthandScope scope(this, propId);
01217 
01218     bool found = false;
01219     bool fnd[6]; //Trust me ;)
01220     for( int i = 0; i < numProperties; i++ )
01221         fnd[i] = false;
01222 
01223     while ( valueList->current() ) {
01224         found = false;
01225         for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
01226             if (!fnd[propIndex]) {
01227                 if ( parseValue( properties[propIndex], important ) ) {
01228                     fnd[propIndex] = found = true;
01229                 }
01230             }
01231         }
01232 
01233         // if we didn't find at least one match, this is an
01234         // invalid shorthand and we have to ignore it
01235         if (!found)
01236             return false;
01237     }
01238 
01239     // Fill in any remaining properties with the initial value.
01240     m_implicitShorthand = true;
01241     for (int i = 0; i < numProperties; ++i) {
01242         if (!fnd[i])
01243             addProperty(properties[i], new CSSInitialValueImpl(), important);
01244     }
01245     m_implicitShorthand = false;
01246 
01247     return true;
01248 }
01249 
01250 bool CSSParser::parse4Values(int propId, const int *properties,  bool important )
01251 {
01252     /* From the CSS 2 specs, 8.3
01253      * If there is only one value, it applies to all sides. If there are two values, the top and
01254      * bottom margins are set to the first value and the right and left margins are set to the second.
01255      * If there are three values, the top is set to the first value, the left and right are set to the
01256      * second, and the bottom is set to the third. If there are four values, they apply to the top,
01257      * right, bottom, and left, respectively.
01258      */
01259 
01260     int num = inShorthand() ? 1 : valueList->size();
01261     //qDebug("parse4Values: num=%d %d", num,  valueList->numValues );
01262 
01263     ShorthandScope scope(this, propId);
01264 
01265     // the order is top, right, bottom, left
01266     switch (num) {
01267         case 1: {
01268             if (!parseValue(properties[0], important))
01269                 return false;
01270             CSSValueImpl *value = parsedProperties[numParsedProperties-1]->value();
01271             m_implicitShorthand = true;
01272             addProperty(properties[1], value, important);
01273             addProperty(properties[2], value, important);
01274             addProperty(properties[3], value, important);
01275             m_implicitShorthand = false;
01276             break;
01277         }
01278         case 2: {
01279             if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
01280                 return false;
01281             CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
01282             m_implicitShorthand = true;
01283             addProperty(properties[2], value, important);
01284             value = parsedProperties[numParsedProperties-2]->value();
01285             addProperty(properties[3], value, important);
01286             m_implicitShorthand = false;
01287             break;
01288         }
01289         case 3: {
01290             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
01291                 return false;
01292             CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
01293             m_implicitShorthand = true;
01294             addProperty(properties[3], value, important);
01295             m_implicitShorthand = false;
01296             break;
01297         }
01298         case 4: {
01299             if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
01300                 !parseValue(properties[2], important) || !parseValue(properties[3], important))
01301                 return false;
01302             break;
01303         }
01304         default: {
01305             return false;
01306         }
01307     }
01308 
01309     return true;
01310 }
01311 
01312 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
01313 // in CSS 2.1 this got somewhat reduced:
01314 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
01315 bool CSSParser::parseContent( int propId, bool important )
01316 {
01317     CSSValueListImpl* values = new CSSValueListImpl();
01318 
01319     bool isValid = true;
01320     Value *val;
01321     CSSValueImpl *parsedValue = 0;
01322     while ( (val = valueList->current()) ) {
01323         parsedValue = 0;
01324         if ( val->unit == CSSPrimitiveValue::CSS_URI ) {
01325             // url
01326             DOMString value = khtml::parseURL(domString(val->string));
01327             parsedValue = new CSSImageValueImpl(
01328                 DOMString(KURL( styleElement->baseURL(), value.string()).url() ), styleElement );
01329 #ifdef CSS_DEBUG
01330             kdDebug( 6080 ) << "content, url=" << value.string() << " base=" << styleElement->baseURL().url( ) << endl;
01331 #endif
01332         } else if ( val->unit == Value::Function ) {
01333             // attr( X ) | counter( X [,Y] ) | counters( X, Y, [,Z] )
01334             ValueList *args = val->function->args;
01335             QString fname = qString( val->function->name ).lower();
01336             if (!args) return false;
01337             if (fname == "attr(") {
01338                 if ( args->size() != 1)
01339                     return false;
01340                 Value *a = args->current();
01341                 if (a->unit != CSSPrimitiveValue::CSS_IDENT) {
01342                     isValid=false;
01343                     break;
01344                 }
01345                 if (qString(a->string)[0] == '-') {
01346                     isValid=false;
01347                     break;
01348                 }
01349                 parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR);
01350             }
01351             else
01352             if (fname == "counter(") {
01353                 parsedValue = parseCounterContent(args, false);
01354                 if (!parsedValue) return false;
01355             } else
01356             if (fname == "counters(") {
01357                 parsedValue = parseCounterContent(args, true);
01358                 if (!parsedValue) return false;
01359             }
01360             else
01361                 return false;
01362 
01363         } else if ( val->unit == CSSPrimitiveValue::CSS_IDENT ) {
01364             // open-quote | close-quote | no-open-quote | no-close-quote
01365             if ( val->id == CSS_VAL_OPEN_QUOTE ||
01366                  val->id == CSS_VAL_CLOSE_QUOTE ||
01367                  val->id == CSS_VAL_NO_OPEN_QUOTE ||
01368                  val->id == CSS_VAL_NO_CLOSE_QUOTE ) {
01369                 parsedValue = new CSSPrimitiveValueImpl(val->id);
01370             }
01371         } else if ( val->unit == CSSPrimitiveValue::CSS_STRING ) {
01372             parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING);
01373         }
01374 
01375         if (parsedValue)
01376             values->append(parsedValue);
01377         else {
01378             isValid = false;
01379             break;
01380         }
01381         valueList->next();
01382     }
01383     if ( isValid && values->length() ) {
01384         addProperty( propId, values, important );
01385         valueList->next();
01386         return true;
01387     }
01388 
01389     delete values;  // also frees any content by deref
01390     return false;
01391 }
01392 
01393 CSSValueImpl* CSSParser::parseCounterContent(ValueList *args, bool counters)
01394 {
01395     if (counters || (args->size() != 1 && args->size() != 3))
01396         if (!counters || (args->size() != 3 && args->size() != 5))
01397             return 0;
01398 
01399     CounterImpl *counter = new CounterImpl;
01400     Value *i = args->current();
01401     if (i->unit != CSSPrimitiveValue::CSS_IDENT) goto invalid;
01402     if (qString(i->string)[0] == '-') goto invalid;
01403     counter->m_identifier = domString(i->string);
01404     if (counters) {
01405         i = args->next();
01406         if (i->unit != Value::Operator || i->iValue != ',') goto invalid;
01407         i = args->next();
01408         if (i->unit != CSSPrimitiveValue::CSS_STRING) goto invalid;
01409         counter->m_separator = domString(i->string);
01410     }
01411     counter->m_listStyle = CSS_VAL_DECIMAL - CSS_VAL_DISC;
01412     i = args->next();
01413     if (i) {
01414         if (i->unit != Value::Operator || i->iValue != ',') goto invalid;
01415         i = args->next();
01416         if (i->unit != CSSPrimitiveValue::CSS_IDENT) goto invalid;
01417         if (i->id < CSS_VAL_DISC || i->id > CSS_VAL__KHTML_CLOSE_QUOTE) goto invalid;
01418         counter->m_listStyle = i->id - CSS_VAL_DISC;
01419     }
01420     return new CSSPrimitiveValueImpl(counter);
01421 invalid:
01422     delete counter;
01423     return 0;
01424 }
01425 
01426 CSSValueImpl* CSSParser::parseBackgroundColor()
01427 {
01428     int id = valueList->current()->id;
01429     if (id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_TRANSPARENT ||
01430         (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || id == CSS_VAL_MENU ||
01431         (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict))
01432        return new CSSPrimitiveValueImpl(id);
01433     return parseColor();
01434 }
01435 
01436 CSSValueImpl* CSSParser::parseBackgroundImage()
01437 {
01438     if (valueList->current()->id == CSS_VAL_NONE)
01439         return new CSSImageValueImpl();
01440     if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
01441         DOMString uri = khtml::parseURL(domString(valueList->current()->string));
01442         if (!uri.isEmpty())
01443             return new CSSImageValueImpl(DOMString(KURL(styleElement->baseURL(), uri.string()).url()),
01444                                          styleElement);
01445     }
01446     return 0;
01447 }
01448 
01449 CSSValueImpl* CSSParser::parseBackgroundPositionXY(bool& xFound, bool& yFound)
01450 {
01451     int id = valueList->current()->id;
01452     if (id == CSS_VAL_LEFT || id == CSS_VAL_TOP || id == CSS_VAL_RIGHT || id == CSS_VAL_BOTTOM || id == CSS_VAL_CENTER) {
01453         int percent = 0;
01454         if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT) {
01455             if (xFound)
01456                 return 0;
01457             xFound = true;
01458             if (id == CSS_VAL_RIGHT)
01459                 percent = 100;
01460         }
01461         else if (id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
01462             if (yFound)
01463                 return 0;
01464             yFound = true;
01465             if (id == CSS_VAL_BOTTOM)
01466                 percent = 100;
01467         }
01468         else if (id == CSS_VAL_CENTER)
01469             // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
01470             percent = 50;
01471         return new CSSPrimitiveValueImpl(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
01472     }
01473     if (validUnit(valueList->current(), FPercent|FLength, strict))
01474         return new CSSPrimitiveValueImpl(valueList->current()->fValue,
01475                                          (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
01476 
01477     return 0;
01478 }
01479 
01480 void CSSParser::parseBackgroundPosition(CSSValueImpl*& value1, CSSValueImpl*& value2)
01481 {
01482     value1 = value2 = 0;
01483     Value* value = valueList->current();
01484 
01485     // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
01486     bool value1IsX = false, value1IsY = false;
01487     value1 = parseBackgroundPositionXY(value1IsX, value1IsY);
01488     if (!value1)
01489         return;
01490 
01491     // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
01492     // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
01493     // value was explicitly specified for our property.
01494     value = valueList->next();
01495 
01496     // First check for the comma.  If so, we are finished parsing this value or value pair.
01497     if (value && value->unit == Value::Operator && value->iValue == ',')
01498         value = 0;
01499 
01500     bool value2IsX = false, value2IsY = false;
01501     if (value) {
01502         value2 = parseBackgroundPositionXY(value2IsX, value2IsY);
01503         if (value2)
01504             valueList->next();
01505         else {
01506             if (!inShorthand()) {
01507                 delete value1;
01508                 value1 = 0;
01509                 return;
01510             }
01511         }
01512     }
01513 
01514     if (!value2)
01515         // Only one value was specified.  If that value was not a keyword, then it sets the x position, and the y position
01516         // is simply 50%.  This is our default.
01517         // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
01518         // For left/right/center, the default of 50% in the y is still correct.
01519         value2 = new CSSPrimitiveValueImpl(50, CSSPrimitiveValue::CSS_PERCENTAGE);
01520 
01521     if (value1IsY || value2IsX) {
01522         // Swap our two values.
01523         CSSValueImpl* val = value2;
01524         value2 = value1;
01525         value1 = val;
01526     }
01527 }
01528 
01529 CSSValueImpl* CSSParser::parseBackgroundSize()
01530 {
01531     Value* value = valueList->current();
01532     CSSPrimitiveValueImpl* parsedValue1;
01533 
01534     if (value->id == CSS_VAL_AUTO)
01535         parsedValue1 = new CSSPrimitiveValueImpl(0, CSSPrimitiveValue::CSS_UNKNOWN);
01536     else {
01537         if (!validUnit(value, FLength|FPercent, strict))
01538             return 0;
01539         parsedValue1 = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
01540     }
01541 
01542     CSSPrimitiveValueImpl* parsedValue2 = parsedValue1;
01543     if ((value = valueList->next())) {
01544         if (value->id == CSS_VAL_AUTO)
01545             parsedValue2 = new CSSPrimitiveValueImpl(0, CSSPrimitiveValue::CSS_UNKNOWN);
01546         else {
01547             if (!validUnit(value, FLength|FPercent, strict)) {
01548                 delete parsedValue1;
01549                 return 0;
01550             }
01551             parsedValue2 = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
01552         }
01553     }
01554 
01555     PairImpl* pair = new PairImpl(parsedValue1, parsedValue2);
01556     return new CSSPrimitiveValueImpl(pair);
01557 }
01558 
01559 bool CSSParser::parseBackgroundProperty(int propId, int& propId1, int& propId2,
01560                                         CSSValueImpl*& retValue1, CSSValueImpl*& retValue2)
01561 {
01562 #ifdef CSS_DEBUG
01563     kdDebug(6080) << "parseBackgroundProperty()" << endl;
01564     kdDebug(6080) << "LOOKING FOR: " << getPropertyName(propId).string() << endl;
01565 #endif
01566     CSSValueListImpl *values = 0, *values2 = 0;
01567     Value* val;
01568     CSSValueImpl *value = 0, *value2 = 0;
01569     bool allowComma = false;
01570 
01571     retValue1 = retValue2 = 0;
01572     propId1 = propId;
01573     propId2 = propId;
01574     if (propId == CSS_PROP_BACKGROUND_POSITION) {
01575         propId1 = CSS_PROP_BACKGROUND_POSITION_X;
01576         propId2 = CSS_PROP_BACKGROUND_POSITION_Y;
01577     }
01578 
01579     while ((val = valueList->current())) {
01580         CSSValueImpl *currValue = 0, *currValue2 = 0;
01581         if (allowComma) {
01582             if (val->unit != Value::Operator || val->iValue != ',')
01583                 goto failed;
01584             valueList->next();
01585             allowComma = false;
01586         }
01587         else {
01588             switch (propId) {
01589                 case CSS_PROP_BACKGROUND_ATTACHMENT:
01590                     if (val->id == CSS_VAL_SCROLL || val->id == CSS_VAL_FIXED) {
01591                         currValue = new CSSPrimitiveValueImpl(val->id);
01592                         valueList->next();
01593                     }
01594                     break;
01595                 case CSS_PROP_BACKGROUND_COLOR:
01596                     currValue = parseBackgroundColor();
01597                     if (currValue)
01598                         valueList->next();
01599                     break;
01600                 case CSS_PROP_BACKGROUND_IMAGE:
01601                     currValue = parseBackgroundImage();
01602                     if (currValue)
01603                         valueList->next();
01604                     break;
01605                 case CSS_PROP__KHTML_BACKGROUND_CLIP:
01606                 case CSS_PROP__KHTML_BACKGROUND_ORIGIN:
01607                     if (val->id == CSS_VAL_BORDER || val->id == CSS_VAL_PADDING || val->id == CSS_VAL_CONTENT) {
01608                         currValue = new CSSPrimitiveValueImpl(val->id);
01609                         valueList->next();
01610                     }
01611                     break;
01612                 case CSS_PROP_BACKGROUND_POSITION:
01613                     parseBackgroundPosition(currValue, currValue2);
01614                     // unlike the other functions, parseBackgroundPosition advances the valueList pointer
01615                     break;
01616                 case CSS_PROP_BACKGROUND_POSITION_X: {
01617                     bool xFound = false, yFound = true;
01618                     currValue = parseBackgroundPositionXY(xFound, yFound);
01619                     if (currValue)
01620                         valueList->next();
01621                     break;
01622                 }
01623                 case CSS_PROP_BACKGROUND_POSITION_Y: {
01624                     bool xFound = true, yFound = false;
01625                     currValue = parseBackgroundPositionXY(xFound, yFound);
01626                     if (currValue)
01627                         valueList->next();
01628                     break;
01629                 }
01630                 case CSS_PROP_BACKGROUND_REPEAT:
01631                     if (val->id >= CSS_VAL_REPEAT && val->id <= CSS_VAL_NO_REPEAT) {
01632                         currValue = new CSSPrimitiveValueImpl(val->id);
01633                         valueList->next();
01634                     }
01635                     break;
01636                 case CSS_PROP__KHTML_BACKGROUND_SIZE:
01637                     currValue = parseBackgroundSize();
01638                     if (currValue)
01639                         valueList->next();
01640                     break;
01641             }
01642 
01643             if (!currValue)
01644                 goto failed;
01645 
01646             if (value && !values) {
01647                 values = new CSSValueListImpl();
01648                 values->append(value);
01649                 value = 0;
01650             }
01651 
01652             if (value2 && !values2) {
01653                 values2 = new CSSValueListImpl();
01654                 values2->append(value2);
01655                 value2 = 0;
01656             }
01657 
01658             if (values)
01659                 values->append(currValue);
01660             else
01661                 value = currValue;
01662             if (currValue2) {
01663                 if (values2)
01664                     values2->append(currValue2);
01665                 else
01666                     value2 = currValue2;
01667             }
01668             allowComma = true;
01669         }
01670 
01671         // When parsing the 'background' shorthand property, we let it handle building up the lists for all
01672         // properties.
01673         if (inShorthand())
01674             break;
01675     }
01676 
01677     if (values && values->length()) {
01678         retValue1 = values;
01679         if (values2 && values2->length())
01680             retValue2 = values2;
01681         return true;
01682     }
01683     if (value) {
01684         retValue1 = value;
01685         retValue2 = value2;
01686         return true;
01687     }
01688 
01689 failed:
01690     delete values; delete values2;
01691     delete value; delete value2;
01692     return false;
01693 }
01694 
01695 bool CSSParser::parseShape( int propId, bool important )
01696 {
01697     Value *value = valueList->current();
01698     ValueList *args = value->function->args;
01699     QString fname = qString( value->function->name ).lower();
01700     //qDebug( "parseShape: fname: %d", fname.latin1() );
01701     if ( fname != "rect(" || !args )
01702         return false;
01703 
01704     // rect( t, r, b, l ) || rect( t r b l )
01705     if ( args->size() != 4 && args->size() != 7 )
01706         return false;
01707     RectImpl *rect = new RectImpl();
01708     bool valid = true;
01709     int i = 0;
01710     Value *a = args->current();
01711     while ( a ) {
01712         valid = validUnit( a, FLength, strict );
01713         if ( !valid )
01714             break;
01715         CSSPrimitiveValueImpl *length =
01716             new CSSPrimitiveValueImpl( a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit );
01717         if ( i == 0 )
01718             rect->setTop( length );
01719         else if ( i == 1 )
01720             rect->setRight( length );
01721         else if ( i == 2 )
01722             rect->setBottom( length );
01723         else
01724             rect->setLeft( length );
01725         a = args->next();
01726         if ( a && args->size() == 7 ) {
01727             if ( a->unit == Value::Operator && a->iValue == ',' ) {
01728                 a = args->next();
01729             } else {
01730                 valid = false;
01731                 break;
01732             }
01733         }
01734         i++;
01735     }
01736     if ( valid ) {
01737         addProperty( propId, new CSSPrimitiveValueImpl( rect ), important );
01738         valueList->next();
01739         return true;
01740     }
01741     delete rect;
01742     return false;
01743 }
01744 
01745 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
01746 bool CSSParser::parseFont( bool important )
01747 {
01748 //     kdDebug(6080) << "parsing font property current=" << valueList->currentValue << endl;
01749     bool valid = true;
01750     Value *value = valueList->current();
01751     FontValueImpl *font = new FontValueImpl;
01752     // optional font-style, font-variant and font-weight
01753     while ( value ) {
01754 //         kdDebug( 6080 ) << "got value " << value->id << " / " << (value->unit == CSSPrimitiveValue::CSS_STRING ||
01755         //                                    value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
01756 //                         << endl;
01757         int id = value->id;
01758         if ( id ) {
01759             if ( id == CSS_VAL_NORMAL ) {
01760                 // do nothing, it's the initial value for all three
01761             }
01762             /*
01763               else if ( id == CSS_VAL_INHERIT ) {
01764               // set all non set ones to inherit
01765               // This is not that simple as the inherit could also apply to the following font-size.
01766               // very ahrd to tell without looking ahead.
01767               inherit = true;
01768                 } */
01769             else if ( id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE ) {
01770                 if ( font->style )
01771                     goto invalid;
01772                 font->style = new CSSPrimitiveValueImpl( id );
01773             } else if ( id == CSS_VAL_SMALL_CAPS ) {
01774                 if ( font->variant )
01775                     goto invalid;
01776                 font->variant = new CSSPrimitiveValueImpl( id );
01777             } else if ( id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER ) {
01778                 if ( font->weight )
01779                     goto invalid;
01780                 font->weight = new CSSPrimitiveValueImpl( id );
01781             } else {
01782                 valid = false;
01783             }
01784         } else if ( !font->weight && validUnit( value, FInteger|FNonNeg, true ) ) {
01785             int weight = (int)value->fValue;
01786             int val = 0;
01787             if ( weight == 100 )
01788                 val = CSS_VAL_100;
01789             else if ( weight == 200 )
01790                 val = CSS_VAL_200;
01791             else if ( weight == 300 )
01792                 val = CSS_VAL_300;
01793             else if ( weight == 400 )
01794                 val = CSS_VAL_400;
01795             else if ( weight == 500 )
01796                 val = CSS_VAL_500;
01797             else if ( weight == 600 )
01798                 val = CSS_VAL_600;
01799             else if ( weight == 700 )
01800                 val = CSS_VAL_700;
01801             else if ( weight == 800 )
01802                 val = CSS_VAL_800;
01803             else if ( weight == 900 )
01804                 val = CSS_VAL_900;
01805 
01806             if ( val )
01807                 font->weight = new CSSPrimitiveValueImpl( val );
01808             else
01809                 valid = false;
01810         } else {
01811             valid = false;
01812         }
01813         if ( !valid )
01814             break;
01815         value = valueList->next();
01816     }
01817     if ( !value )
01818         goto invalid;
01819 
01820     // set undefined values to default
01821     if ( !font->style )
01822         font->style = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01823     if ( !font->variant )
01824         font->variant = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01825     if ( !font->weight )
01826         font->weight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01827 
01828 //     kdDebug( 6080 ) << "  got style, variant and weight current=" << valueList->currentValue << endl;
01829 
01830     // now a font size _must_ come
01831     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
01832     if ( value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER )
01833         font->size = new CSSPrimitiveValueImpl( value->id );
01834     else if ( validUnit( value, FLength|FPercent, strict ) ) {
01835         font->size = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01836     }
01837     value = valueList->next();
01838     if ( !font->size || !value )
01839         goto invalid;
01840 
01841     // kdDebug( 6080 ) << "  got size" << endl;
01842 
01843     if ( value->unit == Value::Operator && value->iValue == '/' ) {
01844         // line-height
01845         value = valueList->next();
01846         if ( !value )
01847             goto invalid;
01848         if ( value->id == CSS_VAL_NORMAL ) {
01849             // default value, nothing to do
01850         } else if ( validUnit( value, FNumber|FLength|FPercent, strict ) ) {
01851             font->lineHeight = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01852         } else {
01853             goto invalid;
01854         }
01855         value = valueList->next();
01856         if ( !value )
01857             goto invalid;
01858     }
01859     if ( !font->lineHeight )
01860         font->lineHeight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01861 
01862 //     kdDebug( 6080 ) << "  got line height current=" << valueList->currentValue << endl;
01863     // font family must come now
01864     font->family = parseFontFamily();
01865 
01866     if ( valueList->current() || !font->family )
01867         goto invalid;
01868     //kdDebug( 6080 ) << "  got family, parsing ok!" << endl;
01869 
01870     addProperty( CSS_PROP_FONT, font, important );
01871     return true;
01872 
01873  invalid:
01874     //kdDebug(6080) << "   -> invalid" << endl;
01875     delete font;
01876     return false;
01877 }
01878 
01879 CSSValueListImpl *CSSParser::parseFontFamily()
01880 {
01881 //     kdDebug( 6080 ) << "CSSParser::parseFontFamily current=" << valueList->currentValue << endl;
01882     CSSValueListImpl *list = new CSSValueListImpl;
01883     Value *value = valueList->current();
01884     QString currFace;
01885 
01886     while ( value ) {
01887 //         kdDebug( 6080 ) << "got value " << value->id << " / "
01888 //                         << (value->unit == CSSPrimitiveValue::CSS_STRING ||
01889 //                             value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
01890 //                         << endl;
01891         Value* nextValue = valueList->next();
01892         bool nextValBreaksFont = !nextValue ||
01893                                  (nextValue->unit == Value::Operator && nextValue->iValue == ',');
01894         bool nextValIsFontName = nextValue &&
01895                                  ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL_MONOSPACE) ||
01896                                   (nextValue->unit == CSSPrimitiveValue::CSS_STRING ||
01897                                    nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
01898 
01899         if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL_MONOSPACE) {
01900             if (!currFace.isNull()) {
01901                 currFace += ' ';
01902                 currFace += qString(value->string);
01903             }
01904             else if (nextValBreaksFont || !nextValIsFontName) {
01905                 if ( !currFace.isNull() ) {
01906                     list->append( new FontFamilyValueImpl( currFace ) );
01907                     currFace = QString::null;
01908                 }
01909                 list->append(new CSSPrimitiveValueImpl(value->id));
01910             }
01911             else {
01912                 currFace = qString( value->string );
01913             }
01914         }
01915         else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
01916             // Strings never share in a family name.
01917             currFace = QString::null;
01918             list->append(new FontFamilyValueImpl(qString( value->string) ) );
01919         }
01920         else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
01921             if (!currFace.isNull()) {
01922                 currFace += ' ';
01923                 currFace += qString(value->string);
01924             }
01925             else if (nextValBreaksFont || !nextValIsFontName) {
01926                 if ( !currFace.isNull() ) {
01927                     list->append( new FontFamilyValueImpl( currFace ) );
01928                     currFace = QString::null;
01929                 }
01930                 list->append(new FontFamilyValueImpl( qString( value->string ) ) );
01931         }
01932         else {
01933                 currFace = qString( value->string);
01934         }
01935         }
01936     else {
01937         //kdDebug( 6080 ) << "invalid family part" << endl;
01938             break;
01939         }
01940 
01941         if (!nextValue)
01942             break;
01943 
01944         if (nextValBreaksFont) {
01945         value = valueList->next();
01946             if ( !currFace.isNull() )
01947                 list->append( new FontFamilyValueImpl( currFace ) );
01948             currFace = QString::null;
01949         }
01950         else if (nextValIsFontName)
01951             value = nextValue;
01952         else
01953             break;
01954     }
01955 
01956     if ( !currFace.isNull() )
01957         list->append( new FontFamilyValueImpl( currFace ) );
01958 
01959     if ( !list->length() ) {
01960         delete list;
01961         list = 0;
01962     }
01963     return list;
01964 }
01965 
01966  
01967 bool CSSParser::parseColorParameters(Value* value, int* colorArray, bool parseAlpha)
01968 {
01969     ValueList* args = value->function->args;
01970     Value* v = args->current();
01971     // Get the first value
01972     if (!validUnit(v, FInteger | FPercent, true))
01973         return false;
01974     colorArray[0] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
01975     for (int i = 1; i < 3; i++) {
01976         v = args->next();
01977         if (v->unit != Value::Operator && v->iValue != ',')
01978             return false;
01979         v = args->next();
01980         if (!validUnit(v, FInteger | FPercent, true))
01981             return false;
01982         colorArray[i] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
01983     }
01984     if (parseAlpha) {
01985         v = args->next();
01986         if (v->unit != Value::Operator && v->iValue != ',')
01987             return false;
01988         v = args->next();
01989         if (!validUnit(v, FNumber, true))
01990             return false;
01991         colorArray[3] = static_cast<int>(kMax(0.0, kMin(1.0, v->fValue)) * 255);
01992     }
01993     return true;
01994 }
01995  
01996 // CSS3 specification defines the format of a HSL color as
01997 // hsl(<number>, <percent>, <percent>)
01998 // and with alpha, the format is
01999 // hsla(<number>, <percent>, <percent>, <number>)
02000 // The first value, HUE, is in an angle with a value between 0 and 360
02001 bool CSSParser::parseHSLParameters(Value* value, double* colorArray, bool parseAlpha)
02002 {
02003     ValueList* args = value->function->args;
02004     Value* v = args->current();
02005     // Get the first value
02006     if (!validUnit(v, FInteger, true))
02007         return false;
02008     // normalize the Hue value and change it to be between 0 and 1.0
02009     colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
02010     for (int i = 1; i < 3; i++) {
02011         v = args->next();
02012         if (v->unit != Value::Operator && v->iValue != ',')
02013             return false;
02014         v = args->next();
02015         if (!validUnit(v, FPercent, true))
02016             return false;
02017         colorArray[i] = kMax(0.0, kMin(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0
02018     }
02019     if (parseAlpha) {
02020         v = args->next();
02021         if (v->unit != Value::Operator && v->iValue != ',')
02022             return false;
02023         v = args->next();
02024         if (!validUnit(v, FNumber, true))
02025             return false;
02026         colorArray[3] = kMax(0.0, kMin(1.0, v->fValue));
02027     }
02028     return true;
02029 }
02030 
02031 static bool parseColor(int unit, const QString &name, QRgb& rgb)
02032 {
02033     int len = name.length();
02034 
02035     if ( !len )
02036         return false;
02037 
02038 
02039     bool ok;
02040 
02041     if ( len == 3 || len == 6 ) {
02042         int val = name.toInt(&ok, 16);
02043         if ( ok ) {
02044             if (len == 6) {
02045                 rgb = (0xff << 24) | val;
02046                 return true;
02047             }
02048             else if ( len == 3 ) {
02049                 // #abc converts to #aabbcc according to the specs
02050                 rgb = (0xff << 24) |
02051                       (val&0xf00)<<12 | (val&0xf00)<<8 |
02052                       (val&0xf0)<<8 | (val&0xf0)<<4 |
02053                       (val&0xf)<<4 | (val&0xf);
02054                 return true;
02055             }
02056         }
02057     }
02058 
02059     if ( unit == CSSPrimitiveValue::CSS_IDENT ) {
02060         // try a little harder
02061         QColor tc;
02062         tc.setNamedColor(name.lower());
02063         if ( tc.isValid() ) {
02064             rgb = tc.rgb();
02065             return true;
02066         }
02067     }
02068 
02069     return false;
02070 }
02071 
02072 CSSPrimitiveValueImpl *CSSParser::parseColor()
02073 {
02074     return parseColorFromValue(valueList->current());
02075 }
02076 
02077 CSSPrimitiveValueImpl *CSSParser::parseColorFromValue(Value* value)
02078 {
02079     QRgb c = khtml::transparentColor;
02080     if ( !strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
02081               value->fValue >= 0. && value->fValue < 1000000. ) {
02082         QString str;
02083         str.sprintf( "%06d", (int)(value->fValue+.5) );
02084         if ( !::parseColor( value->unit, str, c ) )
02085             return 0;
02086     }
02087     else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
02088              value->unit == CSSPrimitiveValue::CSS_IDENT ||
02089              (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
02090         if ( !::parseColor( value->unit, qString( value->string ), c) )
02091             return 0;
02092     }
02093     else if ( value->unit == Value::Function &&
02094         value->function->args != 0 &&
02095                 value->function->args->size() == 5 /* rgb + two commas */ &&
02096                 qString( value->function->name ).lower() == "rgb(" ) {
02097         int colorValues[3];
02098         if (!parseColorParameters(value, colorValues, false))
02099             return 0;
02100         colorValues[0] = kMax( 0, kMin( 255, colorValues[0] ) );
02101         colorValues[1] = kMax( 0, kMin( 255, colorValues[1] ) );
02102         colorValues[2] = kMax( 0, kMin( 255, colorValues[2] ) );
02103         c = qRgb(colorValues[0], colorValues[1], colorValues[2]);
02104     } else if (value->unit == Value::Function &&
02105                 value->function->args != 0 &&
02106                 value->function->args->size() == 7 /* rgba + three commas */ &&
02107                 domString(value->function->name).lower() == "rgba(") {
02108         int colorValues[4];
02109         if (!parseColorParameters(value, colorValues, true))
02110             return 0;
02111         colorValues[0] = kMax( 0, kMin( 255, colorValues[0] ) );
02112         colorValues[1] = kMax( 0, kMin( 255, colorValues[1] ) );
02113         colorValues[2] = kMax( 0, kMin( 255, colorValues[2] ) );
02114         c = qRgba(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
02115     } else if (value->unit == Value::Function &&
02116                 value->function->args != 0 &&
02117                 value->function->args->size() == 5 /* hsl + two commas */ &&
02118                 domString(value->function->name).lower() == "hsl(") {
02119         double colorValues[3];
02120         if (!parseHSLParameters(value, colorValues, false))
02121             return 0;
02122         c = khtml::qRgbaFromHsla(colorValues[0], colorValues[1], colorValues[2], 1.0);
02123     } else if (value->unit == Value::Function &&
02124                 value->function->args != 0 &&
02125                 value->function->args->size() == 7 /* hsla + three commas */ &&
02126                 domString(value->function->name).lower() == "hsla(") {
02127         double colorValues[4];
02128         if (!parseHSLParameters(value, colorValues, true))
02129             return 0;
02130         c = khtml::qRgbaFromHsla(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
02131     }
02132     else
02133         return 0;
02134 
02135     return new CSSPrimitiveValueImpl(c);
02136 }
02137 
02138 // This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
02139 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
02140 struct ShadowParseContext {
02141     ShadowParseContext()
02142     :values(0), x(0), y(0), blur(0), color(0),
02143      allowX(true), allowY(false), allowBlur(false), allowColor(true),
02144      allowBreak(true)
02145     {}
02146 
02147     ~ShadowParseContext() {
02148         if (!allowBreak) {
02149             delete values;
02150             delete x;
02151             delete y;
02152             delete blur;
02153             delete color;
02154         }
02155     }
02156 
02157     bool allowLength() { return allowX || allowY || allowBlur; }
02158 
02159     bool failed() { return allowBreak = false; }
02160 
02161     void commitValue() {
02162         // Handle the ,, case gracefully by doing nothing.
02163         if (x || y || blur || color) {
02164             if (!values)
02165                 values = new CSSValueListImpl();
02166 
02167             // Construct the current shadow value and add it to the list.
02168             values->append(new ShadowValueImpl(x, y, blur, color));
02169         }
02170 
02171         // Now reset for the next shadow value.
02172         x = y = blur = color = 0;
02173         allowX = allowColor = allowBreak = true;
02174         allowY = allowBlur = false;
02175     }
02176 
02177     void commitLength(Value* v) {
02178         CSSPrimitiveValueImpl* val = new CSSPrimitiveValueImpl(v->fValue,
02179                                                                (CSSPrimitiveValue::UnitTypes)v->unit);
02180         if (allowX) {
02181             x = val;
02182             allowX = false; allowY = true; allowColor = false; allowBreak = false;
02183         }
02184         else if (allowY) {
02185             y = val;
02186             allowY = false; allowBlur = true; allowColor = true; allowBreak = true;
02187         }
02188         else if (allowBlur) {
02189             blur = val;
02190             allowBlur = false;
02191         }
02192     else
02193         delete val;
02194     }
02195 
02196     void commitColor(CSSPrimitiveValueImpl* val) {
02197         color = val;
02198         allowColor = false;
02199         if (allowX)
02200             allowBreak = false;
02201         else
02202             allowBlur = false;
02203     }
02204 
02205     CSSValueListImpl* values;
02206     CSSPrimitiveValueImpl* x;
02207     CSSPrimitiveValueImpl* y;
02208     CSSPrimitiveValueImpl* blur;
02209     CSSPrimitiveValueImpl* color;
02210 
02211     bool allowX;
02212     bool allowY;
02213     bool allowBlur;
02214     bool allowColor;
02215     bool allowBreak;
02216 };
02217 
02218 bool CSSParser::parseShadow(int propId, bool important)
02219 {
02220     ShadowParseContext context;
02221     Value* val;
02222     while ((val = valueList->current())) {
02223         // Check for a comma break first.
02224         if (val->unit == Value::Operator) {
02225             if (val->iValue != ',' || !context.allowBreak)
02226                 // Other operators aren't legal or we aren't done with the current shadow
02227                 // value.  Treat as invalid.
02228                 return context.failed();
02229 
02230             // The value is good.  Commit it.
02231             context.commitValue();
02232         }
02233         // Check to see if we're a length.
02234         else if (validUnit(val, FLength, true)) {
02235             // We required a length and didn't get one. Invalid.
02236             if (!context.allowLength())
02237                 return context.failed();
02238 
02239             // A length is allowed here.  Construct the value and add it.
02240             context.commitLength(val);
02241         }
02242         else {
02243             // The only other type of value that's ok is a color value.
02244             CSSPrimitiveValueImpl* parsedColor = 0;
02245             bool isColor = (val->id >= CSS_VAL_AQUA && val->id <= CSS_VAL_WINDOWTEXT || val->id == CSS_VAL_MENU ||
02246                            (val->id >= CSS_VAL_GREY && val->id <= CSS_VAL__KHTML_TEXT && !strict));
02247         if (!context.allowColor)
02248                 return context.failed();
02249 
02250             if (isColor)
02251                parsedColor = new CSSPrimitiveValueImpl(val->id);
02252 
02253             if (!parsedColor)
02254                 // It's not built-in. Try to parse it as a color.
02255                 parsedColor = parseColorFromValue(val);
02256 
02257             if (!parsedColor)
02258                 return context.failed();
02259 
02260             context.commitColor(parsedColor);
02261         }
02262 
02263         valueList->next();
02264     }
02265 
02266     if (context.allowBreak) {
02267         context.commitValue();
02268         if (context.values->length()) {
02269             addProperty(propId, context.values, important);
02270             valueList->next();
02271             return true;
02272         }
02273     }
02274 
02275     return context.failed();
02276 }
02277 
02278 bool CSSParser::parseCounter(int propId, bool increment, bool important)
02279 {
02280     enum { ID, VAL, COMMA } state = ID;
02281 
02282     CSSValueListImpl *list = new CSSValueListImpl;
02283     DOMString c;
02284     Value* val;
02285     while (true) {
02286         val = valueList->current();
02287         switch (state) {
02288             // Commas are not allowed according to the standard, but Opera allows them and being the only
02289             // other browser with counter support we need to match their behavior to work with current use
02290             case COMMA:
02291                 state = ID;
02292                 if (val && val->unit == Value::Operator && val->iValue == ',') {
02293                     valueList->next();
02294                     continue;
02295                 }
02296                 // no break
02297             case ID:
02298                 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
02299                     c = qString(val->string);
02300                     state = VAL;
02301                     valueList->next();
02302                     continue;
02303                 }
02304                 break;
02305             case VAL: {
02306                 short i = 0;
02307                 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
02308                     i = (short)val->fValue;
02309                     valueList->next();
02310                 } else
02311                     i = (increment) ? 1 : 0;
02312 
02313                 CounterActImpl *cv = new CounterActImpl(c,i);
02314                 list->append(cv);
02315                 state = COMMA;
02316                 continue;
02317             }
02318         }
02319         break;
02320     }
02321     if(list->length() > 0) {
02322         addProperty( propId, list, important );
02323         return true;
02324     }
02325     delete list;
02326     return false;
02327 }
02328 
02329 static inline int yyerror( const char *str ) {
02330 //    assert( 0 );
02331 #ifdef CSS_DEBUG
02332     kdDebug( 6080 ) << "CSS parse error " << str << endl;
02333 #else
02334     Q_UNUSED( str );
02335 #endif
02336     return 1;
02337 }
02338 
02339 #define END 0
02340 
02341 #include "parser.h"
02342 
02343 int DOM::CSSParser::lex( void *_yylval )
02344 {
02345     YYSTYPE *yylval = (YYSTYPE *)_yylval;
02346     int token = lex();
02347     int length;
02348     unsigned short *t = text( &length );
02349 
02350 #ifdef TOKEN_DEBUG
02351     qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString( (QChar *)t, length ).latin1() );
02352 #endif
02353     switch( token ) {
02354     case '{':
02355         block_nesting++;
02356         break;
02357     case '}':
02358         if ( block_nesting )
02359             block_nesting--;
02360         break;
02361     case END:
02362         if ( block_nesting ) {
02363             block_nesting--;
02364             return '}';
02365         }
02366         break;
02367     case S:
02368     case SGML_CD:
02369     case INCLUDES:
02370     case DASHMATCH:
02371         break;
02372 
02373     case URI:
02374     case STRING:
02375     case IDENT:
02376     case NTH:
02377     case HASH:
02378     case DIMEN:
02379     case UNICODERANGE:
02380     case NOTFUNCTION:
02381     case FUNCTION:
02382         yylval->string.string = t;
02383         yylval->string.length = length;
02384         break;
02385 
02386     case IMPORT_SYM:
02387     case PAGE_SYM:
02388     case MEDIA_SYM:
02389     case FONT_FACE_SYM:
02390     case CHARSET_SYM:
02391     case NAMESPACE_SYM:
02392 
02393     case IMPORTANT_SYM:
02394         break;
02395 
02396     case QEMS:
02397         length--;
02398     case GRADS:
02399         length--;
02400     case DEGS:
02401     case RADS:
02402     case KHERZ:
02403         length--;
02404     case MSECS:
02405     case HERZ:
02406     case EMS:
02407     case EXS:
02408     case PXS:
02409     case CMS:
02410     case MMS:
02411     case INS:
02412     case PTS:
02413     case PCS:
02414         length--;
02415     case SECS:
02416     case PERCENTAGE:
02417         length--;
02418     case FLOAT:
02419     case INTEGER:
02420         yylval->val = QString( (QChar *)t, length ).toDouble();
02421         //qDebug("value = %s, converted=%.2f", QString( (QChar *)t, length ).latin1(), yylval->val );
02422         break;
02423 
02424     default:
02425         break;
02426     }
02427 
02428     return token;
02429 }
02430 
02431 static inline int toHex( char c ) {
02432     if ( '0' <= c && c <= '9' )
02433         return c - '0';
02434     if ( 'a' <= c && c <= 'f' )
02435         return c - 'a' + 10;
02436     if ( 'A' <= c && c<= 'F' )
02437         return c - 'A' + 10;
02438     return 0;
02439 }
02440 
02441 unsigned short *DOM::CSSParser::text(int *length)
02442 {
02443     unsigned short *start = yytext;
02444     int l = yyleng;
02445     switch( yyTok ) {
02446     case STRING:
02447         l--;
02448         /* nobreak */
02449     case HASH:
02450         start++;
02451         l--;
02452         break;
02453     case URI:
02454         // "url("{w}{string}{w}")"
02455         // "url("{w}{url}{w}")"
02456 
02457         // strip "url(" and ")"
02458         start += 4;
02459         l -= 5;
02460         // strip {w}
02461         while ( l &&
02462                 (*start == ' ' || *start == '\t' || *start == '\r' ||
02463                  *start == '\n' || *start == '\f' ) ) {
02464             start++; l--;
02465         }
02466         if ( *start == '"' || *start == '\'' ) {
02467             start++; l--;
02468         }
02469         while ( l &&
02470                 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
02471                  start[l-1] == '\n' || start[l-1] == '\f' ) ) {
02472             l--;
02473         }
02474         if ( l && (start[l-1] == '\"' || start[l-1] == '\'' ) )
02475              l--;
02476 
02477     default:
02478         break;
02479     }
02480 
02481     // process escapes
02482     unsigned short *out = start;
02483     unsigned short *escape = 0;
02484 
02485     for ( int i = 0; i < l; i++ ) {
02486         unsigned short *current = start+i;
02487         if ( escape == current - 1 ) {
02488             if ( ( *current >= '0' && *current <= '9' ) ||
02489                  ( *current >= 'a' && *current <= 'f' ) ||
02490                  ( *current >= 'A' && *current <= 'F' ) )
02491                 continue;
02492             if ( yyTok == STRING &&
02493                  ( *current == '\n' || *current == '\r' || *current == '\f' ) ) {
02494                 // ### handle \r\n case
02495                 if ( *current != '\r' )
02496                     escape = 0;
02497                 continue;
02498             }
02499             // in all other cases copy the char to output
02500             // ###
02501             *out++ = *current;
02502             escape = 0;
02503             continue;
02504         }
02505         if ( escape == current - 2 && yyTok == STRING &&
02506              *(current-1) == '\r' && *current == '\n' ) {
02507             escape = 0;
02508             continue;
02509         }
02510         if ( escape > current - 7 &&
02511              ( ( *current >= '0' && *current <= '9' ) ||
02512                ( *current >= 'a' && *current <= 'f' ) ||
02513                ( *current >= 'A' && *current <= 'F' ) ) )
02514                 continue;
02515         if ( escape ) {
02516             // add escaped char
02517             int uc = 0;
02518             escape++;
02519             while ( escape < current ) {
02520 //                 qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
02521                 uc *= 16;
02522                 uc += toHex( *escape );
02523                 escape++;
02524             }
02525 //             qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
02526             // can't handle chars outside ucs2
02527             if ( uc > 0xffff )
02528                 uc = 0xfffd;
02529             *(out++) = (unsigned short)uc;
02530             escape = 0;
02531             if ( *current == ' ' ||
02532                  *current == '\t' ||
02533                  *current == '\r' ||
02534                  *current == '\n' ||
02535                  *current == '\f' )
02536                 continue;
02537         }
02538         if ( !escape && *current == '\\' ) {
02539             escape = current;
02540             continue;
02541         }
02542         *(out++) = *current;
02543     }
02544     if ( escape ) {
02545         // add escaped char
02546         int uc = 0;
02547         escape++;
02548         while ( escape < start+l ) {
02549             //                 qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
02550             uc *= 16;
02551             uc += toHex( *escape );
02552             escape++;
02553         }
02554         //             qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
02555         // can't handle chars outside ucs2
02556         if ( uc > 0xffff )
02557             uc = 0xfffd;
02558         *(out++) = (unsigned short)uc;
02559     }
02560 
02561     *length = out - start;
02562     return start;
02563 }
02564 
02565 
02566 #define YY_DECL int DOM::CSSParser::lex()
02567 #define yyconst const
02568 typedef int yy_state_type;
02569 typedef unsigned int YY_CHAR;
02570 // this line makes sure we treat all Unicode chars correctly.
02571 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
02572 #define YY_DO_BEFORE_ACTION \
02573         yytext = yy_bp; \
02574         yyleng = (int) (yy_cp - yy_bp); \
02575         yy_hold_char = *yy_cp; \
02576         *yy_cp = 0; \
02577         yy_c_buf_p = yy_cp;
02578 #define YY_BREAK break;
02579 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).latin1() )
02580 #define YY_RULE_SETUP
02581 #define INITIAL 0
02582 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
02583 #define YY_START ((yy_start - 1) / 2)
02584 #define yyterminate() yyTok = END; return yyTok
02585 #define YY_FATAL_ERROR(a) qFatal(a)
02586 #define BEGIN yy_start = 1 + 2 *
02587 #define COMMENT 1
02588 
02589 #include "tokenizer.cpp"
KDE Home | KDE Accessibility Home | Description of Access Keys