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                 parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR);
01342             }
01343             else
01344             if (fname == "counter(") {
01345                 parsedValue = parseCounterContent(args, false);
01346                 if (!parsedValue) return false;
01347             } else
01348             if (fname == "counters(") {
01349                 parsedValue = parseCounterContent(args, true);
01350                 if (!parsedValue) return false;
01351             }
01352             else
01353                 return false;
01354 
01355         } else if ( val->unit == CSSPrimitiveValue::CSS_IDENT ) {
01356             // open-quote | close-quote | no-open-quote | no-close-quote
01357             if ( val->id == CSS_VAL_OPEN_QUOTE ||
01358                  val->id == CSS_VAL_CLOSE_QUOTE ||
01359                  val->id == CSS_VAL_NO_OPEN_QUOTE ||
01360                  val->id == CSS_VAL_NO_CLOSE_QUOTE ) {
01361                 parsedValue = new CSSPrimitiveValueImpl(val->id);
01362             }
01363         } else if ( val->unit == CSSPrimitiveValue::CSS_STRING ) {
01364             parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING);
01365         }
01366 
01367         if (parsedValue)
01368             values->append(parsedValue);
01369         else {
01370             isValid = false;
01371             break;
01372         }
01373         valueList->next();
01374     }
01375     if ( isValid && values->length() ) {
01376         addProperty( propId, values, important );
01377         valueList->next();
01378         return true;
01379     }
01380 
01381     delete values;  // also frees any content by deref
01382     return false;
01383 }
01384 
01385 CSSValueImpl* CSSParser::parseCounterContent(ValueList *args, bool counters)
01386 {
01387     if (counters || (args->size() != 1 && args->size() != 3))
01388         if (!counters || (args->size() != 3 && args->size() != 5))
01389             return 0;
01390 
01391     CounterImpl *counter = new CounterImpl;
01392     Value *i = args->current();
01393 //    if (i->unit != CSSPrimitiveValue::CSS_IDENT) goto invalid;
01394     counter->m_identifier = domString(i->string);
01395     if (counters) {
01396         i = args->next();
01397         if (i->unit != Value::Operator || i->iValue != ',') goto invalid;
01398         i = args->next();
01399         if (i->unit != CSSPrimitiveValue::CSS_STRING) goto invalid;
01400         counter->m_separator = domString(i->string);
01401     }
01402     counter->m_listStyle = CSS_VAL_DECIMAL - CSS_VAL_DISC;
01403     i = args->next();
01404     if (i) {
01405         if (i->unit != Value::Operator || i->iValue != ',') goto invalid;
01406         i = args->next();
01407         if (i->unit != CSSPrimitiveValue::CSS_IDENT) goto invalid;
01408         if (i->id < CSS_VAL_DISC || i->id > CSS_VAL__KHTML_CLOSE_QUOTE) goto invalid;
01409         counter->m_listStyle = i->id - CSS_VAL_DISC;
01410     }
01411     return new CSSPrimitiveValueImpl(counter);
01412 invalid:
01413     delete counter;
01414     return 0;
01415 }
01416 
01417 CSSValueImpl* CSSParser::parseBackgroundColor()
01418 {
01419     int id = valueList->current()->id;
01420     if (id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_TRANSPARENT ||
01421         (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || id == CSS_VAL_MENU ||
01422         (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict))
01423        return new CSSPrimitiveValueImpl(id);
01424     return parseColor();
01425 }
01426 
01427 CSSValueImpl* CSSParser::parseBackgroundImage()
01428 {
01429     if (valueList->current()->id == CSS_VAL_NONE)
01430         return new CSSImageValueImpl();
01431     if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
01432         DOMString uri = khtml::parseURL(domString(valueList->current()->string));
01433         if (!uri.isEmpty())
01434             return new CSSImageValueImpl(DOMString(KURL(styleElement->baseURL(), uri.string()).url()),
01435                                          styleElement);
01436     }
01437     return 0;
01438 }
01439 
01440 CSSValueImpl* CSSParser::parseBackgroundPositionXY(bool& xFound, bool& yFound)
01441 {
01442     int id = valueList->current()->id;
01443     if (id == CSS_VAL_LEFT || id == CSS_VAL_TOP || id == CSS_VAL_RIGHT || id == CSS_VAL_BOTTOM || id == CSS_VAL_CENTER) {
01444         int percent = 0;
01445         if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT) {
01446             if (xFound)
01447                 return 0;
01448             xFound = true;
01449             if (id == CSS_VAL_RIGHT)
01450                 percent = 100;
01451         }
01452         else if (id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
01453             if (yFound)
01454                 return 0;
01455             yFound = true;
01456             if (id == CSS_VAL_BOTTOM)
01457                 percent = 100;
01458         }
01459         else if (id == CSS_VAL_CENTER)
01460             // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
01461             percent = 50;
01462         return new CSSPrimitiveValueImpl(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
01463     }
01464     if (validUnit(valueList->current(), FPercent|FLength, strict))
01465         return new CSSPrimitiveValueImpl(valueList->current()->fValue,
01466                                          (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
01467 
01468     return 0;
01469 }
01470 
01471 void CSSParser::parseBackgroundPosition(CSSValueImpl*& value1, CSSValueImpl*& value2)
01472 {
01473     value1 = value2 = 0;
01474     Value* value = valueList->current();
01475 
01476     // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
01477     bool value1IsX = false, value1IsY = false;
01478     value1 = parseBackgroundPositionXY(value1IsX, value1IsY);
01479     if (!value1)
01480         return;
01481 
01482     // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
01483     // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
01484     // value was explicitly specified for our property.
01485     value = valueList->next();
01486 
01487     // First check for the comma.  If so, we are finished parsing this value or value pair.
01488     if (value && value->unit == Value::Operator && value->iValue == ',')
01489         value = 0;
01490 
01491     bool value2IsX = false, value2IsY = false;
01492     if (value) {
01493         value2 = parseBackgroundPositionXY(value2IsX, value2IsY);
01494         if (value2)
01495             valueList->next();
01496         else {
01497             if (!inShorthand()) {
01498                 delete value1;
01499                 value1 = 0;
01500                 return;
01501             }
01502         }
01503     }
01504 
01505     if (!value2)
01506         // Only one value was specified.  If that value was not a keyword, then it sets the x position, and the y position
01507         // is simply 50%.  This is our default.
01508         // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
01509         // For left/right/center, the default of 50% in the y is still correct.
01510         value2 = new CSSPrimitiveValueImpl(50, CSSPrimitiveValue::CSS_PERCENTAGE);
01511 
01512     if (value1IsY || value2IsX) {
01513         // Swap our two values.
01514         CSSValueImpl* val = value2;
01515         value2 = value1;
01516         value1 = val;
01517     }
01518 }
01519 
01520 CSSValueImpl* CSSParser::parseBackgroundSize()
01521 {
01522     Value* value = valueList->current();
01523     CSSPrimitiveValueImpl* parsedValue1;
01524 
01525     if (value->id == CSS_VAL_AUTO)
01526         parsedValue1 = new CSSPrimitiveValueImpl(0, CSSPrimitiveValue::CSS_UNKNOWN);
01527     else {
01528         if (!validUnit(value, FLength|FPercent, strict))
01529             return 0;
01530         parsedValue1 = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
01531     }
01532 
01533     CSSPrimitiveValueImpl* parsedValue2 = parsedValue1;
01534     if ((value = valueList->next())) {
01535         if (value->id == CSS_VAL_AUTO)
01536             parsedValue2 = new CSSPrimitiveValueImpl(0, CSSPrimitiveValue::CSS_UNKNOWN);
01537         else {
01538             if (!validUnit(value, FLength|FPercent, strict)) {
01539                 delete parsedValue1;
01540                 return 0;
01541             }
01542             parsedValue2 = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
01543         }
01544     }
01545 
01546     PairImpl* pair = new PairImpl(parsedValue1, parsedValue2);
01547     return new CSSPrimitiveValueImpl(pair);
01548 }
01549 
01550 bool CSSParser::parseBackgroundProperty(int propId, int& propId1, int& propId2,
01551                                         CSSValueImpl*& retValue1, CSSValueImpl*& retValue2)
01552 {
01553 #ifdef CSS_DEBUG
01554     kdDebug(6080) << "parseBackgroundProperty()" << endl;
01555     kdDebug(6080) << "LOOKING FOR: " << getPropertyName(propId).string() << endl;
01556 #endif
01557     CSSValueListImpl *values = 0, *values2 = 0;
01558     Value* val;
01559     CSSValueImpl *value = 0, *value2 = 0;
01560     bool allowComma = false;
01561 
01562     retValue1 = retValue2 = 0;
01563     propId1 = propId;
01564     propId2 = propId;
01565     if (propId == CSS_PROP_BACKGROUND_POSITION) {
01566         propId1 = CSS_PROP_BACKGROUND_POSITION_X;
01567         propId2 = CSS_PROP_BACKGROUND_POSITION_Y;
01568     }
01569 
01570     while ((val = valueList->current())) {
01571         CSSValueImpl *currValue = 0, *currValue2 = 0;
01572         if (allowComma) {
01573             if (val->unit != Value::Operator || val->iValue != ',')
01574                 goto failed;
01575             valueList->next();
01576             allowComma = false;
01577         }
01578         else {
01579             switch (propId) {
01580                 case CSS_PROP_BACKGROUND_ATTACHMENT:
01581                     if (val->id == CSS_VAL_SCROLL || val->id == CSS_VAL_FIXED) {
01582                         currValue = new CSSPrimitiveValueImpl(val->id);
01583                         valueList->next();
01584                     }
01585                     break;
01586                 case CSS_PROP_BACKGROUND_COLOR:
01587                     currValue = parseBackgroundColor();
01588                     if (currValue)
01589                         valueList->next();
01590                     break;
01591                 case CSS_PROP_BACKGROUND_IMAGE:
01592                     currValue = parseBackgroundImage();
01593                     if (currValue)
01594                         valueList->next();
01595                     break;
01596                 case CSS_PROP__KHTML_BACKGROUND_CLIP:
01597                 case CSS_PROP__KHTML_BACKGROUND_ORIGIN:
01598                     if (val->id == CSS_VAL_BORDER || val->id == CSS_VAL_PADDING || val->id == CSS_VAL_CONTENT) {
01599                         currValue = new CSSPrimitiveValueImpl(val->id);
01600                         valueList->next();
01601                     }
01602                     break;
01603                 case CSS_PROP_BACKGROUND_POSITION:
01604                     parseBackgroundPosition(currValue, currValue2);
01605                     // unlike the other functions, parseBackgroundPosition advances the valueList pointer
01606                     break;
01607                 case CSS_PROP_BACKGROUND_POSITION_X: {
01608                     bool xFound = false, yFound = true;
01609                     currValue = parseBackgroundPositionXY(xFound, yFound);
01610                     if (currValue)
01611                         valueList->next();
01612                     break;
01613                 }
01614                 case CSS_PROP_BACKGROUND_POSITION_Y: {
01615                     bool xFound = true, yFound = false;
01616                     currValue = parseBackgroundPositionXY(xFound, yFound);
01617                     if (currValue)
01618                         valueList->next();
01619                     break;
01620                 }
01621                 case CSS_PROP_BACKGROUND_REPEAT:
01622                     if (val->id >= CSS_VAL_REPEAT && val->id <= CSS_VAL_NO_REPEAT) {
01623                         currValue = new CSSPrimitiveValueImpl(val->id);
01624                         valueList->next();
01625                     }
01626                     break;
01627                 case CSS_PROP__KHTML_BACKGROUND_SIZE:
01628                     currValue = parseBackgroundSize();
01629                     if (currValue)
01630                         valueList->next();
01631                     break;
01632             }
01633 
01634             if (!currValue)
01635                 goto failed;
01636 
01637             if (value && !values) {
01638                 values = new CSSValueListImpl();
01639                 values->append(value);
01640                 value = 0;
01641             }
01642 
01643             if (value2 && !values2) {
01644                 values2 = new CSSValueListImpl();
01645                 values2->append(value2);
01646                 value2 = 0;
01647             }
01648 
01649             if (values)
01650                 values->append(currValue);
01651             else
01652                 value = currValue;
01653             if (currValue2) {
01654                 if (values2)
01655                     values2->append(currValue2);
01656                 else
01657                     value2 = currValue2;
01658             }
01659             allowComma = true;
01660         }
01661 
01662         // When parsing the 'background' shorthand property, we let it handle building up the lists for all
01663         // properties.
01664         if (inShorthand())
01665             break;
01666     }
01667 
01668     if (values && values->length()) {
01669         retValue1 = values;
01670         if (values2 && values2->length())
01671             retValue2 = values2;
01672         return true;
01673     }
01674     if (value) {
01675         retValue1 = value;
01676         retValue2 = value2;
01677         return true;
01678     }
01679 
01680 failed:
01681     delete values; delete values2;
01682     delete value; delete value2;
01683     return false;
01684 }
01685 
01686 bool CSSParser::parseShape( int propId, bool important )
01687 {
01688     Value *value = valueList->current();
01689     ValueList *args = value->function->args;
01690     QString fname = qString( value->function->name ).lower();
01691     //qDebug( "parseShape: fname: %d", fname.latin1() );
01692     if ( fname != "rect(" || !args )
01693         return false;
01694 
01695     // rect( t, r, b, l ) || rect( t r b l )
01696     if ( args->size() != 4 && args->size() != 7 )
01697         return false;
01698     RectImpl *rect = new RectImpl();
01699     bool valid = true;
01700     int i = 0;
01701     Value *a = args->current();
01702     while ( a ) {
01703         valid = validUnit( a, FLength, strict );
01704         if ( !valid )
01705             break;
01706         CSSPrimitiveValueImpl *length =
01707             new CSSPrimitiveValueImpl( a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit );
01708         if ( i == 0 )
01709             rect->setTop( length );
01710         else if ( i == 1 )
01711             rect->setRight( length );
01712         else if ( i == 2 )
01713             rect->setBottom( length );
01714         else
01715             rect->setLeft( length );
01716         a = args->next();
01717         if ( a && args->size() == 7 ) {
01718             if ( a->unit == Value::Operator && a->iValue == ',' ) {
01719                 a = args->next();
01720             } else {
01721                 valid = false;
01722                 break;
01723             }
01724         }
01725         i++;
01726     }
01727     if ( valid ) {
01728         addProperty( propId, new CSSPrimitiveValueImpl( rect ), important );
01729         valueList->next();
01730         return true;
01731     }
01732     delete rect;
01733     return false;
01734 }
01735 
01736 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
01737 bool CSSParser::parseFont( bool important )
01738 {
01739 //     kdDebug(6080) << "parsing font property current=" << valueList->currentValue << endl;
01740     bool valid = true;
01741     Value *value = valueList->current();
01742     FontValueImpl *font = new FontValueImpl;
01743     // optional font-style, font-variant and font-weight
01744     while ( value ) {
01745 //         kdDebug( 6080 ) << "got value " << value->id << " / " << (value->unit == CSSPrimitiveValue::CSS_STRING ||
01746         //                                    value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
01747 //                         << endl;
01748         int id = value->id;
01749         if ( id ) {
01750             if ( id == CSS_VAL_NORMAL ) {
01751                 // do nothing, it's the initial value for all three
01752             }
01753             /*
01754               else if ( id == CSS_VAL_INHERIT ) {
01755               // set all non set ones to inherit
01756               // This is not that simple as the inherit could also apply to the following font-size.
01757               // very ahrd to tell without looking ahead.
01758               inherit = true;
01759                 } */
01760             else if ( id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE ) {
01761                 if ( font->style )
01762                     goto invalid;
01763                 font->style = new CSSPrimitiveValueImpl( id );
01764             } else if ( id == CSS_VAL_SMALL_CAPS ) {
01765                 if ( font->variant )
01766                     goto invalid;
01767                 font->variant = new CSSPrimitiveValueImpl( id );
01768             } else if ( id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER ) {
01769                 if ( font->weight )
01770                     goto invalid;
01771                 font->weight = new CSSPrimitiveValueImpl( id );
01772             } else {
01773                 valid = false;
01774             }
01775         } else if ( !font->weight && validUnit( value, FInteger|FNonNeg, true ) ) {
01776             int weight = (int)value->fValue;
01777             int val = 0;
01778             if ( weight == 100 )
01779                 val = CSS_VAL_100;
01780             else if ( weight == 200 )
01781                 val = CSS_VAL_200;
01782             else if ( weight == 300 )
01783                 val = CSS_VAL_300;
01784             else if ( weight == 400 )
01785                 val = CSS_VAL_400;
01786             else if ( weight == 500 )
01787                 val = CSS_VAL_500;
01788             else if ( weight == 600 )
01789                 val = CSS_VAL_600;
01790             else if ( weight == 700 )
01791                 val = CSS_VAL_700;
01792             else if ( weight == 800 )
01793                 val = CSS_VAL_800;
01794             else if ( weight == 900 )
01795                 val = CSS_VAL_900;
01796 
01797             if ( val )
01798                 font->weight = new CSSPrimitiveValueImpl( val );
01799             else
01800                 valid = false;
01801         } else {
01802             valid = false;
01803         }
01804         if ( !valid )
01805             break;
01806         value = valueList->next();
01807     }
01808     if ( !value )
01809         goto invalid;
01810 
01811     // set undefined values to default
01812     if ( !font->style )
01813         font->style = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01814     if ( !font->variant )
01815         font->variant = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01816     if ( !font->weight )
01817         font->weight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01818 
01819 //     kdDebug( 6080 ) << "  got style, variant and weight current=" << valueList->currentValue << endl;
01820 
01821     // now a font size _must_ come
01822     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
01823     if ( value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER )
01824         font->size = new CSSPrimitiveValueImpl( value->id );
01825     else if ( validUnit( value, FLength|FPercent, strict ) ) {
01826         font->size = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01827     }
01828     value = valueList->next();
01829     if ( !font->size || !value )
01830         goto invalid;
01831 
01832     // kdDebug( 6080 ) << "  got size" << endl;
01833 
01834     if ( value->unit == Value::Operator && value->iValue == '/' ) {
01835         // line-height
01836         value = valueList->next();
01837         if ( !value )
01838             goto invalid;
01839         if ( value->id == CSS_VAL_NORMAL ) {
01840             // default value, nothing to do
01841         } else if ( validUnit( value, FNumber|FLength|FPercent, strict ) ) {
01842             font->lineHeight = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01843         } else {
01844             goto invalid;
01845         }
01846         value = valueList->next();
01847         if ( !value )
01848             goto invalid;
01849     }
01850     if ( !font->lineHeight )
01851         font->lineHeight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01852 
01853 //     kdDebug( 6080 ) << "  got line height current=" << valueList->currentValue << endl;
01854     // font family must come now
01855     font->family = parseFontFamily();
01856 
01857     if ( valueList->current() || !font->family )
01858         goto invalid;
01859     //kdDebug( 6080 ) << "  got family, parsing ok!" << endl;
01860 
01861     addProperty( CSS_PROP_FONT, font, important );
01862     return true;
01863 
01864  invalid:
01865     //kdDebug(6080) << "   -> invalid" << endl;
01866     delete font;
01867     return false;
01868 }
01869 
01870 CSSValueListImpl *CSSParser::parseFontFamily()
01871 {
01872 //     kdDebug( 6080 ) << "CSSParser::parseFontFamily current=" << valueList->currentValue << endl;
01873     CSSValueListImpl *list = new CSSValueListImpl;
01874     Value *value = valueList->current();
01875     QString currFace;
01876 
01877     while ( value ) {
01878 //         kdDebug( 6080 ) << "got value " << value->id << " / "
01879 //                         << (value->unit == CSSPrimitiveValue::CSS_STRING ||
01880 //                             value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
01881 //                         << endl;
01882         Value* nextValue = valueList->next();
01883         bool nextValBreaksFont = !nextValue ||
01884                                  (nextValue->unit == Value::Operator && nextValue->iValue == ',');
01885         bool nextValIsFontName = nextValue &&
01886                                  ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL_MONOSPACE) ||
01887                                   (nextValue->unit == CSSPrimitiveValue::CSS_STRING ||
01888                                    nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
01889 
01890         if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL_MONOSPACE) {
01891             if (!currFace.isNull()) {
01892                 currFace += ' ';
01893                 currFace += qString(value->string);
01894             }
01895             else if (nextValBreaksFont || !nextValIsFontName) {
01896                 if ( !currFace.isNull() ) {
01897                     list->append( new FontFamilyValueImpl( currFace ) );
01898                     currFace = QString::null;
01899                 }
01900                 list->append(new CSSPrimitiveValueImpl(value->id));
01901             }
01902             else {
01903                 currFace = qString( value->string );
01904             }
01905         }
01906         else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
01907             // Strings never share in a family name.
01908             currFace = QString::null;
01909             list->append(new FontFamilyValueImpl(qString( value->string) ) );
01910         }
01911         else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
01912             if (!currFace.isNull()) {
01913                 currFace += ' ';
01914                 currFace += qString(value->string);
01915             }
01916             else if (nextValBreaksFont || !nextValIsFontName) {
01917                 if ( !currFace.isNull() ) {
01918                     list->append( new FontFamilyValueImpl( currFace ) );
01919                     currFace = QString::null;
01920                 }
01921                 list->append(new FontFamilyValueImpl( qString( value->string ) ) );
01922         }
01923         else {
01924                 currFace = qString( value->string);
01925         }
01926         }
01927     else {
01928         //kdDebug( 6080 ) << "invalid family part" << endl;
01929             break;
01930         }
01931 
01932         if (!nextValue)
01933             break;
01934 
01935         if (nextValBreaksFont) {
01936         value = valueList->next();
01937             if ( !currFace.isNull() )
01938                 list->append( new FontFamilyValueImpl( currFace ) );
01939             currFace = QString::null;
01940         }
01941         else if (nextValIsFontName)
01942             value = nextValue;
01943         else
01944             break;
01945     }
01946 
01947     if ( !currFace.isNull() )
01948         list->append( new FontFamilyValueImpl( currFace ) );
01949 
01950     if ( !list->length() ) {
01951         delete list;
01952         list = 0;
01953     }
01954     return list;
01955 }
01956 
01957  
01958 bool CSSParser::parseColorParameters(Value* value, int* colorArray, bool parseAlpha)
01959 {
01960     ValueList* args = value->function->args;
01961     Value* v = args->current();
01962     // Get the first value
01963     if (!validUnit(v, FInteger | FPercent, true))
01964         return false;
01965     colorArray[0] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
01966     for (int i = 1; i < 3; i++) {
01967         v = args->next();
01968         if (v->unit != Value::Operator && v->iValue != ',')
01969             return false;
01970         v = args->next();
01971         if (!validUnit(v, FInteger | FPercent, true))
01972             return false;
01973         colorArray[i] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
01974     }
01975     if (parseAlpha) {
01976         v = args->next();
01977         if (v->unit != Value::Operator && v->iValue != ',')
01978             return false;
01979         v = args->next();
01980         if (!validUnit(v, FNumber, true))
01981             return false;
01982         colorArray[3] = static_cast<int>(kMax(0.0, kMin(1.0, v->fValue)) * 255);
01983     }
01984     return true;
01985 }
01986  
01987 // CSS3 specification defines the format of a HSL color as
01988 // hsl(<number>, <percent>, <percent>)
01989 // and with alpha, the format is
01990 // hsla(<number>, <percent>, <percent>, <number>)
01991 // The first value, HUE, is in an angle with a value between 0 and 360
01992 bool CSSParser::parseHSLParameters(Value* value, double* colorArray, bool parseAlpha)
01993 {
01994     ValueList* args = value->function->args;
01995     Value* v = args->current();
01996     // Get the first value
01997     if (!validUnit(v, FInteger, true))
01998         return false;
01999     // normalize the Hue value and change it to be between 0 and 1.0
02000     colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
02001     for (int i = 1; i < 3; i++) {
02002         v = args->next();
02003         if (v->unit != Value::Operator && v->iValue != ',')
02004             return false;
02005         v = args->next();
02006         if (!validUnit(v, FPercent, true))
02007             return false;
02008         colorArray[i] = kMax(0.0, kMin(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0
02009     }
02010     if (parseAlpha) {
02011         v = args->next();
02012         if (v->unit != Value::Operator && v->iValue != ',')
02013             return false;
02014         v = args->next();
02015         if (!validUnit(v, FNumber, true))
02016             return false;
02017         colorArray[3] = kMax(0.0, kMin(1.0, v->fValue));
02018     }
02019     return true;
02020 }
02021 
02022 static bool parseColor(int unit, const QString &name, QRgb& rgb)
02023 {
02024     int len = name.length();
02025 
02026     if ( !len )
02027         return false;
02028 
02029 
02030     bool ok;
02031 
02032     if ( len == 3 || len == 6 ) {
02033         int val = name.toInt(&ok, 16);
02034         if ( ok ) {
02035             if (len == 6) {
02036                 rgb = (0xff << 24) | val;
02037                 return true;
02038             }
02039             else if ( len == 3 ) {
02040                 // #abc converts to #aabbcc according to the specs
02041                 rgb = (0xff << 24) |
02042                       (val&0xf00)<<12 | (val&0xf00)<<8 |
02043                       (val&0xf0)<<8 | (val&0xf0)<<4 |
02044                       (val&0xf)<<4 | (val&0xf);
02045                 return true;
02046             }
02047         }
02048     }
02049 
02050     if ( unit == CSSPrimitiveValue::CSS_IDENT ) {
02051         // try a little harder
02052         QColor tc;
02053         tc.setNamedColor(name.lower());
02054         if ( tc.isValid() ) {
02055             rgb = tc.rgb();
02056             return true;
02057         }
02058     }
02059 
02060     return false;
02061 }
02062 
02063 CSSPrimitiveValueImpl *CSSParser::parseColor()
02064 {
02065     return parseColorFromValue(valueList->current());
02066 }
02067 
02068 CSSPrimitiveValueImpl *CSSParser::parseColorFromValue(Value* value)
02069 {
02070     QRgb c = khtml::transparentColor;
02071     if ( !strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
02072               value->fValue >= 0. && value->fValue < 1000000. ) {
02073         QString str;
02074         str.sprintf( "%06d", (int)(value->fValue+.5) );
02075         if ( !::parseColor( value->unit, str, c ) )
02076             return 0;
02077     }
02078     else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
02079              value->unit == CSSPrimitiveValue::CSS_IDENT ||
02080              (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
02081         if ( !::parseColor( value->unit, qString( value->string ), c) )
02082             return 0;
02083     }
02084     else if ( value->unit == Value::Function &&
02085         value->function->args != 0 &&
02086                 value->function->args->size() == 5 /* rgb + two commas */ &&
02087                 qString( value->function->name ).lower() == "rgb(" ) {
02088         int colorValues[3];
02089         if (!parseColorParameters(value, colorValues, false))
02090             return 0;
02091         colorValues[0] = kMax( 0, kMin( 255, colorValues[0] ) );
02092         colorValues[1] = kMax( 0, kMin( 255, colorValues[1] ) );
02093         colorValues[2] = kMax( 0, kMin( 255, colorValues[2] ) );
02094         c = qRgb(colorValues[0], colorValues[1], colorValues[2]);
02095     } else if (value->unit == Value::Function &&
02096                 value->function->args != 0 &&
02097                 value->function->args->size() == 7 /* rgba + three commas */ &&
02098                 domString(value->function->name).lower() == "rgba(") {
02099         int colorValues[4];
02100         if (!parseColorParameters(value, colorValues, true))
02101             return 0;
02102         colorValues[0] = kMax( 0, kMin( 255, colorValues[0] ) );
02103         colorValues[1] = kMax( 0, kMin( 255, colorValues[1] ) );
02104         colorValues[2] = kMax( 0, kMin( 255, colorValues[2] ) );
02105         c = qRgba(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
02106     } else if (value->unit == Value::Function &&
02107                 value->function->args != 0 &&
02108                 value->function->args->size() == 5 /* hsl + two commas */ &&
02109                 domString(value->function->name).lower() == "hsl(") {
02110         double colorValues[3];
02111         if (!parseHSLParameters(value, colorValues, false))
02112             return 0;
02113         c = khtml::qRgbaFromHsla(colorValues[0], colorValues[1], colorValues[2], 1.0);
02114     } else if (value->unit == Value::Function &&
02115                 value->function->args != 0 &&
02116                 value->function->args->size() == 7 /* hsla + three commas */ &&
02117                 domString(value->function->name).lower() == "hsla(") {
02118         double colorValues[4];
02119         if (!parseHSLParameters(value, colorValues, true))
02120             return 0;
02121         c = khtml::qRgbaFromHsla(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
02122     }
02123     else
02124         return 0;
02125 
02126     return new CSSPrimitiveValueImpl(c);
02127 }
02128 
02129 // This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
02130 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
02131 struct ShadowParseContext {
02132     ShadowParseContext()
02133     :values(0), x(0), y(0), blur(0), color(0),
02134      allowX(true), allowY(false), allowBlur(false), allowColor(true),
02135      allowBreak(true)
02136     {}
02137 
02138     ~ShadowParseContext() {
02139         if (!allowBreak) {
02140             delete values;
02141             delete x;
02142             delete y;
02143             delete blur;
02144             delete color;
02145         }
02146     }
02147 
02148     bool allowLength() { return allowX || allowY || allowBlur; }
02149 
02150     bool failed() { return allowBreak = false; }
02151 
02152     void commitValue() {
02153         // Handle the ,, case gracefully by doing nothing.
02154         if (x || y || blur || color) {
02155             if (!values)
02156                 values = new CSSValueListImpl();
02157 
02158             // Construct the current shadow value and add it to the list.
02159             values->append(new ShadowValueImpl(x, y, blur, color));
02160         }
02161 
02162         // Now reset for the next shadow value.
02163         x = y = blur = color = 0;
02164         allowX = allowColor = allowBreak = true;
02165         allowY = allowBlur = false;
02166     }
02167 
02168     void commitLength(Value* v) {
02169         CSSPrimitiveValueImpl* val = new CSSPrimitiveValueImpl(v->fValue,
02170                                                                (CSSPrimitiveValue::UnitTypes)v->unit);
02171         if (allowX) {
02172             x = val;
02173             allowX = false; allowY = true; allowColor = false; allowBreak = false;
02174         }
02175         else if (allowY) {
02176             y = val;
02177             allowY = false; allowBlur = true; allowColor = true; allowBreak = true;
02178         }
02179         else if (allowBlur) {
02180             blur = val;
02181             allowBlur = false;
02182         }
02183     else
02184         delete val;
02185     }
02186 
02187     void commitColor(CSSPrimitiveValueImpl* val) {
02188         color = val;
02189         allowColor = false;
02190         if (allowX)
02191             allowBreak = false;
02192         else
02193             allowBlur = false;
02194     }
02195 
02196     CSSValueListImpl* values;
02197     CSSPrimitiveValueImpl* x;
02198     CSSPrimitiveValueImpl* y;
02199     CSSPrimitiveValueImpl* blur;
02200     CSSPrimitiveValueImpl* color;
02201 
02202     bool allowX;
02203     bool allowY;
02204     bool allowBlur;
02205     bool allowColor;
02206     bool allowBreak;
02207 };
02208 
02209 bool CSSParser::parseShadow(int propId, bool important)
02210 {
02211     ShadowParseContext context;
02212     Value* val;
02213     while ((val = valueList->current())) {
02214         // Check for a comma break first.
02215         if (val->unit == Value::Operator) {
02216             if (val->iValue != ',' || !context.allowBreak)
02217                 // Other operators aren't legal or we aren't done with the current shadow
02218                 // value.  Treat as invalid.
02219                 return context.failed();
02220 
02221             // The value is good.  Commit it.
02222             context.commitValue();
02223         }
02224         // Check to see if we're a length.
02225         else if (validUnit(val, FLength, true)) {
02226             // We required a length and didn't get one. Invalid.
02227             if (!context.allowLength())
02228                 return context.failed();
02229 
02230             // A length is allowed here.  Construct the value and add it.
02231             context.commitLength(val);
02232         }
02233         else {
02234             // The only other type of value that's ok is a color value.
02235             CSSPrimitiveValueImpl* parsedColor = 0;
02236             bool isColor = (val->id >= CSS_VAL_AQUA && val->id <= CSS_VAL_WINDOWTEXT || val->id == CSS_VAL_MENU ||
02237                            (val->id >= CSS_VAL_GREY && val->id <= CSS_VAL__KHTML_TEXT && !strict));
02238         if (!context.allowColor)
02239                 return context.failed();
02240 
02241             if (isColor)
02242                parsedColor = new CSSPrimitiveValueImpl(val->id);
02243 
02244             if (!parsedColor)
02245                 // It's not built-in. Try to parse it as a color.
02246                 parsedColor = parseColorFromValue(val);
02247 
02248             if (!parsedColor)
02249                 return context.failed();
02250 
02251             context.commitColor(parsedColor);
02252         }
02253 
02254         valueList->next();
02255     }
02256 
02257     if (context.allowBreak) {
02258         context.commitValue();
02259         if (context.values->length()) {
02260             addProperty(propId, context.values, important);
02261             valueList->next();
02262             return true;
02263         }
02264     }
02265 
02266     return context.failed();
02267 }
02268 
02269 bool CSSParser::parseCounter(int propId, bool increment, bool important)
02270 {
02271     enum { ID, VAL, COMMA } state = ID;
02272 
02273     CSSValueListImpl *list = new CSSValueListImpl;
02274     DOMString c;
02275     Value* val;
02276     while (true) {
02277         val = valueList->current();
02278         switch (state) {
02279             // Commas are not allowed according to the standard, but Opera allows them and being the only
02280             // other browser with counter support we need to match their behavior to work with current use
02281             case COMMA:
02282                 state = ID;
02283                 if (val && val->unit == Value::Operator && val->iValue == ',') {
02284                     valueList->next();
02285                     continue;
02286                 }
02287                 // no break
02288             case ID:
02289                 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
02290                     c = qString(val->string);
02291                     state = VAL;
02292                     valueList->next();
02293                     continue;
02294                 }
02295                 break;
02296             case VAL: {
02297                 short i = 0;
02298                 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
02299                     i = (short)val->fValue;
02300                     valueList->next();
02301                 } else
02302                     i = (increment) ? 1 : 0;
02303 
02304                 CounterActImpl *cv = new CounterActImpl(c,i);
02305                 list->append(cv);
02306                 state = COMMA;
02307                 continue;
02308             }
02309         }
02310         break;
02311     }
02312     if(list->length() > 0) {
02313         addProperty( propId, list, important );
02314         return true;
02315     }
02316     delete list;
02317     return false;
02318 }
02319 
02320 static inline int yyerror( const char *str ) {
02321 //    assert( 0 );
02322 #ifdef CSS_DEBUG
02323     kdDebug( 6080 ) << "CSS parse error " << str << endl;
02324 #else
02325     Q_UNUSED( str );
02326 #endif
02327     return 1;
02328 }
02329 
02330 #define END 0
02331 
02332 #include "parser.h"
02333 
02334 int DOM::CSSParser::lex( void *_yylval )
02335 {
02336     YYSTYPE *yylval = (YYSTYPE *)_yylval;
02337     int token = lex();
02338     int length;
02339     unsigned short *t = text( &length );
02340 
02341 #ifdef TOKEN_DEBUG
02342     qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString( (QChar *)t, length ).latin1() );
02343 #endif
02344     switch( token ) {
02345     case '{':
02346         block_nesting++;
02347         break;
02348     case '}':
02349         if ( block_nesting )
02350             block_nesting--;
02351         break;
02352     case END:
02353         if ( block_nesting ) {
02354             block_nesting--;
02355             return '}';
02356         }
02357         break;
02358     case S:
02359     case SGML_CD:
02360     case INCLUDES:
02361     case DASHMATCH:
02362         break;
02363 
02364     case URI:
02365     case STRING:
02366     case IDENT:
02367     case NTH:
02368     case HASH:
02369     case DIMEN:
02370     case UNICODERANGE:
02371     case NOTFUNCTION:
02372     case FUNCTION:
02373         yylval->string.string = t;
02374         yylval->string.length = length;
02375         break;
02376 
02377     case IMPORT_SYM:
02378     case PAGE_SYM:
02379     case MEDIA_SYM:
02380     case FONT_FACE_SYM:
02381     case CHARSET_SYM:
02382     case NAMESPACE_SYM:
02383 
02384     case IMPORTANT_SYM:
02385         break;
02386 
02387     case QEMS:
02388         length--;
02389     case GRADS:
02390         length--;
02391     case DEGS:
02392     case RADS:
02393     case KHERZ:
02394         length--;
02395     case MSECS:
02396     case HERZ:
02397     case EMS:
02398     case EXS:
02399     case PXS:
02400     case CMS:
02401     case MMS:
02402     case INS:
02403     case PTS:
02404     case PCS:
02405         length--;
02406     case SECS:
02407     case PERCENTAGE:
02408         length--;
02409     case FLOAT:
02410     case INTEGER:
02411         yylval->val = QString( (QChar *)t, length ).toDouble();
02412         //qDebug("value = %s, converted=%.2f", QString( (QChar *)t, length ).latin1(), yylval->val );
02413         break;
02414 
02415     default:
02416         break;
02417     }
02418 
02419     return token;
02420 }
02421 
02422 static inline int toHex( char c ) {
02423     if ( '0' <= c && c <= '9' )
02424         return c - '0';
02425     if ( 'a' <= c && c <= 'f' )
02426         return c - 'a' + 10;
02427     if ( 'A' <= c && c<= 'F' )
02428         return c - 'A' + 10;
02429     return 0;
02430 }
02431 
02432 unsigned short *DOM::CSSParser::text(int *length)
02433 {
02434     unsigned short *start = yytext;
02435     int l = yyleng;
02436     switch( yyTok ) {
02437     case STRING:
02438         l--;
02439         /* nobreak */
02440     case HASH:
02441         start++;
02442         l--;
02443         break;
02444     case URI:
02445         // "url("{w}{string}{w}")"
02446         // "url("{w}{url}{w}")"
02447 
02448         // strip "url(" and ")"
02449         start += 4;
02450         l -= 5;
02451         // strip {w}
02452         while ( l &&
02453                 (*start == ' ' || *start == '\t' || *start == '\r' ||
02454                  *start == '\n' || *start == '\f' ) ) {
02455             start++; l--;
02456         }
02457         if ( *start == '"' || *start == '\'' ) {
02458             start++; l--;
02459         }
02460         while ( l &&
02461                 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
02462                  start[l-1] == '\n' || start[l-1] == '\f' ) ) {
02463             l--;
02464         }
02465         if ( l && (start[l-1] == '\"' || start[l-1] == '\'' ) )
02466              l--;
02467 
02468     default:
02469         break;
02470     }
02471 
02472     // process escapes
02473     unsigned short *out = start;
02474     unsigned short *escape = 0;
02475 
02476     for ( int i = 0; i < l; i++ ) {
02477         unsigned short *current = start+i;
02478         if ( escape == current - 1 ) {
02479             if ( ( *current >= '0' && *current <= '9' ) ||
02480                  ( *current >= 'a' && *current <= 'f' ) ||
02481                  ( *current >= 'A' && *current <= 'F' ) )
02482                 continue;
02483             if ( yyTok == STRING &&
02484                  ( *current == '\n' || *current == '\r' || *current == '\f' ) ) {
02485                 // ### handle \r\n case
02486                 if ( *current != '\r' )
02487                     escape = 0;
02488                 continue;
02489             }
02490             // in all other cases copy the char to output
02491             // ###
02492             *out++ = *current;
02493             escape = 0;
02494             continue;
02495         }
02496         if ( escape == current - 2 && yyTok == STRING &&
02497              *(current-1) == '\r' && *current == '\n' ) {
02498             escape = 0;
02499             continue;
02500         }
02501         if ( escape > current - 7 &&
02502              ( ( *current >= '0' && *current <= '9' ) ||
02503                ( *current >= 'a' && *current <= 'f' ) ||
02504                ( *current >= 'A' && *current <= 'F' ) ) )
02505                 continue;
02506         if ( escape ) {
02507             // add escaped char
02508             int uc = 0;
02509             escape++;
02510             while ( escape < current ) {
02511 //                 qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
02512                 uc *= 16;
02513                 uc += toHex( *escape );
02514                 escape++;
02515             }
02516 //             qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
02517             // can't handle chars outside ucs2
02518             if ( uc > 0xffff )
02519                 uc = 0xfffd;
02520             *(out++) = (unsigned short)uc;
02521             escape = 0;
02522             if ( *current == ' ' ||
02523                  *current == '\t' ||
02524                  *current == '\r' ||
02525                  *current == '\n' ||
02526                  *current == '\f' )
02527                 continue;
02528         }
02529         if ( !escape && *current == '\\' ) {
02530             escape = current;
02531             continue;
02532         }
02533         *(out++) = *current;
02534     }
02535     if ( escape ) {
02536         // add escaped char
02537         int uc = 0;
02538         escape++;
02539         while ( escape < start+l ) {
02540             //                 qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
02541             uc *= 16;
02542             uc += toHex( *escape );
02543             escape++;
02544         }
02545         //             qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
02546         // can't handle chars outside ucs2
02547         if ( uc > 0xffff )
02548             uc = 0xfffd;
02549         *(out++) = (unsigned short)uc;
02550     }
02551 
02552     *length = out - start;
02553     return start;
02554 }
02555 
02556 
02557 #define YY_DECL int DOM::CSSParser::lex()
02558 #define yyconst const
02559 typedef int yy_state_type;
02560 typedef unsigned int YY_CHAR;
02561 // this line makes sure we treat all Unicode chars correctly.
02562 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
02563 #define YY_DO_BEFORE_ACTION \
02564         yytext = yy_bp; \
02565         yyleng = (int) (yy_cp - yy_bp); \
02566         yy_hold_char = *yy_cp; \
02567         *yy_cp = 0; \
02568         yy_c_buf_p = yy_cp;
02569 #define YY_BREAK break;
02570 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).latin1() )
02571 #define YY_RULE_SETUP
02572 #define INITIAL 0
02573 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
02574 #define YY_START ((yy_start - 1) / 2)
02575 #define yyterminate() yyTok = END; return yyTok
02576 #define YY_FATAL_ERROR(a) qFatal(a)
02577 #define BEGIN yy_start = 1 + 2 *
02578 #define COMMENT 1
02579 
02580 #include "tokenizer.cpp"
KDE Home | KDE Accessibility Home | Description of Access Keys