khtml Library API Documentation

cssparser.cpp

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