cssparser.cpp

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