cssparser.cpp

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