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->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
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
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
00334 enum Units
00335 {
00336 FUnknown = 0x0000,
00337 FInteger = 0x0001,
00338 FNumber = 0x0002,
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
00418
00419
00420
00421
00422
00423
00424
00425
00426 case CSS_PROP_SIZE:
00427
00428
00429 if (id)
00430 valid_primitive = true;
00431 break;
00432 case CSS_PROP_UNICODE_BIDI:
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:
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:
00448 case CSS_PROP_PAGE_BREAK_BEFORE:
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:
00458 if ( id == CSS_VAL_AUTO ||
00459 id == CSS_VAL_AVOID )
00460 valid_primitive = true;
00461 break;
00462
00463 case CSS_PROP_EMPTY_CELLS:
00464 if ( id == CSS_VAL_SHOW ||
00465 id == CSS_VAL_HIDE )
00466 valid_primitive = true;
00467 break;
00468
00469 case CSS_PROP_QUOTES:
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:
00504
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:
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:
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
00528
00529
00530 case CSS_PROP_CAPTION_SIDE:
00531
00532 if (
00533 id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM)
00534 valid_primitive = true;
00535 break;
00536
00537 case CSS_PROP_BORDER_COLLAPSE:
00538 if ( id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE )
00539 valid_primitive = true;
00540 break;
00541
00542 case CSS_PROP_VISIBILITY:
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:
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:
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
00560
00561
00562
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
00569
00570
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:
00576 if ( id == CSS_VAL_LTR || id == CSS_VAL_RTL )
00577 valid_primitive = true;
00578 break;
00579
00580 case CSS_PROP_TEXT_TRANSFORM:
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:
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:
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
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:
00605 case CSS_PROP_BORDER_TOP_STYLE:
00606 case CSS_PROP_BORDER_RIGHT_STYLE:
00607 case CSS_PROP_BORDER_BOTTOM_STYLE:
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:
00614
00615 if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) {
00616
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:
00654 case CSS_PROP_SCROLLBAR_SHADOW_COLOR:
00655 case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:
00656 case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:
00657 case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:
00658 case CSS_PROP_SCROLLBAR_TRACK_COLOR:
00659 case CSS_PROP_SCROLLBAR_ARROW_COLOR:
00660 case CSS_PROP_SCROLLBAR_BASE_COLOR:
00661 if ( strict )
00662 break;
00663
00664 case CSS_PROP_OUTLINE_COLOR:
00665
00666 if ( propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT ) {
00667 valid_primitive = true;
00668 break;
00669 }
00670
00671 case CSS_PROP_BACKGROUND_COLOR:
00672 case CSS_PROP_BORDER_TOP_COLOR:
00673 case CSS_PROP_BORDER_RIGHT_COLOR:
00674 case CSS_PROP_BORDER_BOTTOM_COLOR:
00675 case CSS_PROP_BORDER_LEFT_COLOR:
00676 case CSS_PROP_COLOR:
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
00691
00692
00693
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:
00718 if (id == CSS_VAL_NONE) {
00719 parsedValue = new CSSImageValueImpl();
00720 valueList->next();
00721 }
00722 else if (value->unit == CSSPrimitiveValue::CSS_URI ) {
00723
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:
00735 case CSS_PROP_BORDER_TOP_WIDTH:
00736 case CSS_PROP_BORDER_RIGHT_WIDTH:
00737 case CSS_PROP_BORDER_BOTTOM_WIDTH:
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:
00746 case CSS_PROP_WORD_SPACING:
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:
00754 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00755 break;
00756
00757 case CSS_PROP_PADDING_TOP:
00758 case CSS_PROP_PADDING_RIGHT:
00759 case CSS_PROP_PADDING_BOTTOM:
00760 case CSS_PROP_PADDING_LEFT:
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:
00766 case CSS_PROP_MAX_WIDTH:
00767 if ( id == CSS_VAL_NONE ) {
00768 valid_primitive = true;
00769 break;
00770 }
00771
00772 case CSS_PROP_MIN_HEIGHT:
00773 case CSS_PROP_MIN_WIDTH:
00774 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00775 break;
00776
00777 case CSS_PROP_FONT_SIZE:
00778
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:
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:
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
00797
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:
00806 case CSS_PROP_WIDTH:
00807 if ( id == CSS_VAL_AUTO )
00808 valid_primitive = true;
00809 else
00810
00811 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00812 break;
00813
00814 case CSS_PROP_BOTTOM:
00815 case CSS_PROP_LEFT:
00816 case CSS_PROP_RIGHT:
00817 case CSS_PROP_TOP:
00818 case CSS_PROP_MARGIN_TOP:
00819 case CSS_PROP_MARGIN_RIGHT:
00820 case CSS_PROP_MARGIN_BOTTOM:
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:
00830
00831 if ( id == CSS_VAL_AUTO ) {
00832 valid_primitive = true;
00833 break;
00834 }
00835
00836 case CSS_PROP_ORPHANS:
00837 case CSS_PROP_WIDOWS:
00838
00839 valid_primitive = ( !id && validUnit( value, FInteger, false ) );
00840 break;
00841
00842 case CSS_PROP_LINE_HEIGHT:
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:
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:
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
00863 {
00864 parsedValue = parseFontFamily();
00865 break;
00866 }
00867
00868 case CSS_PROP_TEXT_DECORATION:
00869
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
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:
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
00910 case CSS_PROP_BOX_SIZING:
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:
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:
00927 if ( id == CSS_VAL_NONE || id == CSS_VAL_ENABLED || id == CSS_VAL_DISABLED )
00928 valid_primitive = true;
00929
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
00967
00968
00969 case CSS_PROP_BACKGROUND:
00970
00971
00972 return parseBackgroundShorthand(important);
00973 case CSS_PROP_BORDER:
00974
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
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
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
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
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
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
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
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
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
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
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
01052
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
01066
01067
01068 break;
01069 }
01070
01071 if ( valid_primitive ) {
01072
01073 if ( id != 0 ) {
01074
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
01082 parsedValue = new CSSPrimitiveValueImpl( value->fValue,
01083 (CSSPrimitiveValue::UnitTypes) value->unit );
01084 } else if ( value->unit >= Value::Q_EMS ) {
01085
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
01123
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 };
01131 CSSValueImpl* values[numProperties] = { 0 };
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
01139 valueList->next();
01140 for (i = 0; i < numProperties; ++i) {
01141 if (properties[i] == CSS_PROP_BACKGROUND_COLOR && parsedProperty[i])
01142
01143
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
01172
01173 if (!found)
01174 goto fail;
01175 }
01176
01177
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
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
01210
01211
01212
01213 inParseShortHand = true;
01214
01215 bool found = false;
01216 int oldPropIndex = numParsedProperties;
01217 bool fnd[6];
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
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
01242
01243 if (!found) {
01244 #ifdef CSS_DEBUG
01245 qDebug("didn't find anything" );
01246 #endif
01247
01248
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
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
01274
01275
01276
01277
01278
01279
01280
01281 int num = inParseShortHand ? 1 : valueList->numValues;
01282
01283
01284
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
01325
01326
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
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
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
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
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
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
01483 bool value1IsX = false, value1IsY = false;
01484 value1 = parseBackgroundPositionXY(value1IsX, value1IsY);
01485 if (!value1)
01486 return;
01487
01488
01489
01490
01491 value = valueList->next();
01492
01493
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
01513
01514
01515
01516 value2 = new CSSPrimitiveValueImpl(50, CSSPrimitiveValue::CSS_PERCENTAGE);
01517
01518 if (value1IsY || value2IsX) {
01519
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
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
01623
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
01652 if ( fname != "rect(" || !args )
01653 return false;
01654
01655
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
01697 bool CSSParser::parseFont( bool important )
01698 {
01699
01700 bool valid = true;
01701 Value *value = valueList->current();
01702 FontValueImpl *font = new FontValueImpl;
01703
01704 while ( value ) {
01705
01706
01707
01708 int id = value->id;
01709 if ( id ) {
01710 if ( id == CSS_VAL_NORMAL ) {
01711
01712 }
01713
01714
01715
01716
01717
01718
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
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
01780
01781
01782
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
01793
01794 if ( value->unit == Value::Operator && value->iValue == '/' ) {
01795
01796 value = valueList->next();
01797 if ( !value )
01798 goto invalid;
01799 if ( value->id == CSS_VAL_NORMAL ) {
01800
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
01814
01815 font->family = parseFontFamily();
01816
01817 if ( valueList->current() || !font->family )
01818 goto invalid;
01819
01820
01821 addProperty( CSS_PROP_FONT, font, important );
01822 return true;
01823
01824 invalid:
01825
01826 delete font;
01827 return false;
01828 }
01829
01830 CSSValueListImpl *CSSParser::parseFontFamily()
01831 {
01832
01833 CSSValueListImpl *list = new CSSValueListImpl;
01834 Value *value = valueList->current();
01835 QString currFace;
01836
01837 while ( value ) {
01838
01839
01840
01841
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
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
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
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
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 &&
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 &&
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
02050
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
02074 if (x || y || blur || color) {
02075 if (!values)
02076 values = new CSSValueListImpl();
02077
02078
02079 values->append(new ShadowValueImpl(x, y, blur, color));
02080 }
02081
02082
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
02135 if (val->unit == Value::Operator) {
02136 if (val->iValue != ',' || !context.allowBreak)
02137
02138
02139 return context.failed();
02140
02141
02142 context.commitValue();
02143 }
02144
02145 else if (validUnit(val, FLength, true)) {
02146
02147 if (!context.allowLength())
02148 return context.failed();
02149
02150
02151 context.commitLength(val);
02152 }
02153 else {
02154
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
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
02200
02201 case COMMA:
02202 state = ID;
02203 if (val && val->unit == Value::Operator && val->iValue == ',') {
02204 valueList->next();
02205 continue;
02206 }
02207
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
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
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
02359 case HASH:
02360 start++;
02361 l--;
02362 break;
02363 case URI:
02364
02365
02366
02367
02368 start += 4;
02369 l -= 5;
02370
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
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
02405 if ( *current != '\r' )
02406 escape = 0;
02407 continue;
02408 }
02409
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
02427 int uc = 0;
02428 escape++;
02429 while ( escape < current ) {
02430
02431 uc *= 16;
02432 uc += toHex( *escape );
02433 escape++;
02434 }
02435
02436
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
02456 int uc = 0;
02457 escape++;
02458 while ( escape < start+l ) {
02459
02460 uc *= 16;
02461 uc += toHex( *escape );
02462 escape++;
02463 }
02464
02465
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
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"