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