khtml Library API Documentation

cssparser.cpp

00001 /* 00002 * This file is part of the DOM implementation for KDE. 00003 * 00004 * Copyright (C) 2003 Lars Knoll (knoll@kde.org) 00005 * 00006 * $Id: cssparser.cpp,v 1.291 2004/06/13 17:08:23 savernik Exp $ 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Library General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Library General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Library General Public License 00019 * along with this library; see the file COPYING.LIB. If not, write to 00020 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00021 * Boston, MA 02111-1307, USA. 00022 */ 00023 00024 //#define CSS_DEBUG 00025 //#define TOKEN_DEBUG 00026 #define YYDEBUG 0 00027 00028 #include <kdebug.h> 00029 #include <kglobal.h> 00030 #include <kurl.h> 00031 00032 #include "cssparser.h" 00033 #include "css_valueimpl.h" 00034 #include "css_ruleimpl.h" 00035 #include "css_stylesheetimpl.h" 00036 #include "cssproperties.h" 00037 #include "cssvalues.h" 00038 #include "misc/helper.h" 00039 #include "csshelper.h" 00040 using namespace DOM; 00041 00042 #include <stdlib.h> 00043 #include <assert.h> 00044 00045 ValueList::ValueList() 00046 { 00047 values = (Value *) malloc( 16 * sizeof ( Value ) ); 00048 numValues = 0; 00049 currentValue = 0; 00050 maxValues = 16; 00051 } 00052 00053 ValueList::~ValueList() 00054 { 00055 for ( int i = 0; i < numValues; i++ ) { 00056 #ifdef CSS_DEBUG 00057 kdDebug( 6080 ) << " value: (unit=" << values[i].unit <<")"<< endl; 00058 #endif 00059 if ( values[i].unit == Value::Function ) 00060 delete values[i].function; 00061 } 00062 free( values ); 00063 } 00064 00065 void ValueList::addValue( const Value &val ) 00066 { 00067 if ( numValues >= maxValues ) { 00068 maxValues += 16; 00069 values = (Value *) realloc( values, maxValues*sizeof( Value ) ); 00070 } 00071 values[numValues++] = val; 00072 } 00073 00074 00075 using namespace DOM; 00076 00077 #if YYDEBUG > 0 00078 extern int cssyydebug; 00079 #endif 00080 00081 extern int cssyyparse( void * parser ); 00082 00083 CSSParser *CSSParser::currentParser = 0; 00084 00085 CSSParser::CSSParser( bool strictParsing ) 00086 { 00087 #ifdef CSS_DEBUG 00088 kdDebug( 6080 ) << "CSSParser::CSSParser this=" << this << endl; 00089 #endif 00090 strict = strictParsing; 00091 00092 parsedProperties = (CSSProperty **) malloc( 32 * sizeof( CSSProperty * ) ); 00093 numParsedProperties = 0; 00094 maxParsedProperties = 32; 00095 00096 defaultNamespace = 0xffff; 00097 00098 data = 0; 00099 valueList = 0; 00100 rule = 0; 00101 id = 0; 00102 important = false; 00103 nonCSSHint = false; 00104 inParseShortHand = false; 00105 yy_start = 1; 00106 00107 #if YYDEBUG > 0 00108 cssyydebug = 1; 00109 #endif 00110 00111 } 00112 00113 CSSParser::~CSSParser() 00114 { 00115 if ( numParsedProperties ) 00116 clearProperties(); 00117 free( parsedProperties ); 00118 00119 delete valueList; 00120 00121 #ifdef CSS_DEBUG 00122 kdDebug( 6080 ) << "CSSParser::~CSSParser this=" << this << endl; 00123 #endif 00124 00125 free( data ); 00126 00127 } 00128 00129 void CSSParser::runParser(int length) 00130 { 00131 data[length-1] = 0; 00132 data[length-2] = 0; 00133 data[length-3] = ' '; 00134 00135 yyTok = -1; 00136 block_nesting = 0; 00137 yy_hold_char = 0; 00138 yyleng = 0; 00139 yytext = yy_c_buf_p = data; 00140 yy_hold_char = *yy_c_buf_p; 00141 00142 CSSParser *old = currentParser; 00143 currentParser = this; 00144 cssyyparse( this ); 00145 currentParser = old; 00146 } 00147 00148 void CSSParser::parseSheet( CSSStyleSheetImpl *sheet, const DOMString &string ) 00149 { 00150 styleElement = sheet; 00151 00152 int length = string.length() + 3; 00153 data = (unsigned short *)malloc( length *sizeof( unsigned short ) ); 00154 memcpy( data, string.unicode(), string.length()*sizeof( unsigned short) ); 00155 00156 #ifdef CSS_DEBUG 00157 kdDebug( 6080 ) << ">>>>>>> start parsing style sheet" << endl; 00158 #endif 00159 runParser(length); 00160 #ifdef CSS_DEBUG 00161 kdDebug( 6080 ) << "<<<<<<< done parsing style sheet" << endl; 00162 #endif 00163 00164 delete rule; 00165 rule = 0; 00166 } 00167 00168 CSSRuleImpl *CSSParser::parseRule( DOM::CSSStyleSheetImpl *sheet, const DOM::DOMString &string ) 00169 { 00170 styleElement = sheet; 00171 00172 const char khtml_rule[] = "@-khtml-rule{"; 00173 int length = string.length() + 4 + strlen(khtml_rule); 00174 assert( !data ); 00175 data = (unsigned short *)malloc( length *sizeof( unsigned short ) ); 00176 for ( unsigned int i = 0; i < strlen(khtml_rule); i++ ) 00177 data[i] = khtml_rule[i]; 00178 memcpy( data + strlen( khtml_rule ), string.unicode(), string.length()*sizeof( unsigned short) ); 00179 // qDebug("parse string = '%s'", QConstString( (const QChar *)data, length ).string().latin1() ); 00180 data[length-4] = '}'; 00181 00182 runParser(length); 00183 00184 CSSRuleImpl *result = rule; 00185 rule = 0; 00186 00187 return result; 00188 } 00189 00190 bool CSSParser::parseValue( DOM::CSSStyleDeclarationImpl *declaration, int _id, const DOM::DOMString &string, 00191 bool _important, bool _nonCSSHint ) 00192 { 00193 #ifdef CSS_DEBUG 00194 kdDebug( 6080 ) << "CSSParser::parseValue: id=" << _id << " important=" << _important 00195 << " nonCSSHint=" << _nonCSSHint << " value='" << string.string() << "'" << endl; 00196 #endif 00197 00198 styleElement = declaration->stylesheet(); 00199 00200 const char khtml_value[] = "@-khtml-value{"; 00201 int length = string.length() + 4 + strlen(khtml_value); 00202 assert( !data ); 00203 data = (unsigned short *)malloc( length *sizeof( unsigned short ) ); 00204 for ( unsigned int i = 0; i < strlen(khtml_value); i++ ) 00205 data[i] = khtml_value[i]; 00206 memcpy( data + strlen( khtml_value ), string.unicode(), string.length()*sizeof( unsigned short) ); 00207 data[length-4] = '}'; 00208 // qDebug("parse string = '%s'", QConstString( (const QChar *)data, length ).string().latin1() ); 00209 00210 id = _id; 00211 important = _important; 00212 nonCSSHint = _nonCSSHint; 00213 00214 runParser(length); 00215 00216 delete rule; 00217 rule = 0; 00218 00219 bool ok = false; 00220 if ( numParsedProperties ) { 00221 ok = true; 00222 for ( int i = 0; i < numParsedProperties; i++ ) { 00223 declaration->removeProperty(parsedProperties[i]->m_id, nonCSSHint); 00224 declaration->values()->append( parsedProperties[i] ); 00225 } 00226 numParsedProperties = 0; 00227 } 00228 00229 return ok; 00230 } 00231 00232 bool CSSParser::parseDeclaration( DOM::CSSStyleDeclarationImpl *declaration, const DOM::DOMString &string, 00233 bool _nonCSSHint ) 00234 { 00235 #ifdef CSS_DEBUG 00236 kdDebug( 6080 ) << "CSSParser::parseDeclaration: nonCSSHint=" << nonCSSHint 00237 << " value='" << string.string() << "'" << endl; 00238 #endif 00239 00240 styleElement = declaration->stylesheet(); 00241 00242 const char khtml_decls[] = "@-khtml-decls{"; 00243 int length = string.length() + 4 + strlen(khtml_decls); 00244 assert( !data ); 00245 data = (unsigned short *)malloc( length *sizeof( unsigned short ) ); 00246 for ( unsigned int i = 0; i < strlen(khtml_decls); i++ ) 00247 data[i] = khtml_decls[i]; 00248 memcpy( data + strlen( khtml_decls ), string.unicode(), string.length()*sizeof( unsigned short) ); 00249 data[length-4] = '}'; 00250 00251 nonCSSHint = _nonCSSHint; 00252 00253 runParser(length); 00254 00255 delete rule; 00256 rule = 0; 00257 00258 bool ok = false; 00259 if ( numParsedProperties ) { 00260 ok = true; 00261 for ( int i = 0; i < numParsedProperties; i++ ) { 00262 declaration->removeProperty(parsedProperties[i]->m_id, false); 00263 declaration->values()->append( parsedProperties[i] ); 00264 } 00265 numParsedProperties = 0; 00266 } 00267 00268 return ok; 00269 } 00270 00271 void CSSParser::addProperty( int propId, CSSValueImpl *value, bool important ) 00272 { 00273 CSSProperty *prop = new CSSProperty; 00274 prop->m_id = propId; 00275 prop->setValue( value ); 00276 prop->m_bImportant = important; 00277 prop->nonCSSHint = nonCSSHint; 00278 00279 if ( numParsedProperties >= maxParsedProperties ) { 00280 maxParsedProperties += 32; 00281 parsedProperties = (CSSProperty **) realloc( parsedProperties, 00282 maxParsedProperties*sizeof( CSSProperty * ) ); 00283 } 00284 parsedProperties[numParsedProperties++] = prop; 00285 } 00286 00287 CSSStyleDeclarationImpl *CSSParser::createStyleDeclaration( CSSStyleRuleImpl *rule ) 00288 { 00289 QPtrList<CSSProperty> *propList = new QPtrList<CSSProperty>; 00290 propList->setAutoDelete( true ); 00291 for ( int i = 0; i < numParsedProperties; i++ ) 00292 propList->append( parsedProperties[i] ); 00293 00294 numParsedProperties = 0; 00295 return new CSSStyleDeclarationImpl(rule, propList); 00296 } 00297 00298 void CSSParser::clearProperties() 00299 { 00300 for ( int i = 0; i < numParsedProperties; i++ ) 00301 delete parsedProperties[i]; 00302 numParsedProperties = 0; 00303 } 00304 00305 DOM::DocumentImpl *CSSParser::document() const 00306 { 00307 const StyleBaseImpl* root = styleElement; 00308 DocumentImpl *doc = 0; 00309 while (root->parent()) 00310 root = root->parent(); 00311 if (root->isCSSStyleSheet()) 00312 doc = static_cast<const CSSStyleSheetImpl*>(root)->doc(); 00313 return doc; 00314 } 00315 00316 00317 // defines units allowed for a certain property, used in parseUnit 00318 enum Units 00319 { 00320 FUnknown = 0x0000, 00321 FInteger = 0x0001, 00322 FNumber = 0x0002, // Real Numbers 00323 FPercent = 0x0004, 00324 FLength = 0x0008, 00325 FAngle = 0x0010, 00326 FTime = 0x0020, 00327 FFrequency = 0x0040, 00328 FRelative = 0x0100, 00329 FNonNeg = 0x0200 00330 }; 00331 00332 static bool validUnit( Value *value, int unitflags, bool strict ) 00333 { 00334 if ( unitflags & FNonNeg && value->fValue < 0 ) 00335 return false; 00336 00337 bool b = false; 00338 switch( value->unit ) { 00339 case CSSPrimitiveValue::CSS_NUMBER: 00340 b = (unitflags & FNumber); 00341 if ( !b && ( (unitflags & FLength) && (value->fValue == 0 || !strict ) ) ) { 00342 value->unit = CSSPrimitiveValue::CSS_PX; 00343 b = true; 00344 } 00345 if ( !b && ( unitflags & FInteger ) && 00346 (value->fValue - (int)value->fValue) < 0.001 ) 00347 b = true; 00348 break; 00349 case CSSPrimitiveValue::CSS_PERCENTAGE: 00350 b = (unitflags & FPercent); 00351 break; 00352 case Value::Q_EMS: 00353 case CSSPrimitiveValue::CSS_EMS: 00354 case CSSPrimitiveValue::CSS_EXS: 00355 case CSSPrimitiveValue::CSS_PX: 00356 case CSSPrimitiveValue::CSS_CM: 00357 case CSSPrimitiveValue::CSS_MM: 00358 case CSSPrimitiveValue::CSS_IN: 00359 case CSSPrimitiveValue::CSS_PT: 00360 case CSSPrimitiveValue::CSS_PC: 00361 b = (unitflags & FLength); 00362 break; 00363 case CSSPrimitiveValue::CSS_MS: 00364 case CSSPrimitiveValue::CSS_S: 00365 b = (unitflags & FTime); 00366 break; 00367 case CSSPrimitiveValue::CSS_DEG: 00368 case CSSPrimitiveValue::CSS_RAD: 00369 case CSSPrimitiveValue::CSS_GRAD: 00370 case CSSPrimitiveValue::CSS_HZ: 00371 case CSSPrimitiveValue::CSS_KHZ: 00372 case CSSPrimitiveValue::CSS_DIMENSION: 00373 default: 00374 break; 00375 } 00376 return b; 00377 } 00378 00379 bool CSSParser::parseValue( int propId, bool important ) 00380 { 00381 if ( !valueList ) return false; 00382 00383 Value *value = valueList->current(); 00384 00385 if ( !value ) 00386 return false; 00387 00388 int id = 0; 00389 id = value->id; 00390 00391 if ( id == CSS_VAL_INHERIT ) { 00392 addProperty( propId, new CSSInheritedValueImpl(), important ); 00393 return true; 00394 } else if (id == CSS_VAL_INITIAL) { 00395 addProperty(propId, new CSSInitialValueImpl(), important); 00396 return true; 00397 } 00398 bool valid_primitive = false; 00399 CSSValueImpl *parsedValue = 0; 00400 00401 switch(propId) { 00402 /* The comment to the left defines all valid value of this properties as defined 00403 * in CSS 2, Appendix F. Property index 00404 */ 00405 00406 /* All the CSS properties are not supported by the renderer at the moment. 00407 * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined 00408 * (see parseAuralValues). As we don't support them at all this seems reasonable. 00409 */ 00410 00411 case CSS_PROP_SIZE: // <length>{1,2} | auto | portrait | landscape | inherit 00412 case CSS_PROP_QUOTES: // [<string> <string>]+ | none | inherit 00413 // case CSS_PROP_PAGE: // <identifier> | auto // ### CHECK 00414 // ### To be done 00415 if (id) 00416 valid_primitive = true; 00417 break; 00418 case CSS_PROP_UNICODE_BIDI: // normal | embed | bidi-override | inherit 00419 if ( id == CSS_VAL_NORMAL || 00420 id == CSS_VAL_EMBED || 00421 id == CSS_VAL_BIDI_OVERRIDE ) 00422 valid_primitive = true; 00423 break; 00424 00425 case CSS_PROP_POSITION: // static | relative | absolute | fixed | inherit 00426 if ( id == CSS_VAL_STATIC || 00427 id == CSS_VAL_RELATIVE || 00428 id == CSS_VAL_ABSOLUTE || 00429 id == CSS_VAL_FIXED ) 00430 valid_primitive = true; 00431 break; 00432 00433 case CSS_PROP_PAGE_BREAK_AFTER: // auto | always | avoid | left | right | inherit 00434 case CSS_PROP_PAGE_BREAK_BEFORE: // auto | always | avoid | left | right | inherit 00435 if ( id == CSS_VAL_AUTO || 00436 id == CSS_VAL_ALWAYS || 00437 id == CSS_VAL_AVOID || 00438 id == CSS_VAL_LEFT || 00439 id == CSS_VAL_RIGHT ) 00440 valid_primitive = true; 00441 break; 00442 00443 case CSS_PROP_PAGE_BREAK_INSIDE: // avoid | auto | inherit 00444 if ( id == CSS_VAL_AUTO || 00445 id == CSS_VAL_AVOID ) 00446 valid_primitive = true; 00447 break; 00448 00449 case CSS_PROP_EMPTY_CELLS: // show | hide | inherit 00450 if ( id == CSS_VAL_SHOW || 00451 id == CSS_VAL_HIDE ) 00452 valid_primitive = true; 00453 break; 00454 00455 case CSS_PROP_CONTENT: // [ <string> | <uri> | <counter> | attr(X) | open-quote | 00456 // close-quote | no-open-quote | no-close-quote ]+ | inherit 00457 return parseContent( propId, important ); 00458 break; 00459 00460 case CSS_PROP_WHITE_SPACE: // normal | pre | nowrap | inherit 00461 if ( id == CSS_VAL_NORMAL || 00462 id == CSS_VAL_PRE || 00463 id == CSS_VAL_NOWRAP ) 00464 valid_primitive = true; 00465 break; 00466 00467 case CSS_PROP_CLIP: // <shape> | auto | inherit 00468 if ( id == CSS_VAL_AUTO ) 00469 valid_primitive = true; 00470 else if ( value->unit == Value::Function ) 00471 return parseShape( propId, important ); 00472 break; 00473 00474 /* Start of supported CSS properties with validation. This is needed for parseShortHand to work 00475 * correctly and allows optimization in khtml::applyRule(..) 00476 */ 00477 case CSS_PROP_CAPTION_SIDE: // top | bottom | left | right | inherit 00478 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || 00479 id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) 00480 valid_primitive = true; 00481 break; 00482 00483 case CSS_PROP_BORDER_COLLAPSE: // collapse | separate | inherit 00484 if ( id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE ) 00485 valid_primitive = true; 00486 break; 00487 00488 case CSS_PROP_VISIBILITY: // visible | hidden | collapse | inherit 00489 if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE) 00490 valid_primitive = true; 00491 break; 00492 00493 case CSS_PROP_OVERFLOW: // visible | hidden | scroll | auto | marquee | inherit 00494 if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO || 00495 id == CSS_VAL_MARQUEE) 00496 valid_primitive = true; 00497 break; 00498 00499 case CSS_PROP_LIST_STYLE_POSITION: // inside | outside | inherit 00500 if ( id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE ) 00501 valid_primitive = true; 00502 break; 00503 00504 case CSS_PROP_LIST_STYLE_TYPE: 00505 // disc | circle | square | decimal | decimal-leading-zero | lower-roman | 00506 // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha | 00507 // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana | 00508 // katakana | hiragana-iroha | katakana-iroha | none | inherit 00509 if ((id >= CSS_VAL_DISC && id <= CSS_VAL_KATAKANA_IROHA) || id == CSS_VAL_NONE) 00510 valid_primitive = true; 00511 break; 00512 00513 case CSS_PROP_DISPLAY: 00514 // inline | block | list-item | run-in | inline-block | -khtml-ruler | table | 00515 // inline-table | table-row-group | table-header-group | table-footer-group | table-row | 00516 // table-column-group | table-column | table-cell | table-caption | none | inherit 00517 if ((id >= CSS_VAL_INLINE && id <= CSS_VAL_TABLE_CAPTION) || id == CSS_VAL_NONE) 00518 valid_primitive = true; 00519 break; 00520 00521 case CSS_PROP_DIRECTION: // ltr | rtl | inherit 00522 if ( id == CSS_VAL_LTR || id == CSS_VAL_RTL ) 00523 valid_primitive = true; 00524 break; 00525 00526 case CSS_PROP_TEXT_TRANSFORM: // capitalize | uppercase | lowercase | none | inherit 00527 if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE) 00528 valid_primitive = true; 00529 break; 00530 00531 case CSS_PROP_FLOAT: // left | right | none | inherit + center for buggy CSS 00532 if ( id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || 00533 id == CSS_VAL_NONE || id == CSS_VAL_CENTER) 00534 valid_primitive = true; 00535 break; 00536 00537 case CSS_PROP_CLEAR: // none | left | right | both | inherit 00538 if ( id == CSS_VAL_NONE || id == CSS_VAL_LEFT || 00539 id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH) 00540 valid_primitive = true; 00541 break; 00542 00543 case CSS_PROP_TEXT_ALIGN: 00544 // left | right | center | justify | -khtml_center | <string> | inherit 00545 if ( ( id >= CSS_VAL__KHTML_AUTO && id <= CSS_VAL__KHTML_CENTER ) || 00546 value->unit == CSSPrimitiveValue::CSS_STRING ) 00547 valid_primitive = true; 00548 break; 00549 00550 case CSS_PROP_OUTLINE_STYLE: // <border-style> | inherit 00551 case CSS_PROP_BORDER_TOP_STYLE: 00552 case CSS_PROP_BORDER_RIGHT_STYLE: // Defined as: none | hidden | dotted | dashed | 00553 case CSS_PROP_BORDER_BOTTOM_STYLE: // solid | double | groove | ridge | inset | outset 00554 case CSS_PROP_BORDER_LEFT_STYLE: 00555 if (id >= CSS_VAL_NONE && id <= CSS_VAL_DOUBLE) 00556 valid_primitive = true; 00557 break; 00558 00559 case CSS_PROP_FONT_WEIGHT: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 00560 // 500 | 600 | 700 | 800 | 900 | inherit 00561 if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) { 00562 // Allready correct id 00563 valid_primitive = true; 00564 } else if ( validUnit( value, FInteger|FNonNeg, false ) ) { 00565 int weight = (int)value->fValue; 00566 if ( (weight % 100) ) 00567 break; 00568 weight /= 100; 00569 if ( weight >= 1 && weight <= 9 ) { 00570 id = CSS_VAL_100 + weight - 1; 00571 valid_primitive = true; 00572 } 00573 } 00574 break; 00575 00576 case CSS_PROP_BACKGROUND_REPEAT: // repeat | repeat-x | repeat-y | no-repeat | inherit 00577 if ( id >= CSS_VAL_REPEAT && id <= CSS_VAL_NO_REPEAT ) 00578 valid_primitive = true; 00579 break; 00580 00581 case CSS_PROP_BACKGROUND_ATTACHMENT: // scroll | fixed 00582 if ( id == CSS_VAL_SCROLL || id == CSS_VAL_FIXED ) 00583 valid_primitive = true; 00584 break; 00585 00586 case CSS_PROP_BACKGROUND_POSITION: 00587 if ( id ) { 00588 /* Problem: center is ambigous 00589 * In case of 'center' center defines X and Y coords 00590 * In case of 'center top', center defines the Y coord 00591 * in case of 'center left', center defines the X coord 00592 */ 00593 int pos[2]; 00594 pos[0] = -1; 00595 pos[1] = -1; 00596 bool invalid = false; 00597 switch( id ) { 00598 case CSS_VAL_TOP: 00599 pos[1] = 0; 00600 break; 00601 case CSS_VAL_BOTTOM: 00602 pos[1] = 100; 00603 break; 00604 case CSS_VAL_LEFT: 00605 pos[0] = 0; 00606 break; 00607 case CSS_VAL_RIGHT: 00608 pos[0] = 100; 00609 break; 00610 case CSS_VAL_CENTER: 00611 break; 00612 default: 00613 invalid = true; 00614 } 00615 if ( invalid ) 00616 break; 00617 value = valueList->next(); 00618 if ( value ) { 00619 id = value->id; 00620 switch( id ) { 00621 case CSS_VAL_TOP: 00622 if ( pos[1] != -1 ) 00623 invalid = true; 00624 pos[1] = 0; 00625 break; 00626 case CSS_VAL_BOTTOM: 00627 if ( pos[1] != -1 ) 00628 invalid = true; 00629 pos[1] = 100; 00630 break; 00631 case CSS_VAL_LEFT: 00632 if ( pos[0] != -1 ) 00633 invalid = true; 00634 pos[0] = 0; 00635 break; 00636 case CSS_VAL_RIGHT: 00637 if ( pos[0] != -1 ) 00638 invalid = true; 00639 pos[0] = 100; 00640 break; 00641 case CSS_VAL_CENTER: 00642 break; 00643 default: 00644 invalid = true; 00645 } 00646 if ( !invalid ) 00647 value = valueList->next(); 00648 } 00649 if ( pos[0] == -1 ) 00650 pos[0] = 50; 00651 if ( pos[1] == -1 ) 00652 pos[1] = 50; 00653 addProperty( CSS_PROP_BACKGROUND_POSITION_X, 00654 new CSSPrimitiveValueImpl( pos[0], CSSPrimitiveValue::CSS_PERCENTAGE ), 00655 important ); 00656 addProperty( CSS_PROP_BACKGROUND_POSITION_Y, 00657 new CSSPrimitiveValueImpl( pos[1], CSSPrimitiveValue::CSS_PERCENTAGE ), 00658 important ); 00659 } else { 00660 bool ok = parseValue( CSS_PROP_BACKGROUND_POSITION_X, important ); 00661 if ( !ok ) 00662 break; 00663 value = valueList->current(); 00664 if ( value ) 00665 ok = parseValue( CSS_PROP_BACKGROUND_POSITION_Y, important ); 00666 if ( !ok ) 00667 addProperty( CSS_PROP_BACKGROUND_POSITION_Y, 00668 new CSSPrimitiveValueImpl( 50, CSSPrimitiveValue::CSS_PERCENTAGE ), 00669 important ); 00670 } 00671 return true; 00672 00673 case CSS_PROP_BACKGROUND_POSITION_X: 00674 case CSS_PROP_BACKGROUND_POSITION_Y: 00675 valid_primitive = validUnit( value, FPercent|FLength, strict&(!nonCSSHint) ); 00676 break; 00677 00678 case CSS_PROP_BORDER_SPACING: 00679 { 00680 const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING, 00681 CSS_PROP__KHTML_BORDER_VERTICAL_SPACING }; 00682 int num = valueList->numValues; 00683 if (num == 1) { 00684 if (!parseValue(properties[0], important)) return false; 00685 CSSValueImpl* value = parsedProperties[numParsedProperties-1]->value(); 00686 addProperty(properties[1], value, important); 00687 return true; 00688 } 00689 else if (num == 2) { 00690 if (!parseValue(properties[0], important)) return false; 00691 if (!parseValue(properties[1], important)) return false; 00692 return true; 00693 } 00694 return false; 00695 } 00696 case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING: 00697 case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING: 00698 valid_primitive = validUnit(value, FLength|FNonNeg, strict&(!nonCSSHint)); 00699 break; 00700 00701 case CSS_PROP_SCROLLBAR_FACE_COLOR: // IE5.5 00702 case CSS_PROP_SCROLLBAR_SHADOW_COLOR: // IE5.5 00703 case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR: // IE5.5 00704 case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR: // IE5.5 00705 case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR: // IE5.5 00706 case CSS_PROP_SCROLLBAR_TRACK_COLOR: // IE5.5 00707 case CSS_PROP_SCROLLBAR_ARROW_COLOR: // IE5.5 00708 case CSS_PROP_SCROLLBAR_BASE_COLOR: // IE5.5 00709 if ( strict ) 00710 break; 00711 /* nobreak */ 00712 case CSS_PROP_OUTLINE_COLOR: // <color> | invert | inherit 00713 // outline has "invert" as additional keyword. 00714 if ( propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT ) { 00715 valid_primitive = true; 00716 break; 00717 } 00718 /* nobreak */ 00719 case CSS_PROP_BACKGROUND_COLOR: // <color> | transparent | inherit 00720 if ( propId == CSS_PROP_BACKGROUND_COLOR && id == CSS_VAL_TRANSPARENT ) { 00721 valid_primitive = true; 00722 break; 00723 } 00724 /* nobreak */ 00725 case CSS_PROP_COLOR: // <color> | transparent | inherit 00726 case CSS_PROP_BORDER_TOP_COLOR: // <color> | transparent | inherit 00727 case CSS_PROP_BORDER_RIGHT_COLOR: // <color> | transparent | inherit 00728 case CSS_PROP_BORDER_BOTTOM_COLOR: // <color> | transparent | inherit 00729 case CSS_PROP_BORDER_LEFT_COLOR: // <color> | transparent | inherit 00730 case CSS_PROP__KHTML_TEXT_DECORATION_COLOR: 00731 if ( id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_MENU || 00732 (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT ) || 00733 id == CSS_VAL_TRANSPARENT || 00734 (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && (nonCSSHint|!strict) ) ) { 00735 valid_primitive = true; 00736 } else { 00737 parsedValue = parseColor(); 00738 if ( parsedValue ) 00739 valueList->next(); 00740 } 00741 break; 00742 00743 case CSS_PROP_CURSOR: 00744 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize | 00745 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | text | 00746 // wait | help ] ] | inherit 00747 // MSIE 5 compatibility :/ 00748 if ( !strict && id == CSS_VAL_HAND ) { 00749 id = CSS_VAL_POINTER; 00750 valid_primitive = true; 00751 } else if ( id >= CSS_VAL_AUTO && id <= CSS_VAL_HELP ) 00752 valid_primitive = true; 00753 break; 00754 00755 case CSS_PROP_BACKGROUND_IMAGE: // <uri> | none | inherit 00756 case CSS_PROP_LIST_STYLE_IMAGE: // <uri> | none | inherit 00757 00758 if ( id == CSS_VAL_NONE ) { 00759 parsedValue = new CSSImageValueImpl(); 00760 valueList->next(); 00761 #ifdef CSS_DEBUG 00762 kdDebug( 6080 ) << "empty image " << endl; 00763 #endif 00764 } else if ( value->unit == CSSPrimitiveValue::CSS_URI ) { 00765 // ### allow string in non strict mode? 00766 DOMString uri = khtml::parseURL( domString( value->string ) ); 00767 if ( !uri.isEmpty() ) { 00768 parsedValue = new CSSImageValueImpl( 00769 DOMString(KURL( styleElement->baseURL(), uri.string()).url()), 00770 styleElement ); 00771 valueList->next(); 00772 #ifdef CSS_DEBUG 00773 kdDebug( 6080 ) << "image, url=" << uri.string() << " base=" << styleElement->baseURL().url() << endl; 00774 #endif 00775 } 00776 } 00777 break; 00778 00779 case CSS_PROP_OUTLINE_WIDTH: // <border-width> | inherit 00780 case CSS_PROP_BORDER_TOP_WIDTH: 00781 case CSS_PROP_BORDER_RIGHT_WIDTH: // Which is defined as 00782 case CSS_PROP_BORDER_BOTTOM_WIDTH: // thin | medium | thick | <length> 00783 case CSS_PROP_BORDER_LEFT_WIDTH: 00784 if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK) 00785 valid_primitive = true; 00786 else 00787 valid_primitive = ( validUnit( value, FLength, strict&(!nonCSSHint) ) ); 00788 break; 00789 00790 case CSS_PROP_LETTER_SPACING: // normal | <length> | inherit 00791 case CSS_PROP_WORD_SPACING: // normal | <length> | inherit 00792 if ( id == CSS_VAL_NORMAL ) 00793 valid_primitive = true; 00794 else 00795 valid_primitive = validUnit( value, FLength, strict&(!nonCSSHint) ); 00796 break; 00797 00798 case CSS_PROP_TEXT_INDENT: // <length> | <percentage> | inherit 00799 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) ); 00800 break; 00801 00802 case CSS_PROP_PADDING_TOP: // <length> | <percentage> | inherit 00803 case CSS_PROP_PADDING_RIGHT: // <padding-width> | inherit 00804 case CSS_PROP_PADDING_BOTTOM: // Which is defined as 00805 case CSS_PROP_PADDING_LEFT: // <length> | <percentage> 00806 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) ); 00807 break; 00808 00809 case CSS_PROP_MAX_HEIGHT: // <length> | <percentage> | none | inherit 00810 case CSS_PROP_MAX_WIDTH: // <length> | <percentage> | none | inherit 00811 if ( id == CSS_VAL_NONE ) { 00812 valid_primitive = true; 00813 break; 00814 } 00815 /* nobreak */ 00816 case CSS_PROP_MIN_HEIGHT: // <length> | <percentage> | inherit 00817 case CSS_PROP_MIN_WIDTH: // <length> | <percentage> | inherit 00818 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) ); 00819 break; 00820 00821 case CSS_PROP_FONT_SIZE: 00822 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit 00823 if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER) 00824 valid_primitive = true; 00825 else 00826 valid_primitive = ( validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) ); 00827 break; 00828 00829 case CSS_PROP_FONT_STYLE: // normal | italic | oblique | inherit 00830 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE) 00831 valid_primitive = true; 00832 break; 00833 00834 case CSS_PROP_FONT_VARIANT: // normal | small-caps | inherit 00835 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS) 00836 valid_primitive = true; 00837 break; 00838 00839 case CSS_PROP_VERTICAL_ALIGN: 00840 // baseline | sub | super | top | text-top | middle | bottom | text-bottom | 00841 // <percentage> | <length> | inherit 00842 00843 if ( id >= CSS_VAL_BASELINE && id <= CSS_VAL__KHTML_BASELINE_MIDDLE ) 00844 valid_primitive = true; 00845 else 00846 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) ); 00847 break; 00848 00849 case CSS_PROP_HEIGHT: // <length> | <percentage> | auto | inherit 00850 case CSS_PROP_WIDTH: // <length> | <percentage> | auto | inherit 00851 if ( id == CSS_VAL_AUTO ) 00852 valid_primitive = true; 00853 else 00854 // ### handle multilength case where we allow relative units 00855 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict&(!nonCSSHint) ) ); 00856 break; 00857 00858 case CSS_PROP_BOTTOM: // <length> | <percentage> | auto | inherit 00859 case CSS_PROP_LEFT: // <length> | <percentage> | auto | inherit 00860 case CSS_PROP_RIGHT: // <length> | <percentage> | auto | inherit 00861 case CSS_PROP_TOP: // <length> | <percentage> | auto | inherit 00862 case CSS_PROP_MARGIN_TOP: 00863 case CSS_PROP_MARGIN_RIGHT: // Which is defined as 00864 case CSS_PROP_MARGIN_BOTTOM: // <length> | <percentage> | auto | inherit 00865 case CSS_PROP_MARGIN_LEFT: 00866 if ( id == CSS_VAL_AUTO ) 00867 valid_primitive = true; 00868 else 00869 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict&(!nonCSSHint) ) ); 00870 break; 00871 00872 case CSS_PROP_Z_INDEX: // auto | <integer> | inherit 00873 // qDebug("parsing z-index: id=%d, fValue=%f", id, value->fValue ); 00874 if ( id == CSS_VAL_AUTO ) { 00875 valid_primitive = true; 00876 break; 00877 } 00878 /* nobreak */ 00879 case CSS_PROP_ORPHANS: // <integer> | inherit 00880 case CSS_PROP_WIDOWS: // <integer> | inherit 00881 // ### not supported later on 00882 valid_primitive = ( !id && validUnit( value, FInteger, false ) ); 00883 break; 00884 00885 case CSS_PROP_LINE_HEIGHT: // normal | <number> | <length> | <percentage> | inherit 00886 if ( id == CSS_VAL_NORMAL ) 00887 valid_primitive = true; 00888 else 00889 valid_primitive = ( !id && validUnit( value, FNumber|FLength|FPercent, strict&(!nonCSSHint) ) ); 00890 break; 00891 #if 0 00892 // removed from CSS 2.1 00893 case CSS_PROP_COUNTER_INCREMENT: // [ <identifier> <integer>? ]+ | none | inherit 00894 case CSS_PROP_COUNTER_RESET: // [ <identifier> <integer>? ]+ | none | inherit 00895 if ( id == CSS_VAL_NONE ) 00896 valid_primitive = true; 00897 else { 00898 CSSValueListImpl *list = new CSSValueListImpl; 00899 int pos=0, pos2; 00900 while( 1 ) 00901 { 00902 pos2 = value.find(',', pos); 00903 QString face = value.mid(pos, pos2-pos); 00904 face = face.stripWhiteSpace(); 00905 if(face.length() == 0) break; 00906 // ### single quoted is missing... 00907 if(face[0] == '\"') face.remove(0, 1); 00908 if(face[face.length()-1] == '\"') face = face.left(face.length()-1); 00909 //kdDebug( 6080 ) << "found face '" << face << "'" << endl; 00910 list->append(new CSSPrimitiveValueImpl(DOMString(face), CSSPrimitiveValue::CSS_STRING)); 00911 pos = pos2 + 1; 00912 if(pos2 == -1) break; 00913 } 00914 //kdDebug( 6080 ) << "got " << list->length() << " faces" << endl; 00915 if(list->length()) { 00916 parsedValue = list; 00917 valueList->next(); 00918 } else 00919 delete list; 00920 break; 00921 } 00922 #endif 00923 case CSS_PROP_FONT_FAMILY: 00924 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit 00925 { 00926 parsedValue = parseFontFamily(); 00927 break; 00928 } 00929 00930 case CSS_PROP_TEXT_DECORATION: 00931 // none | [ underline || overline || line-through || blink ] | inherit 00932 if (id == CSS_VAL_NONE) { 00933 valid_primitive = true; 00934 } else { 00935 CSSValueListImpl *list = new CSSValueListImpl; 00936 bool is_valid = true; 00937 while( is_valid && value ) { 00938 switch ( value->id ) { 00939 case CSS_VAL_BLINK: 00940 break; 00941 case CSS_VAL_UNDERLINE: 00942 case CSS_VAL_OVERLINE: 00943 case CSS_VAL_LINE_THROUGH: 00944 list->append( new CSSPrimitiveValueImpl( value->id ) ); 00945 break; 00946 default: 00947 is_valid = false; 00948 } 00949 value = valueList->next(); 00950 } 00951 //kdDebug( 6080 ) << "got " << list->length() << "d decorations" << endl; 00952 if(list->length() && is_valid) { 00953 parsedValue = list; 00954 valueList->next(); 00955 } else { 00956 delete list; 00957 } 00958 } 00959 break; 00960 00961 case CSS_PROP_TABLE_LAYOUT: // auto | fixed | inherit 00962 if ( id == CSS_VAL_AUTO || id == CSS_VAL_FIXED ) 00963 valid_primitive = true; 00964 break; 00965 00966 case CSS_PROP__KHTML_FLOW_MODE: 00967 if ( id == CSS_VAL__KHTML_NORMAL || id == CSS_VAL__KHTML_AROUND_FLOATS ) 00968 valid_primitive = true; 00969 break; 00970 00971 /* CSS3 properties */ 00972 case CSS_PROP__KHTML_USER_INPUT: // none | enabled | disabled | inherit 00973 if ( id == CSS_VAL_NONE || id == CSS_VAL_ENABLED || id == CSS_VAL_DISABLED ) 00974 valid_primitive = true; 00975 // kdDebug(6080) << "CSS_PROP__KHTML_USER_INPUT: " << valid_primitive << endl; 00976 break; 00977 case CSS_PROP__KHTML_MARQUEE: { 00978 const int properties[5] = { CSS_PROP__KHTML_MARQUEE_DIRECTION, CSS_PROP__KHTML_MARQUEE_INCREMENT, 00979 CSS_PROP__KHTML_MARQUEE_REPETITION, 00980 CSS_PROP__KHTML_MARQUEE_STYLE, CSS_PROP__KHTML_MARQUEE_SPEED }; 00981 return parseShortHand(properties, 5, important); 00982 } 00983 case CSS_PROP__KHTML_MARQUEE_DIRECTION: 00984 if (id == CSS_VAL_FORWARDS || id == CSS_VAL_BACKWARDS || id == CSS_VAL_AHEAD || 00985 id == CSS_VAL_REVERSE || id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_DOWN || 00986 id == CSS_VAL_UP || id == CSS_VAL_AUTO) 00987 valid_primitive = true; 00988 break; 00989 case CSS_PROP__KHTML_MARQUEE_INCREMENT: 00990 if (id == CSS_VAL_SMALL || id == CSS_VAL_LARGE || id == CSS_VAL_MEDIUM) 00991 valid_primitive = true; 00992 else 00993 valid_primitive = validUnit(value, FLength|FPercent, strict&(!nonCSSHint)); 00994 break; 00995 case CSS_PROP__KHTML_MARQUEE_STYLE: 00996 if (id == CSS_VAL_NONE || id == CSS_VAL_SLIDE || id == CSS_VAL_SCROLL || id == CSS_VAL_ALTERNATE || 00997 id == CSS_VAL_UNFURL) 00998 valid_primitive = true; 00999 break; 01000 case CSS_PROP__KHTML_MARQUEE_REPETITION: 01001 if (id == CSS_VAL_INFINITE) 01002 valid_primitive = true; 01003 else 01004 valid_primitive = validUnit(value, FInteger|FNonNeg, strict&(!nonCSSHint)); 01005 break; 01006 case CSS_PROP__KHTML_MARQUEE_SPEED: 01007 if (id == CSS_VAL_NORMAL || id == CSS_VAL_SLOW || id == CSS_VAL_FAST) 01008 valid_primitive = true; 01009 else 01010 valid_primitive = validUnit(value, FTime|FInteger|FNonNeg, strict&(!nonCSSHint)); 01011 break; 01012 // End of CSS3 properties 01013 01014 /* shorthand properties */ 01015 case CSS_PROP_BACKGROUND: 01016 // ['background-color' || 'background-image' ||'background-repeat' || 01017 // 'background-attachment' || 'background-position'] | inherit 01018 { 01019 const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT, 01020 CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION, 01021 CSS_PROP_BACKGROUND_COLOR }; 01022 return parseShortHand(properties, 5, important); 01023 } 01024 case CSS_PROP_BORDER: 01025 // [ 'border-width' || 'border-style' || <color> ] | inherit 01026 { 01027 const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE, 01028 CSS_PROP_BORDER_COLOR }; 01029 return parseShortHand(properties, 3, important); 01030 } 01031 case CSS_PROP_BORDER_TOP: 01032 // [ 'border-top-width' || 'border-style' || <color> ] | inherit 01033 { 01034 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE, 01035 CSS_PROP_BORDER_TOP_COLOR}; 01036 return parseShortHand(properties, 3, important); 01037 } 01038 case CSS_PROP_BORDER_RIGHT: 01039 // [ 'border-right-width' || 'border-style' || <color> ] | inherit 01040 { 01041 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE, 01042 CSS_PROP_BORDER_RIGHT_COLOR }; 01043 return parseShortHand(properties, 3, important); 01044 } 01045 case CSS_PROP_BORDER_BOTTOM: 01046 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit 01047 { 01048 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE, 01049 CSS_PROP_BORDER_BOTTOM_COLOR }; 01050 return parseShortHand(properties, 3, important); 01051 } 01052 case CSS_PROP_BORDER_LEFT: 01053 // [ 'border-left-width' || 'border-style' || <color> ] | inherit 01054 { 01055 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE, 01056 CSS_PROP_BORDER_LEFT_COLOR }; 01057 return parseShortHand(properties, 3, important); 01058 } 01059 case CSS_PROP_OUTLINE: 01060 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit 01061 { 01062 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE, 01063 CSS_PROP_OUTLINE_COLOR }; 01064 return parseShortHand(properties, 3, important); 01065 } 01066 case CSS_PROP_BORDER_COLOR: 01067 // <color>{1,4} | transparent | inherit 01068 { 01069 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR, 01070 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR }; 01071 return parse4Values(properties, important); 01072 } 01073 case CSS_PROP_BORDER_WIDTH: 01074 // <border-width>{1,4} | inherit 01075 { 01076 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH, 01077 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH }; 01078 return parse4Values(properties, important); 01079 } 01080 case CSS_PROP_BORDER_STYLE: 01081 // <border-style>{1,4} | inherit 01082 { 01083 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE, 01084 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE }; 01085 return parse4Values(properties, important); 01086 } 01087 case CSS_PROP_MARGIN: 01088 // <margin-width>{1,4} | inherit 01089 { 01090 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT, 01091 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT }; 01092 return parse4Values(properties, important); 01093 } 01094 case CSS_PROP_PADDING: 01095 // <padding-width>{1,4} | inherit 01096 { 01097 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT, 01098 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT }; 01099 return parse4Values(properties, important); 01100 } 01101 case CSS_PROP_FONT: 01102 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 01103 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit 01104 if ( id >= CSS_VAL_CAPTION && id <= CSS_VAL_STATUS_BAR ) 01105 valid_primitive = true; 01106 else 01107 return parseFont(important); 01108 01109 case CSS_PROP_LIST_STYLE: 01110 { 01111 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION, 01112 CSS_PROP_LIST_STYLE_IMAGE }; 01113 return parseShortHand(properties, 3, important); 01114 } 01115 default: 01116 // #ifdef CSS_DEBUG 01117 // kdDebug( 6080 ) << "illegal or CSS2 Aural property: " << val << endl; 01118 // #endif 01119 break; 01120 } 01121 01122 if ( valid_primitive ) { 01123 if ( id != 0 ) { 01124 // qDebug(" new value: id=%d", id ); 01125 parsedValue = new CSSPrimitiveValueImpl( id ); 01126 } else if ( value->unit == CSSPrimitiveValue::CSS_STRING ) 01127 parsedValue = new CSSPrimitiveValueImpl( domString( value->string ), 01128 (CSSPrimitiveValue::UnitTypes) value->unit ); 01129 else if ( value->unit >= CSSPrimitiveValue::CSS_NUMBER && 01130 value->unit <= CSSPrimitiveValue::CSS_KHZ ) { 01131 // qDebug(" new value: value=%.2f, unit=%d", value->fValue, value->unit ); 01132 parsedValue = new CSSPrimitiveValueImpl( value->fValue, 01133 (CSSPrimitiveValue::UnitTypes) value->unit ); 01134 } else if ( value->unit >= Value::Q_EMS ) { 01135 // qDebug(" new quirks value: value=%.2f, unit=%d", value->fValue, value->unit ); 01136 parsedValue = new CSSQuirkPrimitiveValueImpl( value->fValue, CSSPrimitiveValue::CSS_EMS ); 01137 } 01138 valueList->next(); 01139 } 01140 if ( parsedValue ) { 01141 addProperty( propId, parsedValue, important ); 01142 return true; 01143 } 01144 return false; 01145 } 01146 01147 bool CSSParser::parseShortHand( const int *properties, int numProperties, bool important ) 01148 { 01149 /* We try to match as many properties as possible 01150 * We setup an array of booleans to mark which property has been found, 01151 * and we try to search for properties until it makes no longer any sense 01152 */ 01153 inParseShortHand = true; 01154 01155 bool found = false; 01156 bool fnd[6]; //Trust me ;) 01157 for( int i = 0; i < numProperties; i++ ) 01158 fnd[i] = false; 01159 01160 #ifdef CSS_DEBUG 01161 kdDebug(6080) << "PSH: numProperties=" << numProperties << endl; 01162 #endif 01163 01164 while ( valueList->current() ) { 01165 found = false; 01166 // qDebug("outer loop" ); 01167 for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) { 01168 if (!fnd[propIndex]) { 01169 #ifdef CSS_DEBUG 01170 kdDebug(6080) << "LOOKING FOR: " << getPropertyName(properties[propIndex]).string() << endl; 01171 #endif 01172 if ( parseValue( properties[propIndex], important ) ) { 01173 fnd[propIndex] = found = true; 01174 #ifdef CSS_DEBUG 01175 kdDebug(6080) << "FOUND: " << getPropertyName(properties[propIndex]).string() << endl; 01176 #endif 01177 } 01178 } 01179 } 01180 // if we didn't find at least one match, this is an 01181 // invalid shorthand and we have to ignore it 01182 if (!found) { 01183 #ifdef CSS_DEBUG 01184 qDebug("didn't find anything" ); 01185 #endif 01186 inParseShortHand = false; 01187 return false; 01188 } 01189 } 01190 01191 // Fill in any remaining properties with the initial value. 01192 for (int i = 0; i < numProperties; ++i) { 01193 if (!fnd[i]) 01194 addProperty(properties[i], new CSSInitialValueImpl(), important); 01195 } 01196 01197 inParseShortHand = false; 01198 #ifdef CSS_DEBUG 01199 kdDebug( 6080 ) << "parsed shorthand" << endl; 01200 #endif 01201 return true; 01202 } 01203 01204 bool CSSParser::parse4Values( const int *properties, bool important ) 01205 { 01206 /* From the CSS 2 specs, 8.3 01207 * If there is only one value, it applies to all sides. If there are two values, the top and 01208 * bottom margins are set to the first value and the right and left margins are set to the second. 01209 * If there are three values, the top is set to the first value, the left and right are set to the 01210 * second, and the bottom is set to the third. If there are four values, they apply to the top, 01211 * right, bottom, and left, respectively. 01212 */ 01213 01214 int num = inParseShortHand ? 1 : valueList->numValues; 01215 // qDebug("parse4Values: num=%d", num ); 01216 01217 // the order is top, right, bottom, left 01218 switch( num ) { 01219 case 1: { 01220 if( !parseValue( properties[0], important ) ) return false; 01221 CSSValueImpl *value = parsedProperties[numParsedProperties-1]->value(); 01222 addProperty( properties[1], value, important ); 01223 addProperty( properties[2], value, important ); 01224 addProperty( properties[3], value, important ); 01225 return true; 01226 } 01227 case 2: { 01228 01229 if( !parseValue( properties[0], important ) ) return false; 01230 if( !parseValue( properties[1], important ) ) return false; 01231 CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value(); 01232 addProperty( properties[2], value, important ); 01233 value = parsedProperties[numParsedProperties-2]->value(); 01234 addProperty( properties[3], value, important ); 01235 return true; 01236 } 01237 case 3: { 01238 if( !parseValue( properties[0], important ) ) return false; 01239 if( !parseValue( properties[1], important ) ) return false; 01240 if( !parseValue( properties[2], important ) ) return false; 01241 CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value(); 01242 addProperty( properties[3], value, important ); 01243 return true; 01244 } 01245 case 4: { 01246 if( !parseValue( properties[0], important ) ) return false; 01247 if( !parseValue( properties[1], important ) ) return false; 01248 if( !parseValue( properties[2], important ) ) return false; 01249 if( !parseValue( properties[3], important ) ) return false; 01250 return true; 01251 } 01252 default: 01253 return false; 01254 } 01255 } 01256 01257 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit 01258 // in CSS 2.1 this got somewhat reduced: 01259 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit 01260 bool CSSParser::parseContent( int propId, bool important ) 01261 { 01262 CSSValueListImpl* values = new CSSValueListImpl(); 01263 01264 Value *val; 01265 CSSValueImpl *parsedValue = 0; 01266 while ( (val = valueList->current()) ) { 01267 if ( val->unit == CSSPrimitiveValue::CSS_URI ) { 01268 // url 01269 DOMString value = khtml::parseURL(domString(val->string)); 01270 parsedValue = new CSSImageValueImpl( 01271 DOMString(KURL( styleElement->baseURL(), value.string()).url() ), styleElement ); 01272 #ifdef CSS_DEBUG 01273 kdDebug( 6080 ) << "content, url=" << value.string() << " base=" << styleElement->baseURL().url( ) << endl; 01274 #endif 01275 } else if ( val->unit == Value::Function ) { 01276 // attr( X ) 01277 ValueList *args = val->function->args; 01278 QString fname = qString( val->function->name ).lower(); 01279 if ( fname != "attr(" || !args ) 01280 return false; 01281 if ( args->numValues != 1) 01282 return false; 01283 Value *a = args->current(); 01284 parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR); 01285 } else if ( val->unit == CSSPrimitiveValue::CSS_IDENT ) { 01286 // open-quote 01287 // close-quote 01288 // no-open-quote 01289 // no-close-quote 01290 } else if ( val->unit == CSSPrimitiveValue::CSS_STRING ) { 01291 parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING); 01292 } 01293 if (parsedValue) 01294 values->append(parsedValue); 01295 else 01296 break; 01297 valueList->next(); 01298 } 01299 if ( values->length() ) { 01300 addProperty( propId, values, important ); 01301 valueList->next(); 01302 return true; 01303 } 01304 delete values; 01305 return false; 01306 } 01307 01308 bool CSSParser::parseShape( int propId, bool important ) 01309 { 01310 Value *value = valueList->current(); 01311 ValueList *args = value->function->args; 01312 QString fname = qString( value->function->name ).lower(); 01313 //qDebug( "parseShape: fname: %d", fname.latin1() ); 01314 if ( fname != "rect(" || !args ) 01315 return false; 01316 01317 // rect( t, r, b, l ) || rect( t r b l ) 01318 if ( args->numValues != 4 && args->numValues != 7 ) 01319 return false; 01320 RectImpl *rect = new RectImpl(); 01321 bool valid = true; 01322 int i = 0; 01323 Value *a = args->current(); 01324 while ( a ) { 01325 valid = validUnit( a, FLength, strict ); 01326 if ( !valid ) 01327 break; 01328 CSSPrimitiveValueImpl *length = 01329 new CSSPrimitiveValueImpl( a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit ); 01330 if ( i == 0 ) 01331 rect->setTop( length ); 01332 else if ( i == 1 ) 01333 rect->setRight( length ); 01334 else if ( i == 2 ) 01335 rect->setBottom( length ); 01336 else 01337 rect->setLeft( length ); 01338 a = args->next(); 01339 if ( a && args->numValues == 7 ) { 01340 if ( a->unit == Value::Operator && a->iValue == ',' ) { 01341 a = args->next(); 01342 } else { 01343 valid = false; 01344 break; 01345 } 01346 } 01347 i++; 01348 } 01349 if ( valid ) { 01350 addProperty( propId, new CSSPrimitiveValueImpl( rect ), important ); 01351 valueList->next(); 01352 return true; 01353 } 01354 delete rect; 01355 return false; 01356 } 01357 01358 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family' 01359 bool CSSParser::parseFont( bool important ) 01360 { 01361 // kdDebug(6080) << "parsing font property current=" << valueList->currentValue << endl; 01362 bool valid = true; 01363 Value *value = valueList->current(); 01364 FontValueImpl *font = new FontValueImpl; 01365 // optional font-style, font-variant and font-weight 01366 while ( value ) { 01367 // kdDebug( 6080 ) << "got value " << value->id << " / " << (value->unit == CSSPrimitiveValue::CSS_STRING || 01368 // value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null ) 01369 // << endl; 01370 int id = value->id; 01371 if ( id ) { 01372 if ( id == CSS_VAL_NORMAL ) { 01373 // do nothing, it's the initial value for all three 01374 } 01375 /* 01376 else if ( id == CSS_VAL_INHERIT ) { 01377 // set all non set ones to inherit 01378 // This is not that simple as the inherit could also apply to the following font-size. 01379 // very ahrd to tell without looking ahead. 01380 inherit = true; 01381 } */ 01382 else if ( id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE ) { 01383 if ( font->style ) 01384 goto invalid; 01385 font->style = new CSSPrimitiveValueImpl( id ); 01386 } else if ( id == CSS_VAL_SMALL_CAPS ) { 01387 if ( font->variant ) 01388 goto invalid; 01389 font->variant = new CSSPrimitiveValueImpl( id ); 01390 } else if ( id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER ) { 01391 if ( font->weight ) 01392 goto invalid; 01393 font->weight = new CSSPrimitiveValueImpl( id ); 01394 } else { 01395 valid = false; 01396 } 01397 } else if ( !font->weight && validUnit( value, FInteger|FNonNeg, true ) ) { 01398 int weight = (int)value->fValue; 01399 int val = 0; 01400 if ( weight == 100 ) 01401 val = CSS_VAL_100; 01402 else if ( weight == 200 ) 01403 val = CSS_VAL_200; 01404 else if ( weight == 300 ) 01405 val = CSS_VAL_300; 01406 else if ( weight == 400 ) 01407 val = CSS_VAL_400; 01408 else if ( weight == 500 ) 01409 val = CSS_VAL_500; 01410 else if ( weight == 600 ) 01411 val = CSS_VAL_600; 01412 else if ( weight == 700 ) 01413 val = CSS_VAL_700; 01414 else if ( weight == 800 ) 01415 val = CSS_VAL_800; 01416 else if ( weight == 900 ) 01417 val = CSS_VAL_900; 01418 01419 if ( val ) 01420 font->weight = new CSSPrimitiveValueImpl( val ); 01421 else 01422 valid = false; 01423 } else { 01424 valid = false; 01425 } 01426 if ( !valid ) 01427 break; 01428 value = valueList->next(); 01429 } 01430 if ( !value ) 01431 goto invalid; 01432 01433 // set undefined values to default 01434 if ( !font->style ) 01435 font->style = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL ); 01436 if ( !font->variant ) 01437 font->variant = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL ); 01438 if ( !font->weight ) 01439 font->weight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL ); 01440 01441 // kdDebug( 6080 ) << " got style, variant and weight current=" << valueList->currentValue << endl; 01442 01443 // now a font size _must_ come 01444 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit 01445 if ( value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER ) 01446 font->size = new CSSPrimitiveValueImpl( value->id ); 01447 else if ( validUnit( value, FLength|FPercent, strict ) ) { 01448 font->size = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit ); 01449 } 01450 value = valueList->next(); 01451 if ( !font->size || !value ) 01452 goto invalid; 01453 01454 // kdDebug( 6080 ) << " got size" << endl; 01455 01456 if ( value->unit == Value::Operator && value->iValue == '/' ) { 01457 // line-height 01458 value = valueList->next(); 01459 if ( !value ) 01460 goto invalid; 01461 if ( value->id == CSS_VAL_NORMAL ) { 01462 // default value, nothing to do 01463 } else if ( validUnit( value, FNumber|FLength|FPercent, strict ) ) { 01464 font->lineHeight = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit ); 01465 } else { 01466 goto invalid; 01467 } 01468 value = valueList->next(); 01469 if ( !value ) 01470 goto invalid; 01471 } 01472 if ( !font->lineHeight ) 01473 font->lineHeight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL ); 01474 01475 // kdDebug( 6080 ) << " got line height current=" << valueList->currentValue << endl; 01476 // font family must come now 01477 font->family = parseFontFamily(); 01478 01479 if ( valueList->current() || !font->family ) 01480 goto invalid; 01481 //kdDebug( 6080 ) << " got family, parsing ok!" << endl; 01482 01483 addProperty( CSS_PROP_FONT, font, important ); 01484 return true; 01485 01486 invalid: 01487 //kdDebug(6080) << " -> invalid" << endl; 01488 delete font; 01489 return false; 01490 } 01491 01492 CSSValueListImpl *CSSParser::parseFontFamily() 01493 { 01494 // kdDebug( 6080 ) << "CSSParser::parseFontFamily current=" << valueList->currentValue << endl; 01495 CSSValueListImpl *list = new CSSValueListImpl; 01496 Value *value = valueList->current(); 01497 QString currFace; 01498 01499 while ( value ) { 01500 // kdDebug( 6080 ) << "got value " << value->id << " / " 01501 // << (value->unit == CSSPrimitiveValue::CSS_STRING || 01502 // value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null ) 01503 // << endl; 01504 Value* nextValue = valueList->next(); 01505 bool nextValBreaksFont = !nextValue || 01506 (nextValue->unit == Value::Operator && nextValue->iValue == ','); 01507 bool nextValIsFontName = nextValue && 01508 ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL_MONOSPACE) || 01509 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || 01510 nextValue->unit == CSSPrimitiveValue::CSS_IDENT)); 01511 01512 if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL_MONOSPACE) { 01513 if (!currFace.isNull()) { 01514 currFace += ' '; 01515 currFace += qString(value->string); 01516 } 01517 else if (nextValBreaksFont || !nextValIsFontName) { 01518 if ( !currFace.isNull() ) { 01519 list->append( new FontFamilyValueImpl( currFace ) ); 01520 currFace = QString::null; 01521 } 01522 list->append(new CSSPrimitiveValueImpl(value->id)); 01523 } 01524 else { 01525 currFace = qString( value->string ); 01526 } 01527 } 01528 else if (value->unit == CSSPrimitiveValue::CSS_STRING) { 01529 // Strings never share in a family name. 01530 currFace = QString::null; 01531 list->append(new FontFamilyValueImpl(qString( value->string) ) ); 01532 } 01533 else if (value->unit == CSSPrimitiveValue::CSS_IDENT) { 01534 if (!currFace.isNull()) { 01535 currFace += ' '; 01536 currFace += qString(value->string); 01537 } 01538 else if (nextValBreaksFont || !nextValIsFontName) { 01539 if ( !currFace.isNull() ) { 01540 list->append( new FontFamilyValueImpl( currFace ) ); 01541 currFace = QString::null; 01542 } 01543 list->append(new FontFamilyValueImpl( qString( value->string ) ) ); 01544 } 01545 else { 01546 currFace = qString( value->string); 01547 } 01548 } 01549 else { 01550 //kdDebug( 6080 ) << "invalid family part" << endl; 01551 break; 01552 } 01553 01554 if (!nextValue) 01555 break; 01556 01557 if (nextValBreaksFont) { 01558 value = valueList->next(); 01559 if ( !currFace.isNull() ) 01560 list->append( new FontFamilyValueImpl( currFace ) ); 01561 currFace = QString::null; 01562 } 01563 else if (nextValIsFontName) 01564 value = nextValue; 01565 else 01566 break; 01567 } 01568 01569 if ( !currFace.isNull() ) 01570 list->append( new FontFamilyValueImpl( currFace ) ); 01571 01572 if ( !list->length() ) { 01573 delete list; 01574 list = 0; 01575 } 01576 return list; 01577 } 01578 01579 01580 static bool parseColor(const QString &name, QRgb& rgb) 01581 { 01582 int len = name.length(); 01583 01584 if ( !len ) 01585 return false; 01586 01587 01588 bool ok; 01589 01590 if ( len == 3 || len == 6 ) { 01591 int val = name.toInt(&ok, 16); 01592 if ( ok ) { 01593 if (len == 6) { 01594 rgb = (0xff << 24) | val; 01595 return true; 01596 } 01597 else if ( len == 3 ) { 01598 // #abc converts to #aabbcc according to the specs 01599 rgb = (0xff << 24) | 01600 (val&0xf00)<<12 | (val&0xf00)<<8 | 01601 (val&0xf0)<<8 | (val&0xf0)<<4 | 01602 (val&0xf)<<4 | (val&0xf); 01603 return true; 01604 } 01605 } 01606 } 01607 01608 // try a little harder 01609 QColor tc; 01610 tc.setNamedColor(name.lower()); 01611 if ( tc.isValid() ) { 01612 rgb = tc.rgb(); 01613 return true; 01614 } 01615 01616 return false; 01617 } 01618 01619 01620 CSSPrimitiveValueImpl *CSSParser::parseColor() 01621 { 01622 QRgb c = khtml::transparentColor; 01623 Value *value = valueList->current(); 01624 if ( !strict && value->unit == CSSPrimitiveValue::CSS_NUMBER && 01625 value->fValue >= 0. && value->fValue < 1000000. ) { 01626 QString str; 01627 str.sprintf( "%06d", (int)(value->fValue+.5) ); 01628 if ( !::parseColor( str, c ) ) 01629 return 0; 01630 } else if ( value->unit == CSSPrimitiveValue::CSS_RGBCOLOR || 01631 value->unit == CSSPrimitiveValue::CSS_IDENT || 01632 (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION) ) { 01633 if ( !::parseColor( qString( value->string ), c) ) 01634 return 0; 01635 } 01636 else if ( value->unit == Value::Function && 01637 value->function->args != 0 && 01638 value->function->args->numValues == 5 /* rgb + two commas */ && 01639 qString( value->function->name ).lower() == "rgb(" ) { 01640 ValueList *args = value->function->args; 01641 Value *v = args->current(); 01642 if ( !validUnit( v, FInteger|FPercent, true ) ) 01643 return 0; 01644 int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) ); 01645 v = args->next(); 01646 if ( v->unit != Value::Operator && v->iValue != ',' ) 01647 return 0; 01648 v = args->next(); 01649 if ( !validUnit( v, FInteger|FPercent, true ) ) 01650 return 0; 01651 int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) ); 01652 v = args->next(); 01653 if ( v->unit != Value::Operator && v->iValue != ',' ) 01654 return 0; 01655 v = args->next(); 01656 if ( !validUnit( v, FInteger|FPercent, true ) ) 01657 return 0; 01658 int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) ); 01659 r = kMax( 0, kMin( 255, r ) ); 01660 g = kMax( 0, kMin( 255, g ) ); 01661 b = kMax( 0, kMin( 255, b ) ); 01662 c = qRgb( r, g, b ); 01663 } 01664 else if ( value->unit == Value::Function && 01665 value->function->args != 0 && 01666 value->function->args->numValues == 7 /* rgba + three commas */ && 01667 qString( value->function->name ).lower() == "rgba(" ) { 01668 ValueList *args = value->function->args; 01669 Value *v = args->current(); 01670 if ( !validUnit( v, FInteger|FPercent, true ) ) 01671 return 0; 01672 int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) ); 01673 v = args->next(); 01674 if ( v->unit != Value::Operator && v->iValue != ',' ) 01675 return 0; 01676 v = args->next(); 01677 if ( !validUnit( v, FInteger|FPercent, true ) ) 01678 return 0; 01679 int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) ); 01680 v = args->next(); 01681 if ( v->unit != Value::Operator && v->iValue != ',' ) 01682 return 0; 01683 v = args->next(); 01684 if ( !validUnit( v, FInteger|FPercent, true ) ) 01685 return 0; 01686 int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) ); 01687 v = args->next(); 01688 if ( v->unit != Value::Operator && v->iValue != ',' ) 01689 return 0; 01690 v = args->next(); 01691 if ( !validUnit( v, FNumber, true ) ) 01692 return 0; 01693 r = QMAX( 0, QMIN( 255, r ) ); 01694 g = QMAX( 0, QMIN( 255, g ) ); 01695 b = QMAX( 0, QMIN( 255, b ) ); 01696 int a = (int)(QMAX( 0, QMIN( 1.0f, v->fValue ) ) * 255); 01697 c = qRgba( r, g, b, a ); 01698 } 01699 else 01700 return 0; 01701 01702 return new CSSPrimitiveValueImpl(c); 01703 } 01704 01705 01706 static inline int yyerror( const char *str ) { 01707 // assert( 0 ); 01708 #ifdef CSS_DEBUG 01709 kdDebug( 6080 ) << "CSS parse error " << str << endl; 01710 #else 01711 Q_UNUSED( str ); 01712 #endif 01713 return 1; 01714 } 01715 01716 #define END 0 01717 01718 #include "parser.h" 01719 01720 int DOM::CSSParser::lex( void *_yylval ) 01721 { 01722 YYSTYPE *yylval = (YYSTYPE *)_yylval; 01723 int token = lex(); 01724 int length; 01725 unsigned short *t = text( &length ); 01726 01727 #ifdef TOKEN_DEBUG 01728 qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString( (QChar *)t, length ).latin1() ); 01729 #endif 01730 switch( token ) { 01731 case '{': 01732 block_nesting++; 01733 break; 01734 case '}': 01735 if ( block_nesting ) 01736 block_nesting--; 01737 break; 01738 case END: 01739 if ( block_nesting ) { 01740 block_nesting--; 01741 return '}'; 01742 } 01743 break; 01744 case S: 01745 case SGML_CD: 01746 case INCLUDES: 01747 case DASHMATCH: 01748 break; 01749 01750 case URI: 01751 case STRING: 01752 case IDENT: 01753 case HASH: 01754 case DIMEN: 01755 case UNICODERANGE: 01756 case FUNCTION: 01757 yylval->string.string = t; 01758 yylval->string.length = length; 01759 break; 01760 01761 case IMPORT_SYM: 01762 case PAGE_SYM: 01763 case MEDIA_SYM: 01764 case FONT_FACE_SYM: 01765 case CHARSET_SYM: 01766 01767 case IMPORTANT_SYM: 01768 break; 01769 01770 case QEMS: 01771 length--; 01772 case GRADS: 01773 length--; 01774 case DEGS: 01775 case RADS: 01776 case KHERZ: 01777 length--; 01778 case MSECS: 01779 case HERZ: 01780 case EMS: 01781 case EXS: 01782 case PXS: 01783 case CMS: 01784 case MMS: 01785 case INS: 01786 case PTS: 01787 case PCS: 01788 length--; 01789 case SECS: 01790 case PERCENTAGE: 01791 length--; 01792 case NUMBER: 01793 yylval->val = QString( (QChar *)t, length ).toDouble(); 01794 //qDebug("value = %s, converted=%.2f", QString( (QChar *)t, length ).latin1(), yylval->val ); 01795 break; 01796 01797 default: 01798 break; 01799 } 01800 01801 return token; 01802 } 01803 01804 static inline int toHex( char c ) { 01805 if ( '0' <= c && c <= '9' ) 01806 return c - '0'; 01807 if ( 'a' <= c && c <= 'f' ) 01808 return c - 'a' + 10; 01809 if ( 'A' <= c && c<= 'F' ) 01810 return c - 'A' + 10; 01811 return 0; 01812 } 01813 01814 unsigned short *DOM::CSSParser::text(int *length) 01815 { 01816 unsigned short *start = yytext; 01817 int l = yyleng; 01818 switch( yyTok ) { 01819 case STRING: 01820 l--; 01821 /* nobreak */ 01822 case HASH: 01823 start++; 01824 l--; 01825 break; 01826 case URI: 01827 // "url("{w}{string}{w}")" 01828 // "url("{w}{url}{w}")" 01829 01830 // strip "url(" and ")" 01831 start += 4; 01832 l -= 5; 01833 // strip {w} 01834 while ( l && 01835 (*start == ' ' || *start == '\t' || *start == '\r' || 01836 *start == '\n' || *start == '\f' ) ) { 01837 start++; l--; 01838 } 01839 if ( *start == '"' || *start == '\'' ) { 01840 start++; l--; 01841 } 01842 while ( l && 01843 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' || 01844 start[l-1] == '\n' || start[l-1] == '\f' ) ) { 01845 l--; 01846 } 01847 if ( l && (start[l-1] == '\"' || start[l-1] == '\'' ) ) 01848 l--; 01849 01850 default: 01851 break; 01852 } 01853 01854 // process escapes 01855 unsigned short *out = start; 01856 unsigned short *escape = 0; 01857 01858 for ( int i = 0; i < l; i++ ) { 01859 unsigned short *current = start+i; 01860 if ( escape == current - 1 ) { 01861 if ( ( *current >= '0' && *current <= '9' ) || 01862 ( *current >= 'a' && *current <= 'f' ) || 01863 ( *current >= 'A' && *current <= 'F' ) ) 01864 continue; 01865 if ( yyTok == STRING && 01866 ( *current == '\n' || *current == '\r' || *current == '\f' ) ) { 01867 // ### handle \r\n case 01868 if ( *current != '\r' ) 01869 escape = 0; 01870 continue; 01871 } 01872 // in all other cases copy the char to output 01873 // ### 01874 *out++ = *current; 01875 escape = 0; 01876 continue; 01877 } 01878 if ( escape == current - 2 && yyTok == STRING && 01879 *(current-1) == '\r' && *current == '\n' ) { 01880 escape = 0; 01881 continue; 01882 } 01883 if ( escape > current - 7 && 01884 ( ( *current >= '0' && *current <= '9' ) || 01885 ( *current >= 'a' && *current <= 'f' ) || 01886 ( *current >= 'A' && *current <= 'F' ) ) ) 01887 continue; 01888 if ( escape ) { 01889 // add escaped char 01890 int uc = 0; 01891 escape++; 01892 while ( escape < current ) { 01893 // qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) ); 01894 uc *= 16; 01895 uc += toHex( *escape ); 01896 escape++; 01897 } 01898 // qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc ); 01899 // can't handle chars outside ucs2 01900 if ( uc > 0xffff ) 01901 uc = 0xfffd; 01902 *(out++) = (unsigned short)uc; 01903 escape = 0; 01904 if ( *current == ' ' || 01905 *current == '\t' || 01906 *current == '\r' || 01907 *current == '\n' || 01908 *current == '\f' ) 01909 continue; 01910 } 01911 if ( !escape && *current == '\\' ) { 01912 escape = current; 01913 continue; 01914 } 01915 *(out++) = *current; 01916 } 01917 if ( escape ) { 01918 // add escaped char 01919 int uc = 0; 01920 escape++; 01921 while ( escape < start+l ) { 01922 // qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) ); 01923 uc *= 16; 01924 uc += toHex( *escape ); 01925 escape++; 01926 } 01927 // qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc ); 01928 // can't handle chars outside ucs2 01929 if ( uc > 0xffff ) 01930 uc = 0xfffd; 01931 *(out++) = (unsigned short)uc; 01932 } 01933 01934 *length = out - start; 01935 return start; 01936 } 01937 01938 01939 #define YY_DECL int DOM::CSSParser::lex() 01940 #define yyconst const 01941 typedef int yy_state_type; 01942 typedef unsigned int YY_CHAR; 01943 // this line makes sure we treat all Unicode chars correctly. 01944 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c) 01945 #define YY_DO_BEFORE_ACTION \ 01946 yytext = yy_bp; \ 01947 yyleng = (int) (yy_cp - yy_bp); \ 01948 yy_hold_char = *yy_cp; \ 01949 *yy_cp = 0; \ 01950 yy_c_buf_p = yy_cp; 01951 #define YY_BREAK break; 01952 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).latin1() ) 01953 #define YY_RULE_SETUP 01954 #define INITIAL 0 01955 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) 01956 #define YY_START ((yy_start - 1) / 2) 01957 #define yyterminate() yyTok = END; return yyTok 01958 #define YY_FATAL_ERROR(a) qFatal(a) 01959 #define BEGIN yy_start = 1 + 2 * 01960 #define COMMENT 1 01961 01962 #include "tokenizer.cpp"
KDE Logo
This file is part of the documentation for khtml Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:42:24 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003