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, 0);
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, 0);
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 &&
01909 (cssval->id == CSS_VAL_AUTO || cssval->id == CSS_VAL_FIXED))
01910 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01911 break;
01912 }
01913 case CSS_PROP__KONQ_FLOW_MODE:
01914 {
01915 if (cssval->id==CSS_VAL__KONQ_NORMAL || cssval->id==CSS_VAL__KONQ_AROUND_FLOATS)
01916 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01917 break;
01918 }
01919
01920 case CSS_PROP_BACKGROUND:
01921
01922
01923 {
01924 #ifdef CSS_DEBUG_BCKGR
01925 kdDebug(6080) << "CSS_PROP_BACKGROUND" << endl;
01926 #endif
01927 const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
01928 CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,
01929 CSS_PROP_BACKGROUND_COLOR };
01930 return parseShortHand(curP, endP, properties, 5);
01931
01932
01933 }
01934 case CSS_PROP_BORDER:
01935
01936 {
01937 const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
01938 CSS_PROP_BORDER_COLOR };
01939 return parseShortHand(curP, endP, properties, 3);
01940 }
01941 case CSS_PROP_BORDER_TOP:
01942
01943 {
01944 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
01945 CSS_PROP_BORDER_TOP_COLOR};
01946 return parseShortHand(curP, endP, properties, 3);
01947 }
01948 case CSS_PROP_BORDER_RIGHT:
01949
01950 {
01951 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
01952 CSS_PROP_BORDER_RIGHT_COLOR };
01953 return parseShortHand(curP, endP, properties, 3);
01954 }
01955 case CSS_PROP_BORDER_BOTTOM:
01956
01957 {
01958 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
01959 CSS_PROP_BORDER_BOTTOM_COLOR };
01960 return parseShortHand(curP, endP, properties, 3);
01961 }
01962 case CSS_PROP_BORDER_LEFT:
01963
01964 {
01965 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
01966 CSS_PROP_BORDER_LEFT_COLOR };
01967 return parseShortHand(curP, endP, properties, 3);
01968 }
01969 case CSS_PROP_OUTLINE:
01970
01971 {
01972 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
01973 CSS_PROP_OUTLINE_COLOR };
01974 return parseShortHand(curP, endP, properties, 3);
01975 }
01976 case CSS_PROP_BORDER_COLOR:
01977
01978 {
01979 const struct css_value *cssval = findValue(val, len);
01980 if (cssval && cssval->id == CSS_VAL_TRANSPARENT)
01981 {
01982
01983 parsedValue = new CSSPrimitiveValueImpl(CSS_VAL_TRANSPARENT);
01984 break;
01985 }
01986 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
01987 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
01988 return parse4Values(curP, endP, properties);
01989 }
01990 case CSS_PROP_BORDER_WIDTH:
01991
01992 {
01993 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
01994 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
01995 return parse4Values(curP, endP, properties);
01996 }
01997 case CSS_PROP_BORDER_STYLE:
01998
01999 {
02000 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
02001 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
02002 return parse4Values(curP, endP, properties);
02003 }
02004 case CSS_PROP_MARGIN:
02005
02006 {
02007 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
02008 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
02009 return parse4Values(curP, endP, properties);
02010 }
02011 case CSS_PROP_PADDING:
02012
02013 {
02014 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
02015 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
02016 return parse4Values(curP, endP, properties);
02017 }
02018 case CSS_PROP_FONT:
02019
02020
02021 {
02022 return parseFont(curP, endP);
02023 }
02024 case CSS_PROP_LIST_STYLE:
02025 {
02026 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
02027 CSS_PROP_LIST_STYLE_IMAGE };
02028 return parseShortHand(curP, endP, properties, 3);
02029 }
02030
02031 default:
02032 {
02033 #ifdef CSS_DEBUG
02034 kdDebug( 6080 ) << "illegal or CSS2 Aural property: " << val << endl;
02035 #endif
02036 }
02037 }
02038 }
02039 if ( parsedValue ) {
02040 setParsedValue(propId, parsedValue);
02041 return true;
02042 } else {
02043 #ifndef CSS_AURAL
02044 return false;
02045 #endif
02046 #ifdef CSS_AURAL
02047 return parseAuralValue(curP, endP, propId);
02048 #endif
02049 }
02050 }
02051
02052 #ifdef CSS_AURAL
02053
02054 bool StyleBaseImpl::parseAuralValue( const QChar *curP, const QChar *endP, int propId )
02055 {
02056 QString value(curP, endP - curP);
02057 value = value.lower();
02058 const char *val = value.ascii();
02059
02060 CSSValueImpl *parsedValue = 0;
02061 kdDebug( 6080 ) << "parseAuralValue: " << value << " val: " << val << endl;
02062
02063
02064 switch(propId)
02065 {
02066 case CSS_PROP_AZIMUTH:
02067
02068
02069 case CSS_PROP_PAUSE_AFTER:
02070 case CSS_PROP_PAUSE_BEFORE:
02071 case CSS_PROP_PAUSE:
02072 case CSS_PROP_PLAY_DURING:
02073 case CSS_PROP_VOICE_FAMILY:
02074
02075 {
02076
02077 break;
02078 }
02079 case CSS_PROP_CUE:
02080 {
02081 const int properties[2] = {
02082 CSS_PROP_CUE_BEFORE,
02083 CSS_PROP_CUE_AFTER};
02084 return parse2Values(curP, endP, properties);
02085 }
02086 case CSS_PROP_CUE_AFTER:
02087 case CSS_PROP_CUE_BEFORE:
02088 {
02089 const struct css_value *cssval = findValue(val, endP - curP);
02090 if (cssval) {
02091 if (cssval->id == CSS_VAL_NONE) {
02092 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
02093 }
02094 } else {
02095 DOMString value(curP, endP - curP);
02096 value = khtml::parseURL(value);
02097 parsedValue = new CSSPrimitiveValueImpl(
02098 DOMString(KURL(baseURL(), value).url()),
02099 CSSPrimitiveValue::CSS_URI);
02100 }
02101 break;
02102 }
02103 case CSS_PROP_ELEVATION:
02104
02105 {
02106 const struct css_value *cssval = findValue(val, endP - curP);
02107 if (cssval) {
02108 int id = cssval->id;
02109 if (id == CSS_VAL_BELOW || id == CSS_VAL_LEVEL || id == CSS_VAL_ABOVE ||
02110 id == CSS_VAL_HIGHER || id == CSS_VAL_LOWER) {
02111 parsedValue = new CSSPrimitiveValueImpl(id);
02112 break;
02113 }
02114 }
02115 parsedValue = parseUnit(curP, endP, ANGLE );
02116 break;
02117 }
02118 case CSS_PROP_SPEECH_RATE:
02119
02120 {
02121 const struct css_value *cssval = findValue(val, endP - curP);
02122 if (cssval) {
02123 int id = cssval->id;
02124 if (id == CSS_VAL_X_SLOW || id == CSS_VAL_SLOW || id == CSS_VAL_MEDIUM ||
02125 id == CSS_VAL_FAST || id == CSS_VAL_X_FAST || id == CSS_VAL_FASTER ||
02126 id == CSS_VAL_SLOWER) {
02127 parsedValue = new CSSPrimitiveValueImpl(id);
02128 break;
02129 }
02130 } else {
02131 parsedValue = parseUnit(curP, endP, NUMBER );
02132 }
02133 break;
02134 }
02135 case CSS_PROP_VOLUME:
02136
02137 {
02138 const struct css_value *cssval = findValue(val, endP - curP);
02139 if (cssval) {
02140 int id = cssval->id;
02141 if (id == CSS_VAL_SILENT || id == CSS_VAL_X_SOFT || id == CSS_VAL_SOFT ||
02142 id == CSS_VAL_MEDIUM || id == CSS_VAL_X_LOUD || id == CSS_VAL_X_LOUD) {
02143 parsedValue = new CSSPrimitiveValueImpl(id);
02144 }
02145 } else {
02146 parsedValue = parseUnit(curP, endP, PERCENT | NUMBER);
02147 }
02148 break;
02149 }
02150 case CSS_PROP_PITCH:
02151 {
02152 const struct css_value *cssval = findValue(val, endP - curP);
02153 if (cssval) {
02154 int id = cssval->id;
02155 if (id == CSS_VAL_X_LOW || id == CSS_VAL_LOW || id == CSS_VAL_MEDIUM ||
02156 id == CSS_VAL_HIGH || id == CSS_VAL_X_HIGH ) {
02157 parsedValue = new CSSPrimitiveValueImpl(id);
02158 }
02159 } else {
02160 parsedValue = parseUnit(curP, endP, FREQUENCY);
02161 }
02162 break;
02163 }
02164 case CSS_PROP_SPEAK:
02165 case CSS_PROP_SPEAK_HEADER:
02166 case CSS_PROP_SPEAK_NUMERAL:
02167 case CSS_PROP_SPEAK_PUNCTUATION:
02168 {
02169 const struct css_value *cssval = findValue(val, endP - curP);
02170 if (cssval)
02171 {
02172 parsedValue = new CSSPrimitiveValueImpl(cssval->id);
02173 }
02174 break;
02175 }
02176 case CSS_PROP_PITCH_RANGE:
02177 case CSS_PROP_RICHNESS:
02178 case CSS_PROP_STRESS:
02179 {
02180 parsedValue = parseUnit(curP, endP, NUMBER);
02181 break;
02182 }
02183 default:
02184 {
02185 kdDebug( 6080 ) << "illegal property: " << val << endl;
02186 }
02187 }
02188 if ( parsedValue ) {
02189 setParsedValue( propId, parsedValue );
02190 return true;
02191 }
02192 return false;
02193 }
02194 #endif
02195
02196 void StyleBaseImpl::setParsedValue(int propId, const CSSValueImpl *parsedValue,
02197 bool important, bool nonCSSHint, QPtrList<CSSProperty> *propList)
02198 {
02199 m_bImportant = important;
02200 m_bnonCSSHint = nonCSSHint;
02201 m_propList = propList;
02202 setParsedValue( propId, parsedValue);
02203 }
02204
02205 void StyleBaseImpl::setParsedValue( int propId, const CSSValueImpl *parsedValue)
02206 {
02207 QPtrListIterator<CSSProperty> propIt(*m_propList);
02208 propIt.toLast();
02209 while (propIt.current() &&
02210 ( propIt.current()->m_id != propId || propIt.current()->nonCSSHint != m_bnonCSSHint ||
02211 propIt.current()->m_bImportant != m_bImportant) )
02212 --propIt;
02213 if (propIt.current())
02214 m_propList->removeRef(propIt.current());
02215
02216 CSSProperty *prop = new CSSProperty();
02217 prop->m_id = propId;
02218 prop->setValue((CSSValueImpl *) parsedValue);
02219 prop->m_bImportant = m_bImportant;
02220 prop->nonCSSHint = m_bnonCSSHint;
02221
02222 m_propList->append(prop);
02223 #ifdef CSS_DEBUG
02224 kdDebug( 6080 ) << "added property: " << getPropertyName(propId).string()
02225
02226 << " important: " << prop->m_bImportant
02227 << " nonCSS: " << prop->nonCSSHint << endl;
02228 #endif
02229 }
02230
02231 bool StyleBaseImpl::parseShortHand(const QChar *curP, const QChar *endP, const int *properties, int num)
02232 {
02233
02234
02235
02236
02237
02238 bool isLast = false;
02239 bool foundAnything = false;
02240 bool fnd[6];
02241 for( int i = 0; i < num; i++ )
02242 fnd[i] = false;
02243
02244 #ifdef CSS_DEBUG
02245 kdDebug(6080) << "PSH: parsing \"" << QString(curP, endP - curP) << "\" num=" << num << endl;
02246 #endif
02247
02248 for (int j = 0; j < num; ++j) {
02249 const QChar *nextP = getNext( curP, endP, isLast );
02250
02251 foundAnything = false;
02252 for (int propIndex = 0; propIndex < num; ++propIndex) {
02253 if (!fnd[propIndex]) {
02254
02255
02256 bool found = false;
02257 if (!isLast && properties[propIndex] == CSS_PROP_BACKGROUND_POSITION)
02258 found = parseBackgroundPosition(curP, nextP, endP);
02259 else
02260 found = parseValue(curP, nextP, properties[propIndex]);
02261
02262 if (found) {
02263 fnd[propIndex] = foundAnything = true;
02264 #ifdef CSS_DEBUG
02265 kdDebug(6080) << "FOUND: " << getPropertyName(properties[propIndex]).string() << ": "
02266 << QString(curP, nextP - curP) << endl;
02267 #endif
02268 break;
02269 }
02270 }
02271 }
02272
02273
02274 if (!foundAnything)
02275 return foundAnything;
02276
02277 do {
02278 nextP++;
02279 curP = nextP;
02280
02281
02282 if (curP >= endP)
02283 return foundAnything;
02284 } while (curP->isSpace());
02285 }
02286 return foundAnything;
02287 }
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297
02298
02299 bool StyleBaseImpl::parseBackgroundPosition(const QChar *curP, const QChar *&nextP, const QChar *endP)
02300 {
02301
02302
02303
02304 const QChar *bckgrNextP = nextP;
02305 while (bckgrNextP->isSpace() && bckgrNextP < endP) { bckgrNextP++; }
02306 bool dummy;
02307 bckgrNextP = getNext(bckgrNextP, endP, dummy);
02308
02309
02310 bool found = parseValue(curP, bckgrNextP, CSS_PROP_BACKGROUND_POSITION);
02311 if (!found) {
02312
02313
02314
02315 found = parseValue(curP, nextP, CSS_PROP_BACKGROUND_POSITION);
02316 } else {
02317
02318 nextP = bckgrNextP;
02319 }
02320
02321 return found;
02322 }
02323
02324
02325 CSSValueImpl* StyleBaseImpl::parseContent(const QChar *curP, const QChar *endP)
02326 {
02327 CSSValueListImpl* values = new CSSValueListImpl();
02328
02329
02330 while (curP < endP) {
02331 const QChar *nextP = curP;
02332 bool esc = false;
02333 bool sq = false;
02334 bool dq = false;
02335 while ( nextP < endP ) {
02336 if (esc)
02337 esc = false;
02338 else if (*nextP == '\\')
02339 esc = true;
02340 else if (!sq && (*nextP == '"')) {
02341 if (dq) break;
02342 dq = true;
02343 }
02344 else if (!dq && (*nextP == '\'')) {
02345 if (sq) break;
02346 sq = true;
02347 }
02348 else if (!sq && !dq && nextP->isSpace())
02349 break;
02350 nextP++;
02351 }
02352 QString str = QConstString(curP, nextP-curP).string();
02353 CSSValueImpl* parsedValue=0;
02354 if (str.startsWith("url("))
02355 {
02356
02357 DOMString value = khtml::parseURL(DOMString(str));
02358 parsedValue = new CSSImageValueImpl(
02359 DOMString(KURL(baseURL().string(), value.string()).url()), this);
02360 #ifdef CSS_DEBUG
02361 kdDebug( 6080 ) << "content, url=" << value.string() << " base=" << baseURL().string() << endl;
02362 #endif
02363 }
02364 else if (str.startsWith("attr("))
02365 {
02366
02367 }
02368 else if (str.startsWith("open-quote"))
02369 {
02370
02371 }
02372 else if (str.startsWith("close-quote"))
02373 {
02374
02375 }
02376 else if (str.startsWith("no-open-quote"))
02377 {
02378
02379 }
02380 else if (str.startsWith("no-close-quote"))
02381 {
02382
02383 }
02384 else if (str.length() && (str[0] == '\'' || str[0] == '"'))
02385 {
02386
02387 int l = str.length();
02388 QString strstr;
02389
02390 for (int i = 1; i < l; ++i) {
02391 if (i < l - 1 && str[i] == '\\') {
02392 QChar nextChar = str[i+1];
02393 if (nextChar == '\n') {
02394 i++;
02395 }
02396 else if ( nextChar == '\r' ) {
02397 i++;
02398 if ( str[i+1] == '\n' )
02399 i++;
02400 }
02401 else if ( isHexadecimal( nextChar ) ) {
02402 int initial=i;
02403 QString hex;
02404 bool ok;
02405 while ( i-initial<6 && i<l-1 && isHexadecimal( nextChar ) ) {
02406 hex += nextChar;
02407 i++;
02408 nextChar = str[i+1];
02409 }
02410
02411 strstr += QChar( hex.toInt(&ok, 16) );
02412 if ( i<l-1 && nextChar.isSpace() ) {
02413 i++;
02414 if ( nextChar == '\r' && str[i+1] == '\n' ) {
02415 i++;
02416 }
02417 }
02418 }
02419 else {
02420 ++i;
02421 strstr += nextChar;
02422 }
02423 }
02424 else
02425 strstr += str[i];
02426 }
02427 parsedValue = new CSSPrimitiveValueImpl(DOMString(strstr), CSSPrimitiveValue::CSS_STRING);
02428 }
02429 if (parsedValue)
02430 values->append(parsedValue);
02431
02432
02433 for (curP = ++nextP ; curP < endP && curP->isSpace(); ++curP)
02434 ;
02435 }
02436 return values;
02437 }
02438
02439 bool StyleBaseImpl::isHexadecimal( QChar &c )
02440 {
02441 return ( c >= '0' && c <= '9' ) ||
02442 ( c >= 'a' && c <= 'f' ) ||
02443 ( c >= 'A' && c <= 'F' ) ;
02444 }
02445
02446 QPtrList<QChar> StyleBaseImpl::splitShorthandProperties(const QChar *curP, const QChar *endP)
02447 {
02448 bool last = false;
02449 QPtrList<QChar> list;
02450 while(!last) {
02451 const QChar *nextP = getNext(curP, endP, last);
02452 list.append(curP);
02453 list.append(nextP);
02454 if ( last ) break;
02455 while(nextP->isSpace()) {
02456 nextP++;
02457 curP = nextP;
02458 if(curP >= endP) {
02459 last = true;
02460 break;
02461 }
02462 }
02463 }
02464 return list;
02465 }
02466
02467 #ifdef CSS_AURAL
02468
02469 bool StyleBaseImpl::parse2Values( const QChar *curP, const QChar *endP, const int *properties)
02470 {
02471 QPtrList<QChar> list = splitShorthandProperties(curP, endP);
02472 switch(list.count())
02473 {
02474 case 2:
02475 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02476 setParsedValue(properties[1], m_propList->last()->value() );
02477 return true;
02478 case 4:
02479 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02480 if(!parseValue(list.at(2), list.at(3), properties[1])) return false;
02481 return true;
02482 default:
02483 return false;
02484 }
02485 }
02486 #endif
02487
02488
02489 bool StyleBaseImpl::parse4Values( const QChar *curP, const QChar *endP, const int *properties)
02490 {
02491
02492
02493
02494
02495
02496
02497
02498
02499 QPtrList<QChar> list = splitShorthandProperties(curP, endP);
02500 switch(list.count())
02501 {
02502 case 2:
02503 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02504 setParsedValue(properties[1], m_propList->last()->value());
02505 setParsedValue(properties[2], m_propList->last()->value());
02506 setParsedValue(properties[3], m_propList->last()->value());
02507 return true;
02508 case 4:
02509 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02510 setParsedValue(properties[2], m_propList->last()->value());
02511 if(!parseValue(list.at(2), list.at(3), properties[1])) return false;
02512 setParsedValue(properties[3], m_propList->last()->value());
02513 return true;
02514 case 6:
02515 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02516 if(!parseValue(list.at(2), list.at(3), properties[1])) return false;
02517 setParsedValue(properties[3], m_propList->last()->value());
02518 if(!parseValue(list.at(4), list.at(5), properties[2])) return false;
02519 return true;
02520 case 8:
02521 if(!parseValue(list.at(0), list.at(1), properties[0])) return false;
02522 if(!parseValue(list.at(2), list.at(3), properties[1])) return false;
02523 if(!parseValue(list.at(4), list.at(5), properties[2])) return false;
02524 if(!parseValue(list.at(6), list.at(7), properties[3])) return false;
02525 return true;
02526 default:
02527 return false;
02528 }
02529 }
02530
02531 CSSPrimitiveValueImpl *
02532 StyleBaseImpl::parseUnit(const QChar * curP, const QChar *endP, int allowedUnits)
02533 {
02534
02535 if (curP==endP || *curP=='"')
02536 return 0;
02537
02538 if ( allowedUnits & RELATIVE && *curP == '*' )
02539 return new CSSPrimitiveValueImpl( 1., CSSPrimitiveValue::CSS_HTML_RELATIVE );
02540
02541 endP--;
02542 while(*endP == ' ' && endP > curP) endP--;
02543 const QChar *split = endP;
02544
02545 while( (*split < '0' || *split > '9') && *split != '.' && split > curP)
02546 split--;
02547 split++;
02548
02549 QString s(curP, split-curP);
02550
02551 bool isInt = false;
02552 if(s.find('.') == -1) isInt = true;
02553
02554 bool ok;
02555 float value = s.toFloat(&ok);
02556
02557 if ( !ok || ( value < 0 && (allowedUnits & NONNEGATIVE) ))
02558 return 0;
02559
02560 if(split > endP)
02561 {
02562 if(allowedUnits & NUMBER)
02563 return new CSSPrimitiveValueImpl(value, CSSPrimitiveValue::CSS_NUMBER);
02564
02565 if(allowedUnits & INTEGER && isInt)
02566 return new CSSPrimitiveValueImpl(value, CSSPrimitiveValue::CSS_NUMBER);
02567
02568
02569
02570
02571 if(( allowedUnits & LENGTH ) && (value == 0 || !strictParsing) )
02572 return new CSSPrimitiveValueImpl(value, CSSPrimitiveValue::CSS_PX);
02573
02574 return 0;
02575 }
02576
02577 CSSPrimitiveValue::UnitTypes type = CSSPrimitiveValue::CSS_UNKNOWN;
02578 StyleBaseImpl::Units unit = StyleBaseImpl::UNKNOWN;
02579
02580 switch(split->latin1())
02581 {
02582 case '%':
02583 type = CSSPrimitiveValue::CSS_PERCENTAGE;
02584 unit = StyleBaseImpl::PERCENT;
02585 break;
02586 case '*':
02587 type = CSSPrimitiveValue::CSS_HTML_RELATIVE;
02588 unit = StyleBaseImpl::RELATIVE;
02589 case 'e':
02590 split++;
02591 if(split > endP) break;
02592 switch(split->latin1())
02593 {
02594 case 'm':
02595 type = CSSPrimitiveValue::CSS_EMS;
02596 unit = StyleBaseImpl::LENGTH;
02597 break;
02598 case 'x':
02599 type = CSSPrimitiveValue::CSS_EXS;
02600 unit = StyleBaseImpl::LENGTH;
02601 break;
02602 }
02603 break;
02604 case 'p':
02605 split++;
02606 if(split > endP) break;
02607 switch(split->latin1())
02608 {
02609 case 'x':
02610 type = CSSPrimitiveValue::CSS_PX;
02611 unit = StyleBaseImpl::LENGTH;
02612 break;
02613 case 't':
02614 type = CSSPrimitiveValue::CSS_PT;
02615 unit = StyleBaseImpl::LENGTH;
02616 break;
02617 case 'c':
02618 type = CSSPrimitiveValue::CSS_PC;
02619 unit = StyleBaseImpl::LENGTH;
02620 break;
02621 }
02622 break;
02623 case 'c':
02624 split++;
02625 if(split > endP) break;
02626 if(split->latin1() == 'm')
02627 {
02628 type = CSSPrimitiveValue::CSS_CM;
02629 unit = StyleBaseImpl::LENGTH;
02630 }
02631 break;
02632 case 'm':
02633 split++;
02634 if(split > endP) break;
02635 switch(split->latin1())
02636 {
02637 case 'm':
02638 type = CSSPrimitiveValue::CSS_MM;
02639 unit = StyleBaseImpl::LENGTH;
02640 break;
02641 case 's':
02642 type = CSSPrimitiveValue::CSS_MS;
02643 unit = StyleBaseImpl::TIME;
02644 break;
02645 }
02646 break;
02647 case 'i':
02648 split++;
02649 if(split > endP) break;
02650 if(split->latin1() == 'n')
02651 {
02652 type = CSSPrimitiveValue::CSS_IN;
02653 unit = StyleBaseImpl::LENGTH;
02654 }
02655 break;
02656 case 'd':
02657 type = CSSPrimitiveValue::CSS_DEG;
02658 unit = StyleBaseImpl::ANGLE;
02659 break;
02660 case 'r':
02661 type = CSSPrimitiveValue::CSS_RAD;
02662 unit = StyleBaseImpl::ANGLE;
02663 break;
02664 case 'g':
02665 type = CSSPrimitiveValue::CSS_GRAD;
02666 unit = StyleBaseImpl::ANGLE;
02667 break;
02668 case 's':
02669 type = CSSPrimitiveValue::CSS_S;
02670 unit = StyleBaseImpl::TIME;
02671 break;
02672 case 'h':
02673 type = CSSPrimitiveValue::CSS_HZ;
02674 unit = StyleBaseImpl::FREQUENCY;
02675 break;
02676 case 'k':
02677 type = CSSPrimitiveValue::CSS_KHZ;
02678 unit = StyleBaseImpl::FREQUENCY;
02679 break;
02680 }
02681
02682 if(unit & allowedUnits)
02683 {
02684 #ifdef CSS_DEBUG
02685 kdDebug( 6080 ) << "found allowed number " << value << ", unit " << type << endl;
02686 #endif
02687 return new CSSPrimitiveValueImpl(value, type);
02688 }
02689
02690 return 0;
02691 }
02692
02693 CSSRuleImpl *
02694 StyleBaseImpl::parseStyleRule(const QChar *&curP, const QChar *endP)
02695 {
02696
02697
02698 const QChar *startP;
02699 QPtrList<CSSSelector> *slist;
02700 QPtrList<CSSProperty> *plist;
02701
02702 startP = curP;
02703 curP = parseToChar(startP, endP, '{', false);
02704 if (!curP)
02705 return(0);
02706 #ifdef CSS_DEBUG
02707 kdDebug( 6080 ) << "selector is \'" << QString(startP, curP-startP) << "\'" << endl;
02708 #endif
02709
02710 slist = parseSelector(startP, curP );
02711
02712 curP++;
02713
02714 startP = curP;
02715 curP = parseToChar(startP, endP, '}', false);
02716
02717 if (!curP)
02718 {
02719 delete slist;
02720 return(0);
02721 }
02722 #ifdef CSS_DEBUG
02723 kdDebug( 6080 ) << "rules are \'" << QString(startP, curP-startP) << "\'" << endl;
02724 #endif
02725
02726 plist = parseProperties(startP, curP );
02727
02728 curP++;
02729
02730 if (!plist || !slist)
02731 {
02732
02733 delete slist;
02734 delete plist;
02735 #ifdef CSS_DEBUG
02736 kdDebug( 6080 ) << "bad style rule" << endl;
02737 #endif
02738 return 0;
02739 }
02740
02741
02742 CSSStyleRuleImpl *rule = new CSSStyleRuleImpl(this);
02743 CSSStyleDeclarationImpl *decl = new CSSStyleDeclarationImpl(rule, plist);
02744
02745 rule->setSelector(slist);
02746 rule->setDeclaration(decl);
02747
02748 return rule;
02749 }
02750
02751 CSSRuleImpl *
02752 StyleBaseImpl::parseRule(const QChar *&curP, const QChar *endP)
02753 {
02754 const QChar *startP;
02755
02756 curP = parseSpace( curP, endP );
02757
02758 if (!strictParsing) {
02759
02760 while (curP && curP != endP && (curP->isSpace() || *curP == ';'))
02761 curP++;
02762 }
02763
02764 startP = curP;
02765 CSSRuleImpl *rule = 0;
02766
02767 if(!curP || curP >= endP ) return 0;
02768 #ifdef CSS_DEBUG
02769 kdDebug( 6080 ) << "parse rule: current = " << curP->latin1() << endl;
02770 #endif
02771
02772 if (*curP == '@' && curP < endP && ( (curP+1)->isLetter() || (curP+1)->unicode() > 0xa0 ) )
02773 {
02774 rule = parseAtRule(curP, endP);
02775 }
02776 else
02777 {
02778 rule = parseStyleRule(curP, endP);
02779 if( rule )
02780 hasInlinedDecl = true;
02781 }
02782
02783 if(curP) curP++;
02784 return rule;
02785 }
02786
02787
02788
02789
02790
02791
02792
02793
02794
02795
02796
02797
02798
02799
02800
02801
02802
02803
02804 const QString StyleBaseImpl::preprocess(const QString &str, bool justOneRule)
02805 {
02806
02807 QString processed;
02808
02809 bool sq = false;
02810 bool dq = false;
02811 bool bracket = false;
02812 bool comment = false;
02813 bool skipgarbage = !justOneRule;
02814 bool firstChar = false;
02815 bool space = true;
02816 int curlyBracket = 0;
02817 hasInlinedDecl = false;
02818
02819 const QChar *ch = str.unicode();
02820 const QChar *last = ch + str.length();
02821
02822 #ifdef CSS_DEBUG
02823 kdDebug(6080) << "---Before---" << endl;
02824 kdDebug(6080) << str << endl;
02825 float orgLength = str.length();
02826 kdDebug(6080) << "Length: " << orgLength << endl;
02827 #endif
02828
02829 while(ch < last) {
02830
02831
02832 if( !comment && !sq && *ch == '"' ) {
02833 dq = !dq;
02834 processed += *ch;
02835 space = skipgarbage = false;
02836 } else if ( !comment && !dq && *ch == '\'') {
02837 skipgarbage = sq;
02838 sq = !sq;
02839 processed += *ch;
02840 space = false;
02841 } else if ( !comment && !dq && !sq && *ch == '(') {
02842 bracket = true;
02843 processed += *ch;
02844 space = true;
02845 skipgarbage = false;
02846 } else if ( !comment && !dq && !sq && *ch == ')') {
02847 bracket = false;
02848 processed += *ch;
02849 processed += QChar(' ');
02850 space = true;
02851 skipgarbage = false;
02852 } else if ( !comment && !dq && !sq && *ch == '{') {
02853 ++curlyBracket;
02854 processed += *ch;
02855 space = true;
02856 skipgarbage = true;
02857 } else if ( !comment && !dq && !sq && *ch == '}') {
02858 --curlyBracket;
02859 processed += *ch;
02860 processed += QChar(' ');
02861 space = true;
02862 skipgarbage = true;
02863 } else if ( !comment && skipgarbage && !dq && !sq && (*ch == '-') && ((ch+2) < last)
02864 && (*(ch+1) == '-') && (*(ch+2) == '>')) {
02865 ch += 2;
02866 } else if ( !comment && skipgarbage && !dq && !sq && (*ch == '<') && ((ch+3) < last)
02867 && (*(ch+1) == '!') && (*(ch+2) == '-') && (*(ch+3) == '-')) {
02868 ch += 3;
02869 } else if ( comment ) {
02870 if ( firstChar && *ch == '/' ) {
02871 comment = false;
02872 firstChar = false;
02873 skipgarbage = true;
02874 } else {
02875 firstChar = ( *ch == '*' );
02876 }
02877 } else if ( !sq && !dq && !bracket ) {
02878
02879 if ( firstChar ) {
02880 if ( *ch == '*' ) {
02881 comment = true;
02882 } else {
02883 processed += '/';
02884 processed += *ch;
02885 space = ch->isSpace();
02886 }
02887 firstChar = false;
02888 } else if ( *ch == '/' ) {
02889 firstChar = true;
02890 } else if ( *ch == ',' || *ch == ';') {
02891 processed += *ch;
02892 processed += QChar(' ');
02893 space = true;
02894 skipgarbage = true;
02895 } else {
02896 if (!ch->isSpace())
02897 skipgarbage = false;
02898 goto addChar;
02899 }
02900 } else {
02901 skipgarbage = ch->isSpace();
02902 goto addChar;
02903 }
02904 end:
02905 ++ch;
02906 }
02907
02908 #ifdef CSS_DEBUG
02909 kdDebug(6080) << "---After ---" << endl;
02910 kdDebug(6080) << "[" << processed << "]" << endl;
02911 kdDebug(6080) << "------------" << endl;
02912 kdDebug(6080) << "Length: " << processed.length() << ", reduced size by: "
02913 << 100.0 - (100.0 * (processed.length()/orgLength)) << "%" << endl;
02914 kdDebug(6080) << "------------" << endl;
02915 #endif
02916
02917 return processed;
02918
02919 addChar:
02920 if ( !sq && !dq && !bracket ) {
02921 if (!(space && ch->isSpace())) {
02922 if (ch->isSpace()) {
02923 processed += QChar(' ');
02924 } else {
02925 processed += *ch;
02926 }
02927 }
02928 space = ch->isSpace();
02929 } else {
02930 processed += *ch;
02931 }
02932 goto end;
02933 }
02934
02935
02936
02937 StyleListImpl::~StyleListImpl()
02938 {
02939 StyleBaseImpl *n;
02940
02941 if(!m_lstChildren) return;
02942
02943 for( n = m_lstChildren->first(); n != 0; n = m_lstChildren->next() )
02944 {
02945 n->setParent(0);
02946 if( !n->refCount() ) delete n;
02947 }
02948 delete m_lstChildren;
02949 }
02950
02951
02952
02953 void CSSSelector::print(void)
02954 {
02955 kdDebug( 6080 ) << "[Selector: tag = " << tag << ", attr = \"" << attr << "\", match = \"" << match << "\" value = \"" << value.string().latin1() << "\" relation = " << (int)relation << endl;
02956 if ( tagHistory )
02957 tagHistory->print();
02958 }
02959
02960 unsigned int CSSSelector::specificity()
02961 {
02962 if ( nonCSSHint )
02963 return 0;
02964
02965 int s = (tag != -1);
02966 switch(match)
02967 {
02968 case Exact:
02969 if(attr == ATTR_ID)
02970 {
02971 s += 0x10000;
02972 break;
02973 }
02974 case Set:
02975 case List:
02976 case Hyphen:
02977 case Pseudo:
02978 case Contain:
02979 case Begin:
02980 case End:
02981 s += 0x100;
02982 case None:
02983 break;
02984 }
02985 if(tagHistory)
02986 s += tagHistory->specificity();
02987
02988 return s & 0xffffff;
02989 }
02990
02991 bool CSSSelector::operator == ( const CSSSelector &other )
02992 {
02993 const CSSSelector *sel1 = this;
02994 const CSSSelector *sel2 = &other;
02995
02996 while ( sel1 && sel2 ) {
02997 if ( sel1->tag != sel2->tag || sel1->attr != sel2->attr ||
02998 sel1->relation != sel2->relation || sel1->match != sel2->match ||
02999 sel1->nonCSSHint != sel2->nonCSSHint ||
03000 sel1->value != sel2->value )
03001 return false;
03002 sel1 = sel1->tagHistory;
03003 sel2 = sel2->tagHistory;
03004 }
03005 if ( sel1 || sel2 )
03006 return false;
03007 return true;
03008 }
03009
03010 DOMString CSSSelector::selectorText() const
03011 {
03012 DOMString str;
03013 const CSSSelector* cs = this;
03014 if ( cs->tag == -1 && cs->attr == ATTR_ID && cs->match == CSSSelector::Exact )
03015 {
03016 str = "#";
03017 str += cs->value;
03018 }
03019 else if ( cs->tag == -1 && cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
03020 {
03021 str = ".";
03022 str += cs->value;
03023 }
03024 else if ( cs->tag == -1 && cs->match == CSSSelector::Pseudo )
03025 {
03026 str = ":";
03027 str += cs->value;
03028 }
03029 else
03030 {
03031 if ( cs->tag == -1 )
03032 str = "*";
03033 else
03034 str = getTagName( cs->tag );
03035 if ( cs->attr == ATTR_ID && cs->match == CSSSelector::Exact )
03036 {
03037 str += "#";
03038 str += cs->value;
03039 }
03040 else if ( cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
03041 {
03042 str += ".";
03043 str += cs->value;
03044 }
03045 else if ( cs->match == CSSSelector::Pseudo )
03046 {
03047 str += ":";
03048 str += cs->value;
03049 }
03050
03051 if ( cs->attr ) {
03052 DOMString attrName = getAttrName( cs->attr );
03053 str += "[";
03054 str += attrName;
03055 switch (cs->match) {
03056 case CSSSelector::Exact:
03057 str += "=";
03058 break;
03059 case CSSSelector::Set:
03060 str += " ";
03061 break;
03062 case CSSSelector::List:
03063 str += "~=";
03064 break;
03065 case CSSSelector::Hyphen:
03066 str += "|=";
03067 break;
03068 case CSSSelector::Begin:
03069 str += "^=";
03070 break;
03071 case CSSSelector::End:
03072 str += "$=";
03073 break;
03074 case CSSSelector::Contain:
03075 str += "*=";
03076 break;
03077 default:
03078 kdWarning(6080) << "Unhandled case in CSSStyleRuleImpl::selectorText : match=" << cs->match << endl;
03079 }
03080 str += "\"";
03081 str += cs->value;
03082 str += "\"]";
03083 }
03084 }
03085 if ( cs->tagHistory ) {
03086 DOMString tagHistoryText = cs->tagHistory->selectorText();
03087 if ( cs->relation == Sibling )
03088 str = tagHistoryText + " + " + str;
03089 else if ( cs->relation == Child )
03090 str = tagHistoryText + " > " + str;
03091 else if ( cs->relation == SubSelector )
03092 str += tagHistoryText;
03093 else
03094 str = tagHistoryText + " " + str;
03095 }
03096 return str;
03097 }
03098
03099
03100