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
00026 #define YYDEBUG 0
00027
00028 #include <kdebug.h>
00029 #include <kglobal.h>
00030 #include <kurl.h>
00031
00032 #include "cssparser.h"
00033 #include "css_valueimpl.h"
00034 #include "css_ruleimpl.h"
00035 #include "css_stylesheetimpl.h"
00036 #include "cssproperties.h"
00037 #include "cssvalues.h"
00038 #include "misc/helper.h"
00039 #include "csshelper.h"
00040 using namespace DOM;
00041
00042 #include <stdlib.h>
00043 #include <assert.h>
00044
00045 ValueList::ValueList()
00046 {
00047 values = (Value *) malloc( 16 * sizeof ( Value ) );
00048 numValues = 0;
00049 currentValue = 0;
00050 maxValues = 16;
00051 }
00052
00053 ValueList::~ValueList()
00054 {
00055 for ( int i = 0; i < numValues; i++ ) {
00056 #ifdef CSS_DEBUG
00057 kdDebug( 6080 ) << " value: (unit=" << values[i].unit <<")"<< endl;
00058 #endif
00059 if ( values[i].unit == Value::Function )
00060 delete values[i].function;
00061 }
00062 free( values );
00063 }
00064
00065 void ValueList::addValue( const Value &val )
00066 {
00067 if ( numValues >= maxValues ) {
00068 maxValues += 16;
00069 values = (Value *) realloc( values, maxValues*sizeof( Value ) );
00070 }
00071 values[numValues++] = val;
00072 }
00073
00074
00075 using namespace DOM;
00076
00077 #if YYDEBUG > 0
00078 extern int cssyydebug;
00079 #endif
00080
00081 extern int cssyyparse( void * parser );
00082
00083 CSSParser *CSSParser::currentParser = 0;
00084
00085 CSSParser::CSSParser( bool strictParsing )
00086 {
00087 #ifdef CSS_DEBUG
00088 kdDebug( 6080 ) << "CSSParser::CSSParser this=" << this << endl;
00089 #endif
00090 strict = strictParsing;
00091
00092 parsedProperties = (CSSProperty **) malloc( 32 * sizeof( CSSProperty * ) );
00093 numParsedProperties = 0;
00094 maxParsedProperties = 32;
00095
00096 defaultNamespace = 0xffff;
00097
00098 valueList = 0;
00099 rule = 0;
00100 id = 0;
00101 important = false;
00102 nonCSSHint = false;
00103 inParseShortHand = false;
00104 yy_start = 1;
00105
00106 #if YYDEBUG > 0
00107 cssyydebug = 1;
00108 #endif
00109
00110 }
00111
00112 CSSParser::~CSSParser()
00113 {
00114 if ( numParsedProperties )
00115 clearProperties();
00116 free( parsedProperties );
00117
00118 delete valueList;
00119
00120 #ifdef CSS_DEBUG
00121 kdDebug( 6080 ) << "CSSParser::~CSSParser this=" << this << endl;
00122 #endif
00123
00124 free( data );
00125
00126 }
00127
00128 void CSSParser::parseSheet( CSSStyleSheetImpl *sheet, const DOMString &string )
00129 {
00130 styleElement = sheet;
00131
00132 int length = string.length() + 3;
00133 data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00134 memcpy( data, string.unicode(), string.length()*sizeof( unsigned short) );
00135 data[length-1] = 0;
00136 data[length-2] = 0;
00137 data[length-3] = ' ';
00138 yy_hold_char = 0;
00139 yyleng = 0;
00140 yytext = yy_c_buf_p = data;
00141 yy_hold_char = *yy_c_buf_p;
00142
00143 #ifdef CSS_DEBUG
00144 kdDebug( 6080 ) << ">>>>>>> start parsing style sheet" << endl;
00145 #endif
00146 CSSParser *old = currentParser;
00147 currentParser = this;
00148 cssyyparse( this );
00149 currentParser = old;
00150 #ifdef CSS_DEBUG
00151 kdDebug( 6080 ) << "<<<<<<< done parsing style sheet" << endl;
00152 #endif
00153
00154 delete rule;
00155 rule = 0;
00156 }
00157
00158 CSSRuleImpl *CSSParser::parseRule( DOM::CSSStyleSheetImpl *sheet, const DOM::DOMString &string )
00159 {
00160 styleElement = sheet;
00161
00162 const char khtml_rule[] = "@-khtml-rule{";
00163 int length = string.length() + 4 + strlen(khtml_rule);
00164 data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00165 for ( unsigned int i = 0; i < strlen(khtml_rule); i++ )
00166 data[i] = khtml_rule[i];
00167 memcpy( data + strlen( khtml_rule ), string.unicode(), string.length()*sizeof( unsigned short) );
00168
00169 data[length-1] = 0;
00170 data[length-2] = 0;
00171 data[length-3] = ' ';
00172 data[length-4] = '}';
00173 yy_hold_char = 0;
00174 yyleng = 0;
00175 yytext = yy_c_buf_p = data;
00176 yy_hold_char = *yy_c_buf_p;
00177
00178 CSSParser *old = currentParser;
00179 currentParser = this;
00180 cssyyparse( this );
00181 currentParser = old;
00182
00183 CSSRuleImpl *result = rule;
00184 rule = 0;
00185
00186 return result;
00187 }
00188
00189 bool CSSParser::parseValue( DOM::CSSStyleDeclarationImpl *declaration, int _id, const DOM::DOMString &string,
00190 bool _important, bool _nonCSSHint )
00191 {
00192 #ifdef CSS_DEBUG
00193 kdDebug( 6080 ) << "CSSParser::parseValue: id=" << _id << " important=" << _important
00194 << " nonCSSHint=" << _nonCSSHint << " value='" << string.string() << "'" << endl;
00195 #endif
00196
00197 styleElement = declaration->stylesheet();
00198
00199 const char khtml_value[] = "@-khtml-value{";
00200 int length = string.length() + 4 + strlen(khtml_value);
00201 data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00202 for ( unsigned int i = 0; i < strlen(khtml_value); i++ )
00203 data[i] = khtml_value[i];
00204 memcpy( data + strlen( khtml_value ), string.unicode(), string.length()*sizeof( unsigned short) );
00205 data[length-1] = 0;
00206 data[length-2] = 0;
00207 data[length-3] = ' ';
00208 data[length-4] = '}';
00209
00210 yy_hold_char = 0;
00211 yyleng = 0;
00212 yytext = yy_c_buf_p = data;
00213 yy_hold_char = *yy_c_buf_p;
00214
00215 id = _id;
00216 important = _important;
00217 nonCSSHint = _nonCSSHint;
00218
00219 CSSParser *old = currentParser;
00220 currentParser = this;
00221 cssyyparse( this );
00222 currentParser = old;
00223
00224 delete rule;
00225 rule = 0;
00226
00227 bool ok = false;
00228 if ( numParsedProperties ) {
00229 ok = true;
00230 for ( int i = 0; i < numParsedProperties; i++ ) {
00231 declaration->removeProperty(parsedProperties[i]->m_id, nonCSSHint);
00232 declaration->values()->append( parsedProperties[i] );
00233 }
00234 numParsedProperties = 0;
00235 }
00236
00237 return ok;
00238 }
00239
00240 bool CSSParser::parseDeclaration( DOM::CSSStyleDeclarationImpl *declaration, const DOM::DOMString &string,
00241 bool _nonCSSHint )
00242 {
00243 #ifdef CSS_DEBUG
00244 kdDebug( 6080 ) << "CSSParser::parseDeclaration: nonCSSHint=" << nonCSSHint
00245 << " value='" << string.string() << "'" << endl;
00246 #endif
00247
00248 styleElement = declaration->stylesheet();
00249
00250 const char khtml_decls[] = "@-khtml-decls{";
00251 int length = string.length() + 4 + strlen(khtml_decls);
00252 data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
00253 for ( unsigned int i = 0; i < strlen(khtml_decls); i++ )
00254 data[i] = khtml_decls[i];
00255 memcpy( data + strlen( khtml_decls ), string.unicode(), string.length()*sizeof( unsigned short) );
00256 data[length-1] = 0;
00257 data[length-2] = 0;
00258 data[length-3] = ' ';
00259 data[length-4] = '}';
00260
00261 yy_hold_char = 0;
00262 yyleng = 0;
00263 yytext = yy_c_buf_p = data;
00264 yy_hold_char = *yy_c_buf_p;
00265
00266 nonCSSHint = _nonCSSHint;
00267
00268 CSSParser *old = currentParser;
00269 currentParser = this;
00270 cssyyparse( this );
00271 currentParser = old;
00272
00273 delete rule;
00274 rule = 0;
00275
00276 bool ok = false;
00277 if ( numParsedProperties ) {
00278 ok = true;
00279 for ( int i = 0; i < numParsedProperties; i++ ) {
00280 declaration->removeProperty(parsedProperties[i]->m_id, false);
00281 declaration->values()->append( parsedProperties[i] );
00282 }
00283 numParsedProperties = 0;
00284 }
00285
00286 return ok;
00287 }
00288
00289 void CSSParser::addProperty( int propId, CSSValueImpl *value, bool important )
00290 {
00291 CSSProperty *prop = new CSSProperty;
00292 prop->m_id = propId;
00293 prop->setValue( value );
00294 prop->m_bImportant = important;
00295 prop->nonCSSHint = nonCSSHint;
00296
00297 if ( numParsedProperties >= maxParsedProperties ) {
00298 maxParsedProperties += 32;
00299 parsedProperties = (CSSProperty **) realloc( parsedProperties,
00300 maxParsedProperties*sizeof( CSSProperty * ) );
00301 }
00302 parsedProperties[numParsedProperties++] = prop;
00303 }
00304
00305 CSSStyleDeclarationImpl *CSSParser::createStyleDeclaration( CSSStyleRuleImpl *rule )
00306 {
00307 QPtrList<CSSProperty> *propList = new QPtrList<CSSProperty>;
00308 propList->setAutoDelete( true );
00309 for ( int i = 0; i < numParsedProperties; i++ )
00310 propList->append( parsedProperties[i] );
00311
00312 numParsedProperties = 0;
00313 return new CSSStyleDeclarationImpl(rule, propList);
00314 }
00315
00316 void CSSParser::clearProperties()
00317 {
00318 for ( int i = 0; i < numParsedProperties; i++ )
00319 delete parsedProperties[i];
00320 numParsedProperties = 0;
00321 }
00322
00323 DOM::DocumentImpl *CSSParser::document() const
00324 {
00325 const StyleBaseImpl* root = styleElement;
00326 DocumentImpl *doc = 0;
00327 while (root->parent())
00328 root = root->parent();
00329 if (root->isCSSStyleSheet())
00330 doc = static_cast<const CSSStyleSheetImpl*>(root)->doc();
00331 return doc;
00332 }
00333
00334
00335
00336 enum Units
00337 {
00338 FUnknown = 0x0000,
00339 FInteger = 0x0001,
00340 FNumber = 0x0002,
00341 FPercent = 0x0004,
00342 FLength = 0x0008,
00343 FAngle = 0x0010,
00344 FTime = 0x0020,
00345 FFrequency = 0x0040,
00346 FRelative = 0x0100,
00347 FNonNeg = 0x0200
00348 };
00349
00350 static bool validUnit( Value *value, int unitflags, bool strict )
00351 {
00352 if ( unitflags & FNonNeg && value->fValue < 0 )
00353 return false;
00354
00355 bool b = false;
00356 switch( value->unit ) {
00357 case CSSPrimitiveValue::CSS_NUMBER:
00358 b = (unitflags & FNumber);
00359 if ( !b && ( (unitflags & FLength) && (value->fValue == 0 || !strict ) ) ) {
00360 value->unit = CSSPrimitiveValue::CSS_PX;
00361 b = true;
00362 }
00363 if ( !b && ( unitflags & FInteger ) &&
00364 (value->fValue - (int)value->fValue) < 0.001 )
00365 b = true;
00366 break;
00367 case CSSPrimitiveValue::CSS_PERCENTAGE:
00368 b = (unitflags & FPercent);
00369 break;
00370 case Value::Q_EMS:
00371 case CSSPrimitiveValue::CSS_EMS:
00372 case CSSPrimitiveValue::CSS_EXS:
00373 case CSSPrimitiveValue::CSS_PX:
00374 case CSSPrimitiveValue::CSS_CM:
00375 case CSSPrimitiveValue::CSS_MM:
00376 case CSSPrimitiveValue::CSS_IN:
00377 case CSSPrimitiveValue::CSS_PT:
00378 case CSSPrimitiveValue::CSS_PC:
00379 b = (unitflags & FLength);
00380 break;
00381 case CSSPrimitiveValue::CSS_DEG:
00382 case CSSPrimitiveValue::CSS_RAD:
00383 case CSSPrimitiveValue::CSS_GRAD:
00384 case CSSPrimitiveValue::CSS_MS:
00385 case CSSPrimitiveValue::CSS_S:
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 )
00396 {
00397 if ( !valueList ) return false;
00398
00399 Value *value = valueList->current();
00400
00401 if ( !value )
00402 return false;
00403
00404 int id = 0;
00405 id = value->id;
00406
00407 if ( id == CSS_VAL_INHERIT ) {
00408 addProperty( propId, new CSSInheritedValueImpl(), important );
00409 return true;
00410 }
00411
00412 bool valid_primitive = false;
00413 CSSValueImpl *parsedValue = 0;
00414
00415 switch(propId) {
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 case CSS_PROP_SIZE:
00426 case CSS_PROP_QUOTES:
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_CONTENT:
00470
00471 return parseContent( propId, important );
00472 break;
00473
00474 case CSS_PROP_WHITE_SPACE:
00475 if ( id == CSS_VAL_NORMAL ||
00476 id == CSS_VAL_PRE ||
00477 id == CSS_VAL_NOWRAP )
00478 valid_primitive = true;
00479 break;
00480
00481 case CSS_PROP_CLIP:
00482 if ( id == CSS_VAL_AUTO )
00483 valid_primitive = true;
00484 else if ( value->unit == Value::Function )
00485 return parseShape( propId, important );
00486 break;
00487
00488
00489
00490
00491 case CSS_PROP_CAPTION_SIDE:
00492 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
00493 id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM)
00494 valid_primitive = true;
00495 break;
00496
00497 case CSS_PROP_BORDER_COLLAPSE:
00498 if ( id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE )
00499 valid_primitive = true;
00500 break;
00501
00502 case CSS_PROP_VISIBILITY:
00503 if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE)
00504 valid_primitive = true;
00505 break;
00506
00507 case CSS_PROP_OVERFLOW:
00508 if ( id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO )
00509 valid_primitive = true;
00510 break;
00511
00512 case CSS_PROP_LIST_STYLE_POSITION:
00513 if ( id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE )
00514 valid_primitive = true;
00515 break;
00516
00517 case CSS_PROP_LIST_STYLE_TYPE:
00518
00519
00520
00521
00522 if ((id >= CSS_VAL_DISC && id <= CSS_VAL_KATAKANA_IROHA) || id == CSS_VAL_NONE)
00523 valid_primitive = true;
00524 break;
00525
00526 case CSS_PROP_DISPLAY:
00527
00528
00529
00530 if ((id >= CSS_VAL_INLINE && id <= CSS_VAL_TABLE_CAPTION) || id == CSS_VAL_NONE)
00531 valid_primitive = true;
00532 break;
00533
00534 case CSS_PROP_DIRECTION:
00535 if ( id == CSS_VAL_LTR || id == CSS_VAL_RTL )
00536 valid_primitive = true;
00537 break;
00538
00539 case CSS_PROP_TEXT_TRANSFORM:
00540 if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE)
00541 valid_primitive = true;
00542 break;
00543
00544 case CSS_PROP_FLOAT:
00545 if ( id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
00546 id == CSS_VAL_NONE || id == CSS_VAL_CENTER)
00547 valid_primitive = true;
00548 break;
00549
00550 case CSS_PROP_CLEAR:
00551 if ( id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
00552 id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH)
00553 valid_primitive = true;
00554 break;
00555
00556 case CSS_PROP_TEXT_ALIGN:
00557
00558 if ( ( id >= CSS_VAL__KHTML_AUTO && id <= CSS_VAL__KHTML_CENTER ) ||
00559 value->unit == CSSPrimitiveValue::CSS_STRING )
00560 valid_primitive = true;
00561 break;
00562
00563 case CSS_PROP_OUTLINE_STYLE:
00564 case CSS_PROP_BORDER_TOP_STYLE:
00565 case CSS_PROP_BORDER_RIGHT_STYLE:
00566 case CSS_PROP_BORDER_BOTTOM_STYLE:
00567 case CSS_PROP_BORDER_LEFT_STYLE:
00568 if (id >= CSS_VAL_NONE && id <= CSS_VAL_RIDGE)
00569 valid_primitive = true;
00570 break;
00571
00572 case CSS_PROP_FONT_WEIGHT:
00573
00574 if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) {
00575
00576 valid_primitive = true;
00577 } else if ( validUnit( value, FInteger|FNonNeg, false ) ) {
00578 int weight = (int)value->fValue;
00579 if ( (weight % 100) )
00580 break;
00581 weight /= 100;
00582 if ( weight >= 1 && weight <= 9 ) {
00583 id = CSS_VAL_100 + weight - 1;
00584 valid_primitive = true;
00585 }
00586 }
00587 break;
00588
00589 case CSS_PROP_BACKGROUND_REPEAT:
00590 if ( id >= CSS_VAL_REPEAT && id <= CSS_VAL_NO_REPEAT )
00591 valid_primitive = true;
00592 break;
00593
00594 case CSS_PROP_BACKGROUND_ATTACHMENT:
00595 if ( id == CSS_VAL_SCROLL || id == CSS_VAL_FIXED )
00596 valid_primitive = true;
00597 break;
00598
00599 case CSS_PROP_BACKGROUND_POSITION:
00600 if ( id ) {
00601
00602
00603
00604
00605
00606 int pos[2];
00607 pos[0] = -1;
00608 pos[1] = -1;
00609 bool invalid = false;
00610 switch( id ) {
00611 case CSS_VAL_TOP:
00612 pos[1] = 0;
00613 break;
00614 case CSS_VAL_BOTTOM:
00615 pos[1] = 100;
00616 break;
00617 case CSS_VAL_LEFT:
00618 pos[0] = 0;
00619 break;
00620 case CSS_VAL_RIGHT:
00621 pos[0] = 100;
00622 break;
00623 case CSS_VAL_CENTER:
00624 break;
00625 default:
00626 invalid = true;
00627 }
00628 if ( invalid )
00629 break;
00630 value = valueList->next();
00631 if ( value ) {
00632 id = value->id;
00633 switch( id ) {
00634 case CSS_VAL_TOP:
00635 if ( pos[1] != -1 )
00636 invalid = true;
00637 pos[1] = 0;
00638 break;
00639 case CSS_VAL_BOTTOM:
00640 if ( pos[1] != -1 )
00641 invalid = true;
00642 pos[1] = 100;
00643 break;
00644 case CSS_VAL_LEFT:
00645 if ( pos[0] != -1 )
00646 invalid = true;
00647 pos[0] = 0;
00648 break;
00649 case CSS_VAL_RIGHT:
00650 if ( pos[0] != -1 )
00651 invalid = true;
00652 pos[0] = 100;
00653 break;
00654 case CSS_VAL_CENTER:
00655 break;
00656 default:
00657 invalid = true;
00658 }
00659 if ( !invalid )
00660 value = valueList->next();
00661 }
00662 if ( pos[0] == -1 )
00663 pos[0] = 50;
00664 if ( pos[1] == -1 )
00665 pos[1] = 50;
00666 addProperty( CSS_PROP_BACKGROUND_POSITION_X,
00667 new CSSPrimitiveValueImpl( pos[0], CSSPrimitiveValue::CSS_PERCENTAGE ),
00668 important );
00669 addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
00670 new CSSPrimitiveValueImpl( pos[1], CSSPrimitiveValue::CSS_PERCENTAGE ),
00671 important );
00672 } else {
00673 bool ok = parseValue( CSS_PROP_BACKGROUND_POSITION_X, important );
00674 if ( !ok )
00675 break;
00676 value = valueList->current();
00677 if ( value )
00678 ok = parseValue( CSS_PROP_BACKGROUND_POSITION_Y, important );
00679 if ( !ok )
00680 addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
00681 new CSSPrimitiveValueImpl( 50, CSSPrimitiveValue::CSS_PERCENTAGE ),
00682 important );
00683 }
00684 return true;
00685
00686 case CSS_PROP_BACKGROUND_POSITION_X:
00687 case CSS_PROP_BACKGROUND_POSITION_Y:
00688 valid_primitive = validUnit( value, FPercent|FLength, strict&(!nonCSSHint) );
00689 break;
00690
00691 case CSS_PROP_BORDER_SPACING:
00692 {
00693 const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING,
00694 CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
00695 int num = valueList->numValues;
00696 if (num == 1) {
00697 if (!parseValue(properties[0], important)) return false;
00698 CSSValueImpl* value = parsedProperties[numParsedProperties-1]->value();
00699 addProperty(properties[1], value, important);
00700 return true;
00701 }
00702 else if (num == 2) {
00703 if (!parseValue(properties[0], important)) return false;
00704 if (!parseValue(properties[1], important)) return false;
00705 return true;
00706 }
00707 return false;
00708 }
00709 case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING:
00710 case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING:
00711 valid_primitive = validUnit(value, FLength|FNonNeg, strict&(!nonCSSHint));
00712 break;
00713
00714 case CSS_PROP_SCROLLBAR_FACE_COLOR:
00715 case CSS_PROP_SCROLLBAR_SHADOW_COLOR:
00716 case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:
00717 case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:
00718 case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:
00719 case CSS_PROP_SCROLLBAR_TRACK_COLOR:
00720 case CSS_PROP_SCROLLBAR_ARROW_COLOR:
00721 case CSS_PROP_SCROLLBAR_BASE_COLOR:
00722 if ( strict )
00723 break;
00724
00725 case CSS_PROP_OUTLINE_COLOR:
00726
00727 if ( propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT ) {
00728 valid_primitive = true;
00729 break;
00730 }
00731
00732 case CSS_PROP_BACKGROUND_COLOR:
00733 if ( propId == CSS_PROP_BACKGROUND_COLOR && id == CSS_VAL_TRANSPARENT ) {
00734 valid_primitive = true;
00735 break;
00736 }
00737
00738 case CSS_PROP_COLOR:
00739 case CSS_PROP_BORDER_TOP_COLOR:
00740 case CSS_PROP_BORDER_RIGHT_COLOR:
00741 case CSS_PROP_BORDER_BOTTOM_COLOR:
00742 case CSS_PROP_BORDER_LEFT_COLOR:
00743 case CSS_PROP__KHTML_TEXT_DECORATION_COLOR:
00744 if ( id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_MENU ||
00745 (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT ) ||
00746 (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && (nonCSSHint|!strict) ) ) {
00747 valid_primitive = true;
00748 } else {
00749 parsedValue = parseColor();
00750 if ( parsedValue )
00751 valueList->next();
00752 }
00753 break;
00754
00755 case CSS_PROP_CURSOR:
00756
00757
00758
00759
00760 if ( !strict && id == CSS_VAL_HAND ) {
00761 id = CSS_VAL_POINTER;
00762 valid_primitive = true;
00763 } else if ( id >= CSS_VAL_AUTO && id <= CSS_VAL_HELP )
00764 valid_primitive = true;
00765 break;
00766
00767 case CSS_PROP_BACKGROUND_IMAGE:
00768 case CSS_PROP_LIST_STYLE_IMAGE:
00769
00770 if ( id == CSS_VAL_NONE ) {
00771 parsedValue = new CSSImageValueImpl();
00772 valueList->next();
00773 #ifdef CSS_DEBUG
00774 kdDebug( 6080 ) << "empty image " << endl;
00775 #endif
00776 } else if ( value->unit == CSSPrimitiveValue::CSS_URI ) {
00777
00778 DOMString uri = khtml::parseURL( domString( value->string ) );
00779 if ( !uri.isEmpty() ) {
00780 parsedValue = new CSSImageValueImpl(
00781 DOMString(KURL( styleElement->baseURL(), uri.string()).url()),
00782 styleElement );
00783 valueList->next();
00784 #ifdef CSS_DEBUG
00785 kdDebug( 6080 ) << "image, url=" << uri.string() << " base=" << styleElement->baseURL().url() << endl;
00786 #endif
00787 }
00788 }
00789 break;
00790
00791 case CSS_PROP_OUTLINE_WIDTH:
00792 case CSS_PROP_BORDER_TOP_WIDTH:
00793 case CSS_PROP_BORDER_RIGHT_WIDTH:
00794 case CSS_PROP_BORDER_BOTTOM_WIDTH:
00795 case CSS_PROP_BORDER_LEFT_WIDTH:
00796 if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
00797 valid_primitive = true;
00798 else
00799 valid_primitive = ( validUnit( value, FLength, strict&(!nonCSSHint) ) );
00800 break;
00801
00802 case CSS_PROP_MARKER_OFFSET:
00803 if ( id == CSS_VAL_AUTO )
00804 valid_primitive = true;
00805 else
00806 valid_primitive = validUnit( value, FLength, strict&(!nonCSSHint) );
00807 break;
00808
00809 case CSS_PROP_LETTER_SPACING:
00810 case CSS_PROP_WORD_SPACING:
00811 if ( id == CSS_VAL_NORMAL )
00812 valid_primitive = true;
00813 else
00814 valid_primitive = validUnit( value, FLength, strict&(!nonCSSHint) );
00815 break;
00816
00817 case CSS_PROP_TEXT_INDENT:
00818 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00819 break;
00820
00821 case CSS_PROP_PADDING_TOP:
00822 case CSS_PROP_PADDING_RIGHT:
00823 case CSS_PROP_PADDING_BOTTOM:
00824 case CSS_PROP_PADDING_LEFT:
00825 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00826 break;
00827
00828 case CSS_PROP_MAX_HEIGHT:
00829 case CSS_PROP_MAX_WIDTH:
00830 if ( id == CSS_VAL_NONE ) {
00831 valid_primitive = true;
00832 break;
00833 }
00834
00835 case CSS_PROP_MIN_HEIGHT:
00836 case CSS_PROP_MIN_WIDTH:
00837 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00838 break;
00839
00840 case CSS_PROP_FONT_SIZE:
00841
00842 if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER)
00843 valid_primitive = true;
00844 else
00845 valid_primitive = ( validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00846 break;
00847
00848 case CSS_PROP_FONT_STYLE:
00849 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE)
00850 valid_primitive = true;
00851 break;
00852
00853 case CSS_PROP_FONT_VARIANT:
00854 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS)
00855 valid_primitive = true;
00856 break;
00857
00858 case CSS_PROP_VERTICAL_ALIGN:
00859
00860
00861
00862 if ( id >= CSS_VAL_BASELINE && id <= CSS_VAL__KHTML_BASELINE_MIDDLE )
00863 valid_primitive = true;
00864 else
00865 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00866 break;
00867
00868 case CSS_PROP_HEIGHT:
00869 case CSS_PROP_WIDTH:
00870 if ( id == CSS_VAL_AUTO )
00871 valid_primitive = true;
00872 else
00873
00874 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00875 break;
00876
00877 case CSS_PROP_BOTTOM:
00878 case CSS_PROP_LEFT:
00879 case CSS_PROP_RIGHT:
00880 case CSS_PROP_TOP:
00881 case CSS_PROP_MARGIN_TOP:
00882 case CSS_PROP_MARGIN_RIGHT:
00883 case CSS_PROP_MARGIN_BOTTOM:
00884 case CSS_PROP_MARGIN_LEFT:
00885 if ( id == CSS_VAL_AUTO )
00886 valid_primitive = true;
00887 else
00888 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00889 break;
00890
00891 case CSS_PROP_Z_INDEX:
00892
00893 if ( id == CSS_VAL_AUTO ) {
00894 valid_primitive = true;
00895 break;
00896 }
00897
00898 case CSS_PROP_ORPHANS:
00899 case CSS_PROP_WIDOWS:
00900
00901 valid_primitive = ( !id && validUnit( value, FInteger, false ) );
00902 break;
00903
00904 case CSS_PROP_LINE_HEIGHT:
00905 if ( id == CSS_VAL_NORMAL )
00906 valid_primitive = true;
00907 else
00908 valid_primitive = ( !id && validUnit( value, FNumber|FLength|FPercent, strict&(!nonCSSHint) ) );
00909 break;
00910 #if 0
00911
00912 case CSS_PROP_COUNTER_INCREMENT:
00913 case CSS_PROP_COUNTER_RESET:
00914 if ( id == CSS_VAL_NONE )
00915 valid_primitive = true;
00916 else {
00917 CSSValueListImpl *list = new CSSValueListImpl;
00918 int pos=0, pos2;
00919 while( 1 )
00920 {
00921 pos2 = value.find(',', pos);
00922 QString face = value.mid(pos, pos2-pos);
00923 face = face.stripWhiteSpace();
00924 if(face.length() == 0) break;
00925
00926 if(face[0] == '\"') face.remove(0, 1);
00927 if(face[face.length()-1] == '\"') face = face.left(face.length()-1);
00928
00929 list->append(new CSSPrimitiveValueImpl(DOMString(face), CSSPrimitiveValue::CSS_STRING));
00930 pos = pos2 + 1;
00931 if(pos2 == -1) break;
00932 }
00933
00934 if(list->length()) {
00935 parsedValue = list;
00936 valueList->next();
00937 } else
00938 delete list;
00939 break;
00940 }
00941 #endif
00942 case CSS_PROP_FONT_FAMILY:
00943
00944 {
00945 parsedValue = parseFontFamily();
00946 break;
00947 }
00948
00949 case CSS_PROP_TEXT_DECORATION:
00950
00951 if (id == CSS_VAL_NONE) {
00952 valid_primitive = true;
00953 } else {
00954 CSSValueListImpl *list = new CSSValueListImpl;
00955 bool is_valid = true;
00956 while( is_valid && value ) {
00957 switch ( value->id ) {
00958 case CSS_VAL_BLINK:
00959 break;
00960 case CSS_VAL_UNDERLINE:
00961 case CSS_VAL_OVERLINE:
00962 case CSS_VAL_LINE_THROUGH:
00963 list->append( new CSSPrimitiveValueImpl( value->id ) );
00964 break;
00965 default:
00966 is_valid = false;
00967 }
00968 value = valueList->next();
00969 }
00970
00971 if(list->length() && is_valid) {
00972 parsedValue = list;
00973 valueList->next();
00974 } else {
00975 delete list;
00976 }
00977 }
00978 break;
00979
00980 case CSS_PROP_TABLE_LAYOUT:
00981 if ( id == CSS_VAL_AUTO || id == CSS_VAL_FIXED )
00982 valid_primitive = true;
00983 break;
00984
00985 case CSS_PROP__KHTML_FLOW_MODE:
00986 if ( id == CSS_VAL__KHTML_NORMAL || id == CSS_VAL__KHTML_AROUND_FLOATS )
00987 valid_primitive = true;
00988 break;
00989
00990 case CSS_PROP__KHTML_USER_INPUT:
00991 if ( id == CSS_VAL_NONE || id == CSS_VAL_ENABLED || id == CSS_VAL_DISABLED )
00992 valid_primitive = true;
00993
00994 break;
00995
00996
00997 case CSS_PROP_BACKGROUND:
00998
00999
01000 {
01001 #ifdef CSS_DEBUG_BCKGR
01002 kdDebug(6080) << "CSS_PROP_BACKGROUND" << endl;
01003 #endif
01004 #ifndef NDEBUG
01005 uint old_numParsed = numParsedProperties;
01006 #endif
01007
01008
01009 addProperty( CSS_PROP_BACKGROUND_IMAGE,
01010 new CSSImageValueImpl(),
01011 important );
01012 addProperty( CSS_PROP_BACKGROUND_REPEAT,
01013 new CSSPrimitiveValueImpl( CSS_VAL_REPEAT ),
01014 important );
01015 addProperty( CSS_PROP_BACKGROUND_ATTACHMENT,
01016 new CSSPrimitiveValueImpl( CSS_VAL_SCROLL ),
01017 important );
01018
01019
01020
01021 addProperty( CSS_PROP_BACKGROUND_POSITION_X,
01022 new CSSPrimitiveValueImpl( 0, CSSPrimitiveValue::CSS_PERCENTAGE ),
01023 important );
01024 addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
01025 new CSSPrimitiveValueImpl( 0, CSSPrimitiveValue::CSS_PERCENTAGE ),
01026 important );
01027 addProperty( CSS_PROP_BACKGROUND_COLOR,
01028 new CSSPrimitiveValueImpl( CSS_VAL_TRANSPARENT ),
01029 important );
01030
01031
01032
01033 assert( numParsedProperties - old_numParsed == 6 );
01034
01035 const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
01036 CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,
01037 CSS_PROP_BACKGROUND_COLOR };
01038 bool ret = parseShortHand(properties, 5, important);
01039 if ( !ret ) {
01040 for ( int i = 0; i < 6; i++ )
01041 delete parsedProperties[--numParsedProperties];
01042 }
01043 return ret;
01044 }
01045 case CSS_PROP_BORDER:
01046
01047 {
01048 const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
01049 CSS_PROP_BORDER_COLOR };
01050 return parseShortHand(properties, 3, important);
01051 }
01052 case CSS_PROP_BORDER_TOP:
01053
01054 {
01055 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
01056 CSS_PROP_BORDER_TOP_COLOR};
01057 return parseShortHand(properties, 3, important);
01058 }
01059 case CSS_PROP_BORDER_RIGHT:
01060
01061 {
01062 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
01063 CSS_PROP_BORDER_RIGHT_COLOR };
01064 return parseShortHand(properties, 3, important);
01065 }
01066 case CSS_PROP_BORDER_BOTTOM:
01067
01068 {
01069 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
01070 CSS_PROP_BORDER_BOTTOM_COLOR };
01071 return parseShortHand(properties, 3, important);
01072 }
01073 case CSS_PROP_BORDER_LEFT:
01074
01075 {
01076 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
01077 CSS_PROP_BORDER_LEFT_COLOR };
01078 return parseShortHand(properties, 3, important);
01079 }
01080 case CSS_PROP_OUTLINE:
01081
01082 {
01083 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
01084 CSS_PROP_OUTLINE_COLOR };
01085 return parseShortHand(properties, 3, important);
01086 }
01087 case CSS_PROP_BORDER_COLOR:
01088
01089 {
01090 if ( id == CSS_VAL_TRANSPARENT ) {
01091
01092 valid_primitive = true;
01093 break;
01094 }
01095 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
01096 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
01097 return parse4Values(properties, important);
01098 }
01099 case CSS_PROP_BORDER_WIDTH:
01100
01101 {
01102 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
01103 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
01104 return parse4Values(properties, important);
01105 }
01106 case CSS_PROP_BORDER_STYLE:
01107
01108 {
01109 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
01110 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
01111 return parse4Values(properties, important);
01112 }
01113 case CSS_PROP_MARGIN:
01114
01115 {
01116 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
01117 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
01118 return parse4Values(properties, important);
01119 }
01120 case CSS_PROP_PADDING:
01121
01122 {
01123 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
01124 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
01125 return parse4Values(properties, important);
01126 }
01127 case CSS_PROP_FONT:
01128
01129
01130 if ( id >= CSS_VAL_CAPTION && id <= CSS_VAL_STATUS_BAR )
01131 valid_primitive = true;
01132 else
01133 return parseFont(important);
01134
01135 case CSS_PROP_LIST_STYLE:
01136 {
01137 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
01138 CSS_PROP_LIST_STYLE_IMAGE };
01139 return parseShortHand(properties, 3, important);
01140 }
01141 default:
01142
01143
01144
01145 break;
01146 }
01147
01148 if ( valid_primitive ) {
01149 if ( id != 0 ) {
01150
01151 parsedValue = new CSSPrimitiveValueImpl( id );
01152 } else if ( value->unit == CSSPrimitiveValue::CSS_STRING )
01153 parsedValue = new CSSPrimitiveValueImpl( domString( value->string ),
01154 (CSSPrimitiveValue::UnitTypes) value->unit );
01155 else if ( value->unit >= CSSPrimitiveValue::CSS_NUMBER &&
01156 value->unit <= CSSPrimitiveValue::CSS_KHZ ) {
01157
01158 parsedValue = new CSSPrimitiveValueImpl( value->fValue,
01159 (CSSPrimitiveValue::UnitTypes) value->unit );
01160 } else if ( value->unit >= Value::Q_EMS ) {
01161
01162 parsedValue = new CSSQuirkPrimitiveValueImpl( value->fValue, CSSPrimitiveValue::CSS_EMS );
01163 }
01164 valueList->next();
01165 }
01166 if ( parsedValue ) {
01167 addProperty( propId, parsedValue, important );
01168 return true;
01169 }
01170 return false;
01171 }
01172
01173 bool CSSParser::parseShortHand( const int *properties, int numProperties, bool important )
01174 {
01175
01176
01177
01178
01179 inParseShortHand = true;
01180
01181 bool found = false;
01182 bool fnd[6];
01183 for( int i = 0; i < numProperties; i++ )
01184 fnd[i] = false;
01185
01186 #ifdef CSS_DEBUG
01187 kdDebug(6080) << "PSH: numProperties=" << numProperties << endl;
01188 #endif
01189
01190 while ( valueList->current() ) {
01191 found = false;
01192
01193 for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
01194 if (!fnd[propIndex]) {
01195 #ifdef CSS_DEBUG
01196 kdDebug(6080) << "LOOKING FOR: " << getPropertyName(properties[propIndex]).string() << endl;
01197 #endif
01198 if ( parseValue( properties[propIndex], important ) ) {
01199 fnd[propIndex] = found = true;
01200 #ifdef CSS_DEBUG
01201 kdDebug(6080) << "FOUND: " << getPropertyName(properties[propIndex]).string() << endl;
01202 #endif
01203 }
01204 }
01205 }
01206
01207
01208 if (!found) {
01209 #ifdef CSS_DEBUG
01210 qDebug("didn't find anything" );
01211 #endif
01212 inParseShortHand = false;
01213 return false;
01214 }
01215 }
01216 inParseShortHand = false;
01217 #ifdef CSS_DEBUG
01218 kdDebug( 6080 ) << "parsed shorthand" << endl;
01219 #endif
01220 return true;
01221 }
01222
01223 bool CSSParser::parse4Values( const int *properties, bool important )
01224 {
01225
01226
01227
01228
01229
01230
01231
01232
01233 int num = inParseShortHand ? 1 : valueList->numValues;
01234
01235
01236
01237 switch( num ) {
01238 case 1: {
01239 if( !parseValue( properties[0], important ) ) return false;
01240 CSSValueImpl *value = parsedProperties[numParsedProperties-1]->value();
01241 addProperty( properties[1], value, important );
01242 addProperty( properties[2], value, important );
01243 addProperty( properties[3], value, important );
01244 return true;
01245 }
01246 case 2: {
01247
01248 if( !parseValue( properties[0], important ) ) return false;
01249 if( !parseValue( properties[1], important ) ) return false;
01250 CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
01251 addProperty( properties[2], value, important );
01252 value = parsedProperties[numParsedProperties-2]->value();
01253 addProperty( properties[3], value, important );
01254 return true;
01255 }
01256 case 3: {
01257 if( !parseValue( properties[0], important ) ) return false;
01258 if( !parseValue( properties[1], important ) ) return false;
01259 if( !parseValue( properties[2], important ) ) return false;
01260 CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
01261 addProperty( properties[3], value, important );
01262 return true;
01263 }
01264 case 4: {
01265 if( !parseValue( properties[0], important ) ) return false;
01266 if( !parseValue( properties[1], important ) ) return false;
01267 if( !parseValue( properties[2], important ) ) return false;
01268 if( !parseValue( properties[3], important ) ) return false;
01269 return true;
01270 }
01271 default:
01272 return false;
01273 }
01274 }
01275
01276
01277
01278
01279 bool CSSParser::parseContent( int propId, bool important )
01280 {
01281 CSSValueListImpl* values = new CSSValueListImpl();
01282
01283 Value *val;
01284 CSSValueImpl *parsedValue = 0;
01285 while ( (val = valueList->current()) ) {
01286 if ( val->unit == CSSPrimitiveValue::CSS_URI ) {
01287
01288 DOMString value = khtml::parseURL(domString(val->string));
01289 parsedValue = new CSSImageValueImpl(
01290 DOMString(KURL( styleElement->baseURL(), value.string()).url() ), styleElement );
01291 #ifdef CSS_DEBUG
01292 kdDebug( 6080 ) << "content, url=" << value.string() << " base=" << styleElement->baseURL().url( ) << endl;
01293 #endif
01294 } else if ( val->unit == Value::Function ) {
01295
01296 ValueList *args = val->function->args;
01297 QString fname = qString( val->function->name ).lower();
01298 if ( fname != "attr(" || !args )
01299 return false;
01300 if ( args->numValues != 1)
01301 return false;
01302 Value *a = args->current();
01303 parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR);
01304 } else if ( val->unit == CSSPrimitiveValue::CSS_IDENT ) {
01305
01306
01307
01308
01309 } else if ( val->unit == CSSPrimitiveValue::CSS_STRING ) {
01310 parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING);
01311 }
01312 if (parsedValue)
01313 values->append(parsedValue);
01314 else
01315 break;
01316 valueList->next();
01317 }
01318 if ( values->length() ) {
01319 addProperty( propId, values, important );
01320 valueList->next();
01321 return true;
01322 }
01323 delete values;
01324 return false;
01325 }
01326
01327 bool CSSParser::parseShape( int propId, bool important )
01328 {
01329 Value *value = valueList->current();
01330 ValueList *args = value->function->args;
01331 QString fname = qString( value->function->name ).lower();
01332
01333 if ( fname != "rect(" || !args )
01334 return false;
01335
01336
01337 if ( args->numValues != 4 && args->numValues != 7 )
01338 return false;
01339 RectImpl *rect = new RectImpl();
01340 bool valid = true;
01341 int i = 0;
01342 Value *a = args->current();
01343 while ( a ) {
01344 valid = validUnit( a, FLength, strict );
01345 if ( !valid )
01346 break;
01347 CSSPrimitiveValueImpl *length =
01348 new CSSPrimitiveValueImpl( a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit );
01349 if ( i == 0 )
01350 rect->setTop( length );
01351 else if ( i == 1 )
01352 rect->setRight( length );
01353 else if ( i == 2 )
01354 rect->setBottom( length );
01355 else
01356 rect->setLeft( length );
01357 a = args->next();
01358 if ( a && args->numValues == 7 ) {
01359 if ( a->unit == Value::Operator && a->iValue == ',' ) {
01360 a = args->next();
01361 } else {
01362 valid = false;
01363 break;
01364 }
01365 }
01366 i++;
01367 }
01368 if ( valid ) {
01369 addProperty( propId, new CSSPrimitiveValueImpl( rect ), important );
01370 valueList->next();
01371 return true;
01372 }
01373 delete rect;
01374 return false;
01375 }
01376
01377
01378 bool CSSParser::parseFont( bool important )
01379 {
01380
01381 bool valid = true;
01382 Value *value = valueList->current();
01383 FontValueImpl *font = new FontValueImpl;
01384
01385 while ( value ) {
01386
01387
01388
01389 int id = value->id;
01390 if ( id ) {
01391 if ( id == CSS_VAL_NORMAL ) {
01392
01393 }
01394
01395
01396
01397
01398
01399
01400
01401 else if ( id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE ) {
01402 if ( font->style )
01403 goto invalid;
01404 font->style = new CSSPrimitiveValueImpl( id );
01405 } else if ( id == CSS_VAL_SMALL_CAPS ) {
01406 if ( font->variant )
01407 goto invalid;
01408 font->variant = new CSSPrimitiveValueImpl( id );
01409 } else if ( id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER ) {
01410 if ( font->weight )
01411 goto invalid;
01412 font->weight = new CSSPrimitiveValueImpl( id );
01413 } else {
01414 valid = false;
01415 }
01416 } else if ( !font->weight && validUnit( value, FInteger|FNonNeg, true ) ) {
01417 int weight = (int)value->fValue;
01418 int val = 0;
01419 if ( weight == 100 )
01420 val = CSS_VAL_100;
01421 else if ( weight == 200 )
01422 val = CSS_VAL_200;
01423 else if ( weight == 300 )
01424 val = CSS_VAL_300;
01425 else if ( weight == 400 )
01426 val = CSS_VAL_400;
01427 else if ( weight == 500 )
01428 val = CSS_VAL_500;
01429 else if ( weight == 600 )
01430 val = CSS_VAL_600;
01431 else if ( weight == 700 )
01432 val = CSS_VAL_700;
01433 else if ( weight == 800 )
01434 val = CSS_VAL_800;
01435 else if ( weight == 900 )
01436 val = CSS_VAL_900;
01437
01438 if ( val )
01439 font->weight = new CSSPrimitiveValueImpl( val );
01440 else
01441 valid = false;
01442 } else {
01443 valid = false;
01444 }
01445 if ( !valid )
01446 break;
01447 value = valueList->next();
01448 }
01449 if ( !value )
01450 goto invalid;
01451
01452
01453 if ( !font->style )
01454 font->style = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01455 if ( !font->variant )
01456 font->variant = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01457 if ( !font->weight )
01458 font->weight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01459
01460
01461
01462
01463
01464 if ( value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER )
01465 font->size = new CSSPrimitiveValueImpl( value->id );
01466 else if ( validUnit( value, FLength|FPercent, strict ) ) {
01467 font->size = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01468 }
01469 value = valueList->next();
01470 if ( !font->size || !value )
01471 goto invalid;
01472
01473
01474
01475 if ( value->unit == Value::Operator && value->iValue == '/' ) {
01476
01477 value = valueList->next();
01478 if ( !value )
01479 goto invalid;
01480 if ( value->id == CSS_VAL_NORMAL ) {
01481
01482 } else if ( validUnit( value, FNumber|FLength|FPercent, strict ) ) {
01483 font->lineHeight = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01484 } else {
01485 goto invalid;
01486 }
01487 value = valueList->next();
01488 if ( !value )
01489 goto invalid;
01490 } else {
01491 font->lineHeight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01492 }
01493
01494
01495
01496 font->family = parseFontFamily();
01497
01498 if ( valueList->current() || !font->family )
01499 goto invalid;
01500
01501
01502 addProperty( CSS_PROP_FONT, font, important );
01503 return true;
01504
01505 invalid:
01506
01507 delete font;
01508 return false;
01509 }
01510
01511 CSSValueListImpl *CSSParser::parseFontFamily()
01512 {
01513
01514 CSSValueListImpl *list = new CSSValueListImpl;
01515 Value *value = valueList->current();
01516 QString currFace;
01517
01518 while ( value ) {
01519
01520
01521
01522
01523 Value* nextValue = valueList->next();
01524 bool nextValBreaksFont = !nextValue ||
01525 (nextValue->unit == Value::Operator && nextValue->iValue == ',');
01526 bool nextValIsFontName = nextValue &&
01527 ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL_MONOSPACE) ||
01528 (nextValue->unit == CSSPrimitiveValue::CSS_STRING ||
01529 nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
01530
01531 if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL_MONOSPACE) {
01532 if (!currFace.isNull()) {
01533 currFace += ' ';
01534 currFace += qString(value->string);
01535 }
01536 else if (nextValBreaksFont || !nextValIsFontName) {
01537 if ( !currFace.isNull() ) {
01538 list->append( new FontFamilyValueImpl( currFace ) );
01539 currFace = QString::null;
01540 }
01541 list->append(new CSSPrimitiveValueImpl(value->id));
01542 }
01543 else {
01544 currFace = qString( value->string );
01545 }
01546 }
01547 else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
01548
01549 currFace = QString::null;
01550 list->append(new FontFamilyValueImpl(qString( value->string) ) );
01551 }
01552 else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
01553 if (!currFace.isNull()) {
01554 currFace += ' ';
01555 currFace += qString(value->string);
01556 }
01557 else if (nextValBreaksFont || !nextValIsFontName) {
01558 if ( !currFace.isNull() ) {
01559 list->append( new FontFamilyValueImpl( currFace ) );
01560 currFace = QString::null;
01561 }
01562 list->append(new FontFamilyValueImpl( qString( value->string ) ) );
01563 }
01564 else {
01565 currFace = qString( value->string);
01566 }
01567 }
01568 else {
01569
01570 break;
01571 }
01572
01573 if (!nextValue)
01574 break;
01575
01576 if (nextValBreaksFont) {
01577 value = valueList->next();
01578 if ( !currFace.isNull() )
01579 list->append( new FontFamilyValueImpl( currFace ) );
01580 currFace = QString::null;
01581 }
01582 else if (nextValIsFontName)
01583 value = nextValue;
01584 else
01585 break;
01586 }
01587
01588 if ( !currFace.isNull() )
01589 list->append( new FontFamilyValueImpl( currFace ) );
01590
01591 if ( !list->length() ) {
01592 delete list;
01593 list = 0;
01594 }
01595 return list;
01596 }
01597
01598
01599 static bool parseColor(const QString &name, QRgb& rgb)
01600 {
01601 int len = name.length();
01602
01603 if ( !len )
01604 return false;
01605
01606
01607 bool ok;
01608
01609 if ( len == 3 || len == 6 ) {
01610 int val = name.toInt(&ok, 16);
01611 if ( ok ) {
01612 if (len == 6) {
01613 rgb = (0xff << 24) | val;
01614 return true;
01615 }
01616 else if ( len == 3 ) {
01617
01618 rgb = (0xff << 24) |
01619 (val&0xf00)<<12 | (val&0xf00)<<8 |
01620 (val&0xf0)<<8 | (val&0xf0)<<4 |
01621 (val&0xf)<<4 | (val&0xf);
01622 return true;
01623 }
01624 }
01625 }
01626
01627
01628 QColor tc;
01629 tc.setNamedColor(name.lower());
01630 if ( tc.isValid() ) {
01631 rgb = tc.rgb();
01632 return true;
01633 }
01634
01635 return false;
01636 }
01637
01638
01639 CSSPrimitiveValueImpl *CSSParser::parseColor()
01640 {
01641 QRgb c = khtml::transparentColor;
01642 Value *value = valueList->current();
01643 if ( !strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
01644 value->fValue >= 0. && value->fValue < 1000000. ) {
01645 QString str;
01646 str.sprintf( "%06d", (int)(value->fValue+.5) );
01647 if ( !::parseColor( str, c ) )
01648 return 0;
01649 } else if ( value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
01650 value->unit == CSSPrimitiveValue::CSS_IDENT ||
01651 (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION) ) {
01652 if ( !::parseColor( qString( value->string ), c) )
01653 return 0;
01654 }
01655 else if ( value->unit == Value::Function &&
01656 value->function->args != 0 &&
01657 value->function->args->numValues == 5 &&
01658 qString( value->function->name ).lower() == "rgb(" ) {
01659 ValueList *args = value->function->args;
01660 Value *v = args->current();
01661 if ( !validUnit( v, FInteger|FPercent, true ) )
01662 return 0;
01663 int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01664 v = args->next();
01665 if ( v->unit != Value::Operator && v->iValue != ',' )
01666 return 0;
01667 v = args->next();
01668 if ( !validUnit( v, FInteger|FPercent, true ) )
01669 return 0;
01670 int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01671 v = args->next();
01672 if ( v->unit != Value::Operator && v->iValue != ',' )
01673 return 0;
01674 v = args->next();
01675 if ( !validUnit( v, FInteger|FPercent, true ) )
01676 return 0;
01677 int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01678 r = kMax( 0, kMin( 255, r ) );
01679 g = kMax( 0, kMin( 255, g ) );
01680 b = kMax( 0, kMin( 255, b ) );
01681 c = qRgb( r, g, b );
01682 }
01683 else if ( value->unit == Value::Function &&
01684 value->function->args != 0 &&
01685 value->function->args->numValues == 7 &&
01686 qString( value->function->name ).lower() == "rgba(" ) {
01687 ValueList *args = value->function->args;
01688 Value *v = args->current();
01689 if ( !validUnit( v, FInteger|FPercent, true ) )
01690 return 0;
01691 int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01692 v = args->next();
01693 if ( v->unit != Value::Operator && v->iValue != ',' )
01694 return 0;
01695 v = args->next();
01696 if ( !validUnit( v, FInteger|FPercent, true ) )
01697 return 0;
01698 int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01699 v = args->next();
01700 if ( v->unit != Value::Operator && v->iValue != ',' )
01701 return 0;
01702 v = args->next();
01703 if ( !validUnit( v, FInteger|FPercent, true ) )
01704 return 0;
01705 int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01706 v = args->next();
01707 if ( v->unit != Value::Operator && v->iValue != ',' )
01708 return 0;
01709 v = args->next();
01710 if ( !validUnit( v, FNumber, true ) )
01711 return 0;
01712 r = QMAX( 0, QMIN( 255, r ) );
01713 g = QMAX( 0, QMIN( 255, g ) );
01714 b = QMAX( 0, QMIN( 255, b ) );
01715 int a = (int)(QMAX( 0, QMIN( 1.0f, v->fValue ) ) * 255);
01716 c = qRgba( r, g, b, a );
01717 }
01718 else
01719 return 0;
01720
01721 return new CSSPrimitiveValueImpl(c);
01722 }
01723
01724
01725 static inline int yyerror( const char *str ) {
01726
01727 #ifdef CSS_DEBUG
01728 kdDebug( 6080 ) << "CSS parse error " << str << endl;
01729 #else
01730 Q_UNUSED( str );
01731 #endif
01732 return 1;
01733 }
01734
01735 #define END 0
01736
01737 #include "parser.h"
01738
01739 int DOM::CSSParser::lex( void *_yylval ) {
01740 YYSTYPE *yylval = (YYSTYPE *)_yylval;
01741 int token = lex();
01742 int length;
01743 unsigned short *t = text( &length );
01744
01745 #ifdef TOKEN_DEBUG
01746 qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString( (QChar *)t, length ).latin1() );
01747 #endif
01748 switch( token ) {
01749 case S:
01750 case SGML_CD:
01751 case INCLUDES:
01752 case DASHMATCH:
01753 break;
01754
01755 case URI:
01756 case STRING:
01757 case IDENT:
01758 case HASH:
01759 case DIMEN:
01760 case UNICODERANGE:
01761 case FUNCTION:
01762 yylval->string.string = t;
01763 yylval->string.length = length;
01764 break;
01765
01766 case IMPORT_SYM:
01767 case PAGE_SYM:
01768 case MEDIA_SYM:
01769 case FONT_FACE_SYM:
01770 case CHARSET_SYM:
01771
01772 case IMPORTANT_SYM:
01773 break;
01774
01775 case QEMS:
01776 length--;
01777 case GRADS:
01778 length--;
01779 case DEGS:
01780 case RADS:
01781 case KHERZ:
01782 length--;
01783 case MSECS:
01784 case HERZ:
01785 case EMS:
01786 case EXS:
01787 case PXS:
01788 case CMS:
01789 case MMS:
01790 case INS:
01791 case PTS:
01792 case PCS:
01793 length--;
01794 case SECS:
01795 case PERCENTAGE:
01796 length--;
01797 case NUMBER:
01798 yylval->val = QString( (QChar *)t, length ).toDouble();
01799
01800 break;
01801
01802 default:
01803 break;
01804 }
01805
01806 return token;
01807 }
01808
01809 static inline int toHex( char c ) {
01810 if ( '0' <= c && c <= '9' )
01811 return c - '0';
01812 if ( 'a' <= c && c <= 'f' )
01813 return c - 'a' + 10;
01814 if ( 'A' <= c && c<= 'F' )
01815 return c - 'A' + 10;
01816 return 0;
01817 }
01818
01819 unsigned short *DOM::CSSParser::text(int *length)
01820 {
01821 unsigned short *start = yytext;
01822 int l = yyleng;
01823 switch( yyTok ) {
01824 case STRING:
01825 l--;
01826
01827 case HASH:
01828 start++;
01829 l--;
01830 break;
01831 case URI:
01832
01833
01834
01835
01836 start += 4;
01837 l -= 5;
01838
01839 while ( l &&
01840 (*start == ' ' || *start == '\t' || *start == '\r' ||
01841 *start == '\n' || *start == '\f' ) ) {
01842 start++; l--;
01843 }
01844 if ( *start == '"' || *start == '\'' ) {
01845 start++; l--;
01846 }
01847 while ( l &&
01848 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
01849 start[l-1] == '\n' || start[l-1] == '\f' ) ) {
01850 l--;
01851 }
01852 if ( l && (start[l-1] == '\"' || start[l-1] == '\'' ) )
01853 l--;
01854
01855 default:
01856 break;
01857 }
01858
01859
01860 unsigned short *out = start;
01861 unsigned short *escape = 0;
01862
01863 for ( int i = 0; i < l; i++ ) {
01864 unsigned short *current = start+i;
01865 if ( escape == current - 1 ) {
01866 if ( ( *current >= '0' && *current <= '9' ) ||
01867 ( *current >= 'a' && *current <= 'f' ) ||
01868 ( *current >= 'A' && *current <= 'F' ) )
01869 continue;
01870 if ( yyTok == STRING &&
01871 ( *current == '\n' || *current == '\r' || *current == '\f' ) ) {
01872
01873 if ( *current != '\r' )
01874 escape = 0;
01875 continue;
01876 }
01877
01878
01879 *out++ = *current;
01880 escape = 0;
01881 continue;
01882 }
01883 if ( escape == current - 2 && yyTok == STRING &&
01884 *(current-1) == '\r' && *current == '\n' ) {
01885 escape = 0;
01886 continue;
01887 }
01888 if ( escape > current - 7 &&
01889 ( ( *current >= '0' && *current <= '9' ) ||
01890 ( *current >= 'a' && *current <= 'f' ) ||
01891 ( *current >= 'A' && *current <= 'F' ) ) )
01892 continue;
01893 if ( escape ) {
01894
01895 int uc = 0;
01896 escape++;
01897 while ( escape < current ) {
01898
01899 uc *= 16;
01900 uc += toHex( *escape );
01901 escape++;
01902 }
01903
01904
01905 if ( uc > 0xffff )
01906 uc = 0xfffd;
01907 *(out++) = (unsigned short)uc;
01908 escape = 0;
01909 if ( *current == ' ' ||
01910 *current == '\t' ||
01911 *current == '\r' ||
01912 *current == '\n' ||
01913 *current == '\f' )
01914 continue;
01915 }
01916 if ( !escape && *current == '\\' ) {
01917 escape = current;
01918 continue;
01919 }
01920 *(out++) = *current;
01921 }
01922 if ( escape ) {
01923
01924 int uc = 0;
01925 escape++;
01926 while ( escape < start+l ) {
01927
01928 uc *= 16;
01929 uc += toHex( *escape );
01930 escape++;
01931 }
01932
01933
01934 if ( uc > 0xffff )
01935 uc = 0xfffd;
01936 *(out++) = (unsigned short)uc;
01937 }
01938
01939 *length = out - start;
01940 return start;
01941 }
01942
01943
01944 #define YY_DECL int DOM::CSSParser::lex()
01945 #define yyconst const
01946 typedef int yy_state_type;
01947 typedef unsigned int YY_CHAR;
01948
01949 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
01950 #define YY_DO_BEFORE_ACTION \
01951 yytext = yy_bp; \
01952 yyleng = (int) (yy_cp - yy_bp); \
01953 yy_hold_char = *yy_cp; \
01954 *yy_cp = 0; \
01955 yy_c_buf_p = yy_cp;
01956 #define YY_BREAK break;
01957 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).latin1() )
01958 #define YY_RULE_SETUP
01959 #define INITIAL 0
01960 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
01961 #define yyterminate() yyTok = END; return yyTok
01962 #define YY_FATAL_ERROR(a) qFatal(a)
01963 #define BEGIN yy_start = 1 + 2 *
01964 #define COMMENT 1
01965
01966 #include "tokenizer.cpp"