khtml Library API Documentation

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  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Library General Public License
00017  * along with this library; see the file COPYING.LIB.  If not, write to
00018  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019  * Boston, MA 02111-1307, USA.
00020  */
00021 
00022 //#define CSS_DEBUG
00023 //#define TOKEN_DEBUG
00024 #define YYDEBUG 0
00025 
00026 #include <kdebug.h>
00027 #include <kglobal.h>
00028 #include <kurl.h>
00029 
00030 #include "cssparser.h"
00031 #include "css_valueimpl.h"
00032 #include "css_ruleimpl.h"
00033 #include "css_stylesheetimpl.h"
00034 #include "cssproperties.h"
00035 #include "cssvalues.h"
00036 #include "misc/helper.h"
00037 #include "csshelper.h"
00038 using namespace DOM;
00039 
00040 #include <stdlib.h>
00041 #include <assert.h>
00042 
00043 ValueList::ValueList()
00044 {
00045     values = (Value *) malloc( 16 * sizeof ( Value ) );
00046     numValues = 0;
00047     currentValue = 0;
00048     maxValues = 16;
00049 }
00050 
00051 ValueList::~ValueList()
00052 {
00053     for ( int i = 0; i < numValues; i++ ) {
00054 #ifdef CSS_DEBUG
00055         kdDebug( 6080 ) << "       value: (unit=" << values[i].unit <<")"<< endl;
00056 #endif
00057         if ( values[i].unit == Value::Function )
00058             delete values[i].function;
00059     }
00060     free( values );
00061 }
00062 
00063 void ValueList::addValue( const Value &val )
00064 {
00065     if ( numValues >= maxValues ) {
00066         maxValues += 16;
00067         values = (Value *) realloc( values, maxValues*sizeof( Value ) );
00068     }
00069     values[numValues++] = val;
00070 }
00071 
00072 
00073 using namespace DOM;
00074 
00075 #if YYDEBUG > 0
00076 extern int cssyydebug;
00077 #endif
00078 
00079 extern int cssyyparse( void * parser );
00080 
00081 CSSParser *CSSParser::currentParser = 0;
00082 
00083 CSSParser::CSSParser( bool strictParsing )
00084 {
00085 #ifdef CSS_DEBUG
00086     kdDebug( 6080 ) << "CSSParser::CSSParser this=" << this << endl;
00087 #endif
00088     strict = strictParsing;
00089 
00090     parsedProperties = (CSSProperty **) malloc( 32 * sizeof( CSSProperty * ) );
00091     numParsedProperties = 0;
00092     maxParsedProperties = 32;
00093 
00094     defaultNamespace = 0xffff;
00095 
00096     data = 0;
00097     valueList = 0;
00098     rule = 0;
00099     id = 0;
00100     important = false;
00101     nonCSSHint = false;
00102     inParseShortHand = false;
00103     yy_start = 1;
00104 
00105 #if YYDEBUG > 0
00106     cssyydebug = 1;
00107 #endif
00108 
00109 }
00110 
00111 CSSParser::~CSSParser()
00112 {
00113     if ( numParsedProperties )
00114         clearProperties();
00115     free( parsedProperties );
00116 
00117     delete valueList;
00118 
00119 #ifdef CSS_DEBUG
00120     kdDebug( 6080 ) << "CSSParser::~CSSParser this=" << this << endl;
00121 #endif
00122 
00123     free( data );
00124 
00125 }
00126 
00127 void CSSParser::runParser(int length)
00128 {
00129     data[length-1] = 0;
00130     data[length-2] = 0;
00131     data[length-3] = ' ';
00132 
00133     yyTok = -1;
00134     block_nesting = 0;
00135     yy_hold_char = 0;
00136     yyleng = 0;
00137     yytext = yy_c_buf_p = data;
00138     yy_hold_char = *yy_c_buf_p;
00139 
00140     CSSParser *old = currentParser;
00141     currentParser = this;
00142     cssyyparse( this );
00143     currentParser = old;
00144 }
00145 
00146 void CSSParser::parseSheet( CSSStyleSheetImpl *sheet, const DOMString &string )
00147 {
00148     styleElement = sheet;
00149 
00150     int length = string.length() + 3;
00151     data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00152     memcpy( data, string.unicode(), string.length()*sizeof( unsigned short) );
00153 
00154 #ifdef CSS_DEBUG
00155     kdDebug( 6080 ) << ">>>>>>> start parsing style sheet" << endl;
00156 #endif
00157     runParser(length);
00158 #ifdef CSS_DEBUG
00159     kdDebug( 6080 ) << "<<<<<<< done parsing style sheet" << endl;
00160 #endif
00161 
00162     delete rule;
00163     rule = 0;
00164 }
00165 
00166 CSSRuleImpl *CSSParser::parseRule( DOM::CSSStyleSheetImpl *sheet, const DOM::DOMString &string )
00167 {
00168     styleElement = sheet;
00169 
00170     const char khtml_rule[] = "@-khtml-rule{";
00171     int length = string.length() + 4 + strlen(khtml_rule);
00172     assert( !data );
00173     data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00174     for ( unsigned int i = 0; i < strlen(khtml_rule); i++ )
00175         data[i] = khtml_rule[i];
00176     memcpy( data + strlen( khtml_rule ), string.unicode(), string.length()*sizeof( unsigned short) );
00177     // qDebug("parse string = '%s'", QConstString( (const QChar *)data, length ).string().latin1() );
00178     data[length-4] = '}';
00179 
00180     runParser(length);
00181 
00182     CSSRuleImpl *result = rule;
00183     rule = 0;
00184 
00185     return result;
00186 }
00187 
00188 bool CSSParser::parseValue( DOM::CSSStyleDeclarationImpl *declaration, int _id, const DOM::DOMString &string,
00189                             bool _important, bool _nonCSSHint )
00190 {
00191 #ifdef CSS_DEBUG
00192     kdDebug( 6080 ) << "CSSParser::parseValue: id=" << _id << " important=" << _important
00193                     << " nonCSSHint=" << _nonCSSHint << " value='" << string.string() << "'" << endl;
00194 #endif
00195 
00196     styleElement = declaration->stylesheet();
00197 
00198     const char khtml_value[] = "@-khtml-value{";
00199     int length = string.length() + 4 + strlen(khtml_value);
00200     assert( !data );
00201     data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00202     for ( unsigned int i = 0; i < strlen(khtml_value); i++ )
00203         data[i] = khtml_value[i];
00204     memcpy( data + strlen( khtml_value ), string.unicode(), string.length()*sizeof( unsigned short) );
00205     data[length-4] = '}';
00206     // qDebug("parse string = '%s'", QConstString( (const QChar *)data, length ).string().latin1() );
00207 
00208     id = _id;
00209     important = _important;
00210     nonCSSHint = _nonCSSHint;
00211 
00212     runParser(length);
00213 
00214     delete rule;
00215     rule = 0;
00216 
00217     bool ok = false;
00218     if ( numParsedProperties ) {
00219         ok = true;
00220         for ( int i = 0; i < numParsedProperties; i++ ) {
00221             declaration->removeProperty(parsedProperties[i]->m_id, nonCSSHint);
00222             declaration->values()->append( parsedProperties[i] );
00223         }
00224         numParsedProperties = 0;
00225     }
00226 
00227     return ok;
00228 }
00229 
00230 bool CSSParser::parseDeclaration( DOM::CSSStyleDeclarationImpl *declaration, const DOM::DOMString &string,
00231                                   bool _nonCSSHint )
00232 {
00233 #ifdef CSS_DEBUG
00234     kdDebug( 6080 ) << "CSSParser::parseDeclaration: nonCSSHint=" << nonCSSHint
00235                     << " value='" << string.string() << "'" << endl;
00236 #endif
00237 
00238     styleElement = declaration->stylesheet();
00239 
00240     const char khtml_decls[] = "@-khtml-decls{";
00241     int length = string.length() + 4 + strlen(khtml_decls);
00242     assert( !data );
00243     data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00244     for ( unsigned int i = 0; i < strlen(khtml_decls); i++ )
00245         data[i] = khtml_decls[i];
00246     memcpy( data + strlen( khtml_decls ), string.unicode(), string.length()*sizeof( unsigned short) );
00247     data[length-4] = '}';
00248 
00249     nonCSSHint = _nonCSSHint;
00250 
00251     runParser(length);
00252 
00253     delete rule;
00254     rule = 0;
00255 
00256     bool ok = false;
00257     if ( numParsedProperties ) {
00258         ok = true;
00259         for ( int i = 0; i < numParsedProperties; i++ ) {
00260             declaration->removeProperty(parsedProperties[i]->m_id, false);
00261             declaration->values()->append( parsedProperties[i] );
00262         }
00263         numParsedProperties = 0;
00264     }
00265 
00266     return ok;
00267 }
00268 
00269 void CSSParser::addProperty( int propId, CSSValueImpl *value, bool important )
00270 {
00271     CSSProperty *prop = new CSSProperty;
00272     prop->m_id = propId;
00273     prop->setValue( value );
00274     prop->m_bImportant = important;
00275     prop->nonCSSHint = nonCSSHint;
00276 
00277     if ( numParsedProperties >= maxParsedProperties ) {
00278         maxParsedProperties += 32;
00279         parsedProperties = (CSSProperty **) realloc( parsedProperties,
00280                                                     maxParsedProperties*sizeof( CSSProperty * ) );
00281     }
00282     parsedProperties[numParsedProperties++] = prop;
00283 }
00284 
00285 CSSStyleDeclarationImpl *CSSParser::createStyleDeclaration( CSSStyleRuleImpl *rule )
00286 {
00287     QPtrList<CSSProperty> *propList = new QPtrList<CSSProperty>;
00288     propList->setAutoDelete( true );
00289     for ( int i = 0; i < numParsedProperties; i++ )
00290         propList->append( parsedProperties[i] );
00291 
00292     numParsedProperties = 0;
00293     return new CSSStyleDeclarationImpl(rule, propList);
00294 }
00295 
00296 void CSSParser::clearProperties()
00297 {
00298     for ( int i = 0; i < numParsedProperties; i++ )
00299         delete parsedProperties[i];
00300     numParsedProperties = 0;
00301 }
00302 
00303 DOM::DocumentImpl *CSSParser::document() const
00304 {
00305     const StyleBaseImpl* root = styleElement;
00306     DocumentImpl *doc = 0;
00307     while (root->parent())
00308         root = root->parent();
00309     if (root->isCSSStyleSheet())
00310         doc = static_cast<const CSSStyleSheetImpl*>(root)->doc();
00311     return doc;
00312 }
00313 
00314 
00315 // defines units allowed for a certain property, used in parseUnit
00316 enum Units
00317 {
00318     FUnknown   = 0x0000,
00319     FInteger   = 0x0001,
00320     FNumber    = 0x0002,  // Real Numbers
00321     FPercent   = 0x0004,
00322     FLength    = 0x0008,
00323     FAngle     = 0x0010,
00324     FTime      = 0x0020,
00325     FFrequency = 0x0040,
00326     FRelative  = 0x0100,
00327     FNonNeg    = 0x0200
00328 };
00329 
00330 static bool validUnit( Value *value, int unitflags, bool strict )
00331 {
00332     if ( unitflags & FNonNeg && value->fValue < 0 )
00333         return false;
00334 
00335     bool b = false;
00336     switch( value->unit ) {
00337     case CSSPrimitiveValue::CSS_NUMBER:
00338         b = (unitflags & FNumber);
00339         if ( !b && ( (unitflags & FLength) && (value->fValue == 0 || !strict ) ) ) {
00340             value->unit = CSSPrimitiveValue::CSS_PX;
00341             b = true;
00342         }
00343         if ( !b && ( unitflags & FInteger ) &&
00344              (value->fValue - (int)value->fValue) < 0.001 )
00345             b = true;
00346         break;
00347     case CSSPrimitiveValue::CSS_PERCENTAGE:
00348         b = (unitflags & FPercent);
00349         break;
00350     case Value::Q_EMS:
00351     case CSSPrimitiveValue::CSS_EMS:
00352     case CSSPrimitiveValue::CSS_EXS:
00353     case CSSPrimitiveValue::CSS_PX:
00354     case CSSPrimitiveValue::CSS_CM:
00355     case CSSPrimitiveValue::CSS_MM:
00356     case CSSPrimitiveValue::CSS_IN:
00357     case CSSPrimitiveValue::CSS_PT:
00358     case CSSPrimitiveValue::CSS_PC:
00359         b = (unitflags & FLength);
00360         break;
00361     case CSSPrimitiveValue::CSS_MS:
00362     case CSSPrimitiveValue::CSS_S:
00363         b = (unitflags & FTime);
00364         break;
00365     case CSSPrimitiveValue::CSS_DEG:
00366     case CSSPrimitiveValue::CSS_RAD:
00367     case CSSPrimitiveValue::CSS_GRAD:
00368     case CSSPrimitiveValue::CSS_HZ:
00369     case CSSPrimitiveValue::CSS_KHZ:
00370     case CSSPrimitiveValue::CSS_DIMENSION:
00371     default:
00372         break;
00373     }
00374     return b;
00375 }
00376 
00377 CSSPrimitiveValueImpl *CSSParser::parseBackgroundPositionXY( int propId, bool forward, bool &ok )
00378 {
00379     if ( forward )
00380         valueList->next();
00381 
00382     Value *value = valueList->current();
00383 
00384     ok = true;
00385 
00386     if ( !value )
00387         return 0;
00388 
00389     int id = value->id;
00390 
00391     switch ( id ) {
00392     case 0:
00393         if ( !validUnit( value, FPercent|FLength, strict&(!nonCSSHint) ) )
00394             ok = false;
00395         break;
00396 
00397     case CSS_VAL_LEFT:
00398     case CSS_VAL_RIGHT:
00399         if ( propId == CSS_PROP_BACKGROUND_POSITION_Y ) {
00400             ok = false;
00401             break;
00402         }
00403     case CSS_VAL_TOP:
00404     case CSS_VAL_BOTTOM:
00405         if ( propId == CSS_PROP_BACKGROUND_POSITION_X && ( id == CSS_VAL_BOTTOM || id == CSS_VAL_TOP ) ) {
00406             ok = false;
00407             break;
00408         }
00409     case CSS_VAL_CENTER:
00410         return new CSSPrimitiveValueImpl( id );
00411         break;
00412     default:
00413         ok = false;
00414     }
00415     if ( !ok )
00416         return 0;
00417     return new CSSPrimitiveValueImpl( value->fValue,
00418                                       (CSSPrimitiveValue::UnitTypes) value->unit );
00419 }
00420 
00421 
00422 bool CSSParser::parseValue( int propId, bool important, int expected )
00423 {
00424     if ( !valueList ) return false;
00425 
00426     Value *value = valueList->current();
00427 
00428     if ( !value )
00429         return false;
00430 
00431     int id = value->id;
00432 
00433     if ( id == CSS_VAL_INHERIT && expected == 1 ) {
00434         addProperty( propId, new CSSInheritedValueImpl(), important );
00435         return true;
00436     } else if (id == CSS_VAL_INITIAL && expected == 1 ) {
00437         addProperty(propId, new CSSInitialValueImpl(), important);
00438         return true;
00439     }
00440     bool valid_primitive = false;
00441     CSSValueImpl *parsedValue = 0;
00442 
00443     switch(propId) {
00444         /* The comment to the left defines all valid value of this properties as defined
00445          * in CSS 2, Appendix F. Property index
00446          */
00447 
00448         /* All the CSS properties are not supported by the renderer at the moment.
00449          * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
00450          * (see parseAuralValues). As we don't support them at all this seems reasonable.
00451          */
00452 
00453     case CSS_PROP_SIZE:                 // <length>{1,2} | auto | portrait | landscape | inherit
00454     case CSS_PROP_QUOTES:               // [<string> <string>]+ | none | inherit
00455 //     case CSS_PROP_PAGE:                 // <identifier> | auto // ### CHECK
00456         // ### To be done
00457         if (id)
00458             valid_primitive = true;
00459         break;
00460     case CSS_PROP_UNICODE_BIDI:         // normal | embed | bidi-override | inherit
00461         if ( id == CSS_VAL_NORMAL ||
00462              id == CSS_VAL_EMBED ||
00463              id == CSS_VAL_BIDI_OVERRIDE )
00464             valid_primitive = true;
00465         break;
00466 
00467     case CSS_PROP_POSITION:             // static | relative | absolute | fixed | inherit
00468         if ( id == CSS_VAL_STATIC ||
00469              id == CSS_VAL_RELATIVE ||
00470              id == CSS_VAL_ABSOLUTE ||
00471               id == CSS_VAL_FIXED )
00472             valid_primitive = true;
00473         break;
00474 
00475     case CSS_PROP_PAGE_BREAK_AFTER:     // auto | always | avoid | left | right | inherit
00476     case CSS_PROP_PAGE_BREAK_BEFORE:    // auto | always | avoid | left | right | inherit
00477         if ( id == CSS_VAL_AUTO ||
00478              id == CSS_VAL_ALWAYS ||
00479              id == CSS_VAL_AVOID ||
00480               id == CSS_VAL_LEFT ||
00481               id == CSS_VAL_RIGHT )
00482             valid_primitive = true;
00483         break;
00484 
00485     case CSS_PROP_PAGE_BREAK_INSIDE:    // avoid | auto | inherit
00486         if ( id == CSS_VAL_AUTO ||
00487              id == CSS_VAL_AVOID )
00488             valid_primitive = true;
00489         break;
00490 
00491     case CSS_PROP_EMPTY_CELLS:          // show | hide | inherit
00492         if ( id == CSS_VAL_SHOW ||
00493              id == CSS_VAL_HIDE )
00494             valid_primitive = true;
00495         break;
00496 
00497     case CSS_PROP_CONTENT:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
00498         // close-quote | no-open-quote | no-close-quote ]+ | inherit
00499         return parseContent( propId, important );
00500         break;
00501 
00502     case CSS_PROP_WHITE_SPACE:          // normal | pre | nowrap | inherit
00503         if ( id == CSS_VAL_NORMAL ||
00504              id == CSS_VAL_PRE ||
00505              id == CSS_VAL_NOWRAP )
00506             valid_primitive = true;
00507         break;
00508 
00509     case CSS_PROP_CLIP:                 // <shape> | auto | inherit
00510         if ( id == CSS_VAL_AUTO )
00511             valid_primitive = true;
00512         else if ( value->unit == Value::Function )
00513             return parseShape( propId, important );
00514         break;
00515 
00516     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
00517      * correctly and allows optimization in khtml::applyRule(..)
00518      */
00519     case CSS_PROP_CAPTION_SIDE:         // top | bottom | left | right | inherit
00520         if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
00521             id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM)
00522             valid_primitive = true;
00523         break;
00524 
00525     case CSS_PROP_BORDER_COLLAPSE:      // collapse | separate | inherit
00526         if ( id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE )
00527             valid_primitive = true;
00528         break;
00529 
00530     case CSS_PROP_VISIBILITY:           // visible | hidden | collapse | inherit
00531         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE)
00532             valid_primitive = true;
00533         break;
00534 
00535     case CSS_PROP_OVERFLOW:             // visible | hidden | scroll | auto | marquee | inherit
00536         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ||
00537             id == CSS_VAL_MARQUEE)
00538             valid_primitive = true;
00539         break;
00540 
00541     case CSS_PROP_LIST_STYLE_POSITION:  // inside | outside | inherit
00542         if ( id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE )
00543             valid_primitive = true;
00544         break;
00545 
00546     case CSS_PROP_LIST_STYLE_TYPE:
00547         // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
00548         // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
00549         // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
00550         // katakana | hiragana-iroha | katakana-iroha | none | inherit
00551         if ((id >= CSS_VAL_DISC && id <= CSS_VAL_KATAKANA_IROHA) || id == CSS_VAL_NONE)
00552             valid_primitive = true;
00553         break;
00554 
00555     case CSS_PROP_DISPLAY:
00556         // inline | block | list-item | run-in | inline-block | -khtml-ruler | table |
00557         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
00558         // table-column-group | table-column | table-cell | table-caption | none | inherit
00559         if ((id >= CSS_VAL_INLINE && id <= CSS_VAL_TABLE_CAPTION) || id == CSS_VAL_NONE)
00560             valid_primitive = true;
00561         break;
00562 
00563     case CSS_PROP_DIRECTION:            // ltr | rtl | inherit
00564         if ( id == CSS_VAL_LTR || id == CSS_VAL_RTL )
00565             valid_primitive = true;
00566         break;
00567 
00568     case CSS_PROP_TEXT_TRANSFORM:       // capitalize | uppercase | lowercase | none | inherit
00569         if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE)
00570             valid_primitive = true;
00571         break;
00572 
00573     case CSS_PROP_FLOAT:                // left | right | none | inherit + center for buggy CSS
00574         if ( id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
00575              id == CSS_VAL_NONE || id == CSS_VAL_CENTER)
00576             valid_primitive = true;
00577         break;
00578 
00579     case CSS_PROP_CLEAR:                // none | left | right | both | inherit
00580         if ( id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
00581              id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH)
00582             valid_primitive = true;
00583         break;
00584 
00585     case CSS_PROP_TEXT_ALIGN:
00586         // left | right | center | justify | khtml_left | khtml_right | khtml_center | <string> | inherit
00587         if ( ( id >= CSS_VAL__KHTML_AUTO && id <= CSS_VAL__KHTML_CENTER ) ||
00588              value->unit == CSSPrimitiveValue::CSS_STRING )
00589             valid_primitive = true;
00590         break;
00591 
00592     case CSS_PROP_OUTLINE_STYLE:        // <border-style> | inherit
00593     case CSS_PROP_BORDER_TOP_STYLE:     
00594     case CSS_PROP_BORDER_RIGHT_STYLE:   //   Defined as:    none | hidden | dotted | dashed |
00595     case CSS_PROP_BORDER_BOTTOM_STYLE:  //   solid | double | groove | ridge | inset | outset
00596     case CSS_PROP_BORDER_LEFT_STYLE:    
00597         if (id >= CSS_VAL_NONE && id <= CSS_VAL_DOUBLE)
00598             valid_primitive = true;
00599         break;
00600 
00601     case CSS_PROP_FONT_WEIGHT:  // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 |
00602         // 500 | 600 | 700 | 800 | 900 | inherit
00603         if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) {
00604             // Allready correct id
00605             valid_primitive = true;
00606         } else if ( validUnit( value, FInteger|FNonNeg, false ) ) {
00607             int weight = (int)value->fValue;
00608             if ( (weight % 100) )
00609                 break;
00610             weight /= 100;
00611             if ( weight >= 1 && weight <= 9 ) {
00612                 id = CSS_VAL_100 + weight - 1;
00613                 valid_primitive = true;
00614             }
00615         }
00616         break;
00617 
00618     case CSS_PROP_BACKGROUND_REPEAT:    // repeat | repeat-x | repeat-y | no-repeat | inherit
00619         if ( id >= CSS_VAL_REPEAT && id <= CSS_VAL_NO_REPEAT )
00620             valid_primitive = true;
00621         break;
00622 
00623     case CSS_PROP_BACKGROUND_ATTACHMENT: // scroll | fixed
00624         if ( id == CSS_VAL_SCROLL || id == CSS_VAL_FIXED )
00625             valid_primitive = true;
00626         break;
00627 
00628     case CSS_PROP_BACKGROUND_POSITION:
00629     {
00630         CSSPrimitiveValueImpl *pos[2];
00631         pos[0] = 0;
00632         pos[1] = 0;
00633         bool pos_ok[2];
00634         pos_ok[0] = true;
00635         pos_ok[1] = true;
00636 
00637         // if we loop beyond our values, do not call ->next twice
00638         bool skip_next = true;
00639 
00640         /* Problem: center is ambigous
00641          * In case of 'center' center defines X and Y coords
00642          * In case of 'center top', center defines the Y coord
00643          * in case of 'center left', center defines the X coord
00644          * in case of 'center 30%' center defines the X coord
00645          * in case of '30% center' center defines the Y coord
00646          */
00647         bool invalid = false;
00648         switch( id ) {
00649         case CSS_VAL_TOP:
00650             pos[0] = parseBackgroundPositionXY( CSS_PROP_BACKGROUND_POSITION_X, true, pos_ok[0] );
00651             if ( pos[0] && pos_ok[0] && pos[0]->primitiveType() != CSSPrimitiveValue::CSS_IDENT )
00652                 pos_ok[0] = false; // after top only key words are allowed
00653             pos[1] = new CSSPrimitiveValueImpl( 0, CSSPrimitiveValue::CSS_PERCENTAGE );
00654             break;
00655         case CSS_VAL_BOTTOM:
00656             pos[0] = parseBackgroundPositionXY( CSS_PROP_BACKGROUND_POSITION_X, true, pos_ok[0] );
00657             if ( pos[0] && pos_ok[0] && pos[0]->primitiveType() != CSSPrimitiveValue::CSS_IDENT )
00658                 pos_ok[0] = false; // after bottom only key words are allowed
00659             pos[1] = new CSSPrimitiveValueImpl( 100, CSSPrimitiveValue::CSS_PERCENTAGE );
00660             break;
00661         case CSS_VAL_LEFT:
00662             pos[0] = new CSSPrimitiveValueImpl( 0, CSSPrimitiveValue::CSS_PERCENTAGE );
00663             pos[1] = parseBackgroundPositionXY( CSS_PROP_BACKGROUND_POSITION_Y, true, pos_ok[1] );
00664             // after left everything is allowed
00665             break;
00666         case CSS_VAL_RIGHT:
00667             pos[0] = new CSSPrimitiveValueImpl( 100, CSSPrimitiveValue::CSS_PERCENTAGE );
00668             pos[1] = parseBackgroundPositionXY( CSS_PROP_BACKGROUND_POSITION_Y, true, pos_ok[1] );
00669             // after right everything is allowed
00670             break;
00671         case CSS_VAL_CENTER:
00672             value = valueList->next();
00673             if ( !value ) {
00674                 // only one 'center'
00675                 pos[0] = 0;
00676                 pos[1] = 0;
00677             } else {
00678                 bool ok = true;
00679                 CSSPrimitiveValueImpl *possibly_x = parseBackgroundPositionXY( CSS_PROP_BACKGROUND_POSITION_Y, false, ok );
00680                 if ( !ok ) {
00681                     assert( !possibly_x );
00682                     pos[0] = parseBackgroundPositionXY( CSS_PROP_BACKGROUND_POSITION_X, false, pos_ok[0] );
00683                     if ( !pos_ok[0] && expected != 1 ) {
00684                         pos_ok[0] = true;
00685                         pos[0] = 0;
00686                         skip_next = false;
00687                     }
00688                     pos[1] = 0;
00689                 } else {
00690                     pos[0] = 0;
00691                     pos[1] = possibly_x;
00692                 }
00693             }
00694             break;
00695         case 0: // units
00696             pos[0] = parseBackgroundPositionXY( CSS_PROP_BACKGROUND_POSITION_X, false, pos_ok[0] );
00697             if ( pos[0] ) {
00698                 pos[1] = parseBackgroundPositionXY( CSS_PROP_BACKGROUND_POSITION_Y, true, pos_ok[1] );
00699 
00700                 if ( pos_ok[1] && pos[1] && pos[1]->primitiveType() == CSSPrimitiveValue::CSS_IDENT ) {
00701                     // as the first hit the horizontal value as unit, the second value can only
00702                     // be either a unit or center, top or bottom
00703                     switch ( pos[1]->getIdent() )
00704                     {
00705                     case CSS_VAL_RIGHT:
00706                     case CSS_VAL_LEFT:
00707                         pos_ok[1] = false;
00708                         break;
00709                     }
00710                 }
00711             }
00712             break;
00713         default:
00714             invalid = true;
00715         }
00716         if ( invalid )
00717             break;
00718 
00719         if ( !pos_ok[0] || !pos_ok[1] ) {
00720             delete pos[0];
00721             delete pos[1];
00722             return false; // invalid
00723         }
00724 
00725 
00726         if ( !pos[0] )
00727             pos[0] = new CSSPrimitiveValueImpl( 50, CSSPrimitiveValue::CSS_PERCENTAGE );
00728         else if ( pos[0]->primitiveType() == CSSPrimitiveValue::CSS_IDENT )
00729         {
00730             // map the values to percentages
00731             id = pos[0]->getIdent();
00732             delete pos[0];
00733             switch ( id ) {
00734             case CSS_VAL_LEFT:
00735                 pos[0] =  new CSSPrimitiveValueImpl( 0, CSSPrimitiveValue::CSS_PERCENTAGE );
00736                 break;
00737             case CSS_VAL_CENTER:
00738                 pos[0] =  new CSSPrimitiveValueImpl( 50, CSSPrimitiveValue::CSS_PERCENTAGE );
00739                 break;
00740             case CSS_VAL_RIGHT:
00741                 pos[0] =  new CSSPrimitiveValueImpl( 100, CSSPrimitiveValue::CSS_PERCENTAGE );
00742                 break;
00743             default:
00744                 pos[0] = 0;
00745                 assert( false );
00746                 break;
00747             }
00748         }
00749         if ( !pos[1] )
00750             pos[1] = new CSSPrimitiveValueImpl( 50, CSSPrimitiveValue::CSS_PERCENTAGE );
00751         else if ( pos[1]->primitiveType() == CSSPrimitiveValue::CSS_IDENT )
00752         {
00753             // map the values to percentages
00754             id = pos[1]->getIdent();
00755             delete pos[1];
00756             switch ( id ) {
00757             case CSS_VAL_TOP:
00758                 pos[1] =  new CSSPrimitiveValueImpl( 0, CSSPrimitiveValue::CSS_PERCENTAGE );
00759                 break;
00760             case CSS_VAL_CENTER:
00761                 pos[1] =  new CSSPrimitiveValueImpl( 50, CSSPrimitiveValue::CSS_PERCENTAGE );
00762                 break;
00763             case CSS_VAL_BOTTOM:
00764                 pos[1] =  new CSSPrimitiveValueImpl( 100, CSSPrimitiveValue::CSS_PERCENTAGE );
00765                 break;
00766             default:
00767                 pos[1] = 0;
00768                 assert( false );
00769                 break;
00770             }
00771         }
00772         --expected; // we only expect one as this is always done in one run
00773         if ( skip_next )
00774             valueList->next();
00775         if ( valueList->current() && expected == 0)
00776             return false;
00777 
00778         addProperty( CSS_PROP_BACKGROUND_POSITION_X,
00779                      pos[0],
00780                      important );
00781         addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
00782                      pos[1],
00783                      important );
00784         return true;
00785     }
00786     case CSS_PROP_BORDER_SPACING:
00787     {
00788         const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING,
00789                                     CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
00790         int num = valueList->numValues;
00791         if (num == 1) {
00792             if (!parseValue(properties[0], important)) return false;
00793             CSSValueImpl* value = parsedProperties[numParsedProperties-1]->value();
00794             addProperty(properties[1], value, important);
00795             return true;
00796         }
00797         else if (num == 2) {
00798             if (!parseValue(properties[0], important, 2)) return false;
00799             if (!parseValue(properties[1], important, 1)) return false;
00800             return true;
00801         }
00802         return false;
00803     }
00804     case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING:
00805     case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING:
00806         valid_primitive = validUnit(value, FLength|FNonNeg, strict&(!nonCSSHint));
00807         break;
00808 
00809     case CSS_PROP_SCROLLBAR_FACE_COLOR:         // IE5.5
00810     case CSS_PROP_SCROLLBAR_SHADOW_COLOR:       // IE5.5
00811     case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:    // IE5.5
00812     case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:      // IE5.5
00813     case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:   // IE5.5
00814     case CSS_PROP_SCROLLBAR_TRACK_COLOR:        // IE5.5
00815     case CSS_PROP_SCROLLBAR_ARROW_COLOR:        // IE5.5
00816     case CSS_PROP_SCROLLBAR_BASE_COLOR:         // IE5.5
00817         if ( strict )
00818             break;
00819         /* nobreak */
00820     case CSS_PROP_OUTLINE_COLOR:        // <color> | invert | inherit
00821         // outline has "invert" as additional keyword.
00822         if ( propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT ) {
00823             valid_primitive = true;
00824             break;
00825         }
00826         /* nobreak */
00827     case CSS_PROP_BACKGROUND_COLOR:     // <color> | transparent | inherit
00828         if ( propId == CSS_PROP_BACKGROUND_COLOR && id == CSS_VAL_TRANSPARENT ) {
00829             valid_primitive = true;
00830             break;
00831         }
00832         /* nobreak */
00833     case CSS_PROP_COLOR:                // <color> | transparent | inherit
00834     case CSS_PROP_BORDER_TOP_COLOR:     // <color> | transparent | inherit
00835     case CSS_PROP_BORDER_RIGHT_COLOR:   // <color> | transparent | inherit
00836     case CSS_PROP_BORDER_BOTTOM_COLOR:  // <color> | transparent | inherit
00837     case CSS_PROP_BORDER_LEFT_COLOR:    // <color> | transparent | inherit
00838     case CSS_PROP__KHTML_TEXT_DECORATION_COLOR:
00839         if ( id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_MENU ||
00840              (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT ) ||
00841              id == CSS_VAL_TRANSPARENT ||
00842              (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && (nonCSSHint|!strict) ) ) {
00843             valid_primitive = true;
00844         } else {
00845             parsedValue = parseColor();
00846             if ( parsedValue )
00847                 valueList->next();
00848         }
00849         break;
00850 
00851     case CSS_PROP_CURSOR:
00852         //  [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
00853         // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | text |
00854         // wait | help ] ] | inherit
00855     // MSIE 5 compatibility :/
00856         if ( !strict && id == CSS_VAL_HAND ) {
00857             id = CSS_VAL_POINTER;
00858             valid_primitive = true;
00859         } else if ( id >= CSS_VAL_AUTO && id <= CSS_VAL_HELP )
00860             valid_primitive = true;
00861         break;
00862 
00863     case CSS_PROP_BACKGROUND_IMAGE:     // <uri> | none | inherit
00864     case CSS_PROP_LIST_STYLE_IMAGE:     // <uri> | none | inherit
00865 
00866         if ( id == CSS_VAL_NONE ) {
00867             parsedValue = new CSSImageValueImpl();
00868             valueList->next();
00869 #ifdef CSS_DEBUG
00870             kdDebug( 6080 ) << "empty image " << endl;
00871 #endif
00872         } else if ( value->unit == CSSPrimitiveValue::CSS_URI ) {
00873             // ### allow string in non strict mode?
00874             DOMString uri = khtml::parseURL( domString( value->string ) );
00875             if ( !uri.isEmpty() ) {
00876                 parsedValue = new CSSImageValueImpl(
00877                     DOMString(KURL( styleElement->baseURL(), uri.string()).url()),
00878                     styleElement );
00879                 valueList->next();
00880 #ifdef CSS_DEBUG
00881                 kdDebug( 6080 ) << "image, url=" << uri.string() << " base=" << styleElement->baseURL().url() << endl;
00882 #endif
00883             }
00884         }
00885         break;
00886 
00887     case CSS_PROP_OUTLINE_WIDTH:        // <border-width> | inherit
00888     case CSS_PROP_BORDER_TOP_WIDTH:     
00889     case CSS_PROP_BORDER_RIGHT_WIDTH:   //   Which is defined as
00890     case CSS_PROP_BORDER_BOTTOM_WIDTH:  //   thin | medium | thick | <length>
00891     case CSS_PROP_BORDER_LEFT_WIDTH:    
00892         if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
00893             valid_primitive = true;
00894         else
00895             valid_primitive = ( validUnit( value, FLength, strict&(!nonCSSHint) ) );
00896         break;
00897 
00898     case CSS_PROP_LETTER_SPACING:       // normal | <length> | inherit
00899     case CSS_PROP_WORD_SPACING:         // normal | <length> | inherit
00900         if ( id == CSS_VAL_NORMAL )
00901             valid_primitive = true;
00902         else
00903             valid_primitive = validUnit( value, FLength, strict&(!nonCSSHint) );
00904         break;
00905 
00906     case CSS_PROP_TEXT_INDENT:          //  <length> | <percentage> | inherit
00907         valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00908         break;
00909 
00910     case CSS_PROP_PADDING_TOP:          //  <length> | <percentage> | inherit
00911     case CSS_PROP_PADDING_RIGHT:        //  <padding-width> | inherit
00912     case CSS_PROP_PADDING_BOTTOM:       //   Which is defined as
00913     case CSS_PROP_PADDING_LEFT:         //   <length> | <percentage>
00914         valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00915         break;
00916 
00917     case CSS_PROP_MAX_HEIGHT:           // <length> | <percentage> | none | inherit
00918     case CSS_PROP_MAX_WIDTH:            // <length> | <percentage> | none | inherit
00919         if ( id == CSS_VAL_NONE ) {
00920             valid_primitive = true;
00921             break;
00922         }
00923         /* nobreak */
00924     case CSS_PROP_MIN_HEIGHT:           // <length> | <percentage> | inherit
00925     case CSS_PROP_MIN_WIDTH:            // <length> | <percentage> | inherit
00926             valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00927         break;
00928 
00929     case CSS_PROP_FONT_SIZE:
00930             // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
00931         if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER)
00932             valid_primitive = true;
00933         else
00934             valid_primitive = ( validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00935         break;
00936 
00937     case CSS_PROP_FONT_STYLE:           // normal | italic | oblique | inherit
00938         if ( id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE)
00939             valid_primitive = true;
00940         break;
00941 
00942     case CSS_PROP_FONT_VARIANT:         // normal | small-caps | inherit
00943         if ( id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS)
00944             valid_primitive = true;
00945         break;
00946 
00947     case CSS_PROP_VERTICAL_ALIGN:
00948             // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
00949         // <percentage> | <length> | inherit
00950 
00951         if ( id >= CSS_VAL_BASELINE && id <= CSS_VAL__KHTML_BASELINE_MIDDLE )
00952             valid_primitive = true;
00953         else
00954             valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00955         break;
00956 
00957     case CSS_PROP_HEIGHT:               // <length> | <percentage> | auto | inherit
00958     case CSS_PROP_WIDTH:                // <length> | <percentage> | auto | inherit
00959         if ( id == CSS_VAL_AUTO )
00960             valid_primitive = true;
00961         else
00962             // ### handle multilength case where we allow relative units
00963             valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00964         break;
00965 
00966     case CSS_PROP_BOTTOM:               // <length> | <percentage> | auto | inherit
00967     case CSS_PROP_LEFT:                 // <length> | <percentage> | auto | inherit
00968     case CSS_PROP_RIGHT:                // <length> | <percentage> | auto | inherit
00969     case CSS_PROP_TOP:                  // <length> | <percentage> | auto | inherit
00970     case CSS_PROP_MARGIN_TOP:           
00971     case CSS_PROP_MARGIN_RIGHT:         //   Which is defined as
00972     case CSS_PROP_MARGIN_BOTTOM:        //   <length> | <percentage> | auto | inherit
00973     case CSS_PROP_MARGIN_LEFT:          
00974         if ( id == CSS_VAL_AUTO )
00975             valid_primitive = true;
00976         else
00977             valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00978         break;
00979 
00980     case CSS_PROP_Z_INDEX:              // auto | <integer> | inherit
00981         // qDebug("parsing z-index: id=%d, fValue=%f", id, value->fValue );
00982         if ( id == CSS_VAL_AUTO ) {
00983             valid_primitive = true;
00984             break;
00985         }
00986         /* nobreak */
00987     case CSS_PROP_ORPHANS:              // <integer> | inherit
00988     case CSS_PROP_WIDOWS:               // <integer> | inherit
00989         // ### not supported later on
00990         valid_primitive = ( !id && validUnit( value, FInteger, false ) );
00991         break;
00992 
00993     case CSS_PROP_LINE_HEIGHT:          // normal | <number> | <length> | <percentage> | inherit
00994         if ( id == CSS_VAL_NORMAL )
00995             valid_primitive = true;
00996         else
00997             valid_primitive = ( !id && validUnit( value, FNumber|FLength|FPercent, strict&(!nonCSSHint) ) );
00998         break;
00999 #if 0
01000         // removed from CSS 2.1
01001     case CSS_PROP_COUNTER_INCREMENT:    // [ <identifier> <integer>? ]+ | none | inherit
01002     case CSS_PROP_COUNTER_RESET:        // [ <identifier> <integer>? ]+ | none | inherit
01003         if ( id == CSS_VAL_NONE )
01004             valid_primitive = true;
01005         else {
01006             CSSValueListImpl *list = new CSSValueListImpl;
01007             int pos=0, pos2;
01008             while( 1 )
01009             {
01010                 pos2 = value.find(',', pos);
01011                 QString face = value.mid(pos, pos2-pos);
01012                 face = face.stripWhiteSpace();
01013                 if(face.length() == 0) break;
01014                 // ### single quoted is missing...
01015                 if(face[0] == '\"') face.remove(0, 1);
01016                 if(face[face.length()-1] == '\"') face = face.left(face.length()-1);
01017                 //kdDebug( 6080 ) << "found face '" << face << "'" << endl;
01018                 list->append(new CSSPrimitiveValueImpl(DOMString(face), CSSPrimitiveValue::CSS_STRING));
01019                 pos = pos2 + 1;
01020                 if(pos2 == -1) break;
01021             }
01022             //kdDebug( 6080 ) << "got " << list->length() << " faces" << endl;
01023             if(list->length()) {
01024                 parsedValue = list;
01025                 valueList->next();
01026             } else
01027                 delete list;
01028             break;
01029         }
01030 #endif
01031     case CSS_PROP_FONT_FAMILY:
01032             // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
01033     {
01034         parsedValue = parseFontFamily();
01035         break;
01036     }
01037 
01038     case CSS_PROP_TEXT_DECORATION:
01039             // none | [ underline || overline || line-through || blink ] | inherit
01040         if (id == CSS_VAL_NONE) {
01041             valid_primitive = true;
01042         } else {
01043             CSSValueListImpl *list = new CSSValueListImpl;
01044             bool is_valid = true;
01045             while( is_valid && value ) {
01046                 switch ( value->id ) {
01047                 case CSS_VAL_BLINK:
01048                     break;
01049                 case CSS_VAL_UNDERLINE:
01050                 case CSS_VAL_OVERLINE:
01051                 case CSS_VAL_LINE_THROUGH:
01052                     list->append( new CSSPrimitiveValueImpl( value->id ) );
01053                     break;
01054                 default:
01055                     is_valid = false;
01056                 }
01057                 value = valueList->next();
01058             }
01059             //kdDebug( 6080 ) << "got " << list->length() << "d decorations" << endl;
01060             if(list->length() && is_valid) {
01061                 parsedValue = list;
01062                 valueList->next();
01063             } else {
01064                 delete list;
01065             }
01066         }
01067         break;
01068 
01069     case CSS_PROP_TABLE_LAYOUT:         // auto | fixed | inherit
01070         if ( id == CSS_VAL_AUTO || id == CSS_VAL_FIXED )
01071             valid_primitive = true;
01072         break;
01073 
01074     case CSS_PROP__KHTML_FLOW_MODE:
01075         if ( id == CSS_VAL__KHTML_NORMAL || id == CSS_VAL__KHTML_AROUND_FLOATS )
01076             valid_primitive = true;
01077         break;
01078 
01079     /* CSS3 properties */
01080     case CSS_PROP_BOX_SIZING:        // border-box | content-box | inherit
01081         if ( id == CSS_VAL_BORDER_BOX || id == CSS_VAL_CONTENT_BOX )
01082             valid_primitive = true;
01083         break;
01084     case CSS_PROP__KHTML_USER_INPUT:        // none | enabled | disabled | inherit
01085         if ( id == CSS_VAL_NONE || id == CSS_VAL_ENABLED || id == CSS_VAL_DISABLED )
01086             valid_primitive = true;
01087 //        kdDebug(6080) << "CSS_PROP__KHTML_USER_INPUT: " << valid_primitive << endl;
01088         break;
01089     case CSS_PROP__KHTML_MARQUEE: {
01090         const int properties[5] = { CSS_PROP__KHTML_MARQUEE_DIRECTION, CSS_PROP__KHTML_MARQUEE_INCREMENT,
01091                                     CSS_PROP__KHTML_MARQUEE_REPETITION,
01092                                     CSS_PROP__KHTML_MARQUEE_STYLE, CSS_PROP__KHTML_MARQUEE_SPEED };
01093         return parseShortHand(properties, 5, important);
01094     }
01095     case CSS_PROP__KHTML_MARQUEE_DIRECTION:
01096         if (id == CSS_VAL_FORWARDS || id == CSS_VAL_BACKWARDS || id == CSS_VAL_AHEAD ||
01097             id == CSS_VAL_REVERSE || id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_DOWN ||
01098             id == CSS_VAL_UP || id == CSS_VAL_AUTO)
01099             valid_primitive = true;
01100         break;
01101     case CSS_PROP__KHTML_MARQUEE_INCREMENT:
01102         if (id == CSS_VAL_SMALL || id == CSS_VAL_LARGE || id == CSS_VAL_MEDIUM)
01103             valid_primitive = true;
01104         else
01105             valid_primitive = validUnit(value, FLength|FPercent, strict&(!nonCSSHint));
01106         break;
01107     case CSS_PROP__KHTML_MARQUEE_STYLE:
01108         if (id == CSS_VAL_NONE || id == CSS_VAL_SLIDE || id == CSS_VAL_SCROLL || id == CSS_VAL_ALTERNATE ||
01109             id == CSS_VAL_UNFURL)
01110             valid_primitive = true;
01111         break;
01112     case CSS_PROP__KHTML_MARQUEE_REPETITION:
01113         if (id == CSS_VAL_INFINITE)
01114             valid_primitive = true;
01115         else
01116             valid_primitive = validUnit(value, FInteger|FNonNeg, strict&(!nonCSSHint));
01117         break;
01118     case CSS_PROP__KHTML_MARQUEE_SPEED:
01119         if (id == CSS_VAL_NORMAL || id == CSS_VAL_SLOW || id == CSS_VAL_FAST)
01120             valid_primitive = true;
01121         else
01122             valid_primitive = validUnit(value, FTime|FInteger|FNonNeg, strict&(!nonCSSHint));
01123         break;
01124     // End of CSS3 properties
01125 
01126         /* shorthand properties */
01127     case CSS_PROP_BACKGROUND:
01128             // ['background-color' || 'background-image' ||'background-repeat' ||
01129         // 'background-attachment' || 'background-position'] | inherit
01130     {
01131         /* FIXME: in case the property is invalid, but parsed a position-x and -y, the
01132            invalid catcher will add another _POSITION property, which doesn't really overwrite
01133            the X and Y values. But this case is pretty stupid anyway.
01134            testcase: "background-position: bottom right; background: center nonsense;" should
01135            appear top left (initial values) */
01136         const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
01137                                     CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,
01138                                     CSS_PROP_BACKGROUND_COLOR };
01139         return parseShortHand(properties, 5, important);
01140     }
01141     case CSS_PROP_BORDER:
01142          // [ 'border-width' || 'border-style' || <color> ] | inherit
01143     {
01144         const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
01145                                     CSS_PROP_BORDER_COLOR };
01146         return parseShortHand(properties, 3, important);
01147     }
01148     case CSS_PROP_BORDER_TOP:
01149             // [ 'border-top-width' || 'border-style' || <color> ] | inherit
01150     {
01151         const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
01152                                     CSS_PROP_BORDER_TOP_COLOR};
01153         return parseShortHand(properties, 3, important);
01154     }
01155     case CSS_PROP_BORDER_RIGHT:
01156             // [ 'border-right-width' || 'border-style' || <color> ] | inherit
01157     {
01158         const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
01159                                     CSS_PROP_BORDER_RIGHT_COLOR };
01160         return parseShortHand(properties, 3, important);
01161     }
01162     case CSS_PROP_BORDER_BOTTOM:
01163             // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
01164     {
01165         const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
01166                                     CSS_PROP_BORDER_BOTTOM_COLOR };
01167         return parseShortHand(properties, 3, important);
01168     }
01169     case CSS_PROP_BORDER_LEFT:
01170             // [ 'border-left-width' || 'border-style' || <color> ] | inherit
01171     {
01172         const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
01173                                     CSS_PROP_BORDER_LEFT_COLOR };
01174         return parseShortHand(properties, 3, important);
01175     }
01176     case CSS_PROP_OUTLINE:
01177             // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
01178     {
01179         const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
01180                                     CSS_PROP_OUTLINE_COLOR };
01181         return parseShortHand(properties, 3, important);
01182     }
01183     case CSS_PROP_BORDER_COLOR:
01184             // <color>{1,4} | transparent | inherit
01185     {
01186         const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
01187                                     CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
01188         return parse4Values(properties, important);
01189     }
01190     case CSS_PROP_BORDER_WIDTH:
01191             // <border-width>{1,4} | inherit
01192     {
01193         const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
01194                                     CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
01195         return parse4Values(properties, important);
01196     }
01197     case CSS_PROP_BORDER_STYLE:
01198             // <border-style>{1,4} | inherit
01199     {
01200         const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
01201                                     CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
01202         return parse4Values(properties, important);
01203     }
01204     case CSS_PROP_MARGIN:
01205             // <margin-width>{1,4} | inherit
01206     {
01207         const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
01208                                     CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
01209         return parse4Values(properties, important);
01210     }
01211     case CSS_PROP_PADDING:
01212             // <padding-width>{1,4} | inherit
01213     {
01214         const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
01215                                     CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
01216         return parse4Values(properties, important);
01217     }
01218     case CSS_PROP_FONT:
01219             // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
01220         // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
01221         if ( id >= CSS_VAL_CAPTION && id <= CSS_VAL_STATUS_BAR )
01222             valid_primitive = true;
01223         else
01224             return parseFont(important);
01225 
01226     case CSS_PROP_LIST_STYLE:
01227     {
01228         const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
01229                                     CSS_PROP_LIST_STYLE_IMAGE };
01230         return parseShortHand(properties, 3, important);
01231     }
01232     default:
01233 // #ifdef CSS_DEBUG
01234 //         kdDebug( 6080 ) << "illegal or CSS2 Aural property: " << val << endl;
01235 // #endif
01236         break;
01237     }
01238 
01239     if ( valid_primitive ) {
01240 
01241         if ( id != 0 ) {
01242             // qDebug(" new value: id=%d", id );
01243             parsedValue = new CSSPrimitiveValueImpl( id );
01244         } else if ( value->unit == CSSPrimitiveValue::CSS_STRING )
01245             parsedValue = new CSSPrimitiveValueImpl( domString( value->string ),
01246                                                      (CSSPrimitiveValue::UnitTypes) value->unit );
01247         else if ( value->unit >= CSSPrimitiveValue::CSS_NUMBER &&
01248                   value->unit <= CSSPrimitiveValue::CSS_KHZ ) {
01249             // qDebug(" new value: value=%.2f, unit=%d", value->fValue, value->unit );
01250             parsedValue = new CSSPrimitiveValueImpl( value->fValue,
01251                                                      (CSSPrimitiveValue::UnitTypes) value->unit );
01252         } else if ( value->unit >= Value::Q_EMS ) {
01253             // qDebug(" new quirks value: value=%.2f, unit=%d", value->fValue, value->unit );
01254             parsedValue = new CSSQuirkPrimitiveValueImpl( value->fValue, CSSPrimitiveValue::CSS_EMS );
01255         }
01256         --expected;
01257         valueList->next();
01258         if ( valueList->current() && expected == 0)
01259         {
01260             delete parsedValue;
01261             parsedValue = 0;
01262         }
01263     }
01264     if ( parsedValue ) {
01265         addProperty( propId, parsedValue, important );
01266         return true;
01267     }
01268     return false;
01269 }
01270 
01271 bool CSSParser::parseShortHand( const int *properties, int numProperties, bool important )
01272 {
01273     /* We try to match as many properties as possible
01274      * We setup an array of booleans to mark which property has been found,
01275      * and we try to search for properties until it makes no longer any sense
01276      */
01277     inParseShortHand = true;
01278 
01279     bool found = false;
01280     bool oldPropIndex = numParsedProperties;
01281     bool fnd[6]; //Trust me ;)
01282     for( int i = 0; i < numProperties; i++ )
01283             fnd[i] = false;
01284 
01285 #ifdef CSS_DEBUG
01286     kdDebug(6080) << "PSH: numProperties=" << numProperties << endl;
01287 #endif
01288 
01289     while ( valueList->current() ) {
01290         found = false;
01291         // qDebug("outer loop" );
01292         for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
01293             if (!fnd[propIndex]) {
01294 #ifdef CSS_DEBUG
01295                 kdDebug(6080) << "LOOKING FOR: " << getPropertyName(properties[propIndex]).string() << endl;
01296 #endif
01297                 if ( parseValue( properties[propIndex], important, numProperties ) ) {
01298                     fnd[propIndex] = found = true;
01299 #ifdef CSS_DEBUG
01300                     kdDebug(6080) << "FOUND: " << getPropertyName(properties[propIndex]).string() << endl;
01301 #endif
01302                 }
01303             }
01304         }
01305         // if we didn't find at least one match, this is an
01306         // invalid shorthand and we have to ignore it
01307         if (!found) {
01308 #ifdef CSS_DEBUG
01309             qDebug("didn't find anything" );
01310 #endif
01311 
01312             // need to nuke the already added values
01313             for ( int i = oldPropIndex; i < numParsedProperties; ++i )
01314                 delete parsedProperties[i];
01315 
01316             numParsedProperties = oldPropIndex;
01317             inParseShortHand = false;
01318             return false;
01319         }
01320     }
01321 
01322     // Fill in any remaining properties with the initial value.
01323     for (int i = 0; i < numProperties; ++i) {
01324         if (!fnd[i])
01325             addProperty(properties[i], new CSSInitialValueImpl(), important);
01326     }
01327 
01328     inParseShortHand = false;
01329 #ifdef CSS_DEBUG
01330     kdDebug( 6080 ) << "parsed shorthand" << endl;
01331 #endif
01332     return true;
01333 }
01334 
01335 bool CSSParser::parse4Values( const int *properties,  bool important )
01336 {
01337     /* From the CSS 2 specs, 8.3
01338      * If there is only one value, it applies to all sides. If there are two values, the top and
01339      * bottom margins are set to the first value and the right and left margins are set to the second.
01340      * If there are three values, the top is set to the first value, the left and right are set to the
01341      * second, and the bottom is set to the third. If there are four values, they apply to the top,
01342      * right, bottom, and left, respectively.
01343      */
01344 
01345     int num = inParseShortHand ? 1 : valueList->numValues;
01346     //qDebug("parse4Values: num=%d %d", num,  valueList->numValues );
01347 
01348     // the order is top, right, bottom, left
01349     switch( num ) {
01350     case 1: {
01351         if( !parseValue( properties[0], important, valueList->numValues ) ) return false;
01352         CSSValueImpl *value = parsedProperties[numParsedProperties-1]->value();
01353         addProperty( properties[1], value, important );
01354         addProperty( properties[2], value, important );
01355         addProperty( properties[3], value, important );
01356         return true;
01357     }
01358     case 2: {
01359 
01360         if( !parseValue( properties[0], important, valueList->numValues ) ) return false;
01361         if( !parseValue( properties[1], important, valueList->numValues) ) return false;
01362         CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
01363         addProperty( properties[2], value, important );
01364         value = parsedProperties[numParsedProperties-2]->value();
01365         addProperty( properties[3], value, important );
01366         return true;
01367     }
01368     case 3: {
01369         if( !parseValue( properties[0], important, valueList->numValues ) ) return false;
01370         if( !parseValue( properties[1], important, valueList->numValues ) ) return false;
01371         if( !parseValue( properties[2], important, valueList->numValues ) ) return false;
01372         CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
01373         addProperty( properties[3], value, important );
01374         return true;
01375     }
01376     case 4: {
01377         if( !parseValue( properties[0], important, valueList->numValues ) ) return false;
01378         if( !parseValue( properties[1], important, valueList->numValues ) ) return false;
01379         if( !parseValue( properties[2], important, valueList->numValues ) ) return false;
01380         if( !parseValue( properties[3], important, valueList->numValues ) ) return false;
01381         return true;
01382     }
01383     default:
01384         return false;
01385     }
01386 }
01387 
01388 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
01389 // in CSS 2.1 this got somewhat reduced:
01390 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
01391 bool CSSParser::parseContent( int propId, bool important )
01392 {
01393     CSSValueListImpl* values = new CSSValueListImpl();
01394 
01395     Value *val;
01396     CSSValueImpl *parsedValue = 0;
01397     while ( (val = valueList->current()) ) {
01398         if ( val->unit == CSSPrimitiveValue::CSS_URI ) {
01399             // url
01400             DOMString value = khtml::parseURL(domString(val->string));
01401             parsedValue = new CSSImageValueImpl(
01402                 DOMString(KURL( styleElement->baseURL(), value.string()).url() ), styleElement );
01403 #ifdef CSS_DEBUG
01404             kdDebug( 6080 ) << "content, url=" << value.string() << " base=" << styleElement->baseURL().url( ) << endl;
01405 #endif
01406         } else if ( val->unit == Value::Function ) {
01407             // attr( X )
01408             ValueList *args = val->function->args;
01409             QString fname = qString( val->function->name ).lower();
01410             if ( fname != "attr(" || !args )
01411                 return false;
01412             if ( args->numValues != 1)
01413                 return false;
01414             Value *a = args->current();
01415             parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR);
01416         } else if ( val->unit == CSSPrimitiveValue::CSS_IDENT ) {
01417             // open-quote
01418             // close-quote
01419             // no-open-quote
01420             // no-close-quote
01421         } else if ( val->unit == CSSPrimitiveValue::CSS_STRING ) {
01422             parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING);
01423         }
01424         if (parsedValue)
01425             values->append(parsedValue);
01426         else
01427             break;
01428         valueList->next();
01429     }
01430     if ( values->length() ) {
01431         addProperty( propId, values, important );
01432         valueList->next();
01433         return true;
01434     }
01435     delete values;
01436     return false;
01437 }
01438 
01439 bool CSSParser::parseShape( int propId, bool important )
01440 {
01441     Value *value = valueList->current();
01442     ValueList *args = value->function->args;
01443     QString fname = qString( value->function->name ).lower();
01444     //qDebug( "parseShape: fname: %d", fname.latin1() );
01445     if ( fname != "rect(" || !args )
01446         return false;
01447 
01448     // rect( t, r, b, l ) || rect( t r b l )
01449     if ( args->numValues != 4 && args->numValues != 7 )
01450         return false;
01451     RectImpl *rect = new RectImpl();
01452     bool valid = true;
01453     int i = 0;
01454     Value *a = args->current();
01455     while ( a ) {
01456         valid = validUnit( a, FLength, strict );
01457         if ( !valid )
01458             break;
01459         CSSPrimitiveValueImpl *length =
01460             new CSSPrimitiveValueImpl( a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit );
01461         if ( i == 0 )
01462             rect->setTop( length );
01463         else if ( i == 1 )
01464             rect->setRight( length );
01465         else if ( i == 2 )
01466             rect->setBottom( length );
01467         else
01468             rect->setLeft( length );
01469         a = args->next();
01470         if ( a && args->numValues == 7 ) {
01471             if ( a->unit == Value::Operator && a->iValue == ',' ) {
01472                 a = args->next();
01473             } else {
01474                 valid = false;
01475                 break;
01476             }
01477         }
01478         i++;
01479     }
01480     if ( valid ) {
01481         addProperty( propId, new CSSPrimitiveValueImpl( rect ), important );
01482         valueList->next();
01483         return true;
01484     }
01485     delete rect;
01486     return false;
01487 }
01488 
01489 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
01490 bool CSSParser::parseFont( bool important )
01491 {
01492 //     kdDebug(6080) << "parsing font property current=" << valueList->currentValue << endl;
01493     bool valid = true;
01494     Value *value = valueList->current();
01495     FontValueImpl *font = new FontValueImpl;
01496     // optional font-style, font-variant and font-weight
01497     while ( value ) {
01498 //         kdDebug( 6080 ) << "got value " << value->id << " / " << (value->unit == CSSPrimitiveValue::CSS_STRING ||
01499         //                                    value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
01500 //                         << endl;
01501         int id = value->id;
01502         if ( id ) {
01503             if ( id == CSS_VAL_NORMAL ) {
01504                 // do nothing, it's the initial value for all three
01505             }
01506             /*
01507               else if ( id == CSS_VAL_INHERIT ) {
01508               // set all non set ones to inherit
01509               // This is not that simple as the inherit could also apply to the following font-size.
01510               // very ahrd to tell without looking ahead.
01511               inherit = true;
01512                 } */
01513             else if ( id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE ) {
01514                 if ( font->style )
01515                     goto invalid;
01516                 font->style = new CSSPrimitiveValueImpl( id );
01517             } else if ( id == CSS_VAL_SMALL_CAPS ) {
01518                 if ( font->variant )
01519                     goto invalid;
01520                 font->variant = new CSSPrimitiveValueImpl( id );
01521             } else if ( id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER ) {
01522                 if ( font->weight )
01523                     goto invalid;
01524                 font->weight = new CSSPrimitiveValueImpl( id );
01525             } else {
01526                 valid = false;
01527             }
01528         } else if ( !font->weight && validUnit( value, FInteger|FNonNeg, true ) ) {
01529             int weight = (int)value->fValue;
01530             int val = 0;
01531             if ( weight == 100 )
01532                 val = CSS_VAL_100;
01533             else if ( weight == 200 )
01534                 val = CSS_VAL_200;
01535             else if ( weight == 300 )
01536                 val = CSS_VAL_300;
01537             else if ( weight == 400 )
01538                 val = CSS_VAL_400;
01539             else if ( weight == 500 )
01540                 val = CSS_VAL_500;
01541             else if ( weight == 600 )
01542                 val = CSS_VAL_600;
01543             else if ( weight == 700 )
01544                 val = CSS_VAL_700;
01545             else if ( weight == 800 )
01546                 val = CSS_VAL_800;
01547             else if ( weight == 900 )
01548                 val = CSS_VAL_900;
01549 
01550             if ( val )
01551                 font->weight = new CSSPrimitiveValueImpl( val );
01552             else
01553                 valid = false;
01554         } else {
01555             valid = false;
01556         }
01557         if ( !valid )
01558             break;
01559         value = valueList->next();
01560     }
01561     if ( !value )
01562         goto invalid;
01563 
01564     // set undefined values to default
01565     if ( !font->style )
01566         font->style = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01567     if ( !font->variant )
01568         font->variant = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01569     if ( !font->weight )
01570         font->weight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01571 
01572 //     kdDebug( 6080 ) << "  got style, variant and weight current=" << valueList->currentValue << endl;
01573 
01574     // now a font size _must_ come
01575     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
01576     if ( value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER )
01577         font->size = new CSSPrimitiveValueImpl( value->id );
01578     else if ( validUnit( value, FLength|FPercent, strict ) ) {
01579         font->size = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01580     }
01581     value = valueList->next();
01582     if ( !font->size || !value )
01583         goto invalid;
01584 
01585     // kdDebug( 6080 ) << "  got size" << endl;
01586 
01587     if ( value->unit == Value::Operator && value->iValue == '/' ) {
01588         // line-height
01589         value = valueList->next();
01590         if ( !value )
01591             goto invalid;
01592         if ( value->id == CSS_VAL_NORMAL ) {
01593             // default value, nothing to do
01594         } else if ( validUnit( value, FNumber|FLength|FPercent, strict ) ) {
01595             font->lineHeight = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01596         } else {
01597             goto invalid;
01598         }
01599         value = valueList->next();
01600         if ( !value )
01601             goto invalid;
01602     }
01603     if ( !font->lineHeight )
01604         font->lineHeight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01605 
01606 //     kdDebug( 6080 ) << "  got line height current=" << valueList->currentValue << endl;
01607     // font family must come now
01608     font->family = parseFontFamily();
01609 
01610     if ( valueList->current() || !font->family )
01611         goto invalid;
01612     //kdDebug( 6080 ) << "  got family, parsing ok!" << endl;
01613 
01614     addProperty( CSS_PROP_FONT, font, important );
01615     return true;
01616 
01617  invalid:
01618     //kdDebug(6080) << "   -> invalid" << endl;
01619     delete font;
01620     return false;
01621 }
01622 
01623 CSSValueListImpl *CSSParser::parseFontFamily()
01624 {
01625 //     kdDebug( 6080 ) << "CSSParser::parseFontFamily current=" << valueList->currentValue << endl;
01626     CSSValueListImpl *list = new CSSValueListImpl;
01627     Value *value = valueList->current();
01628     QString currFace;
01629 
01630     while ( value ) {
01631 //         kdDebug( 6080 ) << "got value " << value->id << " / "
01632 //                         << (value->unit == CSSPrimitiveValue::CSS_STRING ||
01633 //                             value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
01634 //                         << endl;
01635         Value* nextValue = valueList->next();
01636         bool nextValBreaksFont = !nextValue ||
01637                                  (nextValue->unit == Value::Operator && nextValue->iValue == ',');
01638         bool nextValIsFontName = nextValue &&
01639                                  ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL_MONOSPACE) ||
01640                                   (nextValue->unit == CSSPrimitiveValue::CSS_STRING ||
01641                                    nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
01642 
01643         if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL_MONOSPACE) {
01644             if (!currFace.isNull()) {
01645                 currFace += ' ';
01646                 currFace += qString(value->string);
01647             }
01648             else if (nextValBreaksFont || !nextValIsFontName) {
01649                 if ( !currFace.isNull() ) {
01650                     list->append( new FontFamilyValueImpl( currFace ) );
01651                     currFace = QString::null;
01652                 }
01653                 list->append(new CSSPrimitiveValueImpl(value->id));
01654             }
01655             else {
01656                 currFace = qString( value->string );
01657             }
01658         }
01659         else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
01660             // Strings never share in a family name.
01661             currFace = QString::null;
01662             list->append(new FontFamilyValueImpl(qString( value->string) ) );
01663         }
01664         else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
01665             if (!currFace.isNull()) {
01666                 currFace += ' ';
01667                 currFace += qString(value->string);
01668             }
01669             else if (nextValBreaksFont || !nextValIsFontName) {
01670                 if ( !currFace.isNull() ) {
01671                     list->append( new FontFamilyValueImpl( currFace ) );
01672                     currFace = QString::null;
01673                 }
01674                 list->append(new FontFamilyValueImpl( qString( value->string ) ) );
01675         }
01676         else {
01677                 currFace = qString( value->string);
01678         }
01679         }
01680     else {
01681         //kdDebug( 6080 ) << "invalid family part" << endl;
01682             break;
01683         }
01684 
01685         if (!nextValue)
01686             break;
01687 
01688         if (nextValBreaksFont) {
01689         value = valueList->next();
01690             if ( !currFace.isNull() )
01691                 list->append( new FontFamilyValueImpl( currFace ) );
01692             currFace = QString::null;
01693         }
01694         else if (nextValIsFontName)
01695             value = nextValue;
01696         else
01697             break;
01698     }
01699 
01700     if ( !currFace.isNull() )
01701         list->append( new FontFamilyValueImpl( currFace ) );
01702 
01703     if ( !list->length() ) {
01704         delete list;
01705         list = 0;
01706     }
01707     return list;
01708 }
01709 
01710 
01711 static bool parseColor(int unit, const QString &name, QRgb& rgb)
01712 {
01713     int len = name.length();
01714 
01715     if ( !len )
01716         return false;
01717 
01718 
01719     bool ok;
01720 
01721     if ( len == 3 || len == 6 ) {
01722         int val = name.toInt(&ok, 16);
01723         if ( ok ) {
01724             if (len == 6) {
01725                 rgb = (0xff << 24) | val;
01726                 return true;
01727             }
01728             else if ( len == 3 ) {
01729                 // #abc converts to #aabbcc according to the specs
01730                 rgb = (0xff << 24) |
01731                       (val&0xf00)<<12 | (val&0xf00)<<8 |
01732                       (val&0xf0)<<8 | (val&0xf0)<<4 |
01733                       (val&0xf)<<4 | (val&0xf);
01734                 return true;
01735             }
01736         }
01737     }
01738 
01739     if ( unit == CSSPrimitiveValue::CSS_IDENT ) {
01740         // try a little harder
01741         QColor tc;
01742         tc.setNamedColor(name.lower());
01743         if ( tc.isValid() ) {
01744             rgb = tc.rgb();
01745             return true;
01746         }
01747     }
01748 
01749     return false;
01750 }
01751 
01752 
01753 CSSPrimitiveValueImpl *CSSParser::parseColor()
01754 {
01755     QRgb c = khtml::transparentColor;
01756     Value *value = valueList->current();
01757     if ( !strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
01758               value->fValue >= 0. && value->fValue < 1000000. ) {
01759         QString str;
01760         str.sprintf( "%06d", (int)(value->fValue+.5) );
01761         if ( !::parseColor( value->unit, str, c ) )
01762             return 0;
01763     } else if ( value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
01764               value->unit == CSSPrimitiveValue::CSS_IDENT ||
01765               (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION) ) {
01766         if ( !::parseColor( value->unit, qString( value->string ), c) )
01767             return 0;
01768     }
01769     else if ( value->unit == Value::Function &&
01770         value->function->args != 0 &&
01771                 value->function->args->numValues == 5 /* rgb + two commas */ &&
01772                 qString( value->function->name ).lower() == "rgb(" ) {
01773         ValueList *args = value->function->args;
01774         Value *v = args->current();
01775         if ( !validUnit( v, FInteger|FPercent, true ) )
01776             return 0;
01777         int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01778         v = args->next();
01779         if ( v->unit != Value::Operator && v->iValue != ',' )
01780             return 0;
01781         v = args->next();
01782         if ( !validUnit( v, FInteger|FPercent, true ) )
01783             return 0;
01784         int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01785         v = args->next();
01786         if ( v->unit != Value::Operator && v->iValue != ',' )
01787             return 0;
01788         v = args->next();
01789         if ( !validUnit( v, FInteger|FPercent, true ) )
01790             return 0;
01791         int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01792         r = kMax( 0, kMin( 255, r ) );
01793         g = kMax( 0, kMin( 255, g ) );
01794         b = kMax( 0, kMin( 255, b ) );
01795         c = qRgb( r, g, b );
01796     }
01797     else if ( value->unit == Value::Function &&
01798               value->function->args != 0 &&
01799               value->function->args->numValues == 7 /* rgba + three commas */ &&
01800               qString( value->function->name ).lower() == "rgba(" ) {
01801         ValueList *args = value->function->args;
01802         Value *v = args->current();
01803         if ( !validUnit( v, FInteger|FPercent, true ) )
01804             return 0;
01805         int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01806         v = args->next();
01807         if ( v->unit != Value::Operator && v->iValue != ',' )
01808             return 0;
01809         v = args->next();
01810         if ( !validUnit( v, FInteger|FPercent, true ) )
01811             return 0;
01812         int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01813         v = args->next();
01814         if ( v->unit != Value::Operator && v->iValue != ',' )
01815             return 0;
01816         v = args->next();
01817         if ( !validUnit( v, FInteger|FPercent, true ) )
01818             return 0;
01819         int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01820         v = args->next();
01821         if ( v->unit != Value::Operator && v->iValue != ',' )
01822             return 0;
01823         v = args->next();
01824         if ( !validUnit( v, FNumber, true ) )
01825             return 0;
01826         r = QMAX( 0, QMIN( 255, r ) );
01827         g = QMAX( 0, QMIN( 255, g ) );
01828         b = QMAX( 0, QMIN( 255, b ) );
01829         int a = (int)(QMAX( 0, QMIN( 1.0f, v->fValue ) ) * 255);
01830         c = qRgba( r, g, b, a );
01831     }
01832     else
01833         return 0;
01834 
01835     return new CSSPrimitiveValueImpl(c);
01836 }
01837 
01838 
01839 static inline int yyerror( const char *str ) {
01840 //    assert( 0 );
01841 #ifdef CSS_DEBUG
01842     kdDebug( 6080 ) << "CSS parse error " << str << endl;
01843 #else
01844     Q_UNUSED( str );
01845 #endif
01846     return 1;
01847 }
01848 
01849 #define END 0
01850 
01851 #include "parser.h"
01852 
01853 int DOM::CSSParser::lex( void *_yylval )
01854 {
01855     YYSTYPE *yylval = (YYSTYPE *)_yylval;
01856     int token = lex();
01857     int length;
01858     unsigned short *t = text( &length );
01859 
01860 #ifdef TOKEN_DEBUG
01861     qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString( (QChar *)t, length ).latin1() );
01862 #endif
01863     switch( token ) {
01864     case '{':
01865         block_nesting++;
01866         break;
01867     case '}':
01868         if ( block_nesting )
01869             block_nesting--;
01870         break;
01871     case END:
01872         if ( block_nesting ) {
01873             block_nesting--;
01874             return '}';
01875         }
01876         break;
01877     case S:
01878     case SGML_CD:
01879     case INCLUDES:
01880     case DASHMATCH:
01881         break;
01882 
01883     case URI:
01884     case STRING:
01885     case IDENT:
01886     case HASH:
01887     case DIMEN:
01888     case UNICODERANGE:
01889     case FUNCTION:
01890         yylval->string.string = t;
01891         yylval->string.length = length;
01892         break;
01893 
01894     case IMPORT_SYM:
01895     case PAGE_SYM:
01896     case MEDIA_SYM:
01897     case FONT_FACE_SYM:
01898     case CHARSET_SYM:
01899 
01900     case IMPORTANT_SYM:
01901         break;
01902 
01903     case QEMS:
01904         length--;
01905     case GRADS:
01906         length--;
01907     case DEGS:
01908     case RADS:
01909     case KHERZ:
01910         length--;
01911     case MSECS:
01912     case HERZ:
01913     case EMS:
01914     case EXS:
01915     case PXS:
01916     case CMS:
01917     case MMS:
01918     case INS:
01919     case PTS:
01920     case PCS:
01921         length--;
01922     case SECS:
01923     case PERCENTAGE:
01924         length--;
01925     case NUMBER:
01926         yylval->val = QString( (QChar *)t, length ).toDouble();
01927         //qDebug("value = %s, converted=%.2f", QString( (QChar *)t, length ).latin1(), yylval->val );
01928         break;
01929 
01930     default:
01931         break;
01932     }
01933 
01934     return token;
01935 }
01936 
01937 static inline int toHex( char c ) {
01938     if ( '0' <= c && c <= '9' )
01939         return c - '0';
01940     if ( 'a' <= c && c <= 'f' )
01941         return c - 'a' + 10;
01942     if ( 'A' <= c && c<= 'F' )
01943         return c - 'A' + 10;
01944     return 0;
01945 }
01946 
01947 unsigned short *DOM::CSSParser::text(int *length)
01948 {
01949     unsigned short *start = yytext;
01950     int l = yyleng;
01951     switch( yyTok ) {
01952     case STRING:
01953         l--;
01954         /* nobreak */
01955     case HASH:
01956         start++;
01957         l--;
01958         break;
01959     case URI:
01960         // "url("{w}{string}{w}")"
01961         // "url("{w}{url}{w}")"
01962 
01963         // strip "url(" and ")"
01964         start += 4;
01965         l -= 5;
01966         // strip {w}
01967         while ( l &&
01968                 (*start == ' ' || *start == '\t' || *start == '\r' ||
01969                  *start == '\n' || *start == '\f' ) ) {
01970             start++; l--;
01971         }
01972         if ( *start == '"' || *start == '\'' ) {
01973             start++; l--;
01974         }
01975         while ( l &&
01976                 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
01977                  start[l-1] == '\n' || start[l-1] == '\f' ) ) {
01978             l--;
01979         }
01980         if ( l && (start[l-1] == '\"' || start[l-1] == '\'' ) )
01981              l--;
01982 
01983     default:
01984         break;
01985     }
01986 
01987     // process escapes
01988     unsigned short *out = start;
01989     unsigned short *escape = 0;
01990 
01991     for ( int i = 0; i < l; i++ ) {
01992         unsigned short *current = start+i;
01993         if ( escape == current - 1 ) {
01994             if ( ( *current >= '0' && *current <= '9' ) ||
01995                  ( *current >= 'a' && *current <= 'f' ) ||
01996                  ( *current >= 'A' && *current <= 'F' ) )
01997                 continue;
01998             if ( yyTok == STRING &&
01999                  ( *current == '\n' || *current == '\r' || *current == '\f' ) ) {
02000                 // ### handle \r\n case
02001                 if ( *current != '\r' )
02002                     escape = 0;
02003                 continue;
02004             }
02005             // in all other cases copy the char to output
02006             // ###
02007             *out++ = *current;
02008             escape = 0;
02009             continue;
02010         }
02011         if ( escape == current - 2 && yyTok == STRING &&
02012              *(current-1) == '\r' && *current == '\n' ) {
02013             escape = 0;
02014             continue;
02015         }
02016         if ( escape > current - 7 &&
02017              ( ( *current >= '0' && *current <= '9' ) ||
02018                ( *current >= 'a' && *current <= 'f' ) ||
02019                ( *current >= 'A' && *current <= 'F' ) ) )
02020                 continue;
02021         if ( escape ) {
02022             // add escaped char
02023             int uc = 0;
02024             escape++;
02025             while ( escape < current ) {
02026 //                 qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
02027                 uc *= 16;
02028                 uc += toHex( *escape );
02029                 escape++;
02030             }
02031 //             qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
02032             // can't handle chars outside ucs2
02033             if ( uc > 0xffff )
02034                 uc = 0xfffd;
02035             *(out++) = (unsigned short)uc;
02036             escape = 0;
02037             if ( *current == ' ' ||
02038                  *current == '\t' ||
02039                  *current == '\r' ||
02040                  *current == '\n' ||
02041                  *current == '\f' )
02042                 continue;
02043         }
02044         if ( !escape && *current == '\\' ) {
02045             escape = current;
02046             continue;
02047         }
02048         *(out++) = *current;
02049     }
02050     if ( escape ) {
02051         // add escaped char
02052         int uc = 0;
02053         escape++;
02054         while ( escape < start+l ) {
02055             //                 qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
02056             uc *= 16;
02057             uc += toHex( *escape );
02058             escape++;
02059         }
02060         //             qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
02061         // can't handle chars outside ucs2
02062         if ( uc > 0xffff )
02063             uc = 0xfffd;
02064         *(out++) = (unsigned short)uc;
02065     }
02066 
02067     *length = out - start;
02068     return start;
02069 }
02070 
02071 
02072 #define YY_DECL int DOM::CSSParser::lex()
02073 #define yyconst const
02074 typedef int yy_state_type;
02075 typedef unsigned int YY_CHAR;
02076 // this line makes sure we treat all Unicode chars correctly.
02077 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
02078 #define YY_DO_BEFORE_ACTION \
02079         yytext = yy_bp; \
02080         yyleng = (int) (yy_cp - yy_bp); \
02081         yy_hold_char = *yy_cp; \
02082         *yy_cp = 0; \
02083         yy_c_buf_p = yy_cp;
02084 #define YY_BREAK break;
02085 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).latin1() )
02086 #define YY_RULE_SETUP
02087 #define INITIAL 0
02088 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
02089 #define YY_START ((yy_start - 1) / 2)
02090 #define yyterminate() yyTok = END; return yyTok
02091 #define YY_FATAL_ERROR(a) qFatal(a)
02092 #define BEGIN yy_start = 1 + 2 *
02093 #define COMMENT 1
02094 
02095 #include "tokenizer.cpp"
KDE Logo
This file is part of the documentation for khtml Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Jan 15 13:34:36 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003