# khtml Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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"

This file is part of the documentation for khtml Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:33:08 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003