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