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