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 parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR);
01342 }
01343 else
01344 if (fname == "counter(") {
01345 parsedValue = parseCounterContent(args, false);
01346 if (!parsedValue) return false;
01347 } else
01348 if (fname == "counters(") {
01349 parsedValue = parseCounterContent(args, true);
01350 if (!parsedValue) return false;
01351 }
01352 else
01353 return false;
01354
01355 } else if ( val->unit == CSSPrimitiveValue::CSS_IDENT ) {
01356
01357 if ( val->id == CSS_VAL_OPEN_QUOTE ||
01358 val->id == CSS_VAL_CLOSE_QUOTE ||
01359 val->id == CSS_VAL_NO_OPEN_QUOTE ||
01360 val->id == CSS_VAL_NO_CLOSE_QUOTE ) {
01361 parsedValue = new CSSPrimitiveValueImpl(val->id);
01362 }
01363 } else if ( val->unit == CSSPrimitiveValue::CSS_STRING ) {
01364 parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING);
01365 }
01366
01367 if (parsedValue)
01368 values->append(parsedValue);
01369 else {
01370 isValid = false;
01371 break;
01372 }
01373 valueList->next();
01374 }
01375 if ( isValid && values->length() ) {
01376 addProperty( propId, values, important );
01377 valueList->next();
01378 return true;
01379 }
01380
01381 delete values;
01382 return false;
01383 }
01384
01385 CSSValueImpl* CSSParser::parseCounterContent(ValueList *args, bool counters)
01386 {
01387 if (counters || (args->size() != 1 && args->size() != 3))
01388 if (!counters || (args->size() != 3 && args->size() != 5))
01389 return 0;
01390
01391 CounterImpl *counter = new CounterImpl;
01392 Value *i = args->current();
01393
01394 counter->m_identifier = domString(i->string);
01395 if (counters) {
01396 i = args->next();
01397 if (i->unit != Value::Operator || i->iValue != ',') goto invalid;
01398 i = args->next();
01399 if (i->unit != CSSPrimitiveValue::CSS_STRING) goto invalid;
01400 counter->m_separator = domString(i->string);
01401 }
01402 counter->m_listStyle = CSS_VAL_DECIMAL - CSS_VAL_DISC;
01403 i = args->next();
01404 if (i) {
01405 if (i->unit != Value::Operator || i->iValue != ',') goto invalid;
01406 i = args->next();
01407 if (i->unit != CSSPrimitiveValue::CSS_IDENT) goto invalid;
01408 if (i->id < CSS_VAL_DISC || i->id > CSS_VAL__KHTML_CLOSE_QUOTE) goto invalid;
01409 counter->m_listStyle = i->id - CSS_VAL_DISC;
01410 }
01411 return new CSSPrimitiveValueImpl(counter);
01412 invalid:
01413 delete counter;
01414 return 0;
01415 }
01416
01417 CSSValueImpl* CSSParser::parseBackgroundColor()
01418 {
01419 int id = valueList->current()->id;
01420 if (id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_TRANSPARENT ||
01421 (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || id == CSS_VAL_MENU ||
01422 (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict))
01423 return new CSSPrimitiveValueImpl(id);
01424 return parseColor();
01425 }
01426
01427 CSSValueImpl* CSSParser::parseBackgroundImage()
01428 {
01429 if (valueList->current()->id == CSS_VAL_NONE)
01430 return new CSSImageValueImpl();
01431 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
01432 DOMString uri = khtml::parseURL(domString(valueList->current()->string));
01433 if (!uri.isEmpty())
01434 return new CSSImageValueImpl(DOMString(KURL(styleElement->baseURL(), uri.string()).url()),
01435 styleElement);
01436 }
01437 return 0;
01438 }
01439
01440 CSSValueImpl* CSSParser::parseBackgroundPositionXY(bool& xFound, bool& yFound)
01441 {
01442 int id = valueList->current()->id;
01443 if (id == CSS_VAL_LEFT || id == CSS_VAL_TOP || id == CSS_VAL_RIGHT || id == CSS_VAL_BOTTOM || id == CSS_VAL_CENTER) {
01444 int percent = 0;
01445 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT) {
01446 if (xFound)
01447 return 0;
01448 xFound = true;
01449 if (id == CSS_VAL_RIGHT)
01450 percent = 100;
01451 }
01452 else if (id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
01453 if (yFound)
01454 return 0;
01455 yFound = true;
01456 if (id == CSS_VAL_BOTTOM)
01457 percent = 100;
01458 }
01459 else if (id == CSS_VAL_CENTER)
01460
01461 percent = 50;
01462 return new CSSPrimitiveValueImpl(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
01463 }
01464 if (validUnit(valueList->current(), FPercent|FLength, strict))
01465 return new CSSPrimitiveValueImpl(valueList->current()->fValue,
01466 (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
01467
01468 return 0;
01469 }
01470
01471 void CSSParser::parseBackgroundPosition(CSSValueImpl*& value1, CSSValueImpl*& value2)
01472 {
01473 value1 = value2 = 0;
01474 Value* value = valueList->current();
01475
01476
01477 bool value1IsX = false, value1IsY = false;
01478 value1 = parseBackgroundPositionXY(value1IsX, value1IsY);
01479 if (!value1)
01480 return;
01481
01482
01483
01484
01485 value = valueList->next();
01486
01487
01488 if (value && value->unit == Value::Operator && value->iValue == ',')
01489 value = 0;
01490
01491 bool value2IsX = false, value2IsY = false;
01492 if (value) {
01493 value2 = parseBackgroundPositionXY(value2IsX, value2IsY);
01494 if (value2)
01495 valueList->next();
01496 else {
01497 if (!inShorthand()) {
01498 delete value1;
01499 value1 = 0;
01500 return;
01501 }
01502 }
01503 }
01504
01505 if (!value2)
01506
01507
01508
01509
01510 value2 = new CSSPrimitiveValueImpl(50, CSSPrimitiveValue::CSS_PERCENTAGE);
01511
01512 if (value1IsY || value2IsX) {
01513
01514 CSSValueImpl* val = value2;
01515 value2 = value1;
01516 value1 = val;
01517 }
01518 }
01519
01520 CSSValueImpl* CSSParser::parseBackgroundSize()
01521 {
01522 Value* value = valueList->current();
01523 CSSPrimitiveValueImpl* parsedValue1;
01524
01525 if (value->id == CSS_VAL_AUTO)
01526 parsedValue1 = new CSSPrimitiveValueImpl(0, CSSPrimitiveValue::CSS_UNKNOWN);
01527 else {
01528 if (!validUnit(value, FLength|FPercent, strict))
01529 return 0;
01530 parsedValue1 = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
01531 }
01532
01533 CSSPrimitiveValueImpl* parsedValue2 = parsedValue1;
01534 if ((value = valueList->next())) {
01535 if (value->id == CSS_VAL_AUTO)
01536 parsedValue2 = new CSSPrimitiveValueImpl(0, CSSPrimitiveValue::CSS_UNKNOWN);
01537 else {
01538 if (!validUnit(value, FLength|FPercent, strict)) {
01539 delete parsedValue1;
01540 return 0;
01541 }
01542 parsedValue2 = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
01543 }
01544 }
01545
01546 PairImpl* pair = new PairImpl(parsedValue1, parsedValue2);
01547 return new CSSPrimitiveValueImpl(pair);
01548 }
01549
01550 bool CSSParser::parseBackgroundProperty(int propId, int& propId1, int& propId2,
01551 CSSValueImpl*& retValue1, CSSValueImpl*& retValue2)
01552 {
01553 #ifdef CSS_DEBUG
01554 kdDebug(6080) << "parseBackgroundProperty()" << endl;
01555 kdDebug(6080) << "LOOKING FOR: " << getPropertyName(propId).string() << endl;
01556 #endif
01557 CSSValueListImpl *values = 0, *values2 = 0;
01558 Value* val;
01559 CSSValueImpl *value = 0, *value2 = 0;
01560 bool allowComma = false;
01561
01562 retValue1 = retValue2 = 0;
01563 propId1 = propId;
01564 propId2 = propId;
01565 if (propId == CSS_PROP_BACKGROUND_POSITION) {
01566 propId1 = CSS_PROP_BACKGROUND_POSITION_X;
01567 propId2 = CSS_PROP_BACKGROUND_POSITION_Y;
01568 }
01569
01570 while ((val = valueList->current())) {
01571 CSSValueImpl *currValue = 0, *currValue2 = 0;
01572 if (allowComma) {
01573 if (val->unit != Value::Operator || val->iValue != ',')
01574 goto failed;
01575 valueList->next();
01576 allowComma = false;
01577 }
01578 else {
01579 switch (propId) {
01580 case CSS_PROP_BACKGROUND_ATTACHMENT:
01581 if (val->id == CSS_VAL_SCROLL || val->id == CSS_VAL_FIXED) {
01582 currValue = new CSSPrimitiveValueImpl(val->id);
01583 valueList->next();
01584 }
01585 break;
01586 case CSS_PROP_BACKGROUND_COLOR:
01587 currValue = parseBackgroundColor();
01588 if (currValue)
01589 valueList->next();
01590 break;
01591 case CSS_PROP_BACKGROUND_IMAGE:
01592 currValue = parseBackgroundImage();
01593 if (currValue)
01594 valueList->next();
01595 break;
01596 case CSS_PROP__KHTML_BACKGROUND_CLIP:
01597 case CSS_PROP__KHTML_BACKGROUND_ORIGIN:
01598 if (val->id == CSS_VAL_BORDER || val->id == CSS_VAL_PADDING || val->id == CSS_VAL_CONTENT) {
01599 currValue = new CSSPrimitiveValueImpl(val->id);
01600 valueList->next();
01601 }
01602 break;
01603 case CSS_PROP_BACKGROUND_POSITION:
01604 parseBackgroundPosition(currValue, currValue2);
01605
01606 break;
01607 case CSS_PROP_BACKGROUND_POSITION_X: {
01608 bool xFound = false, yFound = true;
01609 currValue = parseBackgroundPositionXY(xFound, yFound);
01610 if (currValue)
01611 valueList->next();
01612 break;
01613 }
01614 case CSS_PROP_BACKGROUND_POSITION_Y: {
01615 bool xFound = true, yFound = false;
01616 currValue = parseBackgroundPositionXY(xFound, yFound);
01617 if (currValue)
01618 valueList->next();
01619 break;
01620 }
01621 case CSS_PROP_BACKGROUND_REPEAT:
01622 if (val->id >= CSS_VAL_REPEAT && val->id <= CSS_VAL_NO_REPEAT) {
01623 currValue = new CSSPrimitiveValueImpl(val->id);
01624 valueList->next();
01625 }
01626 break;
01627 case CSS_PROP__KHTML_BACKGROUND_SIZE:
01628 currValue = parseBackgroundSize();
01629 if (currValue)
01630 valueList->next();
01631 break;
01632 }
01633
01634 if (!currValue)
01635 goto failed;
01636
01637 if (value && !values) {
01638 values = new CSSValueListImpl();
01639 values->append(value);
01640 value = 0;
01641 }
01642
01643 if (value2 && !values2) {
01644 values2 = new CSSValueListImpl();
01645 values2->append(value2);
01646 value2 = 0;
01647 }
01648
01649 if (values)
01650 values->append(currValue);
01651 else
01652 value = currValue;
01653 if (currValue2) {
01654 if (values2)
01655 values2->append(currValue2);
01656 else
01657 value2 = currValue2;
01658 }
01659 allowComma = true;
01660 }
01661
01662
01663
01664 if (inShorthand())
01665 break;
01666 }
01667
01668 if (values && values->length()) {
01669 retValue1 = values;
01670 if (values2 && values2->length())
01671 retValue2 = values2;
01672 return true;
01673 }
01674 if (value) {
01675 retValue1 = value;
01676 retValue2 = value2;
01677 return true;
01678 }
01679
01680 failed:
01681 delete values; delete values2;
01682 delete value; delete value2;
01683 return false;
01684 }
01685
01686 bool CSSParser::parseShape( int propId, bool important )
01687 {
01688 Value *value = valueList->current();
01689 ValueList *args = value->function->args;
01690 QString fname = qString( value->function->name ).lower();
01691
01692 if ( fname != "rect(" || !args )
01693 return false;
01694
01695
01696 if ( args->size() != 4 && args->size() != 7 )
01697 return false;
01698 RectImpl *rect = new RectImpl();
01699 bool valid = true;
01700 int i = 0;
01701 Value *a = args->current();
01702 while ( a ) {
01703 valid = validUnit( a, FLength, strict );
01704 if ( !valid )
01705 break;
01706 CSSPrimitiveValueImpl *length =
01707 new CSSPrimitiveValueImpl( a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit );
01708 if ( i == 0 )
01709 rect->setTop( length );
01710 else if ( i == 1 )
01711 rect->setRight( length );
01712 else if ( i == 2 )
01713 rect->setBottom( length );
01714 else
01715 rect->setLeft( length );
01716 a = args->next();
01717 if ( a && args->size() == 7 ) {
01718 if ( a->unit == Value::Operator && a->iValue == ',' ) {
01719 a = args->next();
01720 } else {
01721 valid = false;
01722 break;
01723 }
01724 }
01725 i++;
01726 }
01727 if ( valid ) {
01728 addProperty( propId, new CSSPrimitiveValueImpl( rect ), important );
01729 valueList->next();
01730 return true;
01731 }
01732 delete rect;
01733 return false;
01734 }
01735
01736
01737 bool CSSParser::parseFont( bool important )
01738 {
01739
01740 bool valid = true;
01741 Value *value = valueList->current();
01742 FontValueImpl *font = new FontValueImpl;
01743
01744 while ( value ) {
01745
01746
01747
01748 int id = value->id;
01749 if ( id ) {
01750 if ( id == CSS_VAL_NORMAL ) {
01751
01752 }
01753
01754
01755
01756
01757
01758
01759
01760 else if ( id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE ) {
01761 if ( font->style )
01762 goto invalid;
01763 font->style = new CSSPrimitiveValueImpl( id );
01764 } else if ( id == CSS_VAL_SMALL_CAPS ) {
01765 if ( font->variant )
01766 goto invalid;
01767 font->variant = new CSSPrimitiveValueImpl( id );
01768 } else if ( id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER ) {
01769 if ( font->weight )
01770 goto invalid;
01771 font->weight = new CSSPrimitiveValueImpl( id );
01772 } else {
01773 valid = false;
01774 }
01775 } else if ( !font->weight && validUnit( value, FInteger|FNonNeg, true ) ) {
01776 int weight = (int)value->fValue;
01777 int val = 0;
01778 if ( weight == 100 )
01779 val = CSS_VAL_100;
01780 else if ( weight == 200 )
01781 val = CSS_VAL_200;
01782 else if ( weight == 300 )
01783 val = CSS_VAL_300;
01784 else if ( weight == 400 )
01785 val = CSS_VAL_400;
01786 else if ( weight == 500 )
01787 val = CSS_VAL_500;
01788 else if ( weight == 600 )
01789 val = CSS_VAL_600;
01790 else if ( weight == 700 )
01791 val = CSS_VAL_700;
01792 else if ( weight == 800 )
01793 val = CSS_VAL_800;
01794 else if ( weight == 900 )
01795 val = CSS_VAL_900;
01796
01797 if ( val )
01798 font->weight = new CSSPrimitiveValueImpl( val );
01799 else
01800 valid = false;
01801 } else {
01802 valid = false;
01803 }
01804 if ( !valid )
01805 break;
01806 value = valueList->next();
01807 }
01808 if ( !value )
01809 goto invalid;
01810
01811
01812 if ( !font->style )
01813 font->style = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01814 if ( !font->variant )
01815 font->variant = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01816 if ( !font->weight )
01817 font->weight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01818
01819
01820
01821
01822
01823 if ( value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER )
01824 font->size = new CSSPrimitiveValueImpl( value->id );
01825 else if ( validUnit( value, FLength|FPercent, strict ) ) {
01826 font->size = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01827 }
01828 value = valueList->next();
01829 if ( !font->size || !value )
01830 goto invalid;
01831
01832
01833
01834 if ( value->unit == Value::Operator && value->iValue == '/' ) {
01835
01836 value = valueList->next();
01837 if ( !value )
01838 goto invalid;
01839 if ( value->id == CSS_VAL_NORMAL ) {
01840
01841 } else if ( validUnit( value, FNumber|FLength|FPercent, strict ) ) {
01842 font->lineHeight = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
01843 } else {
01844 goto invalid;
01845 }
01846 value = valueList->next();
01847 if ( !value )
01848 goto invalid;
01849 }
01850 if ( !font->lineHeight )
01851 font->lineHeight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
01852
01853
01854
01855 font->family = parseFontFamily();
01856
01857 if ( valueList->current() || !font->family )
01858 goto invalid;
01859
01860
01861 addProperty( CSS_PROP_FONT, font, important );
01862 return true;
01863
01864 invalid:
01865
01866 delete font;
01867 return false;
01868 }
01869
01870 CSSValueListImpl *CSSParser::parseFontFamily()
01871 {
01872
01873 CSSValueListImpl *list = new CSSValueListImpl;
01874 Value *value = valueList->current();
01875 QString currFace;
01876
01877 while ( value ) {
01878
01879
01880
01881
01882 Value* nextValue = valueList->next();
01883 bool nextValBreaksFont = !nextValue ||
01884 (nextValue->unit == Value::Operator && nextValue->iValue == ',');
01885 bool nextValIsFontName = nextValue &&
01886 ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL_MONOSPACE) ||
01887 (nextValue->unit == CSSPrimitiveValue::CSS_STRING ||
01888 nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
01889
01890 if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL_MONOSPACE) {
01891 if (!currFace.isNull()) {
01892 currFace += ' ';
01893 currFace += qString(value->string);
01894 }
01895 else if (nextValBreaksFont || !nextValIsFontName) {
01896 if ( !currFace.isNull() ) {
01897 list->append( new FontFamilyValueImpl( currFace ) );
01898 currFace = QString::null;
01899 }
01900 list->append(new CSSPrimitiveValueImpl(value->id));
01901 }
01902 else {
01903 currFace = qString( value->string );
01904 }
01905 }
01906 else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
01907
01908 currFace = QString::null;
01909 list->append(new FontFamilyValueImpl(qString( value->string) ) );
01910 }
01911 else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
01912 if (!currFace.isNull()) {
01913 currFace += ' ';
01914 currFace += qString(value->string);
01915 }
01916 else if (nextValBreaksFont || !nextValIsFontName) {
01917 if ( !currFace.isNull() ) {
01918 list->append( new FontFamilyValueImpl( currFace ) );
01919 currFace = QString::null;
01920 }
01921 list->append(new FontFamilyValueImpl( qString( value->string ) ) );
01922 }
01923 else {
01924 currFace = qString( value->string);
01925 }
01926 }
01927 else {
01928
01929 break;
01930 }
01931
01932 if (!nextValue)
01933 break;
01934
01935 if (nextValBreaksFont) {
01936 value = valueList->next();
01937 if ( !currFace.isNull() )
01938 list->append( new FontFamilyValueImpl( currFace ) );
01939 currFace = QString::null;
01940 }
01941 else if (nextValIsFontName)
01942 value = nextValue;
01943 else
01944 break;
01945 }
01946
01947 if ( !currFace.isNull() )
01948 list->append( new FontFamilyValueImpl( currFace ) );
01949
01950 if ( !list->length() ) {
01951 delete list;
01952 list = 0;
01953 }
01954 return list;
01955 }
01956
01957
01958 bool CSSParser::parseColorParameters(Value* value, int* colorArray, bool parseAlpha)
01959 {
01960 ValueList* args = value->function->args;
01961 Value* v = args->current();
01962
01963 if (!validUnit(v, FInteger | FPercent, true))
01964 return false;
01965 colorArray[0] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
01966 for (int i = 1; i < 3; i++) {
01967 v = args->next();
01968 if (v->unit != Value::Operator && v->iValue != ',')
01969 return false;
01970 v = args->next();
01971 if (!validUnit(v, FInteger | FPercent, true))
01972 return false;
01973 colorArray[i] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
01974 }
01975 if (parseAlpha) {
01976 v = args->next();
01977 if (v->unit != Value::Operator && v->iValue != ',')
01978 return false;
01979 v = args->next();
01980 if (!validUnit(v, FNumber, true))
01981 return false;
01982 colorArray[3] = static_cast<int>(kMax(0.0, kMin(1.0, v->fValue)) * 255);
01983 }
01984 return true;
01985 }
01986
01987
01988
01989
01990
01991
01992 bool CSSParser::parseHSLParameters(Value* value, double* colorArray, bool parseAlpha)
01993 {
01994 ValueList* args = value->function->args;
01995 Value* v = args->current();
01996
01997 if (!validUnit(v, FInteger, true))
01998 return false;
01999
02000 colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
02001 for (int i = 1; i < 3; i++) {
02002 v = args->next();
02003 if (v->unit != Value::Operator && v->iValue != ',')
02004 return false;
02005 v = args->next();
02006 if (!validUnit(v, FPercent, true))
02007 return false;
02008 colorArray[i] = kMax(0.0, kMin(100.0, v->fValue)) / 100.0;
02009 }
02010 if (parseAlpha) {
02011 v = args->next();
02012 if (v->unit != Value::Operator && v->iValue != ',')
02013 return false;
02014 v = args->next();
02015 if (!validUnit(v, FNumber, true))
02016 return false;
02017 colorArray[3] = kMax(0.0, kMin(1.0, v->fValue));
02018 }
02019 return true;
02020 }
02021
02022 static bool parseColor(int unit, const QString &name, QRgb& rgb)
02023 {
02024 int len = name.length();
02025
02026 if ( !len )
02027 return false;
02028
02029
02030 bool ok;
02031
02032 if ( len == 3 || len == 6 ) {
02033 int val = name.toInt(&ok, 16);
02034 if ( ok ) {
02035 if (len == 6) {
02036 rgb = (0xff << 24) | val;
02037 return true;
02038 }
02039 else if ( len == 3 ) {
02040
02041 rgb = (0xff << 24) |
02042 (val&0xf00)<<12 | (val&0xf00)<<8 |
02043 (val&0xf0)<<8 | (val&0xf0)<<4 |
02044 (val&0xf)<<4 | (val&0xf);
02045 return true;
02046 }
02047 }
02048 }
02049
02050 if ( unit == CSSPrimitiveValue::CSS_IDENT ) {
02051
02052 QColor tc;
02053 tc.setNamedColor(name.lower());
02054 if ( tc.isValid() ) {
02055 rgb = tc.rgb();
02056 return true;
02057 }
02058 }
02059
02060 return false;
02061 }
02062
02063 CSSPrimitiveValueImpl *CSSParser::parseColor()
02064 {
02065 return parseColorFromValue(valueList->current());
02066 }
02067
02068 CSSPrimitiveValueImpl *CSSParser::parseColorFromValue(Value* value)
02069 {
02070 QRgb c = khtml::transparentColor;
02071 if ( !strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
02072 value->fValue >= 0. && value->fValue < 1000000. ) {
02073 QString str;
02074 str.sprintf( "%06d", (int)(value->fValue+.5) );
02075 if ( !::parseColor( value->unit, str, c ) )
02076 return 0;
02077 }
02078 else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
02079 value->unit == CSSPrimitiveValue::CSS_IDENT ||
02080 (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
02081 if ( !::parseColor( value->unit, qString( value->string ), c) )
02082 return 0;
02083 }
02084 else if ( value->unit == Value::Function &&
02085 value->function->args != 0 &&
02086 value->function->args->size() == 5 &&
02087 qString( value->function->name ).lower() == "rgb(" ) {
02088 int colorValues[3];
02089 if (!parseColorParameters(value, colorValues, false))
02090 return 0;
02091 colorValues[0] = kMax( 0, kMin( 255, colorValues[0] ) );
02092 colorValues[1] = kMax( 0, kMin( 255, colorValues[1] ) );
02093 colorValues[2] = kMax( 0, kMin( 255, colorValues[2] ) );
02094 c = qRgb(colorValues[0], colorValues[1], colorValues[2]);
02095 } else if (value->unit == Value::Function &&
02096 value->function->args != 0 &&
02097 value->function->args->size() == 7 &&
02098 domString(value->function->name).lower() == "rgba(") {
02099 int colorValues[4];
02100 if (!parseColorParameters(value, colorValues, true))
02101 return 0;
02102 colorValues[0] = kMax( 0, kMin( 255, colorValues[0] ) );
02103 colorValues[1] = kMax( 0, kMin( 255, colorValues[1] ) );
02104 colorValues[2] = kMax( 0, kMin( 255, colorValues[2] ) );
02105 c = qRgba(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
02106 } else if (value->unit == Value::Function &&
02107 value->function->args != 0 &&
02108 value->function->args->size() == 5 &&
02109 domString(value->function->name).lower() == "hsl(") {
02110 double colorValues[3];
02111 if (!parseHSLParameters(value, colorValues, false))
02112 return 0;
02113 c = khtml::qRgbaFromHsla(colorValues[0], colorValues[1], colorValues[2], 1.0);
02114 } else if (value->unit == Value::Function &&
02115 value->function->args != 0 &&
02116 value->function->args->size() == 7 &&
02117 domString(value->function->name).lower() == "hsla(") {
02118 double colorValues[4];
02119 if (!parseHSLParameters(value, colorValues, true))
02120 return 0;
02121 c = khtml::qRgbaFromHsla(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
02122 }
02123 else
02124 return 0;
02125
02126 return new CSSPrimitiveValueImpl(c);
02127 }
02128
02129
02130
02131 struct ShadowParseContext {
02132 ShadowParseContext()
02133 :values(0), x(0), y(0), blur(0), color(0),
02134 allowX(true), allowY(false), allowBlur(false), allowColor(true),
02135 allowBreak(true)
02136 {}
02137
02138 ~ShadowParseContext() {
02139 if (!allowBreak) {
02140 delete values;
02141 delete x;
02142 delete y;
02143 delete blur;
02144 delete color;
02145 }
02146 }
02147
02148 bool allowLength() { return allowX || allowY || allowBlur; }
02149
02150 bool failed() { return allowBreak = false; }
02151
02152 void commitValue() {
02153
02154 if (x || y || blur || color) {
02155 if (!values)
02156 values = new CSSValueListImpl();
02157
02158
02159 values->append(new ShadowValueImpl(x, y, blur, color));
02160 }
02161
02162
02163 x = y = blur = color = 0;
02164 allowX = allowColor = allowBreak = true;
02165 allowY = allowBlur = false;
02166 }
02167
02168 void commitLength(Value* v) {
02169 CSSPrimitiveValueImpl* val = new CSSPrimitiveValueImpl(v->fValue,
02170 (CSSPrimitiveValue::UnitTypes)v->unit);
02171 if (allowX) {
02172 x = val;
02173 allowX = false; allowY = true; allowColor = false; allowBreak = false;
02174 }
02175 else if (allowY) {
02176 y = val;
02177 allowY = false; allowBlur = true; allowColor = true; allowBreak = true;
02178 }
02179 else if (allowBlur) {
02180 blur = val;
02181 allowBlur = false;
02182 }
02183 else
02184 delete val;
02185 }
02186
02187 void commitColor(CSSPrimitiveValueImpl* val) {
02188 color = val;
02189 allowColor = false;
02190 if (allowX)
02191 allowBreak = false;
02192 else
02193 allowBlur = false;
02194 }
02195
02196 CSSValueListImpl* values;
02197 CSSPrimitiveValueImpl* x;
02198 CSSPrimitiveValueImpl* y;
02199 CSSPrimitiveValueImpl* blur;
02200 CSSPrimitiveValueImpl* color;
02201
02202 bool allowX;
02203 bool allowY;
02204 bool allowBlur;
02205 bool allowColor;
02206 bool allowBreak;
02207 };
02208
02209 bool CSSParser::parseShadow(int propId, bool important)
02210 {
02211 ShadowParseContext context;
02212 Value* val;
02213 while ((val = valueList->current())) {
02214
02215 if (val->unit == Value::Operator) {
02216 if (val->iValue != ',' || !context.allowBreak)
02217
02218
02219 return context.failed();
02220
02221
02222 context.commitValue();
02223 }
02224
02225 else if (validUnit(val, FLength, true)) {
02226
02227 if (!context.allowLength())
02228 return context.failed();
02229
02230
02231 context.commitLength(val);
02232 }
02233 else {
02234
02235 CSSPrimitiveValueImpl* parsedColor = 0;
02236 bool isColor = (val->id >= CSS_VAL_AQUA && val->id <= CSS_VAL_WINDOWTEXT || val->id == CSS_VAL_MENU ||
02237 (val->id >= CSS_VAL_GREY && val->id <= CSS_VAL__KHTML_TEXT && !strict));
02238 if (!context.allowColor)
02239 return context.failed();
02240
02241 if (isColor)
02242 parsedColor = new CSSPrimitiveValueImpl(val->id);
02243
02244 if (!parsedColor)
02245
02246 parsedColor = parseColorFromValue(val);
02247
02248 if (!parsedColor)
02249 return context.failed();
02250
02251 context.commitColor(parsedColor);
02252 }
02253
02254 valueList->next();
02255 }
02256
02257 if (context.allowBreak) {
02258 context.commitValue();
02259 if (context.values->length()) {
02260 addProperty(propId, context.values, important);
02261 valueList->next();
02262 return true;
02263 }
02264 }
02265
02266 return context.failed();
02267 }
02268
02269 bool CSSParser::parseCounter(int propId, bool increment, bool important)
02270 {
02271 enum { ID, VAL, COMMA } state = ID;
02272
02273 CSSValueListImpl *list = new CSSValueListImpl;
02274 DOMString c;
02275 Value* val;
02276 while (true) {
02277 val = valueList->current();
02278 switch (state) {
02279
02280
02281 case COMMA:
02282 state = ID;
02283 if (val && val->unit == Value::Operator && val->iValue == ',') {
02284 valueList->next();
02285 continue;
02286 }
02287
02288 case ID:
02289 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
02290 c = qString(val->string);
02291 state = VAL;
02292 valueList->next();
02293 continue;
02294 }
02295 break;
02296 case VAL: {
02297 short i = 0;
02298 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
02299 i = (short)val->fValue;
02300 valueList->next();
02301 } else
02302 i = (increment) ? 1 : 0;
02303
02304 CounterActImpl *cv = new CounterActImpl(c,i);
02305 list->append(cv);
02306 state = COMMA;
02307 continue;
02308 }
02309 }
02310 break;
02311 }
02312 if(list->length() > 0) {
02313 addProperty( propId, list, important );
02314 return true;
02315 }
02316 delete list;
02317 return false;
02318 }
02319
02320 static inline int yyerror( const char *str ) {
02321
02322 #ifdef CSS_DEBUG
02323 kdDebug( 6080 ) << "CSS parse error " << str << endl;
02324 #else
02325 Q_UNUSED( str );
02326 #endif
02327 return 1;
02328 }
02329
02330 #define END 0
02331
02332 #include "parser.h"
02333
02334 int DOM::CSSParser::lex( void *_yylval )
02335 {
02336 YYSTYPE *yylval = (YYSTYPE *)_yylval;
02337 int token = lex();
02338 int length;
02339 unsigned short *t = text( &length );
02340
02341 #ifdef TOKEN_DEBUG
02342 qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString( (QChar *)t, length ).latin1() );
02343 #endif
02344 switch( token ) {
02345 case '{':
02346 block_nesting++;
02347 break;
02348 case '}':
02349 if ( block_nesting )
02350 block_nesting--;
02351 break;
02352 case END:
02353 if ( block_nesting ) {
02354 block_nesting--;
02355 return '}';
02356 }
02357 break;
02358 case S:
02359 case SGML_CD:
02360 case INCLUDES:
02361 case DASHMATCH:
02362 break;
02363
02364 case URI:
02365 case STRING:
02366 case IDENT:
02367 case NTH:
02368 case HASH:
02369 case DIMEN:
02370 case UNICODERANGE:
02371 case NOTFUNCTION:
02372 case FUNCTION:
02373 yylval->string.string = t;
02374 yylval->string.length = length;
02375 break;
02376
02377 case IMPORT_SYM:
02378 case PAGE_SYM:
02379 case MEDIA_SYM:
02380 case FONT_FACE_SYM:
02381 case CHARSET_SYM:
02382 case NAMESPACE_SYM:
02383
02384 case IMPORTANT_SYM:
02385 break;
02386
02387 case QEMS:
02388 length--;
02389 case GRADS:
02390 length--;
02391 case DEGS:
02392 case RADS:
02393 case KHERZ:
02394 length--;
02395 case MSECS:
02396 case HERZ:
02397 case EMS:
02398 case EXS:
02399 case PXS:
02400 case CMS:
02401 case MMS:
02402 case INS:
02403 case PTS:
02404 case PCS:
02405 length--;
02406 case SECS:
02407 case PERCENTAGE:
02408 length--;
02409 case FLOAT:
02410 case INTEGER:
02411 yylval->val = QString( (QChar *)t, length ).toDouble();
02412
02413 break;
02414
02415 default:
02416 break;
02417 }
02418
02419 return token;
02420 }
02421
02422 static inline int toHex( char c ) {
02423 if ( '0' <= c && c <= '9' )
02424 return c - '0';
02425 if ( 'a' <= c && c <= 'f' )
02426 return c - 'a' + 10;
02427 if ( 'A' <= c && c<= 'F' )
02428 return c - 'A' + 10;
02429 return 0;
02430 }
02431
02432 unsigned short *DOM::CSSParser::text(int *length)
02433 {
02434 unsigned short *start = yytext;
02435 int l = yyleng;
02436 switch( yyTok ) {
02437 case STRING:
02438 l--;
02439
02440 case HASH:
02441 start++;
02442 l--;
02443 break;
02444 case URI:
02445
02446
02447
02448
02449 start += 4;
02450 l -= 5;
02451
02452 while ( l &&
02453 (*start == ' ' || *start == '\t' || *start == '\r' ||
02454 *start == '\n' || *start == '\f' ) ) {
02455 start++; l--;
02456 }
02457 if ( *start == '"' || *start == '\'' ) {
02458 start++; l--;
02459 }
02460 while ( l &&
02461 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
02462 start[l-1] == '\n' || start[l-1] == '\f' ) ) {
02463 l--;
02464 }
02465 if ( l && (start[l-1] == '\"' || start[l-1] == '\'' ) )
02466 l--;
02467
02468 default:
02469 break;
02470 }
02471
02472
02473 unsigned short *out = start;
02474 unsigned short *escape = 0;
02475
02476 for ( int i = 0; i < l; i++ ) {
02477 unsigned short *current = start+i;
02478 if ( escape == current - 1 ) {
02479 if ( ( *current >= '0' && *current <= '9' ) ||
02480 ( *current >= 'a' && *current <= 'f' ) ||
02481 ( *current >= 'A' && *current <= 'F' ) )
02482 continue;
02483 if ( yyTok == STRING &&
02484 ( *current == '\n' || *current == '\r' || *current == '\f' ) ) {
02485
02486 if ( *current != '\r' )
02487 escape = 0;
02488 continue;
02489 }
02490
02491
02492 *out++ = *current;
02493 escape = 0;
02494 continue;
02495 }
02496 if ( escape == current - 2 && yyTok == STRING &&
02497 *(current-1) == '\r' && *current == '\n' ) {
02498 escape = 0;
02499 continue;
02500 }
02501 if ( escape > current - 7 &&
02502 ( ( *current >= '0' && *current <= '9' ) ||
02503 ( *current >= 'a' && *current <= 'f' ) ||
02504 ( *current >= 'A' && *current <= 'F' ) ) )
02505 continue;
02506 if ( escape ) {
02507
02508 int uc = 0;
02509 escape++;
02510 while ( escape < current ) {
02511
02512 uc *= 16;
02513 uc += toHex( *escape );
02514 escape++;
02515 }
02516
02517
02518 if ( uc > 0xffff )
02519 uc = 0xfffd;
02520 *(out++) = (unsigned short)uc;
02521 escape = 0;
02522 if ( *current == ' ' ||
02523 *current == '\t' ||
02524 *current == '\r' ||
02525 *current == '\n' ||
02526 *current == '\f' )
02527 continue;
02528 }
02529 if ( !escape && *current == '\\' ) {
02530 escape = current;
02531 continue;
02532 }
02533 *(out++) = *current;
02534 }
02535 if ( escape ) {
02536
02537 int uc = 0;
02538 escape++;
02539 while ( escape < start+l ) {
02540
02541 uc *= 16;
02542 uc += toHex( *escape );
02543 escape++;
02544 }
02545
02546
02547 if ( uc > 0xffff )
02548 uc = 0xfffd;
02549 *(out++) = (unsigned short)uc;
02550 }
02551
02552 *length = out - start;
02553 return start;
02554 }
02555
02556
02557 #define YY_DECL int DOM::CSSParser::lex()
02558 #define yyconst const
02559 typedef int yy_state_type;
02560 typedef unsigned int YY_CHAR;
02561
02562 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
02563 #define YY_DO_BEFORE_ACTION \
02564 yytext = yy_bp; \
02565 yyleng = (int) (yy_cp - yy_bp); \
02566 yy_hold_char = *yy_cp; \
02567 *yy_cp = 0; \
02568 yy_c_buf_p = yy_cp;
02569 #define YY_BREAK break;
02570 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).latin1() )
02571 #define YY_RULE_SETUP
02572 #define INITIAL 0
02573 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
02574 #define YY_START ((yy_start - 1) / 2)
02575 #define yyterminate() yyTok = END; return yyTok
02576 #define YY_FATAL_ERROR(a) qFatal(a)
02577 #define BEGIN yy_start = 1 + 2 *
02578 #define COMMENT 1
02579
02580 #include "tokenizer.cpp"