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