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