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