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