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 valid_primitive = true;
00496 break;
00497
00498 case CSS_PROP_LIST_STYLE_POSITION:
00499 if ( id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE )
00500 valid_primitive = true;
00501 break;
00502
00503 case CSS_PROP_LIST_STYLE_TYPE:
00504
00505
00506
00507
00508 if ((id >= CSS_VAL_DISC && id <= CSS_VAL_KATAKANA_IROHA) || id == CSS_VAL_NONE)
00509 valid_primitive = true;
00510 break;
00511
00512 case CSS_PROP_DISPLAY:
00513
00514
00515
00516 if ((id >= CSS_VAL_INLINE && id <= CSS_VAL_TABLE_CAPTION) || id == CSS_VAL_NONE)
00517 valid_primitive = true;
00518 break;
00519
00520 case CSS_PROP_DIRECTION:
00521 if ( id == CSS_VAL_LTR || id == CSS_VAL_RTL )
00522 valid_primitive = true;
00523 break;
00524
00525 case CSS_PROP_TEXT_TRANSFORM:
00526 if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE)
00527 valid_primitive = true;
00528 break;
00529
00530 case CSS_PROP_FLOAT:
00531 if ( id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
00532 id == CSS_VAL_NONE || id == CSS_VAL_CENTER)
00533 valid_primitive = true;
00534 break;
00535
00536 case CSS_PROP_CLEAR:
00537 if ( id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
00538 id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH)
00539 valid_primitive = true;
00540 break;
00541
00542 case CSS_PROP_TEXT_ALIGN:
00543
00544 if ( ( id >= CSS_VAL__KHTML_AUTO && id <= CSS_VAL__KHTML_CENTER ) ||
00545 value->unit == CSSPrimitiveValue::CSS_STRING )
00546 valid_primitive = true;
00547 break;
00548
00549 case CSS_PROP_OUTLINE_STYLE:
00550 case CSS_PROP_BORDER_TOP_STYLE:
00551 case CSS_PROP_BORDER_RIGHT_STYLE:
00552 case CSS_PROP_BORDER_BOTTOM_STYLE:
00553 case CSS_PROP_BORDER_LEFT_STYLE:
00554 if (id >= CSS_VAL_NONE && id <= CSS_VAL_RIDGE)
00555 valid_primitive = true;
00556 break;
00557
00558 case CSS_PROP_FONT_WEIGHT:
00559
00560 if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) {
00561
00562 valid_primitive = true;
00563 } else if ( validUnit( value, FInteger|FNonNeg, false ) ) {
00564 int weight = (int)value->fValue;
00565 if ( (weight % 100) )
00566 break;
00567 weight /= 100;
00568 if ( weight >= 1 && weight <= 9 ) {
00569 id = CSS_VAL_100 + weight - 1;
00570 valid_primitive = true;
00571 }
00572 }
00573 break;
00574
00575 case CSS_PROP_BACKGROUND_REPEAT:
00576 if ( id >= CSS_VAL_REPEAT && id <= CSS_VAL_NO_REPEAT )
00577 valid_primitive = true;
00578 break;
00579
00580 case CSS_PROP_BACKGROUND_ATTACHMENT:
00581 if ( id == CSS_VAL_SCROLL || id == CSS_VAL_FIXED )
00582 valid_primitive = true;
00583 break;
00584
00585 case CSS_PROP_BACKGROUND_POSITION:
00586 if ( id ) {
00587
00588
00589
00590
00591
00592 int pos[2];
00593 pos[0] = -1;
00594 pos[1] = -1;
00595 bool invalid = false;
00596 switch( id ) {
00597 case CSS_VAL_TOP:
00598 pos[1] = 0;
00599 break;
00600 case CSS_VAL_BOTTOM:
00601 pos[1] = 100;
00602 break;
00603 case CSS_VAL_LEFT:
00604 pos[0] = 0;
00605 break;
00606 case CSS_VAL_RIGHT:
00607 pos[0] = 100;
00608 break;
00609 case CSS_VAL_CENTER:
00610 break;
00611 default:
00612 invalid = true;
00613 }
00614 if ( invalid )
00615 break;
00616 value = valueList->next();
00617 if ( value ) {
00618 id = value->id;
00619 switch( id ) {
00620 case CSS_VAL_TOP:
00621 if ( pos[1] != -1 )
00622 invalid = true;
00623 pos[1] = 0;
00624 break;
00625 case CSS_VAL_BOTTOM:
00626 if ( pos[1] != -1 )
00627 invalid = true;
00628 pos[1] = 100;
00629 break;
00630 case CSS_VAL_LEFT:
00631 if ( pos[0] != -1 )
00632 invalid = true;
00633 pos[0] = 0;
00634 break;
00635 case CSS_VAL_RIGHT:
00636 if ( pos[0] != -1 )
00637 invalid = true;
00638 pos[0] = 100;
00639 break;
00640 case CSS_VAL_CENTER:
00641 break;
00642 default:
00643 invalid = true;
00644 }
00645 if ( !invalid )
00646 value = valueList->next();
00647 }
00648 if ( pos[0] == -1 )
00649 pos[0] = 50;
00650 if ( pos[1] == -1 )
00651 pos[1] = 50;
00652 addProperty( CSS_PROP_BACKGROUND_POSITION_X,
00653 new CSSPrimitiveValueImpl( pos[0], CSSPrimitiveValue::CSS_PERCENTAGE ),
00654 important );
00655 addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
00656 new CSSPrimitiveValueImpl( pos[1], CSSPrimitiveValue::CSS_PERCENTAGE ),
00657 important );
00658 } else {
00659 bool ok = parseValue( CSS_PROP_BACKGROUND_POSITION_X, important );
00660 if ( !ok )
00661 break;
00662 value = valueList->current();
00663 if ( value )
00664 ok = parseValue( CSS_PROP_BACKGROUND_POSITION_Y, important );
00665 if ( !ok )
00666 addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
00667 new CSSPrimitiveValueImpl( 50, CSSPrimitiveValue::CSS_PERCENTAGE ),
00668 important );
00669 }
00670 return true;
00671
00672 case CSS_PROP_BACKGROUND_POSITION_X:
00673 case CSS_PROP_BACKGROUND_POSITION_Y:
00674 valid_primitive = validUnit( value, FPercent|FLength, strict&(!nonCSSHint) );
00675 break;
00676
00677 case CSS_PROP_BORDER_SPACING:
00678 {
00679 const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING,
00680 CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
00681 int num = valueList->numValues;
00682 if (num == 1) {
00683 if (!parseValue(properties[0], important)) return false;
00684 CSSValueImpl* value = parsedProperties[numParsedProperties-1]->value();
00685 addProperty(properties[1], value, important);
00686 return true;
00687 }
00688 else if (num == 2) {
00689 if (!parseValue(properties[0], important)) return false;
00690 if (!parseValue(properties[1], important)) return false;
00691 return true;
00692 }
00693 return false;
00694 }
00695 case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING:
00696 case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING:
00697 valid_primitive = validUnit(value, FLength|FNonNeg, strict&(!nonCSSHint));
00698 break;
00699
00700 case CSS_PROP_SCROLLBAR_FACE_COLOR:
00701 case CSS_PROP_SCROLLBAR_SHADOW_COLOR:
00702 case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:
00703 case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:
00704 case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:
00705 case CSS_PROP_SCROLLBAR_TRACK_COLOR:
00706 case CSS_PROP_SCROLLBAR_ARROW_COLOR:
00707 case CSS_PROP_SCROLLBAR_BASE_COLOR:
00708 if ( strict )
00709 break;
00710
00711 case CSS_PROP_OUTLINE_COLOR:
00712
00713 if ( propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT ) {
00714 valid_primitive = true;
00715 break;
00716 }
00717
00718 case CSS_PROP_BACKGROUND_COLOR:
00719 if ( propId == CSS_PROP_BACKGROUND_COLOR && id == CSS_VAL_TRANSPARENT ) {
00720 valid_primitive = true;
00721 break;
00722 }
00723
00724 case CSS_PROP_COLOR:
00725 case CSS_PROP_BORDER_TOP_COLOR:
00726 case CSS_PROP_BORDER_RIGHT_COLOR:
00727 case CSS_PROP_BORDER_BOTTOM_COLOR:
00728 case CSS_PROP_BORDER_LEFT_COLOR:
00729 case CSS_PROP__KHTML_TEXT_DECORATION_COLOR:
00730 if ( id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_MENU ||
00731 (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT ) ||
00732 (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && (nonCSSHint|!strict) ) ) {
00733 valid_primitive = true;
00734 } else {
00735 parsedValue = parseColor();
00736 if ( parsedValue )
00737 valueList->next();
00738 }
00739 break;
00740
00741 case CSS_PROP_CURSOR:
00742
00743
00744
00745
00746 if ( !strict && id == CSS_VAL_HAND ) {
00747 id = CSS_VAL_POINTER;
00748 valid_primitive = true;
00749 } else if ( id >= CSS_VAL_AUTO && id <= CSS_VAL_HELP )
00750 valid_primitive = true;
00751 break;
00752
00753 case CSS_PROP_BACKGROUND_IMAGE:
00754 case CSS_PROP_LIST_STYLE_IMAGE:
00755
00756 if ( id == CSS_VAL_NONE ) {
00757 parsedValue = new CSSImageValueImpl();
00758 valueList->next();
00759 #ifdef CSS_DEBUG
00760 kdDebug( 6080 ) << "empty image " << endl;
00761 #endif
00762 } else if ( value->unit == CSSPrimitiveValue::CSS_URI ) {
00763
00764 DOMString uri = khtml::parseURL( domString( value->string ) );
00765 if ( !uri.isEmpty() ) {
00766 parsedValue = new CSSImageValueImpl(
00767 DOMString(KURL( styleElement->baseURL(), uri.string()).url()),
00768 styleElement );
00769 valueList->next();
00770 #ifdef CSS_DEBUG
00771 kdDebug( 6080 ) << "image, url=" << uri.string() << " base=" << styleElement->baseURL().url() << endl;
00772 #endif
00773 }
00774 }
00775 break;
00776
00777 case CSS_PROP_OUTLINE_WIDTH:
00778 case CSS_PROP_BORDER_TOP_WIDTH:
00779 case CSS_PROP_BORDER_RIGHT_WIDTH:
00780 case CSS_PROP_BORDER_BOTTOM_WIDTH:
00781 case CSS_PROP_BORDER_LEFT_WIDTH:
00782 if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
00783 valid_primitive = true;
00784 else
00785 valid_primitive = ( validUnit( value, FLength, strict&(!nonCSSHint) ) );
00786 break;
00787
00788 case CSS_PROP_LETTER_SPACING:
00789 case CSS_PROP_WORD_SPACING:
00790 if ( id == CSS_VAL_NORMAL )
00791 valid_primitive = true;
00792 else
00793 valid_primitive = validUnit( value, FLength, strict&(!nonCSSHint) );
00794 break;
00795
00796 case CSS_PROP_TEXT_INDENT:
00797 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00798 break;
00799
00800 case CSS_PROP_PADDING_TOP:
00801 case CSS_PROP_PADDING_RIGHT:
00802 case CSS_PROP_PADDING_BOTTOM:
00803 case CSS_PROP_PADDING_LEFT:
00804 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00805 break;
00806
00807 case CSS_PROP_MAX_HEIGHT:
00808 case CSS_PROP_MAX_WIDTH:
00809 if ( id == CSS_VAL_NONE ) {
00810 valid_primitive = true;
00811 break;
00812 }
00813
00814 case CSS_PROP_MIN_HEIGHT:
00815 case CSS_PROP_MIN_WIDTH:
00816 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00817 break;
00818
00819 case CSS_PROP_FONT_SIZE:
00820
00821 if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER)
00822 valid_primitive = true;
00823 else
00824 valid_primitive = ( validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00825 break;
00826
00827 case CSS_PROP_FONT_STYLE:
00828 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE)
00829 valid_primitive = true;
00830 break;
00831
00832 case CSS_PROP_FONT_VARIANT:
00833 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS)
00834 valid_primitive = true;
00835 break;
00836
00837 case CSS_PROP_VERTICAL_ALIGN:
00838
00839
00840
00841 if ( id >= CSS_VAL_BASELINE && id <= CSS_VAL__KHTML_BASELINE_MIDDLE )
00842 valid_primitive = true;
00843 else
00844 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00845 break;
00846
00847 case CSS_PROP_HEIGHT:
00848 case CSS_PROP_WIDTH:
00849 if ( id == CSS_VAL_AUTO )
00850 valid_primitive = true;
00851 else
00852
00853 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) );
00854 break;
00855
00856 case CSS_PROP_BOTTOM:
00857 case CSS_PROP_LEFT:
00858 case CSS_PROP_RIGHT:
00859 case CSS_PROP_TOP:
00860 case CSS_PROP_MARGIN_TOP:
00861 case CSS_PROP_MARGIN_RIGHT:
00862 case CSS_PROP_MARGIN_BOTTOM:
00863 case CSS_PROP_MARGIN_LEFT:
00864 if ( id == CSS_VAL_AUTO )
00865 valid_primitive = true;
00866 else
00867 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) );
00868 break;
00869
00870 case CSS_PROP_Z_INDEX:
00871
00872 if ( id == CSS_VAL_AUTO ) {
00873 valid_primitive = true;
00874 break;
00875 }
00876
00877 case CSS_PROP_ORPHANS:
00878 case CSS_PROP_WIDOWS:
00879
00880 valid_primitive = ( !id && validUnit( value, FInteger, false ) );
00881 break;
00882
00883 case CSS_PROP_LINE_HEIGHT:
00884 if ( id == CSS_VAL_NORMAL )
00885 valid_primitive = true;
00886 else
00887 valid_primitive = ( !id && validUnit( value, FNumber|FLength|FPercent, strict&(!nonCSSHint) ) );
00888 break;
00889 #if 0
00890
00891 case CSS_PROP_COUNTER_INCREMENT:
00892 case CSS_PROP_COUNTER_RESET:
00893 if ( id == CSS_VAL_NONE )
00894 valid_primitive = true;
00895 else {
00896 CSSValueListImpl *list = new CSSValueListImpl;
00897 int pos=0, pos2;
00898 while( 1 )
00899 {
00900 pos2 = value.find(',', pos);
00901 QString face = value.mid(pos, pos2-pos);
00902 face = face.stripWhiteSpace();
00903 if(face.length() == 0) break;
00904
00905 if(face[0] == '\"') face.remove(0, 1);
00906 if(face[face.length()-1] == '\"') face = face.left(face.length()-1);
00907
00908 list->append(new CSSPrimitiveValueImpl(DOMString(face), CSSPrimitiveValue::CSS_STRING));
00909 pos = pos2 + 1;
00910 if(pos2 == -1) break;
00911 }
00912
00913 if(list->length()) {
00914 parsedValue = list;
00915 valueList->next();
00916 } else
00917 delete list;
00918 break;
00919 }
00920 #endif
00921 case CSS_PROP_FONT_FAMILY:
00922
00923 {
00924 parsedValue = parseFontFamily();
00925 break;
00926 }
00927
00928 case CSS_PROP_TEXT_DECORATION:
00929
00930 if (id == CSS_VAL_NONE) {
00931 valid_primitive = true;
00932 } else {
00933 CSSValueListImpl *list = new CSSValueListImpl;
00934 bool is_valid = true;
00935 while( is_valid && value ) {
00936 switch ( value->id ) {
00937 case CSS_VAL_BLINK:
00938 break;
00939 case CSS_VAL_UNDERLINE:
00940 case CSS_VAL_OVERLINE:
00941 case CSS_VAL_LINE_THROUGH:
00942 list->append( new CSSPrimitiveValueImpl( value->id ) );
00943 break;
00944 default:
00945 is_valid = false;
00946 }
00947 value = valueList->next();
00948 }
00949
00950 if(list->length() && is_valid) {
00951 parsedValue = list;
00952 valueList->next();
00953 } else {
00954 delete list;
00955 }
00956 }
00957 break;
00958
00959 case CSS_PROP_TABLE_LAYOUT:
00960 if ( id == CSS_VAL_AUTO || id == CSS_VAL_FIXED )
00961 valid_primitive = true;
00962 break;
00963
00964 case CSS_PROP__KHTML_FLOW_MODE:
00965 if ( id == CSS_VAL__KHTML_NORMAL || id == CSS_VAL__KHTML_AROUND_FLOATS )
00966 valid_primitive = true;
00967 break;
00968
00969 case CSS_PROP__KHTML_USER_INPUT:
00970 if ( id == CSS_VAL_NONE || id == CSS_VAL_ENABLED || id == CSS_VAL_DISABLED )
00971 valid_primitive = true;
00972
00973 break;
00974
00975
00976 case CSS_PROP_BACKGROUND:
00977
00978
00979 {
00980 const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
00981 CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,
00982 CSS_PROP_BACKGROUND_COLOR };
00983 return parseShortHand(properties, 5, important);
00984 }
00985 case CSS_PROP_BORDER:
00986
00987 {
00988 const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
00989 CSS_PROP_BORDER_COLOR };
00990 return parseShortHand(properties, 3, important);
00991 }
00992 case CSS_PROP_BORDER_TOP:
00993
00994 {
00995 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
00996 CSS_PROP_BORDER_TOP_COLOR};
00997 return parseShortHand(properties, 3, important);
00998 }
00999 case CSS_PROP_BORDER_RIGHT:
01000
01001 {
01002 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
01003 CSS_PROP_BORDER_RIGHT_COLOR };
01004 return parseShortHand(properties, 3, important);
01005 }
01006 case CSS_PROP_BORDER_BOTTOM:
01007
01008 {
01009 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
01010 CSS_PROP_BORDER_BOTTOM_COLOR };
01011 return parseShortHand(properties, 3, important);
01012 }
01013 case CSS_PROP_BORDER_LEFT:
01014
01015 {
01016 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
01017 CSS_PROP_BORDER_LEFT_COLOR };
01018 return parseShortHand(properties, 3, important);
01019 }
01020 case CSS_PROP_OUTLINE:
01021
01022 {
01023 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
01024 CSS_PROP_OUTLINE_COLOR };
01025 return parseShortHand(properties, 3, important);
01026 }
01027 case CSS_PROP_BORDER_COLOR:
01028
01029 {
01030 if ( id == CSS_VAL_TRANSPARENT ) {
01031
01032 valid_primitive = true;
01033 break;
01034 }
01035 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
01036 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
01037 return parse4Values(properties, important);
01038 }
01039 case CSS_PROP_BORDER_WIDTH:
01040
01041 {
01042 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
01043 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
01044 return parse4Values(properties, important);
01045 }
01046 case CSS_PROP_BORDER_STYLE:
01047
01048 {
01049 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
01050 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
01051 return parse4Values(properties, important);
01052 }
01053 case CSS_PROP_MARGIN:
01054
01055 {
01056 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
01057 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
01058 return parse4Values(properties, important);
01059 }
01060 case CSS_PROP_PADDING:
01061
01062 {
01063 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
01064 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
01065 return parse4Values(properties, important);
01066 }
01067 case CSS_PROP_FONT:
01068
01069
01070 if ( id >= CSS_VAL_CAPTION && id <= CSS_VAL_STATUS_BAR )
01071 valid_primitive = true;
01072 else
01073 return parseFont(important);
01074
01075 case CSS_PROP_LIST_STYLE:
01076 {
01077 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
01078 CSS_PROP_LIST_STYLE_IMAGE };
01079 return parseShortHand(properties, 3, important);
01080 }
01081 default:
01082
01083
01084
01085 break;
01086 }
01087
01088 if ( valid_primitive ) {
01089 if ( id != 0 ) {
01090
01091 parsedValue = new CSSPrimitiveValueImpl( id );
01092 } else if ( value->unit == CSSPrimitiveValue::CSS_STRING )
01093 parsedValue = new CSSPrimitiveValueImpl( domString( value->string ),
01094 (CSSPrimitiveValue::UnitTypes) value->unit );
01095 else if ( value->unit >= CSSPrimitiveValue::CSS_NUMBER &&
01096 value->unit <= CSSPrimitiveValue::CSS_KHZ ) {
01097
01098 parsedValue = new CSSPrimitiveValueImpl( value->fValue,
01099 (CSSPrimitiveValue::UnitTypes) value->unit );
01100 } else if ( value->unit >= Value::Q_EMS ) {
01101
01102 parsedValue = new CSSQuirkPrimitiveValueImpl( value->fValue, CSSPrimitiveValue::CSS_EMS );
01103 }
01104 valueList->next();
01105 }
01106 if ( parsedValue ) {
01107 addProperty( propId, parsedValue, important );
01108 return true;
01109 }
01110 return false;
01111 }
01112
01113 bool CSSParser::parseShortHand( const int *properties, int numProperties, bool important )
01114 {
01115
01116
01117
01118
01119 inParseShortHand = true;
01120
01121 bool found = false;
01122 bool fnd[6];
01123 for( int i = 0; i < numProperties; i++ )
01124 fnd[i] = false;
01125
01126 #ifdef CSS_DEBUG
01127 kdDebug(6080) << "PSH: numProperties=" << numProperties << endl;
01128 #endif
01129
01130 while ( valueList->current() ) {
01131 found = false;
01132
01133 for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
01134 if (!fnd[propIndex]) {
01135 #ifdef CSS_DEBUG
01136 kdDebug(6080) << "LOOKING FOR: " << getPropertyName(properties[propIndex]).string() << endl;
01137 #endif
01138 if ( parseValue( properties[propIndex], important ) ) {
01139 fnd[propIndex] = found = true;
01140 #ifdef CSS_DEBUG
01141 kdDebug(6080) << "FOUND: " << getPropertyName(properties[propIndex]).string() << endl;
01142 #endif
01143 }
01144 }
01145 }
01146
01147
01148 if (!found) {
01149 #ifdef CSS_DEBUG
01150 qDebug("didn't find anything" );
01151 #endif
01152 inParseShortHand = false;
01153 return false;
01154 }
01155 }
01156
01157
01158 for (int i = 0; i < numProperties; ++i) {
01159 if (!fnd[i])
01160 addProperty(properties[i], new CSSInitialValueImpl(), important);
01161 }
01162
01163 inParseShortHand = false;
01164 #ifdef CSS_DEBUG
01165 kdDebug( 6080 ) << "parsed shorthand" << endl;
01166 #endif
01167 return true;
01168 }
01169
01170 bool CSSParser::parse4Values( const int *properties, bool important )
01171 {
01172
01173
01174
01175
01176
01177
01178
01179
01180 int num = inParseShortHand ? 1 : valueList->numValues;
01181
01182
01183
01184 switch( num ) {
01185 case 1: {
01186 if( !parseValue( properties[0], important ) ) return false;
01187 CSSValueImpl *value = parsedProperties[numParsedProperties-1]->value();
01188 addProperty( properties[1], value, important );
01189 addProperty( properties[2], value, important );
01190 addProperty( properties[3], value, important );
01191 return true;
01192 }
01193 case 2: {
01194
01195 if( !parseValue( properties[0], important ) ) return false;
01196 if( !parseValue( properties[1], important ) ) return false;
01197 CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
01198 addProperty( properties[2], value, important );
01199 value = parsedProperties[numParsedProperties-2]->value();
01200 addProperty( properties[3], value, important );
01201 return true;
01202 }
01203 case 3: {
01204 if( !parseValue( properties[0], important ) ) return false;
01205 if( !parseValue( properties[1], important ) ) return false;
01206 if( !parseValue( properties[2], important ) ) return false;
01207 CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
01208 addProperty( properties[3], value, important );
01209 return true;
01210 }
01211 case 4: {
01212 if( !parseValue( properties[0], important ) ) return false;
01213 if( !parseValue( properties[1], important ) ) return false;
01214 if( !parseValue( properties[2], important ) ) return false;
01215 if( !parseValue( properties[3], important ) ) return false;
01216 return true;
01217 }
01218 default:
01219 return false;
01220 }
01221 }
01222
01223
01224
01225
01226 bool CSSParser::parseContent( int propId, bool important )
01227 {
01228 CSSValueListImpl* values = new CSSValueListImpl();
01229
01230 Value *val;
01231 CSSValueImpl *parsedValue = 0;
01232 while ( (val = valueList->current()) ) {
01233 if ( val->unit == CSSPrimitiveValue::CSS_URI ) {
01234
01235 DOMString value = khtml::parseURL(domString(val->string));
01236 parsedValue = new CSSImageValueImpl(
01237 DOMString(KURL( styleElement->baseURL(), value.string()).url() ), styleElement );
01238 #ifdef CSS_DEBUG
01239 kdDebug( 6080 ) << "content, url=" << value.string() << " base=" << styleElement->baseURL().url( ) << endl;
01240 #endif
01241 } else if ( val->unit == Value::Function ) {
01242
01243 ValueList *args = val->function->args;
01244 QString fname = qString( val->function->name ).lower();
01245 if ( fname != "attr(" || !args )
01246 return false;
01247 if ( args->numValues != 1)
01248 return false;
01249 Value *a = args->current();
01250 parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR);
01251 } else if ( val->unit == CSSPrimitiveValue::CSS_IDENT ) {
01252
01253
01254
01255
01256 } else if ( val->unit == CSSPrimitiveValue::CSS_STRING ) {
01257 parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING);
01258 }
01259 if (parsedValue)
01260 values->append(parsedValue);
01261 else
01262 break;
01263 valueList->next();
01264 }
01265 if ( values->length() ) {
01266 addProperty( propId, values, important );
01267 valueList->next();
01268 return true;
01269 }
01270 delete values;
01271 return false;
01272 }
01273
01274 bool CSSParser::parseShape( int propId, bool important )
01275 {
01276 Value *value = valueList->current();
01277 ValueList *args = value->function->args;
01278 QString fname = qString( value->function->name ).lower();
01279
01280 if ( fname != "rect(" || !args )
01281 return false;
01282
01283
01284 if ( args->numValues != 4 && args->numValues != 7 )
01285 return false;
01286 RectImpl *rect = new RectImpl();
01287 bool valid = true;
01288 int i = 0;
01289 Value *a = args->current();
01290 while ( a ) {
01291 valid = validUnit( a, FLength, strict );
01292 if ( !valid )
01293 break;
01294 CSSPrimitiveValueImpl *length =
01295 new CSSPrimitiveValueImpl( a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit );
01296 if ( i == 0 )
01297 rect->setTop( length );
01298 else if ( i == 1 )
01299 rect->setRight( length );
01300 else if ( i == 2 )
01301 rect->setBottom( length );
01302 else
01303 rect->setLeft( length );
01304 a = args->next();
01305 if ( a && args->numValues == 7 ) {
01306 if ( a->unit == Value::Operator && a->iValue == ',' ) {
01307 a = args->next();
01308 } else {
01309 valid = false;
01310 break;
01311 }
01312 }
01313 i++;
01314 }
01315 if ( valid ) {
01316 addProperty( propId, new CSSPrimitiveValueImpl( rect ), important );
01317 valueList->next();
01318 return true;
01319 }
01320 delete rect;
01321 return false;
01322 }
01323
01324
01325 bool CSSParser::parseFont( bool important )
01326 {
01327
01328 bool valid = true;
01329 Value *value = valueList->current();
01330 FontValueImpl *font = new FontValueImpl;
01331
01332 while ( value ) {
01333
01334
01335
01336 int id = value->id;
01337 if ( id ) {
01338 if ( id == CSS_VAL_NORMAL ) {
01339
01340 }
01341
01342
01343
01344
01345
01346
01347
01348 else if ( id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE ) {
01349 if ( font->style )
01350 goto invalid;
01351 font->style = new CSSPrimitiveValueImpl( id );
01352 } else if ( id == CSS_VAL_SMALL_CAPS ) {
01353 if ( font->variant )
01354 goto invalid;
01355 font->variant = new CSSPrimitiveValueImpl( id );
01356 } else if ( id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER ) {
01357 if ( font->weight )
01358 goto invalid;
01359 font->weight = new CSSPrimitiveValueImpl( id );
01360 } else {
01361 valid = false;
01362 }
01363 } else if ( !font->weight && validUnit( value, FInteger|FNonNeg, true ) ) {
01364 int weight = (int)value->fValue;
01365 int val = 0;
01366 if ( weight == 100 )
01367 val = CSS_VAL_100;
01368 else if ( weight == 200 )
01369 val = CSS_VAL_200;
01370 else if ( weight == 300 )
01371 val = CSS_VAL_300;
01372 else if ( weight == 400 )
01373 val = CSS_VAL_400;
01374 else if ( weight == 500 )
01375 val = CSS_VAL_500;
01376 else if ( weight == 600 )
01377 val = CSS_VAL_600;
01378 else if ( weight == 700 )
01379 val = CSS_VAL_700;
01380 else if ( weight == 800 )
01381 val = CSS_VAL_800;
01382 else if ( weight == 900 )
01383 val = CSS_VAL_900;
01384
01385 if ( val )
01386 font->weight = new CSSPrimitiveValueImpl( val );
01387 else
01388 valid = false;
01389 } else {
01390 valid = false;
01391 }
01392 if ( !valid )
01393 break;
01394 value = valueList->next();
01395 }
01396 if ( !value )
01397 goto invalid;
01398
01399
01400 if ( !font->style )
01401 font->style = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01402 if ( !font->variant )
01403 font->variant = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01404 if ( !font->weight )
01405 font->weight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01406
01407
01408
01409
01410
01411 if ( value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER )
01412 font->size = new CSSPrimitiveValueImpl( value->id );
01413 else if ( validUnit( value, FLength|FPercent, strict ) ) {
01414 font->size = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01415 }
01416 value = valueList->next();
01417 if ( !font->size || !value )
01418 goto invalid;
01419
01420
01421
01422 if ( value->unit == Value::Operator && value->iValue == '/' ) {
01423
01424 value = valueList->next();
01425 if ( !value )
01426 goto invalid;
01427 if ( value->id == CSS_VAL_NORMAL ) {
01428
01429 } else if ( validUnit( value, FNumber|FLength|FPercent, strict ) ) {
01430 font->lineHeight = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01431 } else {
01432 goto invalid;
01433 }
01434 value = valueList->next();
01435 if ( !value )
01436 goto invalid;
01437 }
01438 if ( !font->lineHeight )
01439 font->lineHeight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01440
01441
01442
01443 font->family = parseFontFamily();
01444
01445 if ( valueList->current() || !font->family )
01446 goto invalid;
01447
01448
01449 addProperty( CSS_PROP_FONT, font, important );
01450 return true;
01451
01452 invalid:
01453
01454 delete font;
01455 return false;
01456 }
01457
01458 CSSValueListImpl *CSSParser::parseFontFamily()
01459 {
01460
01461 CSSValueListImpl *list = new CSSValueListImpl;
01462 Value *value = valueList->current();
01463 QString currFace;
01464
01465 while ( value ) {
01466
01467
01468
01469
01470 Value* nextValue = valueList->next();
01471 bool nextValBreaksFont = !nextValue ||
01472 (nextValue->unit == Value::Operator && nextValue->iValue == ',');
01473 bool nextValIsFontName = nextValue &&
01474 ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL_MONOSPACE) ||
01475 (nextValue->unit == CSSPrimitiveValue::CSS_STRING ||
01476 nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
01477
01478 if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL_MONOSPACE) {
01479 if (!currFace.isNull()) {
01480 currFace += ' ';
01481 currFace += qString(value->string);
01482 }
01483 else if (nextValBreaksFont || !nextValIsFontName) {
01484 if ( !currFace.isNull() ) {
01485 list->append( new FontFamilyValueImpl( currFace ) );
01486 currFace = QString::null;
01487 }
01488 list->append(new CSSPrimitiveValueImpl(value->id));
01489 }
01490 else {
01491 currFace = qString( value->string );
01492 }
01493 }
01494 else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
01495
01496 currFace = QString::null;
01497 list->append(new FontFamilyValueImpl(qString( value->string) ) );
01498 }
01499 else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
01500 if (!currFace.isNull()) {
01501 currFace += ' ';
01502 currFace += qString(value->string);
01503 }
01504 else if (nextValBreaksFont || !nextValIsFontName) {
01505 if ( !currFace.isNull() ) {
01506 list->append( new FontFamilyValueImpl( currFace ) );
01507 currFace = QString::null;
01508 }
01509 list->append(new FontFamilyValueImpl( qString( value->string ) ) );
01510 }
01511 else {
01512 currFace = qString( value->string);
01513 }
01514 }
01515 else {
01516
01517 break;
01518 }
01519
01520 if (!nextValue)
01521 break;
01522
01523 if (nextValBreaksFont) {
01524 value = valueList->next();
01525 if ( !currFace.isNull() )
01526 list->append( new FontFamilyValueImpl( currFace ) );
01527 currFace = QString::null;
01528 }
01529 else if (nextValIsFontName)
01530 value = nextValue;
01531 else
01532 break;
01533 }
01534
01535 if ( !currFace.isNull() )
01536 list->append( new FontFamilyValueImpl( currFace ) );
01537
01538 if ( !list->length() ) {
01539 delete list;
01540 list = 0;
01541 }
01542 return list;
01543 }
01544
01545
01546 static bool parseColor(const QString &name, QRgb& rgb)
01547 {
01548 int len = name.length();
01549
01550 if ( !len )
01551 return false;
01552
01553
01554 bool ok;
01555
01556 if ( len == 3 || len == 6 ) {
01557 int val = name.toInt(&ok, 16);
01558 if ( ok ) {
01559 if (len == 6) {
01560 rgb = (0xff << 24) | val;
01561 return true;
01562 }
01563 else if ( len == 3 ) {
01564
01565 rgb = (0xff << 24) |
01566 (val&0xf00)<<12 | (val&0xf00)<<8 |
01567 (val&0xf0)<<8 | (val&0xf0)<<4 |
01568 (val&0xf)<<4 | (val&0xf);
01569 return true;
01570 }
01571 }
01572 }
01573
01574
01575 QColor tc;
01576 tc.setNamedColor(name.lower());
01577 if ( tc.isValid() ) {
01578 rgb = tc.rgb();
01579 return true;
01580 }
01581
01582 return false;
01583 }
01584
01585
01586 CSSPrimitiveValueImpl *CSSParser::parseColor()
01587 {
01588 QRgb c = khtml::transparentColor;
01589 Value *value = valueList->current();
01590 if ( !strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
01591 value->fValue >= 0. && value->fValue < 1000000. ) {
01592 QString str;
01593 str.sprintf( "%06d", (int)(value->fValue+.5) );
01594 if ( !::parseColor( str, c ) )
01595 return 0;
01596 } else if ( value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
01597 value->unit == CSSPrimitiveValue::CSS_IDENT ||
01598 (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION) ) {
01599 if ( !::parseColor( qString( value->string ), c) )
01600 return 0;
01601 }
01602 else if ( value->unit == Value::Function &&
01603 value->function->args != 0 &&
01604 value->function->args->numValues == 5 &&
01605 qString( value->function->name ).lower() == "rgb(" ) {
01606 ValueList *args = value->function->args;
01607 Value *v = args->current();
01608 if ( !validUnit( v, FInteger|FPercent, true ) )
01609 return 0;
01610 int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01611 v = args->next();
01612 if ( v->unit != Value::Operator && v->iValue != ',' )
01613 return 0;
01614 v = args->next();
01615 if ( !validUnit( v, FInteger|FPercent, true ) )
01616 return 0;
01617 int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01618 v = args->next();
01619 if ( v->unit != Value::Operator && v->iValue != ',' )
01620 return 0;
01621 v = args->next();
01622 if ( !validUnit( v, FInteger|FPercent, true ) )
01623 return 0;
01624 int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01625 r = kMax( 0, kMin( 255, r ) );
01626 g = kMax( 0, kMin( 255, g ) );
01627 b = kMax( 0, kMin( 255, b ) );
01628 c = qRgb( r, g, b );
01629 }
01630 else if ( value->unit == Value::Function &&
01631 value->function->args != 0 &&
01632 value->function->args->numValues == 7 &&
01633 qString( value->function->name ).lower() == "rgba(" ) {
01634 ValueList *args = value->function->args;
01635 Value *v = args->current();
01636 if ( !validUnit( v, FInteger|FPercent, true ) )
01637 return 0;
01638 int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01639 v = args->next();
01640 if ( v->unit != Value::Operator && v->iValue != ',' )
01641 return 0;
01642 v = args->next();
01643 if ( !validUnit( v, FInteger|FPercent, true ) )
01644 return 0;
01645 int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01646 v = args->next();
01647 if ( v->unit != Value::Operator && v->iValue != ',' )
01648 return 0;
01649 v = args->next();
01650 if ( !validUnit( v, FInteger|FPercent, true ) )
01651 return 0;
01652 int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
01653 v = args->next();
01654 if ( v->unit != Value::Operator && v->iValue != ',' )
01655 return 0;
01656 v = args->next();
01657 if ( !validUnit( v, FNumber, true ) )
01658 return 0;
01659 r = QMAX( 0, QMIN( 255, r ) );
01660 g = QMAX( 0, QMIN( 255, g ) );
01661 b = QMAX( 0, QMIN( 255, b ) );
01662 int a = (int)(QMAX( 0, QMIN( 1.0f, v->fValue ) ) * 255);
01663 c = qRgba( r, g, b, a );
01664 }
01665 else
01666 return 0;
01667
01668 return new CSSPrimitiveValueImpl(c);
01669 }
01670
01671
01672 static inline int yyerror( const char *str ) {
01673
01674 #ifdef CSS_DEBUG
01675 kdDebug( 6080 ) << "CSS parse error " << str << endl;
01676 #else
01677 Q_UNUSED( str );
01678 #endif
01679 return 1;
01680 }
01681
01682 #define END 0
01683
01684 #include "parser.h"
01685
01686 int DOM::CSSParser::lex( void *_yylval )
01687 {
01688 YYSTYPE *yylval = (YYSTYPE *)_yylval;
01689 int token = lex();
01690 int length;
01691 unsigned short *t = text( &length );
01692
01693 #ifdef TOKEN_DEBUG
01694 qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString( (QChar *)t, length ).latin1() );
01695 #endif
01696 switch( token ) {
01697 case '{':
01698 block_nesting++;
01699 break;
01700 case '}':
01701 if ( block_nesting )
01702 block_nesting--;
01703 break;
01704 case END:
01705 if ( block_nesting ) {
01706 block_nesting--;
01707 return '}';
01708 }
01709 break;
01710 case S:
01711 case SGML_CD:
01712 case INCLUDES:
01713 case DASHMATCH:
01714 break;
01715
01716 case URI:
01717 case STRING:
01718 case IDENT:
01719 case HASH:
01720 case DIMEN:
01721 case UNICODERANGE:
01722 case FUNCTION:
01723 yylval->string.string = t;
01724 yylval->string.length = length;
01725 break;
01726
01727 case IMPORT_SYM:
01728 case PAGE_SYM:
01729 case MEDIA_SYM:
01730 case FONT_FACE_SYM:
01731 case CHARSET_SYM:
01732
01733 case IMPORTANT_SYM:
01734 break;
01735
01736 case QEMS:
01737 length--;
01738 case GRADS:
01739 length--;
01740 case DEGS:
01741 case RADS:
01742 case KHERZ:
01743 length--;
01744 case MSECS:
01745 case HERZ:
01746 case EMS:
01747 case EXS:
01748 case PXS:
01749 case CMS:
01750 case MMS:
01751 case INS:
01752 case PTS:
01753 case PCS:
01754 length--;
01755 case SECS:
01756 case PERCENTAGE:
01757 length--;
01758 case NUMBER:
01759 yylval->val = QString( (QChar *)t, length ).toDouble();
01760
01761 break;
01762
01763 default:
01764 break;
01765 }
01766
01767 return token;
01768 }
01769
01770 static inline int toHex( char c ) {
01771 if ( '0' <= c && c <= '9' )
01772 return c - '0';
01773 if ( 'a' <= c && c <= 'f' )
01774 return c - 'a' + 10;
01775 if ( 'A' <= c && c<= 'F' )
01776 return c - 'A' + 10;
01777 return 0;
01778 }
01779
01780 unsigned short *DOM::CSSParser::text(int *length)
01781 {
01782 unsigned short *start = yytext;
01783 int l = yyleng;
01784 switch( yyTok ) {
01785 case STRING:
01786 l--;
01787
01788 case HASH:
01789 start++;
01790 l--;
01791 break;
01792 case URI:
01793
01794
01795
01796
01797 start += 4;
01798 l -= 5;
01799
01800 while ( l &&
01801 (*start == ' ' || *start == '\t' || *start == '\r' ||
01802 *start == '\n' || *start == '\f' ) ) {
01803 start++; l--;
01804 }
01805 if ( *start == '"' || *start == '\'' ) {
01806 start++; l--;
01807 }
01808 while ( l &&
01809 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
01810 start[l-1] == '\n' || start[l-1] == '\f' ) ) {
01811 l--;
01812 }
01813 if ( l && (start[l-1] == '\"' || start[l-1] == '\'' ) )
01814 l--;
01815
01816 default:
01817 break;
01818 }
01819
01820
01821 unsigned short *out = start;
01822 unsigned short *escape = 0;
01823
01824 for ( int i = 0; i < l; i++ ) {
01825 unsigned short *current = start+i;
01826 if ( escape == current - 1 ) {
01827 if ( ( *current >= '0' && *current <= '9' ) ||
01828 ( *current >= 'a' && *current <= 'f' ) ||
01829 ( *current >= 'A' && *current <= 'F' ) )
01830 continue;
01831 if ( yyTok == STRING &&
01832 ( *current == '\n' || *current == '\r' || *current == '\f' ) ) {
01833
01834 if ( *current != '\r' )
01835 escape = 0;
01836 continue;
01837 }
01838
01839
01840 *out++ = *current;
01841 escape = 0;
01842 continue;
01843 }
01844 if ( escape == current - 2 && yyTok == STRING &&
01845 *(current-1) == '\r' && *current == '\n' ) {
01846 escape = 0;
01847 continue;
01848 }
01849 if ( escape > current - 7 &&
01850 ( ( *current >= '0' && *current <= '9' ) ||
01851 ( *current >= 'a' && *current <= 'f' ) ||
01852 ( *current >= 'A' && *current <= 'F' ) ) )
01853 continue;
01854 if ( escape ) {
01855
01856 int uc = 0;
01857 escape++;
01858 while ( escape < current ) {
01859
01860 uc *= 16;
01861 uc += toHex( *escape );
01862 escape++;
01863 }
01864
01865
01866 if ( uc > 0xffff )
01867 uc = 0xfffd;
01868 *(out++) = (unsigned short)uc;
01869 escape = 0;
01870 if ( *current == ' ' ||
01871 *current == '\t' ||
01872 *current == '\r' ||
01873 *current == '\n' ||
01874 *current == '\f' )
01875 continue;
01876 }
01877 if ( !escape && *current == '\\' ) {
01878 escape = current;
01879 continue;
01880 }
01881 *(out++) = *current;
01882 }
01883 if ( escape ) {
01884
01885 int uc = 0;
01886 escape++;
01887 while ( escape < start+l ) {
01888
01889 uc *= 16;
01890 uc += toHex( *escape );
01891 escape++;
01892 }
01893
01894
01895 if ( uc > 0xffff )
01896 uc = 0xfffd;
01897 *(out++) = (unsigned short)uc;
01898 }
01899
01900 *length = out - start;
01901 return start;
01902 }
01903
01904
01905 #define YY_DECL int DOM::CSSParser::lex()
01906 #define yyconst const
01907 typedef int yy_state_type;
01908 typedef unsigned int YY_CHAR;
01909
01910 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
01911 #define YY_DO_BEFORE_ACTION \
01912 yytext = yy_bp; \
01913 yyleng = (int) (yy_cp - yy_bp); \
01914 yy_hold_char = *yy_cp; \
01915 *yy_cp = 0; \
01916 yy_c_buf_p = yy_cp;
01917 #define YY_BREAK break;
01918 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).latin1() )
01919 #define YY_RULE_SETUP
01920 #define INITIAL 0
01921 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
01922 #define YY_START ((yy_start - 1) / 2)
01923 #define yyterminate() yyTok = END; return yyTok
01924 #define YY_FATAL_ERROR(a) qFatal(a)
01925 #define BEGIN yy_start = 1 + 2 *
01926 #define COMMENT 1
01927
01928 #include "tokenizer.cpp"