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
00027
00028
00029
00030
00031 #include <assert.h>
00032
00033 #include "css/css_stylesheetimpl.h"
00034 #include "css/css_ruleimpl.h"
00035 #include "css/css_valueimpl.h"
00036 #include "css/csshelper.h"
00037
00038 #include "dom/css_stylesheet.h"
00039 #include "dom/css_rule.h"
00040 #include "dom/dom_string.h"
00041 #include "dom/dom_exception.h"
00042
00043 #include "xml/dom_nodeimpl.h"
00044 #include "html/html_documentimpl.h"
00045 #include "khtml_part.h"
00046 #include "khtmlview.h"
00047
00048 using namespace DOM;
00049
00050 #include <kdebug.h>
00051 #include <kglobal.h>
00052 #include <kglobalsettings.h>
00053 #include <kapplication.h>
00054
00055 #include "misc/htmlhashes.h"
00056 #include "misc/helper.h"
00057
00058
00059
00060
00061
00062
00063
00064 #include "cssproperties.c"
00065 #include "cssvalues.c"
00066
00067
00068 static QPtrList<CSSProperty>* m_propList;
00069 static bool m_bImportant;
00070 static bool m_bnonCSSHint;
00071
00072 int DOM::getPropertyID(const char *tagStr, int len)
00073 {
00074 const struct props *propsPtr = findProp(tagStr, len);
00075 if (!propsPtr)
00076 return 0;
00077
00078 return propsPtr->id;
00079 }
00080
00081
00082
00083 void StyleBaseImpl::checkLoaded()
00084 {
00085 if(m_parent) m_parent->checkLoaded();
00086 }
00087
00088 DOMString StyleBaseImpl::baseURL()
00089 {
00090
00091
00092
00093 StyleBaseImpl *b = this;
00094 while(b && !b->isStyleSheet())
00095 b = b->m_parent;
00096
00097 if(!b) return DOMString();
00098
00099 StyleSheetImpl *sheet = static_cast<StyleSheetImpl *>(b);
00100 if(!sheet->href().isNull())
00101 return sheet->href();
00102
00103
00104 if(sheet->parent()) return sheet->parent()->baseURL();
00105
00106 if(!sheet->ownerNode()) return DOMString();
00107
00108 DocumentImpl *doc = sheet->ownerNode()->getDocument();
00109
00110 return doc->baseURL();
00111 }
00112
00113
00114
00115
00116
00117 const QChar *
00118 StyleBaseImpl::parseSpace(const QChar *curP, const QChar *endP)
00119 {
00120 bool sc = false;
00121 bool ec = false;
00122 bool ic = false;
00123
00124 while (curP < endP)
00125 {
00126 if (ic)
00127 {
00128 if (ec && (*curP == '/'))
00129 ic = false;
00130 else if (*curP == '*')
00131 ec = true;
00132 else
00133 ec = false;
00134 }
00135 else if (sc && (*curP == '*'))
00136 {
00137 ic = true;
00138 }
00139 else if (*curP == '/')
00140 {
00141 sc = true;
00142 }
00143
00144 else if (!(curP->isSpace()))
00145 {
00146 return(curP);
00147 }
00148 else
00149 {
00150 sc = false;
00151 }
00152 curP++;
00153 }
00154
00155 return(0);
00156 }
00157
00158
00159
00160
00161
00162
00163
00164 const QChar *
00165 StyleBaseImpl::parseToChar(const QChar *curP, const QChar *endP, QChar c, bool chkws, bool endAtBlock)
00166 {
00167
00168
00169 bool sq = false;
00170 bool dq = false;
00171 bool esc = false;
00172
00173 while (curP < endP)
00174 {
00175 if (esc)
00176 esc = false;
00177 else if (*curP == '\\')
00178 esc = true;
00179 else if (!sq && (*curP == '"'))
00180 dq = !dq;
00181 else if (!dq && (*curP == '\''))
00182 sq = !sq;
00183 else if (!sq && !dq && *curP == c)
00184 return(curP);
00185 else if (!sq && !dq && chkws && curP->isSpace())
00186 return(curP);
00187 else if(!sq && !dq ) {
00188 if (*curP == '{') {
00189 if(endAtBlock)
00190 return curP;
00191 curP = parseToChar(curP + 1, endP, '}', false);
00192 if (!curP)
00193 return(0);
00194 } else if (*curP == '(') {
00195 curP = parseToChar(curP + 1, endP, ')', false);
00196 if (!curP)
00197 return(0);
00198 } else if (*curP == '[') {
00199 curP = parseToChar(curP + 1, endP, ']', false);
00200 if (!curP)
00201 return(0);
00202 }
00203 }
00204 curP++;
00205 }
00206
00207 return(0);
00208 }
00209
00210 CSSRuleImpl *
00211 StyleBaseImpl::parseAtRule(const QChar *&curP, const QChar *endP)
00212 {
00213 curP++;
00214 const QChar *startP = curP;
00215 while( *curP != ' ' && *curP != '{' && *curP != '\'')
00216 curP++;
00217
00218 QString rule(startP, curP-startP);
00219 rule = rule.lower();
00220
00221
00222
00223 if(rule == "import")
00224 {
00225
00226 curP = parseSpace(curP, endP);
00227 if(!curP) return 0;
00228 startP = curP++;
00229 curP = parseToChar(startP, endP, ';', true);
00230
00231
00232
00233 if( !curP || hasInlinedDecl ) return 0;
00234 DOMString url = khtml::parseURL(DOMString(startP, curP - startP));
00235 startP = curP;
00236 if(*curP != ';')
00237 curP = parseToChar(startP, endP, ';', false, true);
00238 if(!curP) return 0;
00239
00240 DOMString mediaList = DOMString( startP, curP - startP);
00241
00242
00243 #ifdef CSS_DEBUG
00244 kdDebug( 6080 ) << "import rule = " << url.string() << ", mediaList = "
00245 << mediaList.string() << endl;
00246 #endif
00247
00248 if( *curP == '{' ) {
00249 curP++;
00250 curP = parseToChar(curP, endP, '}', false);
00251 if(curP)
00252 curP++;
00253 }
00254 if(!this->isCSSStyleSheet()) return 0;
00255
00256 return new CSSImportRuleImpl( this, url, mediaList );
00257 }
00258 else if(rule == "charset")
00259 {
00260
00261 startP = curP++;
00262 curP = parseToChar(startP, endP, ';', false);
00263 #ifdef CSS_DEBUG
00264 kdDebug( 6080 ) << "charset = " << QString(startP, curP - startP) << endl;
00265 #endif
00266 }
00267 else if(rule == "font-face")
00268 {
00269 startP = curP++;
00270 curP = parseToChar(startP, endP, '{', false);
00271 if ( !curP || curP >= endP ) return 0;
00272 curP++;
00273 curP = parseToChar(curP, endP, '}', false);
00274 #ifdef CSS_DEBUG
00275 kdDebug( 6080 ) << "font rule = " << QString(startP, curP - startP) << endl;
00276 #endif
00277 }
00278 else if(rule == "media")
00279 {
00280 startP = curP++;
00281 curP = parseToChar(startP, endP, '{', false);
00282
00283 if ( !curP || curP >= endP ) return 0;
00284 DOMString mediaList = DOMString( startP, curP - startP);
00285 curP++;
00286 startP = curP;
00287 if ( curP >= endP ) return 0;
00288 curP = parseToChar(curP, endP, '}', false);
00289 if ( !curP || startP >= curP )
00290 return 0;
00291 #ifdef CSS_DEBUG
00292 kdDebug( 6080 ) << "media rule = " << QString(startP, curP - startP)
00293 << ", mediaList = " << mediaList.string() << endl;
00294 #endif
00295 return new CSSMediaRuleImpl( this, startP, curP, mediaList );
00296 }
00297 else if(rule == "page")
00298 {
00299 startP = curP++;
00300 curP = parseToChar(startP, endP, '{', false);
00301 if ( !curP || curP >= endP ) return 0;
00302 curP++;
00303 curP = parseToChar(curP, endP, '}', false);
00304 #ifdef CSS_DEBUG
00305 kdDebug( 6080 ) << "page rule = " << QString(startP, curP - startP) << endl;
00306 #endif
00307 }
00308
00309
00310 return 0;
00311 }
00312
00313 static DOMString getValue( const QChar *curP, const QChar *endP, const QChar *&endVal)
00314 {
00315
00316
00317 endVal = curP;
00318 endVal++;
00319 while( endVal < endP && *endVal != '.' && *endVal != ':' && *endVal != '[' )
00320 endVal++;
00321 const QChar *end = endVal;
00322 if(endVal == endP)
00323 endVal = 0;
00324 return DOMString( curP, end - curP);
00325 }
00326
00327 CSSSelector *
00328 StyleBaseImpl::parseSelector2(const QChar *curP, const QChar *endP,
00329 CSSSelector::Relation relation)
00330 {
00331 CSSSelector *cs = new CSSSelector();
00332 #ifdef CSS_DEBUG
00333 QString selecString( curP, endP - curP );
00334 kdDebug( 6080 ) << "selectString = \"" << selecString << "\"" << endl;
00335 #endif
00336 const QChar *endVal = 0;
00337
00338 if (*curP == '#' && (curP < endP && !((*(curP+1)).isDigit())))
00339 {
00340 cs->tag = -1;
00341 cs->attr = ATTR_ID;
00342 cs->match = CSSSelector::Exact;
00343 cs->value = getValue( curP+1, endP, endVal);
00344 }
00345 else if (*curP == '.' && curP < endP && ( !strictParsing || !(*(curP+1)).isDigit() ) )
00346 {
00347 cs->tag = -1;
00348 cs->attr = ATTR_CLASS;
00349 cs->match = CSSSelector::List;
00350 cs->value = getValue( curP+1, endP, endVal);
00351 }
00352 else if (*curP == ':' && (curP < endP && !((*(curP+1)).isDigit())))
00353 {
00354
00355 cs->tag = -1;
00356 cs->match = CSSSelector::Pseudo;
00357 cs->value = getValue(curP+1, endP, endVal);
00358 cs->value = cs->value.implementation()->lower();
00359 }
00360 else
00361 {
00362 const QChar *startP = curP;
00363 QString tag;
00364 while (curP < endP)
00365 {
00366 if (*curP =='#' && (curP < endP && !((*(curP+1)).isDigit())))
00367 {
00368 tag = QString( startP, curP-startP );
00369 cs->attr = ATTR_ID;
00370 cs->match = CSSSelector::Exact;
00371 cs->value = getValue(curP+1, endP, endVal);
00372 break;
00373 }
00374 else if (*curP == '.' && curP < endP && ( !strictParsing || !(*(curP+1)).isDigit() ) )
00375 {
00376 tag = QString( startP, curP - startP );
00377 cs->attr = ATTR_CLASS;
00378 cs->match = CSSSelector::List;
00379 cs->value = getValue(curP+1, endP, endVal);
00380 break;
00381 }
00382 else if (*curP == ':' && (curP < endP && !((*(curP+1)).isDigit())))
00383 {
00384
00385 tag = QString( startP, curP - startP );
00386 cs->match = CSSSelector::Pseudo;
00387 cs->value = getValue(curP+1, endP, endVal);
00388 cs->value = cs->value.implementation()->lower();
00389 break;
00390 }
00391 else if (*curP == '[')
00392 {
00393 tag = QString( startP, curP - startP );
00394 curP++;
00395 if ( curP >= endP ) {
00396 delete cs;
00397 return 0;
00398 }
00399 #ifdef CSS_DEBUG
00400 kdDebug( 6080 ) << "tag = \"" << tag << "\"" << endl;
00401 #endif
00402 const QChar *closebracket = parseToChar(curP, endP, ']', false);
00403 if (!closebracket)
00404 {
00405 kdWarning()<<"error in css: closing bracket not found!"<<endl;
00406 delete cs;
00407 return 0;
00408 }
00409 QString attr;
00410 const QChar *equal = parseToChar(curP, closebracket, '=', false);
00411 if(!equal)
00412 {
00413 attr = QString( curP, closebracket - curP );
00414 attr = attr.stripWhiteSpace();
00415 #ifdef CSS_DEBUG
00416 kdDebug( 6080 ) << "attr = '" << attr << "'" << endl;
00417 #endif
00418 cs->match = CSSSelector::Set;
00419 endVal = closebracket + 1;
00420
00421 if( endVal == endP )
00422 endVal = 0;
00423 }
00424 else
00425 {
00426
00427
00428 if(*(equal-1) == '~')
00429 {
00430 attr = QString( curP, equal - curP - 1 );
00431 cs->match = CSSSelector::List;
00432 }
00433 else if(*(equal-1) == '|')
00434 {
00435 attr = QString( curP, equal - curP - 1 );
00436 cs->match = CSSSelector::Hyphen;
00437 }
00438 else if(*(equal-1) == '^')
00439 {
00440 attr = QString( curP, equal - curP - 1);
00441 cs->match = CSSSelector::Begin;
00442 }
00443 else if(*(equal-1) == '$')
00444 {
00445 attr = QString( curP, equal - curP - 1);
00446 cs->match = CSSSelector::End;
00447 }
00448 else if(*(equal-1) == '*')
00449 {
00450 attr = QString( curP, equal - curP - 1);
00451 cs->match = CSSSelector::Contain;
00452 }
00453 else
00454 {
00455 attr = QString(curP, equal - curP );
00456 cs->match = CSSSelector::Exact;
00457 }
00458 }
00459 {
00460 attr = attr.stripWhiteSpace();
00461 StyleBaseImpl *root = this;
00462 DocumentImpl *doc = 0;
00463 while (root->parent())
00464 root = root->parent();
00465 if (root->isCSSStyleSheet())
00466 doc = static_cast<CSSStyleSheetImpl*>(root)->doc();
00467
00468 if ( doc ) {
00469 if (doc->isHTMLDocument())
00470 attr = attr.lower();
00471 const DOMString dattr(attr);
00472 cs->attr = doc->attrId(0, dattr.implementation(), false);
00473 }
00474 else {
00475 cs->attr = khtml::getAttrID(attr.lower().ascii(), attr.length());
00476
00477
00478 assert(cs->attr);
00479 }
00480 if (!cs->attr) {
00481 delete cs;
00482 return 0;
00483 }
00484 }
00485 if(equal)
00486 {
00487 equal++;
00488 while(equal < endP && *equal == ' ')
00489 equal++;
00490 if(equal >= endP ) {
00491 delete cs;
00492 return 0;
00493 }
00494 endVal = equal;
00495 bool hasQuote = false;
00496 if(*equal == '\'') {
00497 equal++;
00498 endVal++;
00499 while(endVal < endP && *endVal != '\'')
00500 endVal++;
00501 hasQuote = true;
00502 } else if(*equal == '\"') {
00503 equal++;
00504 endVal++;
00505 while(endVal < endP && *endVal != '\"')
00506 endVal++;
00507 hasQuote = true;
00508 } else {
00509 while(endVal < endP && *endVal != ']')
00510 endVal++;
00511 }
00512 cs->value = DOMString(equal, endVal - equal);
00513 if ( hasQuote ) {
00514 while( endVal < endP - 1 && *endVal != ']' )
00515 endVal++;
00516 }
00517 endVal++;
00518
00519 if( endVal == endP )
00520 endVal = 0;
00521 }
00522 break;
00523 }
00524 else
00525 {
00526 curP++;
00527 }
00528 }
00529 if (curP == endP)
00530 {
00531 tag = QString( startP, curP - startP );
00532 }
00533 if(tag.isEmpty() || tag == "*")
00534 {
00535
00536 cs->tag = -1;
00537 }
00538 else {
00539 StyleBaseImpl *root = this;
00540 DocumentImpl *doc = 0;
00541 while (root->parent())
00542 root = root->parent();
00543 if (root->isCSSStyleSheet())
00544 doc = static_cast<CSSStyleSheetImpl*>(root)->doc();
00545
00546 if ( doc ) {
00547 if (doc->isHTMLDocument())
00548 tag = tag.lower();
00549 const DOMString dtag(tag);
00550 cs->tag = doc->tagId(0, dtag.implementation(), false);
00551 }
00552 else {
00553 cs->tag = khtml::getTagID(tag.lower().ascii(), tag.length());
00554
00555
00556 assert(cs->tag);
00557 }
00558 if (!cs->tag) {
00559 delete cs;
00560 return 0;
00561 }
00562 }
00563 }
00564 #ifdef CSS_DEBUG
00565 kdDebug( 6080 ) << "[Selector: tag=" << cs->tag << " Attribute=" << cs->attr << " match=" << (int)cs->match << " value=" << cs->value.string() << " specificity=" << cs->specificity() << "]" << endl;
00566 #endif
00567
00568
00569
00570 if( endVal ) {
00571
00572 relation = CSSSelector::SubSelector;
00573 CSSSelector *stack = parseSelector2(endVal, endP, relation);
00574 cs->tagHistory = stack;
00575 cs->relation = relation;
00576 }
00577
00578 return cs;
00579 }
00580
00581 CSSSelector *
00582 StyleBaseImpl::parseSelector1(const QChar *curP, const QChar *endP)
00583 {
00584 #ifdef CSS_DEBUG
00585 kdDebug( 6080 ) << "selector1 is \'" << QString(curP, endP-curP) << "\'" << endl;
00586 #endif
00587
00588 CSSSelector *selecStack=0;
00589
00590 curP = parseSpace(curP, endP);
00591 if (!curP)
00592 return(0);
00593
00594 CSSSelector::Relation relation = CSSSelector::Descendant;
00595
00596 const QChar *startP = curP;
00597 while (curP && curP <= endP)
00598 {
00599 if ((curP == endP) || curP->isSpace() || *curP == '+' || *curP == '>')
00600 {
00601 CSSSelector *newsel = parseSelector2(startP, curP, relation);
00602 if (!newsel) {
00603 delete selecStack;
00604 return 0;
00605 }
00606 CSSSelector *end = newsel;
00607 while( end->tagHistory )
00608 end = end->tagHistory;
00609 end->tagHistory = selecStack;
00610 end->relation = relation;
00611 selecStack = newsel;
00612
00613 curP = parseSpace(curP, endP);
00614 if (!curP) {
00615 #ifdef CSS_DEBUG
00616 kdDebug( 6080 ) << "selector stack is:" << endl;
00617 selecStack->print();
00618 kdDebug( 6080 ) << endl;
00619 #endif
00620 return(selecStack);
00621 }
00622 relation = CSSSelector::Descendant;
00623 if(*curP == '+')
00624 {
00625 relation = CSSSelector::Sibling;
00626 curP++;
00627 curP = parseSpace(curP, endP);
00628 }
00629 else if(*curP == '>')
00630 {
00631 #ifdef CSS_DEBUG
00632 kdDebug( 6080 ) << "child selector" << endl;
00633 #endif
00634 relation = CSSSelector::Child;
00635 curP++;
00636 curP = parseSpace(curP, endP);
00637 }
00638
00639
00640 startP = curP;
00641 }
00642 else
00643 {
00644 curP++;
00645 }
00646 }
00647 #ifdef CSS_DEBUG
00648 selecStack->print();
00649 #endif
00650 return(selecStack);
00651 }
00652
00653 QPtrList<CSSSelector> *
00654 StyleBaseImpl::parseSelector(const QChar *curP, const QChar *endP)
00655 {
00656 #ifdef CSS_DEBUG
00657 kdDebug( 6080 ) << "selector is \'" << QString(curP, endP-curP) << "\'" << endl;
00658 #endif
00659
00660 QPtrList<CSSSelector> *slist = 0;
00661 const QChar *startP;
00662
00663 while (curP < endP)
00664 {
00665 startP = curP;
00666 curP = parseToChar(curP, endP, ',', false);
00667 if (!curP)
00668 curP = endP;
00669
00670 CSSSelector *selector = parseSelector1(startP, curP);
00671 if (selector)
00672 {
00673 if (!slist)
00674 {
00675 slist = new QPtrList<CSSSelector>;
00676 slist->setAutoDelete(true);
00677 }
00678 slist->append(selector);
00679 }
00680 else
00681 {
00682 #ifdef CSS_DEBUG
00683 kdDebug( 6080 ) << "invalid selector" << endl;
00684 #endif
00685
00686 delete slist;
00687 return 0;
00688 }
00689 curP++;
00690 }
00691 return slist;
00692 }
00693
00694
00695 void StyleBaseImpl::parseProperty(const QChar *curP, const QChar *endP)
00696 {
00697 m_bnonCSSHint = false;
00698 m_bImportant = false;
00699
00700
00701 curP = parseSpace(curP, endP);
00702 if (!curP)
00703 return;
00704
00705
00706 const QChar *colon = parseToChar(curP, endP, ':', true);
00707 if (!colon)
00708 return;
00709
00710 const QString propName( curP, colon - curP );
00711 #ifdef CSS_DEBUG
00712 kdDebug( 6080 ) << "Property-name = \"" << propName << "\"" << endl;
00713 #endif
00714
00715
00716 if (*colon != ':')
00717 {
00718
00719 colon = parseToChar(curP, endP, ':', false);
00720 if (!colon)
00721 return;
00722 }
00723 curP = colon+1;
00724
00725 while(curP < endP && *curP == ' ')
00726 curP++;
00727 if ( curP >= endP )
00728 return;
00729
00730
00731 const QChar *exclam = parseToChar(curP, endP, '!', false);
00732 if(exclam)
00733 {
00734
00735 QString s(exclam+1, endP - exclam - 1);
00736 s = s.stripWhiteSpace();
00737 s = s.lower();
00738 if(s != "important")
00739 return;
00740 m_bImportant = true;
00741 endP = exclam;
00742 #ifdef CSS_DEBUG
00743 kdDebug( 6080 ) << "important property!" << endl;
00744 #endif
00745 }
00746
00747
00748 while (endP > curP)
00749 {
00750
00751 if (!((endP-1)->isSpace()))
00752 break;
00753 endP--;
00754 }
00755
00756 #ifdef CSS_DEBUG
00757 QString propVal( curP , endP - curP );
00758 kdDebug( 6080 ) << "Property-value = \"" << propVal.latin1() << "\"" << endl;
00759 #endif
00760
00761 const struct props *propPtr = findProp(propName.lower().ascii(), propName.length());
00762 if (!propPtr)
00763 {
00764 #ifdef CSS_DEBUG
00765 kdDebug( 6080 ) << "Unknown property" << propName << endl;
00766 #endif
00767 return;
00768 }
00769
00770 unsigned int numProps = m_propList->count();
00771 if(!parseValue(curP, endP, propPtr->id)) {
00772 #ifdef CSS_DEBUG
00773 kdDebug(6080) << "invalid property, removing added properties from m_propList" << endl;
00774 #endif
00775 while(m_propList->count() > numProps)
00776 m_propList->removeLast();
00777 }
00778 }
00779
00780 QPtrList<CSSProperty> *StyleBaseImpl::parseProperties(const QChar *curP, const QChar *endP)
00781 {
00782 m_propList = new QPtrList<CSSProperty>;
00783 m_propList->setAutoDelete(true);
00784 while (curP < endP)
00785 {
00786 const QChar *startP = curP;
00787 curP = parseToChar(curP, endP, ';', false);
00788 if (!curP)
00789 curP = endP;
00790
00791 #ifdef CSS_DEBUG
00792 QString propVal( startP , curP - startP );
00793 kdDebug( 6080 ) << "Property = \"" << propVal.latin1() << "\"" << endl;
00794 #endif
00795
00796 parseProperty(startP, curP);
00797 curP++;
00798 }
00799 if(!m_propList->isEmpty()) {
00800 return m_propList;
00801 } else {
00802 #ifdef CSS_DEBUG
00803 kdDebug( 6080 ) << "empty property list" << endl;
00804 #endif
00805 delete m_propList;
00806 return 0;
00807 }
00808 }
00809
00810 static const QChar *getNext( const QChar *curP, const QChar *endP, bool &last )
00811 {
00812 last = false;
00813 const QChar *nextP = curP;
00814 bool ignoreSpace = false;
00815 while(nextP < endP) {
00816 if ( *nextP == '(' ) {
00817 ignoreSpace = true;
00818 } else if ( *nextP == ')' ) {
00819 ignoreSpace = false;
00820 }
00821 if ( *nextP == ' ' && !ignoreSpace )
00822 return nextP;
00823 if ( *nextP == ';')
00824 break;
00825 nextP++;
00826 }
00827 last = true;
00828 return nextP;
00829 }
00830
00831
00832
00833
00834
00835
00836
00837
00838 class FontParser {
00839 public:
00840 enum { TOK_NONE, TOK_EOI, TOK_SLASH, TOK_COMMA, TOK_STRING, TOK_SYMBOL };
00841
00842 QChar m_yyChar;
00843 QString m_yyIn, m_yyStr;
00844 unsigned int m_yyPos;
00845 int m_yyTok;
00846 bool strictParsing;
00847
00848 QChar getChar() {
00849 return ( m_yyPos == m_yyIn.length() ) ? QChar('\0') : m_yyIn.unicode()[m_yyPos++];
00850 }
00851
00852 void startTokenizer( const QString& str, bool _strictParsing ) {
00853 m_yyIn = str.simplifyWhiteSpace();
00854 #ifdef CSS_DEBUG
00855 kdDebug( 6080 ) << "startTokenizer: [" << m_yyIn << "]" << endl;
00856 #endif
00857 m_yyPos = 0;
00858 m_yyChar = getChar();
00859 strictParsing = _strictParsing;
00860 m_yyTok = TOK_NONE;
00861 }
00862
00863 int getToken();
00864
00865 bool match( int tok )
00866 {
00867 if ( m_yyTok == tok ) {
00868 m_yyTok = getToken();
00869 return true;
00870 }
00871 return false;
00872 }
00873
00874 bool matchFontStyle( QString *fstyle )
00875 {
00876 if ( m_yyTok == TOK_SYMBOL ) {
00877 const struct css_value *cssval = findValue(m_yyStr.latin1(), m_yyStr.length());
00878 if (cssval) {
00879 int id = cssval->id;
00880 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC ||
00881 id == CSS_VAL_OBLIQUE || id == CSS_VAL_INHERIT ) {
00882 *fstyle = m_yyStr;
00883 m_yyTok = getToken();
00884 return true;
00885 }
00886 }
00887 }
00888 return false;
00889 }
00890
00891 bool matchFontVariant( QString *fvariant )
00892 {
00893 if ( m_yyTok == TOK_SYMBOL ) {
00894 const struct css_value *cssval = findValue(m_yyStr.latin1(), m_yyStr.length());
00895 if (cssval) {
00896 int id = cssval->id;
00897 if (id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS || id == CSS_VAL_INHERIT) {
00898 *fvariant = m_yyStr;
00899 m_yyTok = getToken();
00900 return true;
00901 }
00902 }
00903 }
00904 return false;
00905 }
00906
00907 bool matchFontWeight( QString *fweight )
00908 {
00909 if ( m_yyTok == TOK_SYMBOL ) {
00910 const struct css_value *cssval = findValue(m_yyStr.latin1(), m_yyStr.length());
00911 if (cssval) {
00912 int id = cssval->id;
00913 if ((id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) || id == CSS_VAL_INHERIT ) {
00914 *fweight = m_yyStr;
00915 m_yyTok = getToken();
00916 return true;
00917 }
00918 }
00919 }
00920 return false ;
00921 }
00922
00923 bool matchFontSize( QString *fsize )
00924 {
00925 if ( m_yyTok == TOK_SYMBOL ) {
00926 *fsize = m_yyStr;
00927 m_yyTok = getToken();
00928 return true;
00929 }
00930 return false;
00931 }
00932
00933 bool matchLineHeight( QString *lheight )
00934 {
00935 if ( m_yyTok == TOK_SYMBOL ) {
00936 *lheight = m_yyStr;
00937 m_yyTok = getToken();
00938 return true;
00939 }
00940 return false;
00941 }
00942
00943 bool matchNameFamily( QString *ffamily )
00944 {
00945 #ifdef CSS_DEBUG
00946 kdDebug( 6080 ) << "matchNameFamily: [" << *ffamily << "]" << endl;
00947 #endif
00948 bool matched = false;
00949 if ( m_yyTok == TOK_SYMBOL || ( m_yyTok == TOK_STRING && !strictParsing ) ) {
00950
00951 *ffamily = m_yyStr;
00952
00953 while( (m_yyTok = getToken()) == TOK_SYMBOL ) {
00954 *ffamily += " " + m_yyStr;
00955 }
00956 matched = true;
00957 } else if ( m_yyTok == TOK_STRING ) {
00958
00959 const struct css_value *cssval = findValue(m_yyStr.latin1(), m_yyStr.length());
00960 if (!cssval || !(cssval->id >= CSS_VAL_SERIF && cssval->id <= CSS_VAL_MONOSPACE)) {
00961 *ffamily = m_yyStr;
00962 m_yyTok = getToken();
00963 matched = true;
00964 }
00965 }
00966 return matched;
00967 }
00968
00969 bool matchFontFamily( QString *ffamily )
00970 {
00971 #ifdef CSS_DEBUG
00972 kdDebug( 6080 ) << "matchFontFamily: [" << *ffamily << "]" << endl;
00973 #endif
00974 QStringList t;
00975 if ( !matchFontFamily( &t ) )
00976 return false;
00977
00978 *ffamily = t.join(", ");
00979 return TRUE;
00980 }
00981
00982 bool matchFontFamily ( QStringList *ffamily );
00983 bool matchRealFont( QString *fstyle, QString *fvariant, QString *fweight,
00984 QString *fsize, QString *lheight, QString *ffamily );
00985 };
00986
00987 int FontParser::getToken()
00988 {
00989 m_yyStr = QString::null;
00990
00991 if ( m_yyChar == '\0' )
00992 return TOK_EOI;
00993 if ( m_yyChar == ' ' )
00994 m_yyChar = getChar();
00995
00996 if ( m_yyChar == '/' ) {
00997 m_yyChar = getChar();
00998 return TOK_SLASH;
00999 } else if ( m_yyChar == ',' ) {
01000 m_yyChar = getChar();
01001 return TOK_COMMA;
01002 } else if ( m_yyChar == '"' ) {
01003 m_yyChar = getChar();
01004 while ( m_yyChar != '"' && m_yyChar != '\0' ) {
01005 m_yyStr += m_yyChar;
01006 m_yyChar = getChar();
01007 }
01008 m_yyChar = getChar();
01009 return TOK_STRING;
01010 } else if ( m_yyChar == '\'' ) {
01011 m_yyChar = getChar();
01012 while ( m_yyChar != '\'' && m_yyChar != '\0' ) {
01013 m_yyStr += m_yyChar;
01014 m_yyChar = getChar();
01015 }
01016 m_yyChar = getChar();
01017 return TOK_STRING;
01018 } else {
01019 while ( m_yyChar != '/' && m_yyChar != ',' && m_yyChar != '\0' && m_yyChar != ' ') {
01020 m_yyStr += m_yyChar;
01021 m_yyChar = getChar();
01022 }
01023 return TOK_SYMBOL;
01024 }
01025 }
01026
01027
01028 bool FontParser::matchFontFamily ( QStringList *ffamily )
01029 {
01030 if ( m_yyTok == TOK_NONE )
01031 m_yyTok = getToken();
01032 #if 0
01033
01034 if ( m_yyTok == TOK_STRING && m_yyStr == "inherit" ) {
01035 ffamily->clear();
01036 m_yyTok = getToken();
01037 return TRUE;
01038 }
01039 #endif
01040
01041 QString name;
01042 do {
01043 if ( !matchNameFamily(&name) )
01044 return FALSE;
01045 ffamily->append( name );
01046 } while ( match(TOK_COMMA) );
01047
01048 return true;
01049 }
01050
01051 bool FontParser::matchRealFont( QString *fstyle, QString *fvariant, QString *fweight,
01052 QString *fsize, QString *lheight, QString *ffamily )
01053 {
01054 bool metFstyle = matchFontStyle( fstyle );
01055 bool metFvariant = matchFontVariant( fvariant );
01056 matchFontWeight( fweight );
01057 if ( !metFstyle )
01058 metFstyle = matchFontStyle( fstyle );
01059 if ( !metFvariant )
01060 matchFontVariant( fvariant );
01061 if ( !metFstyle )
01062 matchFontStyle( fstyle );
01063
01064 if ( !matchFontSize(fsize) )
01065 return FALSE;
01066 if ( match(TOK_SLASH) ) {
01067 if ( !matchLineHeight(lheight) )
01068 return FALSE;
01069 }
01070 if ( !matchFontFamily(ffamily) )
01071 return FALSE;
01072 return true;
01073 }
01074
01075 bool StyleBaseImpl::parseFont(const QChar *curP, const QChar *endP)
01076 {
01077 QString str( curP, endP - curP );
01078 QString fstyle, fvariant, fweight, fsize, lheight, ffamily;
01079
01080 FontParser fontParser;
01081 fontParser.startTokenizer( str, strictParsing );
01082
01083
01084 const struct css_value *cssval = findValue(fontParser.m_yyIn.latin1(), fontParser.m_yyIn.length());
01085
01086 if (cssval) {
01087
01088 QFont sysFont;
01089 switch (cssval->id) {
01090 case CSS_VAL_MENU:
01091 sysFont = KGlobalSettings::menuFont();
01092 break;
01093 case CSS_VAL_CAPTION:
01094 sysFont = KGlobalSettings::windowTitleFont();
01095 break;
01096 case CSS_VAL_STATUS_BAR:
01097 case CSS_VAL_ICON:
01098 case CSS_VAL_MESSAGE_BOX:
01099 case CSS_VAL_SMALL_CAPTION:
01100 default:
01101 sysFont = KGlobalSettings::generalFont();
01102 break;
01103 }
01104 if (sysFont.italic()) {
01105 fstyle = "italic";
01106 } else {
01107 fstyle = "normal";
01108 }
01109 if (sysFont.bold()) {
01110 fweight = "bold";
01111 } else {
01112 fweight = "normal";
01113 }
01114 fsize = QString::number( sysFont.pixelSize() ) + "px";
01115 ffamily = sysFont.family();
01116
01117 } else {
01118 fontParser.m_yyTok = fontParser.getToken();
01119 if (!(fontParser.matchRealFont(&fstyle, &fvariant, &fweight, &fsize, &lheight, &ffamily)))
01120 {
01121 return false;
01122 }
01123 }
01124
01125
01126
01127 if(!fstyle.isNull())
01128 parseValue(fstyle.unicode(), fstyle.unicode()+fstyle.length(), CSS_PROP_FONT_STYLE);
01129 if(!fvariant.isNull())
01130 parseValue(fvariant.unicode(), fvariant.unicode()+fvariant.length(), CSS_PROP_FONT_VARIANT);
01131 if(!fweight.isNull())
01132 parseValue(fweight.unicode(), fweight.unicode()+fweight.length(), CSS_PROP_FONT_WEIGHT);
01133 if(!fsize.isNull())
01134 parseValue(fsize.unicode(), fsize.unicode()+fsize.length(), CSS_PROP_FONT_SIZE);
01135 if(!lheight.isNull())
01136 parseValue(lheight.unicode(), lheight.unicode()+lheight.length(), CSS_PROP_LINE_HEIGHT);
01137 if(!ffamily.isNull())
01138 parseValue(ffamily.unicode(), ffamily.unicode()+ffamily.length(), CSS_PROP_FONT_FAMILY);
01139 return true;
01140 }
01141
01142
01143
01144 bool StyleBaseImpl::parseValue( const QChar *curP, const QChar *endP, int propId,
01145 bool important, bool nonCSSHint, QPtrList<CSSProperty> *propList)
01146 {
01147 m_bImportant = important;
01148 m_bnonCSSHint = nonCSSHint;
01149 m_propList = propList;
01150 return parseValue(curP, endP, propId);
01151 }
01152
01153 bool StyleBaseImpl::parseValue( const QChar *curP, const QChar *endP, int propId)
01154 {
01155 if (curP==endP) {return 0; }
01156
01157 QString value(curP, endP - curP);
01158 value = value.lower().stripWhiteSpace();
01159 #ifdef CSS_DEBUG
01160 kdDebug( 6080 ) << "id [" << getPropertyName(propId).string() << "] parseValue [" << value << "]" << endl;
01161 #endif
01162 int len = value.length();
01163 const char *val = value.latin1();
01164
01165 CSSValueImpl *parsedValue = 0;
01166
01167
01168 const struct css_value *cssval = findValue(val, len);
01169 if (cssval && cssval->id == CSS_VAL_INHERIT) {
01170 parsedValue = new CSSInheritedValueImpl();
01171 } else {
01172 switch(propId)
01173 {
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183 case CSS_PROP_SIZE:
01184 case CSS_PROP_QUOTES:
01185 case CSS_PROP_UNICODE_BIDI:
01186 case CSS_PROP_PAGE:
01187 case CSS_PROP_PAGE_BREAK_AFTER:
01188 case CSS_PROP_PAGE_BREAK_BEFORE:
01189 case CSS_PROP_PAGE_BREAK_INSIDE:
01190 case CSS_PROP_POSITION:
01191 case CSS_PROP_EMPTY_CELLS:
01192 {
01193 const struct css_value *cssval = findValue(val, len);
01194 if (cssval)
01195 {
01196 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01197 }
01198
01199 break;
01200 }
01201
01202 case CSS_PROP_CONTENT:
01203
01204 parsedValue = parseContent(curP,endP);
01205 break;
01206 case CSS_PROP_WHITE_SPACE:
01207 if (cssval && ( cssval->id == CSS_VAL_NORMAL || cssval->id == CSS_VAL_PRE ||
01208 cssval->id == CSS_VAL_NOWRAP ) )
01209 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01210 break;
01211 case CSS_PROP_CLIP:
01212 {
01213 int i;
01214 if ( cssval && cssval->id == CSS_VAL_AUTO )
01215 parsedValue = new CSSPrimitiveValueImpl( cssval->id );
01216 else {
01217
01218 QString str = QConstString( const_cast<QChar*>( curP ), endP - curP ).string();
01219
01220 QChar *uc = (QChar *)str.unicode();
01221 int len = str.length();
01222 while( len ) {
01223 if ( *uc == ',' )
01224 *uc = ' ';
01225 uc++;
01226 len--;
01227 }
01228 str = str.simplifyWhiteSpace();
01229 if ( str.find( "rect", 0, false ) != 0 )
01230 break;
01231 int pos = str.find( '(', 4 );
01232 int end = str.findRev( ')' );
01233 if ( end <= pos )
01234 break;
01235 str = str.mid( pos + 1, end - pos - 1 );
01236 str = str.simplifyWhiteSpace();
01237 str += " ";
01238
01239
01240 pos = 0;
01241 RectImpl *rect = new RectImpl();
01242 for ( i = 0; i < 4; i++ ) {
01243 int space;
01244 space = str.find( ' ', pos );
01245 const QChar *start = str.unicode() + pos;
01246 const QChar *end = str.unicode() + space;
01247
01248 if ( start >= end )
01249 goto cleanup;
01250 CSSPrimitiveValueImpl *length = 0;
01251 if ( str.find( "auto", pos, FALSE ) == pos )
01252 length = new CSSPrimitiveValueImpl( CSS_VAL_AUTO );
01253 else
01254 length = parseUnit( start, end, LENGTH );
01255 if ( !length )
01256 goto cleanup;
01257 switch ( i ) {
01258 case 0:
01259 rect->setTop( length );
01260 break;
01261 case 1:
01262 rect->setRight( length );
01263 break;
01264 case 2:
01265 rect->setBottom( length );
01266 break;
01267 case 3:
01268 rect->setLeft( length );
01269 break;
01270 }
01271 pos = space + 1;
01272 }
01273 parsedValue = new CSSPrimitiveValueImpl( rect );
01274
01275 break;
01276
01277 cleanup:
01278
01279 delete rect;
01280 }
01281 break;
01282 }
01283
01284
01285
01286
01287 case CSS_PROP_CAPTION_SIDE:
01288 {
01289 if (cssval) {
01290 int id = cssval->id;
01291 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
01292 parsedValue = new CSSPrimitiveValueImpl(id);
01293 }
01294 }
01295 break;
01296 }
01297 case CSS_PROP_BORDER_COLLAPSE:
01298 if (cssval) {
01299 int id = cssval->id;
01300 if ( id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE ) {
01301 parsedValue = new CSSPrimitiveValueImpl(id);
01302 }
01303 }
01304 break;
01305 case CSS_PROP_VISIBILITY:
01306 if (cssval) {
01307 int id = cssval->id;
01308 if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE) {
01309 parsedValue = new CSSPrimitiveValueImpl(id);
01310 }
01311 }
01312 break;
01313 case CSS_PROP_OVERFLOW:
01314 if (cssval) {
01315 int id = cssval->id;
01316 if ( id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ) {
01317 parsedValue = new CSSPrimitiveValueImpl(id);
01318 }
01319 }
01320 break;
01321 case CSS_PROP_LIST_STYLE_POSITION:
01322 {
01323 if (cssval) {
01324 int id = cssval->id;
01325 if ( id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE ) {
01326 parsedValue = new CSSPrimitiveValueImpl(id);
01327 }
01328 }
01329 break;
01330 }
01331 case CSS_PROP_LIST_STYLE_TYPE:
01332
01333
01334
01335
01336 {
01337 if (cssval) {
01338 int id = cssval->id;
01339 if ((id >= CSS_VAL_DISC && id <= CSS_VAL_KATAKANA_IROHA) || id == CSS_VAL_NONE) {
01340 parsedValue = new CSSPrimitiveValueImpl(id);
01341 }
01342 }
01343 break;
01344 }
01345 case CSS_PROP_DISPLAY:
01346
01347
01348
01349 {
01350 if (cssval) {
01351 int id = cssval->id;
01352 if ((id >= CSS_VAL_INLINE && id <= CSS_VAL_TABLE_CAPTION) || id == CSS_VAL_NONE) {
01353 parsedValue = new CSSPrimitiveValueImpl(id);
01354 }
01355 }
01356 break;
01357 }
01358 case CSS_PROP_DIRECTION:
01359 {
01360 if (cssval) {
01361 int id = cssval->id;
01362 if ( id == CSS_VAL_LTR || id == CSS_VAL_RTL ) {
01363 parsedValue = new CSSPrimitiveValueImpl(id);
01364 }
01365 }
01366 break;
01367 }
01368 case CSS_PROP_TEXT_TRANSFORM:
01369 {
01370 if (cssval) {
01371 int id = cssval->id;
01372 if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE) {
01373 parsedValue = new CSSPrimitiveValueImpl(id);
01374 }
01375 }
01376 break;
01377 }
01378 case CSS_PROP_FLOAT:
01379 {
01380 if (cssval) {
01381 int id = cssval->id;
01382 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT
01383 || id == CSS_VAL_NONE || id == CSS_VAL_CENTER) {
01384 parsedValue = new CSSPrimitiveValueImpl(id);
01385 }
01386 }
01387 break;
01388 }
01389 case CSS_PROP_CLEAR:
01390 {
01391 if (cssval) {
01392 int id = cssval->id;
01393 if (id == CSS_VAL_NONE || id == CSS_VAL_LEFT
01394 || id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH) {
01395 parsedValue = new CSSPrimitiveValueImpl(id);
01396 }
01397 }
01398 break;
01399 }
01400 case CSS_PROP_TEXT_ALIGN:
01401
01402 {
01403 if (cssval) {
01404 int id = cssval->id;
01405 if (id >= CSS_VAL__KONQ_AUTO && id <= CSS_VAL__KONQ_CENTER) {
01406 parsedValue = new CSSPrimitiveValueImpl(id);
01407 break;
01408 }
01409 } else {
01410 parsedValue = new CSSPrimitiveValueImpl(DOMString(curP, endP - curP),
01411 CSSPrimitiveValue::CSS_STRING);
01412 }
01413 break;
01414 }
01415 case CSS_PROP_OUTLINE_STYLE:
01416 case CSS_PROP_BORDER_TOP_STYLE:
01417 case CSS_PROP_BORDER_RIGHT_STYLE:
01418 case CSS_PROP_BORDER_BOTTOM_STYLE:
01419 case CSS_PROP_BORDER_LEFT_STYLE:
01420 {
01421 if (cssval) {
01422 int id = cssval->id;
01423 if (id >= CSS_VAL_NONE && id <= CSS_VAL_RIDGE) {
01424 parsedValue = new CSSPrimitiveValueImpl(id);
01425 }
01426 }
01427 break;
01428 }
01429 case CSS_PROP_FONT_WEIGHT:
01430
01431 {
01432 if (cssval) {
01433 int id = cssval->id;
01434 if (id) {
01435 if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_LIGHTER) {
01436
01437 } else if (id >= CSS_VAL_100 && id <= CSS_VAL_500) {
01438 id = CSS_VAL_NORMAL;
01439 } else if (id >= CSS_VAL_600 && id <= CSS_VAL_900) {
01440 id = CSS_VAL_BOLD;
01441 }
01442 parsedValue = new CSSPrimitiveValueImpl(id);
01443 }
01444 }
01445 break;
01446 }
01447 case CSS_PROP_BACKGROUND_REPEAT:
01448 {
01449 #ifdef CSS_DEBUG_BCKGR
01450 kdDebug( 6080 ) << "CSS_PROP_BACKGROUND_REPEAT: " << val << endl;
01451 #endif
01452 if (cssval) {
01453 int id = cssval->id;
01454 if ( id >= CSS_VAL_REPEAT && id <= CSS_VAL_NO_REPEAT ) {
01455 parsedValue = new CSSPrimitiveValueImpl(id);
01456 }
01457 }
01458 break;
01459 }
01460 case CSS_PROP_BACKGROUND_ATTACHMENT:
01461 {
01462 #ifdef CSS_DEBUG_BCKGR
01463 kdDebug( 6080 ) << "CSS_PROP_BACKGROUND_ATTACHEMENT: " << val << endl;
01464 #endif
01465 if (cssval) {
01466 int id = cssval->id;
01467 if ( id == CSS_VAL_SCROLL || id == CSS_VAL_FIXED ) {
01468 parsedValue = new CSSPrimitiveValueImpl(id);
01469 }
01470 }
01471 break;
01472 }
01473 case CSS_PROP_BACKGROUND_POSITION:
01474 {
01475 #ifdef CSS_DEBUG_BCKGR
01476 kdDebug( 6080 ) << "CSS_PROP_BACKGROUND_POSITION: " << val << endl;
01477 #endif
01478
01479
01480
01481
01482
01483 bool isLast;
01484 const QChar* nextP = getNext(curP, endP, isLast);
01485 QConstString property1(const_cast<QChar*>( curP ), nextP - curP);
01486 const struct css_value *cssval1 = findValue( property1.string().ascii(),
01487 property1.string().length());
01488 if ( !cssval1 ) {
01489 const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X,
01490 CSS_PROP_BACKGROUND_POSITION_Y };
01491 return parseShortHand(curP, endP, properties, 2);
01492 }
01493 const struct css_value *cssval2 = 0;
01494 #ifdef CSS_DEBUG
01495 kdDebug( 6080 ) << "prop 1: [" << property1.string() << "]" << " isLast: " << isLast << endl;
01496 #endif
01497 if ( !isLast) {
01498 curP = nextP+1;
01499 nextP = getNext(curP, endP, isLast);
01500 QConstString property2(const_cast<QChar*>( curP ), nextP - curP);
01501 cssval2 = findValue( property2.string().ascii(), property2.string().length());
01502 #ifdef CSS_DEBUG
01503 kdDebug( 6080 ) << "prop 2: [" << property2.string() << "]" << " isLast: " << isLast << endl;
01504 #endif
01505 }
01506
01507 int valX = -1;
01508 int valY = -1;
01509 int id1 = cssval1 ? cssval1->id : -1;
01510 int id2 = cssval2 ? cssval2->id : CSS_VAL_CENTER;
01511
01512 if ( id2 == CSS_VAL_LEFT || id2 == CSS_VAL_RIGHT ||
01513 id1 == CSS_VAL_TOP || id1 == CSS_VAL_BOTTOM) {
01514 int h = id1; id1 = id2; id2 = h;
01515 }
01516
01517 switch( id1 ) {
01518 case CSS_VAL_LEFT: valX = 0; break;
01519 case CSS_VAL_CENTER: valX = 50; break;
01520 case CSS_VAL_RIGHT: valX = 100; break;
01521 default: break;
01522 }
01523
01524 switch ( id2 ) {
01525 case CSS_VAL_TOP: valY = 0; break;
01526 case CSS_VAL_CENTER: valY = 50; break;
01527 case CSS_VAL_BOTTOM: valY = 100; break;
01528 default: break;
01529 }
01530
01531 #ifdef CSS_DEBUG
01532 kdDebug( 6080 ) << "valX: " << valX << " valY: " << valY << endl;
01533 #endif
01534
01535
01536
01537
01538 if (valX !=-1 && valY !=-1) {
01539 setParsedValue( CSS_PROP_BACKGROUND_POSITION_X,
01540 new CSSPrimitiveValueImpl(valX, CSSPrimitiveValue::CSS_PERCENTAGE));
01541 setParsedValue( CSS_PROP_BACKGROUND_POSITION_Y,
01542 new CSSPrimitiveValueImpl(valY, CSSPrimitiveValue::CSS_PERCENTAGE));
01543 return true;
01544 }
01545 break;
01546 }
01547 case CSS_PROP_BACKGROUND_POSITION_X:
01548 case CSS_PROP_BACKGROUND_POSITION_Y:
01549 {
01550 #ifdef CSS_DEBUG
01551 kdDebug( 6080 ) << "CSS_PROP_BACKGROUND_POSITION_{X|Y}: " << val << endl;
01552 #endif
01553 parsedValue = parseUnit(curP, endP, PERCENT | NUMBER | LENGTH);
01554 break;
01555 }
01556 case CSS_PROP_BORDER_SPACING:
01557 {
01558
01559 parsedValue = parseUnit(curP, endP, LENGTH | NONNEGATIVE);
01560 break;
01561 }
01562 case CSS_PROP_OUTLINE_COLOR:
01563 {
01564 #ifdef CSS_DEBUG
01565 kdDebug( 6080 ) << "CSS_PROP_OUTLINE_COLOR: " << val << endl;
01566 #endif
01567
01568 if (cssval && cssval->id == CSS_VAL_INVERT) {
01569 parsedValue = new CSSPrimitiveValueImpl( khtml::invertedColor );
01570 break;
01571 }
01572
01573 }
01574 case CSS_PROP_BACKGROUND_COLOR:
01575 {
01576 #ifdef CSS_DEBUG_BCKGR
01577 kdDebug( 6080 ) << "CSS_PROP_BACKGROUND_COLOR: " << val << endl;
01578 #endif
01579 if (cssval && cssval->id == CSS_VAL_TRANSPARENT) {
01580 parsedValue = new CSSPrimitiveValueImpl( khtml::transparentColor );
01581 break;
01582 }
01583
01584 }
01585 case CSS_PROP_COLOR:
01586 case CSS_PROP_BORDER_TOP_COLOR:
01587 case CSS_PROP_BORDER_RIGHT_COLOR:
01588 case CSS_PROP_BORDER_BOTTOM_COLOR:
01589 case CSS_PROP_BORDER_LEFT_COLOR:
01590 case CSS_PROP_TEXT_DECORATION_COLOR:
01591 case CSS_PROP_SCROLLBAR_FACE_COLOR:
01592 case CSS_PROP_SCROLLBAR_SHADOW_COLOR:
01593 case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:
01594 case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:
01595 case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:
01596 case CSS_PROP_SCROLLBAR_TRACK_COLOR:
01597 case CSS_PROP_SCROLLBAR_ARROW_COLOR:
01598 case CSS_PROP_SCROLLBAR_BASE_COLOR:
01599 {
01600 const QString val2( value.stripWhiteSpace() );
01601
01602 QRgb c = khtml::parseColor(val2, !m_bnonCSSHint);
01603 if(c == khtml::invalidColor) return false;
01604
01605 parsedValue = new CSSPrimitiveValueImpl(c);
01606 break;
01607 }
01608 case CSS_PROP_CURSOR:
01609
01610
01611
01612 if (cssval) {
01613
01614 if (!strictParsing && cssval->id == CSS_VAL_HAND)
01615 parsedValue = new CSSPrimitiveValueImpl(CSS_VAL_POINTER);
01616 else if (cssval->id >= CSS_VAL_AUTO && cssval->id <= CSS_VAL_HELP)
01617 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01618 }
01619 break;
01620 case CSS_PROP_BACKGROUND_IMAGE:
01621 case CSS_PROP_LIST_STYLE_IMAGE:
01622 {
01623 if (cssval && cssval->id == CSS_VAL_NONE)
01624 {
01625 parsedValue = new CSSImageValueImpl();
01626 #ifdef CSS_DEBUG
01627 kdDebug( 6080 ) << "empty image " << endl;
01628 #endif
01629 } else {
01630 const QString str(value.stripWhiteSpace());
01631 if (str.left(4).lower() == "url(") {
01632 DOMString value(curP, endP - curP);
01633 value = khtml::parseURL(value);
01634 if (!value.isEmpty())
01635 parsedValue = new CSSImageValueImpl(DOMString(KURL(baseURL().string(), value.string()).url()), this);
01636 #ifdef CSS_DEBUG
01637 kdDebug( 6080 ) << "image, url=" << value.string() << " base=" << baseURL().string() << endl;
01638 #endif
01639 }
01640 }
01641 break;
01642 }
01643 case CSS_PROP_OUTLINE_WIDTH:
01644 case CSS_PROP_BORDER_TOP_WIDTH:
01645 case CSS_PROP_BORDER_RIGHT_WIDTH:
01646 case CSS_PROP_BORDER_BOTTOM_WIDTH:
01647 case CSS_PROP_BORDER_LEFT_WIDTH:
01648 {
01649 if (cssval) {
01650 int id = cssval->id;
01651 if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK) {
01652 parsedValue = new CSSPrimitiveValueImpl(id);
01653 }
01654 } else {
01655 parsedValue = parseUnit(curP, endP, LENGTH|NONNEGATIVE);
01656 }
01657 break;
01658 }
01659 case CSS_PROP_MARKER_OFFSET:
01660 {
01661 if (cssval && cssval->id == CSS_VAL_AUTO) {
01662 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01663 } else {
01664 parsedValue = parseUnit(curP, endP, LENGTH);
01665 }
01666 break;
01667 }
01668 case CSS_PROP_LETTER_SPACING:
01669 case CSS_PROP_WORD_SPACING:
01670 {
01671 if (cssval) {
01672 if (cssval->id == CSS_VAL_NORMAL) {
01673 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01674 }
01675 } else {
01676 parsedValue = parseUnit(curP, endP, LENGTH);
01677 }
01678 break;
01679 }
01680 case CSS_PROP_PADDING_TOP:
01681 case CSS_PROP_PADDING_RIGHT:
01682 case CSS_PROP_PADDING_BOTTOM:
01683 case CSS_PROP_PADDING_LEFT:
01684 {
01685 parsedValue = parseUnit(curP, endP, LENGTH | PERCENT|NONNEGATIVE);
01686 break;
01687 }
01688 case CSS_PROP_TEXT_INDENT:
01689 case CSS_PROP_MIN_HEIGHT:
01690 case CSS_PROP_MIN_WIDTH:
01691 {
01692 parsedValue = parseUnit(curP, endP, LENGTH | PERCENT);
01693 break;
01694 }
01695 case CSS_PROP_FONT_SIZE:
01696
01697 {
01698 if (cssval) {
01699 int id = cssval->id;
01700 if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER) {
01701 parsedValue = new CSSPrimitiveValueImpl(id);
01702 break;
01703 }
01704 } else {
01705 parsedValue = parseUnit(curP, endP, LENGTH | PERCENT | NONNEGATIVE);
01706 }
01707 break;
01708 }
01709 case CSS_PROP_FONT_STYLE:
01710 {
01711 if (cssval) {
01712 int id = cssval->id;
01713 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE) {
01714 parsedValue = new CSSPrimitiveValueImpl(id);
01715 }
01716 }
01717 break;
01718 }
01719 case CSS_PROP_FONT_VARIANT:
01720 {
01721 if (cssval) {
01722 int id = cssval->id;
01723 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS) {
01724 parsedValue = new CSSPrimitiveValueImpl(id);
01725 }
01726 }
01727 break;
01728 }
01729 case CSS_PROP_VERTICAL_ALIGN:
01730
01731
01732 {
01733 if (cssval) {
01734 int id = cssval->id;
01735 if ( id >= CSS_VAL_BASELINE && id <= CSS_VAL__KONQ_BASELINE_MIDDLE ) {
01736 parsedValue = new CSSPrimitiveValueImpl(id);
01737 }
01738 } else {
01739 parsedValue = parseUnit(curP, endP, LENGTH | PERCENT );
01740 }
01741 break;
01742 }
01743 case CSS_PROP_MAX_HEIGHT:
01744 case CSS_PROP_MAX_WIDTH:
01745 {
01746 if (cssval && cssval->id == CSS_VAL_NONE) {
01747 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01748 } else {
01749 parsedValue = parseUnit(curP, endP, LENGTH | PERCENT );
01750 }
01751 break;
01752 }
01753 case CSS_PROP_HEIGHT:
01754 case CSS_PROP_WIDTH:
01755 {
01756 if (cssval && cssval->id == CSS_VAL_AUTO) {
01757 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01758 } else {
01759 parsedValue = parseUnit(curP, endP, LENGTH | PERCENT | NONNEGATIVE | (multiLength ? RELATIVE : 0) );
01760 }
01761 break;
01762 }
01763 case CSS_PROP_BOTTOM:
01764 case CSS_PROP_LEFT:
01765 case CSS_PROP_RIGHT:
01766 case CSS_PROP_TOP:
01767 case CSS_PROP_MARGIN_TOP:
01768 case CSS_PROP_MARGIN_RIGHT:
01769 case CSS_PROP_MARGIN_BOTTOM:
01770 case CSS_PROP_MARGIN_LEFT:
01771 {
01772 if (cssval && cssval->id == CSS_VAL_AUTO) {
01773 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01774 } else {
01775 parsedValue = parseUnit(curP, endP, LENGTH | PERCENT );
01776 }
01777 break;
01778 }
01779 case CSS_PROP_Z_INDEX:
01780 {
01781 if (cssval && cssval->id == CSS_VAL_AUTO) {
01782 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01783 break;
01784 }
01785
01786 }
01787 case CSS_PROP_ORPHANS:
01788 case CSS_PROP_WIDOWS:
01789
01790 {
01791 parsedValue = parseUnit(curP, endP, INTEGER);
01792 break;
01793 }
01794 case CSS_PROP_LINE_HEIGHT:
01795 {
01796 if (cssval && cssval->id == CSS_VAL_NORMAL) {
01797 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01798 } else {
01799 parsedValue = parseUnit(curP, endP, NUMBER | LENGTH | PERCENT | NONNEGATIVE);
01800 }
01801 break;
01802 }
01803 case CSS_PROP_COUNTER_INCREMENT:
01804 case CSS_PROP_COUNTER_RESET:
01805 {
01806 if (cssval && cssval->id == CSS_VAL_NONE) {
01807 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01808 } else {
01809 CSSValueListImpl *list = new CSSValueListImpl;
01810 int pos=0, pos2;
01811 while( 1 )
01812 {
01813 pos2 = value.find(',', pos);
01814 QString face = value.mid(pos, pos2-pos);
01815 face = face.stripWhiteSpace();
01816 if(face.length() == 0) break;
01817
01818 if(face[0] == '\"') face.remove(0, 1);
01819 if(face[face.length()-1] == '\"') face = face.left(face.length()-1);
01820
01821 list->append(new CSSPrimitiveValueImpl(DOMString(face), CSSPrimitiveValue::CSS_STRING));
01822 pos = pos2 + 1;
01823 if(pos2 == -1) break;
01824 }
01825
01826 if(list->length())
01827 parsedValue = list;
01828 else
01829 delete list;
01830 break;
01831 }
01832 }
01833 case CSS_PROP_FONT_FAMILY:
01834
01835 {
01836
01837 FontParser fp;
01838 fp.startTokenizer( value, strictParsing );
01839 QStringList families;
01840 if ( !fp.matchFontFamily( &families ) )
01841 return false;
01842 CSSValueListImpl *list = new CSSValueListImpl;
01843 for ( QStringList::Iterator it = families.begin(); it != families.end(); ++it ) {
01844 if( *it != QString::null ) {
01845 list->append( new FontFamilyValueImpl(*it) );
01846
01847 }
01848 }
01849
01850 if(list->length())
01851 parsedValue = list;
01852 else
01853 delete list;
01854 break;
01855 }
01856 case CSS_PROP_TEXT_DECORATION:
01857
01858 {
01859 bool is_valid = true;
01860 if (cssval && cssval->id == CSS_VAL_NONE) {
01861 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01862 } else {
01863 CSSValueListImpl *list = new CSSValueListImpl;
01864 value.simplifyWhiteSpace();
01865
01866 int pos=0, pos2;
01867 while( 1 )
01868 {
01869 pos2 = value.find(' ', pos);
01870 QString decoration = value.mid(pos, pos2-pos);
01871 decoration = decoration.stripWhiteSpace();
01872
01873 const struct css_value *cssval = findValue(decoration.lower().ascii(),
01874 decoration.length());
01875
01876 if (cssval) {
01877 switch (cssval->id) {
01878 case CSS_VAL_NONE:
01879 case CSS_VAL_UNDERLINE:
01880 case CSS_VAL_OVERLINE:
01881 case CSS_VAL_LINE_THROUGH:
01882 case CSS_VAL_BLINK:
01883 case CSS_VAL_INHERIT:
01884 list->append(new CSSPrimitiveValueImpl(cssval->id));
01885 break;
01886 default:
01887 list->append(new CSSPrimitiveValueImpl(cssval->id));
01888 is_valid = false;
01889 }
01890 } else {
01891 is_valid = false;
01892 }
01893 pos = pos2 + 1;
01894 if(pos2 == -1) break;
01895 }
01896
01897 if(list->length() && is_valid) {
01898 parsedValue = list;
01899 } else {
01900 delete list;
01901 }
01902 }
01903 break;
01904 }
01905 case CSS_PROP_TABLE_LAYOUT:
01906 {
01907 const struct css_value *cssval = findValue(val, len);
01908 if (cssval->id == CSS_VAL_AUTO || cssval->id == CSS_VAL_FIXED)
01909 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01910 break;
01911 }
01912 case CSS_PROP__KONQ_FLOW_MODE:
01913 {
01914 if (cssval->id==CSS_VAL__KONQ_NORMAL || cssval->id==CSS_VAL__KONQ_AROUND_FLOATS)
01915 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01916 break;
01917 }
01918
01919 case CSS_PROP_BACKGROUND:
01920
01921
01922 {
01923 #ifdef CSS_DEBUG_BCKGR
01924 kdDebug(6080) << "CSS_PROP_BACKGROUND" << endl;
01925 #endif
01926 const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
01927 CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,
01928 CSS_PROP_BACKGROUND_COLOR };
01929 return parseShortHand(curP, endP, properties, 5);
01930
01931
01932 }
01933 case CSS_PROP_BORDER:
01934
01935 {
01936 const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
01937 CSS_PROP_BORDER_COLOR };
01938 return parseShortHand(curP, endP, properties, 3);
01939 }
01940 case CSS_PROP_BORDER_TOP:
01941
01942 {
01943 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
01944 CSS_PROP_BORDER_TOP_COLOR};
01945 return parseShortHand(curP, endP, properties, 3);
01946 }
01947 case CSS_PROP_BORDER_RIGHT:
01948
01949 {
01950 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
01951 CSS_PROP_BORDER_RIGHT_COLOR };
01952 return parseShortHand(curP, endP, properties, 3);
01953 }
01954 case CSS_PROP_BORDER_BOTTOM:
01955
01956 {
01957 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
01958 CSS_PROP_BORDER_BOTTOM_COLOR };
01959 return parseShortHand(curP, endP, properties, 3);
01960 }
01961 case CSS_PROP_BORDER_LEFT:
01962
01963 {
01964 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
01965 CSS_PROP_BORDER_LEFT_COLOR };
01966 return parseShortHand(curP, endP, properties, 3);
01967 }
01968 case CSS_PROP_OUTLINE:
01969
01970 {
01971 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
01972 CSS_PROP_OUTLINE_COLOR };
01973 return parseShortHand(curP, endP, properties, 3);
01974 }
01975 case CSS_PROP_BORDER_COLOR:
01976
01977 {
01978 const struct css_value *cssval = findValue(val, len);
01979 if (cssval && cssval->id == CSS_VAL_TRANSPARENT)
01980 {
01981
01982 parsedValue = new CSSPrimitiveValueImpl(CSS_VAL_TRANSPARENT);
01983 break;
01984 }
01985 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
01986 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
01987 return parse4Values(curP, endP, properties);
01988 }
01989 case CSS_PROP_BORDER_WIDTH:
01990
01991 {
01992 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
01993 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
01994 return parse4Values(curP, endP, properties);
01995 }
01996 case CSS_PROP_BORDER_STYLE:
01997
01998 {
01999 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
02000 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
02001 return parse4Values(curP, endP, properties);
02002 }
02003 case CSS_PROP_MARGIN:
02004
02005 {
02006 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
02007 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
02008 return parse4Values(curP, endP, properties);
02009 }
02010 case CSS_PROP_PADDING:
02011
02012 {
02013 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
02014 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
02015 return parse4Values(curP, endP, properties);
02016 }
02017 case CSS_PROP_FONT:
02018
02019
02020 {
02021 return parseFont(curP, endP);
02022 }
02023 case CSS_PROP_LIST_STYLE:
02024 {
02025 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
02026 CSS_PROP_LIST_STYLE_IMAGE };
02027 return parseShortHand(curP, endP, properties, 3);
02028 }
02029
02030 default:
02031 {
02032 #ifdef CSS_DEBUG
02033 kdDebug( 6080 ) << "illegal or CSS2 Aural property: " << val << endl;
02034 #endif
02035 }
02036 }
02037 }
02038 if ( parsedValue ) {
02039 setParsedValue(propId, parsedValue);
02040 return true;
02041 } else {
02042 #ifndef CSS_AURAL
02043 return false;
02044 #endif
02045 #ifdef CSS_AURAL
02046 return parseAuralValue(curP, endP, propId);
02047 #endif
02048 }
02049 }
02050
02051 #ifdef CSS_AURAL
02052
02053 bool StyleBaseImpl::parseAuralValue( const QChar *curP, const QChar *endP, int propId )
02054 {
02055 QString value(curP, endP - curP);
02056 value = value.lower();
02057 const char *val = value.ascii();
02058
02059 CSSValueImpl *parsedValue = 0;
02060 kdDebug( 6080 ) << "parseAuralValue: " << value << " val: " << val << endl;
02061
02062
02063 switch(propId)
02064 {
02065 case CSS_PROP_AZIMUTH:
02066
02067
02068 case CSS_PROP_PAUSE_AFTER:
02069 case CSS_PROP_PAUSE_BEFORE:
02070 case CSS_PROP_PAUSE:
02071 case CSS_PROP_PLAY_DURING:
02072 case CSS_PROP_VOICE_FAMILY:
02073
02074 {
02075
02076 break;
02077 }
02078 case CSS_PROP_CUE:
02079 {
02080 const int properties[2] = {
02081 CSS_PROP_CUE_BEFORE,
02082 CSS_PROP_CUE_AFTER};
02083 return parse2Values(curP, endP, properties);
02084 }
02085 case CSS_PROP_CUE_AFTER:
02086 case CSS_PROP_CUE_BEFORE:
02087 {
02088 const struct css_value *cssval = findValue(val, endP - curP);
02089 if (cssval) {
02090 if (cssval->id == CSS_VAL_NONE) {
02091 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
02092 }
02093 } else {
02094 DOMString value(curP, endP - curP);
02095 value = khtml::parseURL(value);
02096 parsedValue = new CSSPrimitiveValueImpl(
02097 DOMString(KURL(baseURL(), value).url()),
02098 CSSPrimitiveValue::CSS_URI);
02099 }
02100 break;
02101 }
02102 case CSS_PROP_ELEVATION:
02103
02104 {
02105 const struct css_value *cssval = findValue(val, endP - curP);
02106 if (cssval) {
02107 int id = cssval->id;
02108 if (id == CSS_VAL_BELOW || id == CSS_VAL_LEVEL || id == CSS_VAL_ABOVE ||
02109 id == CSS_VAL_HIGHER || id == CSS_VAL_LOWER) {
02110 parsedValue = new CSSPrimitiveValueImpl(id);
02111 break;
02112 }
02113 }
02114 parsedValue = parseUnit(curP, endP, ANGLE );
02115 break;
02116 }
02117 case CSS_PROP_SPEECH_RATE:
02118
02119 {
02120 const struct css_value *cssval = findValue(val, endP - curP);
02121 if (cssval) {
02122 int id = cssval->id;
02123 if (id == CSS_VAL_X_SLOW || id == CSS_VAL_SLOW || id == CSS_VAL_MEDIUM ||
02124 id == CSS_VAL_FAST || id == CSS_VAL_X_FAST || id == CSS_VAL_FASTER ||
02125 id == CSS_VAL_SLOWER) {
02126 parsedValue = new CSSPrimitiveValueImpl(id);
02127 break;
02128 }
02129 } else {
02130 parsedValue = parseUnit(curP, endP, NUMBER );
02131 }
02132 break;
02133 }
02134 case CSS_PROP_VOLUME:
02135
02136 {
02137 const struct css_value *cssval = findValue(val, endP - curP);
02138 if (cssval) {
02139 int id = cssval->id;
02140 if (id == CSS_VAL_SILENT || id == CSS_VAL_X_SOFT || id == CSS_VAL_SOFT ||
02141 id == CSS_VAL_MEDIUM || id == CSS_VAL_X_LOUD || id == CSS_VAL_X_LOUD) {
02142 parsedValue = new CSSPrimitiveValueImpl(id);
02143 }
02144 } else {
02145 parsedValue = parseUnit(curP, endP, PERCENT | NUMBER);
02146 }
02147 break;
02148 }
02149 case CSS_PROP_PITCH:
02150 {
02151 const struct css_value *cssval = findValue(val, endP - curP);
02152 if (cssval) {
02153 int id = cssval->id;
02154 if (id == CSS_VAL_X_LOW || id == CSS_VAL_LOW || id == CSS_VAL_MEDIUM ||
02155 id == CSS_VAL_HIGH || id == CSS_VAL_X_HIGH ) {
02156 parsedValue = new CSSPrimitiveValueImpl(id);
02157 }
02158 } else {
02159 parsedValue = parseUnit(curP, endP, FREQUENCY);
02160 }
02161 break;
02162 }
02163 case CSS_PROP_SPEAK:
02164 case CSS_PROP_SPEAK_HEADER:
02165 case CSS_PROP_SPEAK_NUMERAL:
02166 case CSS_PROP_SPEAK_PUNCTUATION:
02167 {
02168 const struct css_value *cssval = findValue(val, endP - curP);
02169 if (cssval)
02170 {
02171 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
02172 }
02173 break;
02174 }
02175 case CSS_PROP_PITCH_RANGE:
02176 case CSS_PROP_RICHNESS:
02177 case CSS_PROP_STRESS:
02178 {
02179 parsedValue = parseUnit(curP, endP, NUMBER);
02180 break;
02181 }
02182 default:
02183 {
02184 kdDebug( 6080 ) << "illegal property: " << val << endl;
02185 }
02186 }
02187 if ( parsedValue ) {
02188 setParsedValue( propId, parsedValue );
02189 return true;
02190 }
02191 return false;
02192 }
02193 #endif
02194
02195 void StyleBaseImpl::setParsedValue(int propId, const CSSValueImpl *parsedValue,
02196 bool important, bool nonCSSHint, QPtrList<CSSProperty> *propList)
02197 {
02198 m_bImportant = important;
02199 m_bnonCSSHint = nonCSSHint;
02200 m_propList = propList;
02201 setParsedValue( propId, parsedValue);
02202 }
02203
02204 void StyleBaseImpl::setParsedValue( int propId, const CSSValueImpl *parsedValue)
02205 {
02206 QPtrListIterator<CSSProperty> propIt(*m_propList);
02207 propIt.toLast();
02208 while (propIt.current() &&
02209 ( propIt.current()->m_id != propId || propIt.current()->nonCSSHint != m_bnonCSSHint ||
02210 propIt.current()->m_bImportant != m_bImportant) )
02211 --propIt;
02212 if (propIt.current())
02213 m_propList->removeRef(propIt.current());
02214
02215 CSSProperty *prop = new CSSProperty();
02216 prop->m_id = propId;
02217 prop->setValue((CSSValueImpl *) parsedValue);
02218 prop->m_bImportant = m_bImportant;
02219 prop->nonCSSHint = m_bnonCSSHint;
02220
02221 m_propList->append(prop);
02222 #ifdef CSS_DEBUG
02223 kdDebug( 6080 ) << "added property: " << getPropertyName(propId).string()
02224
02225 << " important: " << prop->m_bImportant
02226 << " nonCSS: " << prop->nonCSSHint << endl;
02227 #endif
02228 }
02229
02230 bool StyleBaseImpl::parseShortHand(const QChar *curP, const QChar *endP, const int *properties, int num)
02231 {
02232
02233
02234
02235
02236
02237 bool isLast = false;
02238 bool foundAnything = false;
02239 bool fnd[6];
02240 for( int i = 0; i < num; i++ )
02241 fnd[i] = false;
02242
02243 #ifdef CSS_DEBUG
02244 kdDebug(6080) << "PSH: parsing \"" << QString(curP, endP - curP) << "\" num=" << num << endl;
02245 #endif
02246
02247 for (int j = 0; j < num; ++j) {
02248 const QChar *nextP = getNext( curP, endP, isLast );
02249
02250 foundAnything = false;
02251 for (int propIndex = 0; propIndex < num; ++propIndex) {
02252 if (!fnd[propIndex]) {
02253
02254
02255 bool found = false;
02256 if (!isLast && properties[propIndex] == CSS_PROP_BACKGROUND_POSITION)
02257 found = parseBackgroundPosition(curP, nextP, endP);
02258 else
02259 found = parseValue(curP, nextP, properties[propIndex]);
02260
02261 if (found) {
02262 fnd[propIndex] = foundAnything = true;
02263 #ifdef CSS_DEBUG
02264 kdDebug(6080) << "FOUND: " << getPropertyName(properties[propIndex]).string() << ": "
02265 << QString(curP, nextP - curP) << endl;
02266 #endif
02267 break;
02268 }
02269 }
02270 }
02271
02272
02273 if (!foundAnything)
02274 return foundAnything;
02275
02276 do {
02277 nextP++;
02278 curP = nextP;
02279
02280
02281 if (curP >= endP)
02282 return foundAnything;
02283 } while (curP->isSpace());
02284 }
02285 return foundAnything;
02286 }
02287
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297
02298 bool StyleBaseImpl::parseBackgroundPosition(const QChar *curP, const QChar *&nextP, const QChar *endP)
02299 {
02300
02301
02302
02303 const QChar *bckgrNextP = nextP;
02304 while (bckgrNextP->isSpace() && bckgrNextP < endP) { bckgrNextP++; }
02305 bool dummy;
02306 bckgrNextP = getNext(bckgrNextP, endP, dummy);
02307
02308
02309 bool found = parseValue(curP, bckgrNextP, CSS_PROP_BACKGROUND_POSITION);
02310 if (!found) {
02311
02312
02313
02314 found = parseValue(curP, nextP, CSS_PROP_BACKGROUND_POSITION);
02315 } else {
02316
02317 nextP = bckgrNextP;
02318 }
02319
02320 return found;
02321 }
02322
02323
02324 CSSValueImpl* StyleBaseImpl::parseContent(const QChar *curP, const QChar *endP)
02325 {
02326 CSSValueListImpl* values = new CSSValueListImpl();
02327
02328
02329 while (curP < endP) {
02330 const QChar *nextP = curP;
02331 bool esc = false;
02332 bool sq = false;
02333 bool dq = false;
02334 while ( nextP < endP ) {
02335 if (esc)
02336 esc = false;
02337 else if (*nextP == '\\')
02338 esc = true;
02339 else if (!sq && (*nextP == '"')) {
02340 if (dq) break;
02341 dq = true;
02342 }
02343 else if (!dq && (*nextP == '\'')) {
02344 if (sq) break;
02345 sq = true;
02346 }
02347 else if (!sq && !dq && nextP->isSpace())
02348 break;
02349 nextP++;
02350 }
02351 QString str = QConstString(curP, nextP-curP).string();
02352 CSSValueImpl* parsedValue=0;
02353 if (str.startsWith("url("))
02354 {
02355
02356 DOMString value = khtml::parseURL(DOMString(str));
02357 parsedValue = new CSSImageValueImpl(
02358 DOMString(KURL(baseURL().string(), value.string()).url()), this);
02359 #ifdef CSS_DEBUG
02360 kdDebug( 6080 ) << "content, url=" << value.string() << " base=" << baseURL().string() << endl;
02361 #endif
02362 }
02363 else if (str.startsWith("attr("))
02364 {
02365
02366 }
02367 else if (str.startsWith("open-quote"))
02368 {
02369
02370 }
02371 else if (str.startsWith("close-quote"))
02372 {
02373
02374 }
02375 else if (str.startsWith("no-open-quote"))
02376 {
02377
02378 }
02379 else if (str.startsWith("no-close-quote"))
02380 {
02381
02382 }
02383 else if (str.length() && (str[0] == '\'' || str[0] == '"'))
02384 {
02385
02386 int l = str.length();
02387 QString strstr;
02388
02389 for (int i = 1; i < l; ++i) {
02390 if (i < l - 1 && str[i] == '\\') {
02391 QChar nextChar = str[i+1];
02392 if (nextChar == '\n') {
02393 i++;
02394 }
02395 else if ( nextChar == '\r' ) {
02396 i++;
02397 if ( str[i+1] == '\n' )
02398 i++;
02399 }
02400 else if ( isHexadecimal( nextChar ) ) {
02401 int initial=i;
02402 QString hex;
02403 bool ok;
02404 while ( i-initial<6 && i<l-1 && isHexadecimal( nextChar ) ) {
02405 hex += nextChar;
02406 i++;
02407 nextChar = str[i+1];
02408 }
02409
02410 strstr += QChar( hex.toInt(&ok, 16) );
02411 if ( i<l-1 && nextChar.isSpace() ) {
02412 i++;
02413 if ( nextChar == '\r' && str[i+1] == '\n' ) {
02414 i++;
02415 }
02416 }
02417 }
02418 else {
02419 ++i;
02420 strstr += nextChar;
02421 }
02422 }
02423 else
02424 strstr += str[i];
02425 }
02426 parsedValue = new CSSPrimitiveValueImpl(DOMString(strstr), CSSPrimitiveValue::CSS_STRING);
02427 }
02428 if (parsedValue)
02429 values->append(parsedValue);
02430
02431
02432 for (curP = ++nextP ; curP < endP && curP->isSpace(); ++curP)
02433 ;
02434 }
02435 return values;
02436 }
02437
02438 bool StyleBaseImpl::isHexadecimal( QChar &c )
02439 {
02440 return ( c >= '0' && c <= '9' ) ||
02441 ( c >= 'a' && c <= 'f' ) ||
02442 ( c >= 'A' && c <= 'F' ) ;
02443 }
02444
02445 QPtrList<QChar> StyleBaseImpl::splitShorthandProperties(const QChar *curP, const QChar *endP)
02446 {
02447 bool last = false;
02448 QPtrList<QChar> list;
02449 while(!last) {
02450 const QChar *nextP = getNext(curP, endP, last);
02451 list.append(curP);
02452 list.append(nextP);
02453 if ( last ) break;
02454 while(nextP->isSpace()) {
02455 nextP++;
02456 curP = nextP;
02457 if(curP >= endP) {
02458 last = true;
02459 break;
02460 }
02461 }
02462 }
02463 return list;
02464 }
02465
02466 #ifdef CSS_AURAL
02467
02468 bool StyleBaseImpl::parse2Values( const QChar *curP, const QChar *endP, const int *properties)
02469 {
02470 QPtrList<QChar> list = splitShorthandProperties(curP, endP);
02471 switch(list.count())
02472 {
02473 case 2:
02474 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02475 setParsedValue(properties[1], m_propList->last()->value() );
02476 return true;
02477 case 4:
02478 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02479 if(!parseValue(list.at(2), list.at(3), properties[1])) return false;
02480 return true;
02481 default:
02482 return false;
02483 }
02484 }
02485 #endif
02486
02487
02488 bool StyleBaseImpl::parse4Values( const QChar *curP, const QChar *endP, const int *properties)
02489 {
02490
02491
02492
02493
02494
02495
02496
02497
02498 QPtrList<QChar> list = splitShorthandProperties(curP, endP);
02499 switch(list.count())
02500 {
02501 case 2:
02502 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02503 setParsedValue(properties[1], m_propList->last()->value());
02504 setParsedValue(properties[2], m_propList->last()->value());
02505 setParsedValue(properties[3], m_propList->last()->value());
02506 return true;
02507 case 4:
02508 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02509 setParsedValue(properties[2], m_propList->last()->value());
02510 if(!parseValue(list.at(2), list.at(3), properties[1])) return false;
02511 setParsedValue(properties[3], m_propList->last()->value());
02512 return true;
02513 case 6:
02514 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02515 if(!parseValue(list.at(2), list.at(3), properties[1])) return false;
02516 setParsedValue(properties[3], m_propList->last()->value());
02517 if(!parseValue(list.at(4), list.at(5), properties[2])) return false;
02518 return true;
02519 case 8:
02520 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02521 if(!parseValue(list.at(2), list.at(3), properties[1])) return false;
02522 if(!parseValue(list.at(4), list.at(5), properties[2])) return false;
02523 if(!parseValue(list.at(6), list.at(7), properties[3])) return false;
02524 return true;
02525 default:
02526 return false;
02527 }
02528 }
02529
02530 CSSPrimitiveValueImpl *
02531 StyleBaseImpl::parseUnit(const QChar * curP, const QChar *endP, int allowedUnits)
02532 {
02533
02534 if (curP==endP || *curP=='"')
02535 return 0;
02536
02537 if ( allowedUnits & RELATIVE && *curP == '*' )
02538 return new CSSPrimitiveValueImpl( 1., CSSPrimitiveValue::CSS_HTML_RELATIVE );
02539
02540 endP--;
02541 while(*endP == ' ' && endP > curP) endP--;
02542 const QChar *split = endP;
02543
02544 while( (*split < '0' || *split > '9') && *split != '.' && split > curP)
02545 split--;
02546 split++;
02547
02548 QString s(curP, split-curP);
02549
02550 bool isInt = false;
02551 if(s.find('.') == -1) isInt = true;
02552
02553 bool ok;
02554 float value = s.toFloat(&ok);
02555
02556 if ( !ok || ( value < 0 && (allowedUnits & NONNEGATIVE) ))
02557 return 0;
02558
02559 if(split > endP)
02560 {
02561 if(allowedUnits & NUMBER)
02562 return new CSSPrimitiveValueImpl(value, CSSPrimitiveValue::CSS_NUMBER);
02563
02564 if(allowedUnits & INTEGER && isInt)
02565 return new CSSPrimitiveValueImpl(value, CSSPrimitiveValue::CSS_NUMBER);
02566
02567
02568
02569
02570 if(( allowedUnits & LENGTH ) && (value == 0 || !strictParsing) )
02571 return new CSSPrimitiveValueImpl(value, CSSPrimitiveValue::CSS_PX);
02572
02573 return 0;
02574 }
02575
02576 CSSPrimitiveValue::UnitTypes type = CSSPrimitiveValue::CSS_UNKNOWN;
02577 StyleBaseImpl::Units unit = StyleBaseImpl::UNKNOWN;
02578
02579 switch(split->latin1())
02580 {
02581 case '%':
02582 type = CSSPrimitiveValue::CSS_PERCENTAGE;
02583 unit = StyleBaseImpl::PERCENT;
02584 break;
02585 case '*':
02586 type = CSSPrimitiveValue::CSS_HTML_RELATIVE;
02587 unit = StyleBaseImpl::RELATIVE;
02588 case 'e':
02589 split++;
02590 if(split > endP) break;
02591 switch(split->latin1())
02592 {
02593 case 'm':
02594 type = CSSPrimitiveValue::CSS_EMS;
02595 unit = StyleBaseImpl::LENGTH;
02596 break;
02597 case 'x':
02598 type = CSSPrimitiveValue::CSS_EXS;
02599 unit = StyleBaseImpl::LENGTH;
02600 break;
02601 }
02602 break;
02603 case 'p':
02604 split++;
02605 if(split > endP) break;
02606 switch(split->latin1())
02607 {
02608 case 'x':
02609 type = CSSPrimitiveValue::CSS_PX;
02610 unit = StyleBaseImpl::LENGTH;
02611 break;
02612 case 't':
02613 type = CSSPrimitiveValue::CSS_PT;
02614 unit = StyleBaseImpl::LENGTH;
02615 break;
02616 case 'c':
02617 type = CSSPrimitiveValue::CSS_PC;
02618 unit = StyleBaseImpl::LENGTH;
02619 break;
02620 }
02621 break;
02622 case 'c':
02623 split++;
02624 if(split > endP) break;
02625 if(split->latin1() == 'm')
02626 {
02627 type = CSSPrimitiveValue::CSS_CM;
02628 unit = StyleBaseImpl::LENGTH;
02629 }
02630 break;
02631 case 'm':
02632 split++;
02633 if(split > endP) break;
02634 switch(split->latin1())
02635 {
02636 case 'm':
02637 type = CSSPrimitiveValue::CSS_MM;
02638 unit = StyleBaseImpl::LENGTH;
02639 break;
02640 case 's':
02641 type = CSSPrimitiveValue::CSS_MS;
02642 unit = StyleBaseImpl::TIME;
02643 break;
02644 }
02645 break;
02646 case 'i':
02647 split++;
02648 if(split > endP) break;
02649 if(split->latin1() == 'n')
02650 {
02651 type = CSSPrimitiveValue::CSS_IN;
02652 unit = StyleBaseImpl::LENGTH;
02653 }
02654 break;
02655 case 'd':
02656 type = CSSPrimitiveValue::CSS_DEG;
02657 unit = StyleBaseImpl::ANGLE;
02658 break;
02659 case 'r':
02660 type = CSSPrimitiveValue::CSS_RAD;
02661 unit = StyleBaseImpl::ANGLE;
02662 break;
02663 case 'g':
02664 type = CSSPrimitiveValue::CSS_GRAD;
02665 unit = StyleBaseImpl::ANGLE;
02666 break;
02667 case 's':
02668 type = CSSPrimitiveValue::CSS_S;
02669 unit = StyleBaseImpl::TIME;
02670 break;
02671 case 'h':
02672 type = CSSPrimitiveValue::CSS_HZ;
02673 unit = StyleBaseImpl::FREQUENCY;
02674 break;
02675 case 'k':
02676 type = CSSPrimitiveValue::CSS_KHZ;
02677 unit = StyleBaseImpl::FREQUENCY;
02678 break;
02679 }
02680
02681 if(unit & allowedUnits)
02682 {
02683 #ifdef CSS_DEBUG
02684 kdDebug( 6080 ) << "found allowed number " << value << ", unit " << type << endl;
02685 #endif
02686 return new CSSPrimitiveValueImpl(value, type);
02687 }
02688
02689 return 0;
02690 }
02691
02692 CSSRuleImpl *
02693 StyleBaseImpl::parseStyleRule(const QChar *&curP, const QChar *endP)
02694 {
02695
02696
02697 const QChar *startP;
02698 QPtrList<CSSSelector> *slist;
02699 QPtrList<CSSProperty> *plist;
02700
02701 startP = curP;
02702 curP = parseToChar(startP, endP, '{', false);
02703 if (!curP)
02704 return(0);
02705 #ifdef CSS_DEBUG
02706 kdDebug( 6080 ) << "selector is \'" << QString(startP, curP-startP) << "\'" << endl;
02707 #endif
02708
02709 slist = parseSelector(startP, curP );
02710
02711 curP++;
02712
02713 startP = curP;
02714 curP = parseToChar(startP, endP, '}', false);
02715
02716 if (!curP)
02717 {
02718 delete slist;
02719 return(0);
02720 }
02721 #ifdef CSS_DEBUG
02722 kdDebug( 6080 ) << "rules are \'" << QString(startP, curP-startP) << "\'" << endl;
02723 #endif
02724
02725 plist = parseProperties(startP, curP );
02726
02727 curP++;
02728
02729 if (!plist || !slist)
02730 {
02731
02732 delete slist;
02733 delete plist;
02734 #ifdef CSS_DEBUG
02735 kdDebug( 6080 ) << "bad style rule" << endl;
02736 #endif
02737 return 0;
02738 }
02739
02740
02741 CSSStyleRuleImpl *rule = new CSSStyleRuleImpl(this);
02742 CSSStyleDeclarationImpl *decl = new CSSStyleDeclarationImpl(rule, plist);
02743
02744 rule->setSelector(slist);
02745 rule->setDeclaration(decl);
02746
02747 return rule;
02748 }
02749
02750 CSSRuleImpl *
02751 StyleBaseImpl::parseRule(const QChar *&curP, const QChar *endP)
02752 {
02753 const QChar *startP;
02754
02755 curP = parseSpace( curP, endP );
02756
02757 if (!strictParsing) {
02758
02759 while (curP && curP != endP && (curP->isSpace() || *curP == ';'))
02760 curP++;
02761 }
02762
02763 startP = curP;
02764 CSSRuleImpl *rule = 0;
02765
02766 if(!curP || curP >= endP ) return 0;
02767 #ifdef CSS_DEBUG
02768 kdDebug( 6080 ) << "parse rule: current = " << curP->latin1() << endl;
02769 #endif
02770
02771 if (*curP == '@' && curP < endP && ( (curP+1)->isLetter() || (curP+1)->unicode() > 0xa0 ) )
02772 {
02773 rule = parseAtRule(curP, endP);
02774 }
02775 else
02776 {
02777 rule = parseStyleRule(curP, endP);
02778 if( rule )
02779 hasInlinedDecl = true;
02780 }
02781
02782 if(curP) curP++;
02783 return rule;
02784 }
02785
02786
02787
02788
02789
02790
02791
02792
02793
02794
02795
02796
02797
02798
02799
02800
02801
02802
02803 const QString StyleBaseImpl::preprocess(const QString &str, bool justOneRule)
02804 {
02805
02806 QString processed;
02807
02808 bool sq = false;
02809 bool dq = false;
02810 bool bracket = false;
02811 bool comment = false;
02812 bool skipgarbage = !justOneRule;
02813 bool firstChar = false;
02814 bool space = true;
02815 int curlyBracket = 0;
02816 hasInlinedDecl = false;
02817
02818 const QChar *ch = str.unicode();
02819 const QChar *last = ch + str.length();
02820
02821 #ifdef CSS_DEBUG
02822 kdDebug(6080) << "---Before---" << endl;
02823 kdDebug(6080) << str << endl;
02824 float orgLength = str.length();
02825 kdDebug(6080) << "Length: " << orgLength << endl;
02826 #endif
02827
02828 while(ch < last) {
02829
02830
02831 if( !comment && !sq && *ch == '"' ) {
02832 dq = !dq;
02833 processed += *ch;
02834 space = skipgarbage = false;
02835 } else if ( !comment && !dq && *ch == '\'') {
02836 skipgarbage = sq;
02837 sq = !sq;
02838 processed += *ch;
02839 space = false;
02840 } else if ( !comment && !dq && !sq && *ch == '(') {
02841 bracket = true;
02842 processed += *ch;
02843 space = true;
02844 skipgarbage = false;
02845 } else if ( !comment && !dq && !sq && *ch == ')') {
02846 bracket = false;
02847 processed += *ch;
02848 processed += QChar(' ');
02849 space = true;
02850 skipgarbage = false;
02851 } else if ( !comment && !dq && !sq && *ch == '{') {
02852 ++curlyBracket;
02853 processed += *ch;
02854 space = true;
02855 skipgarbage = true;
02856 } else if ( !comment && !dq && !sq && *ch == '}') {
02857 --curlyBracket;
02858 processed += *ch;
02859 processed += QChar(' ');
02860 space = true;
02861 skipgarbage = true;
02862 } else if ( !comment && skipgarbage && !dq && !sq && (*ch == '-') && ((ch+2) < last)
02863 && (*(ch+1) == '-') && (*(ch+2) == '>')) {
02864 ch += 2;
02865 } else if ( !comment && skipgarbage && !dq && !sq && (*ch == '<') && ((ch+3) < last)
02866 && (*(ch+1) == '!') && (*(ch+2) == '-') && (*(ch+3) == '-')) {
02867 ch += 3;
02868 } else if ( comment ) {
02869 if ( firstChar && *ch == '/' ) {
02870 comment = false;
02871 firstChar = false;
02872 skipgarbage = true;
02873 } else {
02874 firstChar = ( *ch == '*' );
02875 }
02876 } else if ( !sq && !dq && !bracket ) {
02877
02878 if ( firstChar ) {
02879 if ( *ch == '*' ) {
02880 comment = true;
02881 } else {
02882 processed += '/';
02883 processed += *ch;
02884 space = ch->isSpace();
02885 }
02886 firstChar = false;
02887 } else if ( *ch == '/' ) {
02888 firstChar = true;
02889 } else if ( *ch == ',' || *ch == ';') {
02890 processed += *ch;
02891 processed += QChar(' ');
02892 space = true;
02893 skipgarbage = true;
02894 } else {
02895 if (!ch->isSpace())
02896 skipgarbage = false;
02897 goto addChar;
02898 }
02899 } else {
02900 skipgarbage = ch->isSpace();
02901 goto addChar;
02902 }
02903 end:
02904 ++ch;
02905 }
02906
02907 #ifdef CSS_DEBUG
02908 kdDebug(6080) << "---After ---" << endl;
02909 kdDebug(6080) << "[" << processed << "]" << endl;
02910 kdDebug(6080) << "------------" << endl;
02911 kdDebug(6080) << "Length: " << processed.length() << ", reduced size by: "
02912 << 100.0 - (100.0 * (processed.length()/orgLength)) << "%" << endl;
02913 kdDebug(6080) << "------------" << endl;
02914 #endif
02915
02916 return processed;
02917
02918 addChar:
02919 if ( !sq && !dq && !bracket ) {
02920 if (!(space && ch->isSpace())) {
02921 if (ch->isSpace()) {
02922 processed += QChar(' ');
02923 } else {
02924 processed += *ch;
02925 }
02926 }
02927 space = ch->isSpace();
02928 } else {
02929 processed += *ch;
02930 }
02931 goto end;
02932 }
02933
02934
02935
02936 StyleListImpl::~StyleListImpl()
02937 {
02938 StyleBaseImpl *n;
02939
02940 if(!m_lstChildren) return;
02941
02942 for( n = m_lstChildren->first(); n != 0; n = m_lstChildren->next() )
02943 {
02944 n->setParent(0);
02945 if( !n->refCount() ) delete n;
02946 }
02947 delete m_lstChildren;
02948 }
02949
02950
02951
02952 void CSSSelector::print(void)
02953 {
02954 kdDebug( 6080 ) << "[Selector: tag = " << tag << ", attr = \"" << attr << "\", match = \"" << match << "\" value = \"" << value.string().latin1() << "\" relation = " << (int)relation << endl;
02955 if ( tagHistory )
02956 tagHistory->print();
02957 }
02958
02959 unsigned int CSSSelector::specificity()
02960 {
02961 if ( nonCSSHint )
02962 return 0;
02963
02964 int s = (tag != -1);
02965 switch(match)
02966 {
02967 case Exact:
02968 if(attr == ATTR_ID)
02969 {
02970 s += 0x10000;
02971 break;
02972 }
02973 case Set:
02974 case List:
02975 case Hyphen:
02976 case Pseudo:
02977 case Contain:
02978 case Begin:
02979 case End:
02980 s += 0x100;
02981 case None:
02982 break;
02983 }
02984 if(tagHistory)
02985 s += tagHistory->specificity();
02986
02987 return s & 0xffffff;
02988 }
02989
02990 bool CSSSelector::operator == ( const CSSSelector &other )
02991 {
02992 const CSSSelector *sel1 = this;
02993 const CSSSelector *sel2 = &other;
02994
02995 while ( sel1 && sel2 ) {
02996 if ( sel1->tag != sel2->tag || sel1->attr != sel2->attr ||
02997 sel1->relation != sel2->relation || sel1->match != sel2->match ||
02998 sel1->nonCSSHint != sel2->nonCSSHint ||
02999 sel1->value != sel2->value )
03000 return false;
03001 sel1 = sel1->tagHistory;
03002 sel2 = sel2->tagHistory;
03003 }
03004 if ( sel1 || sel2 )
03005 return false;
03006 return true;
03007 }
03008
03009 DOMString CSSSelector::selectorText() const
03010 {
03011 DOMString str;
03012 const CSSSelector* cs = this;
03013 if ( cs->tag == -1 && cs->attr == ATTR_ID && cs->match == CSSSelector::Exact )
03014 {
03015 str = "#";
03016 str += cs->value;
03017 }
03018 else if ( cs->tag == -1 && cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
03019 {
03020 str = ".";
03021 str += cs->value;
03022 }
03023 else if ( cs->tag == -1 && cs->match == CSSSelector::Pseudo )
03024 {
03025 str = ":";
03026 str += cs->value;
03027 }
03028 else
03029 {
03030 if ( cs->tag == -1 )
03031 str = "*";
03032 else
03033 str = getTagName( cs->tag );
03034 if ( cs->attr == ATTR_ID && cs->match == CSSSelector::Exact )
03035 {
03036 str += "#";
03037 str += cs->value;
03038 }
03039 else if ( cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
03040 {
03041 str += ".";
03042 str += cs->value;
03043 }
03044 else if ( cs->match == CSSSelector::Pseudo )
03045 {
03046 str += ":";
03047 str += cs->value;
03048 }
03049
03050 if ( cs->attr ) {
03051 DOMString attrName = getAttrName( cs->attr );
03052 str += "[";
03053 str += attrName;
03054 switch (cs->match) {
03055 case CSSSelector::Exact:
03056 str += "=";
03057 break;
03058 case CSSSelector::Set:
03059 str += " ";
03060 break;
03061 case CSSSelector::List:
03062 str += "~=";
03063 break;
03064 case CSSSelector::Hyphen:
03065 str += "|=";
03066 break;
03067 case CSSSelector::Begin:
03068 str += "^=";
03069 break;
03070 case CSSSelector::End:
03071 str += "$=";
03072 break;
03073 case CSSSelector::Contain:
03074 str += "*=";
03075 break;
03076 default:
03077 kdWarning(6080) << "Unhandled case in CSSStyleRuleImpl::selectorText : match=" << cs->match << endl;
03078 }
03079 str += "\"";
03080 str += cs->value;
03081 str += "\"]";
03082 }
03083 }
03084 if ( cs->tagHistory ) {
03085 DOMString tagHistoryText = cs->tagHistory->selectorText();
03086 if ( cs->relation == Sibling )
03087 str = tagHistoryText + " + " + str;
03088 else if ( cs->relation == Child )
03089 str = tagHistoryText + " > " + str;
03090 else if ( cs->relation == SubSelector )
03091 str += tagHistoryText;
03092 else
03093 str = tagHistoryText + " " + str;
03094 }
03095 return str;
03096 }
03097
03098
03099