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