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