khtml Library API Documentation

cssparser.cpp

00001 /*
00002  * This file is part of the DOM implementation for KDE.
00003  *
00004  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
00005  *               1999 Waldo Bastian (bastian@kde.org)
00006  *               2001 Andreas Schlapbach (schlpbch@iam.unibe.ch)
00007  *               2001 Dirk Mueller (mueller@kde.org)
00008  *
00009  * $Id: cssparser.cpp,v 1.231.2.3 2003/06/26 20:57:57 staikos Exp $
00010  *
00011  * This library is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Library General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2 of the License, or (at your option) any later version.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Library General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Library General Public License
00022  * along with this library; see the file COPYING.LIB.  If not, write to
00023  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00024  * Boston, MA 02111-1307, USA.
00025  */
00026 
00027 //#define CSS_DEBUG
00028 //#define CSS_AURAL
00029 //#define CSS_DEBUG_BCKGR
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> // For system fonts
00053 #include <kapplication.h>
00054 
00055 #include "misc/htmlhashes.h"
00056 #include "misc/helper.h"
00057 
00058 //
00059 // The following file defines the function
00060 //     const struct props *findProp(const char *word, int len)
00061 //
00062 // with 'props->id' a CSS property in the range from CSS_PROP_MIN to
00063 // (and including) CSS_PROP_TOTAL-1
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     // try to find the style sheet. If found look for its url.
00091     // If it has none, look for the parentsheet, or the parentNode and
00092     // try to find out about their url
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     // find parent
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  * parsing functions for stylesheets
00115  */
00116 
00117 const QChar *
00118 StyleBaseImpl::parseSpace(const QChar *curP, const QChar *endP)
00119 {
00120   bool sc = false;     // possible start comment?
00121   bool ec = false;     // possible end comment?
00122   bool ic = false;     // in comment?
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       //else if (!isspace(*curP))
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  * ParseToChar
00160  *
00161  * Search for an expected character.  Deals with escaped characters,
00162  * quoted strings, and pairs of braces/parens/brackets.
00163  */
00164 const QChar *
00165 StyleBaseImpl::parseToChar(const QChar *curP, const QChar *endP, QChar c, bool chkws, bool endAtBlock)
00166 {
00167     //kdDebug( 6080 ) << "parsetochar: \"" << QString(curP, endP-curP) << "\" searching " << c << " ws=" << chkws << endl;
00168 
00169     bool sq = false; /* in single quote? */
00170     bool dq = false; /* in double quote? */
00171     bool esc = false; /* escape mode? */
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     //kdDebug( 6080 ) << "rule = '" << rule << "'" << endl;
00222 
00223     if(rule == "import")
00224     {
00225         // load stylesheet and pass it over
00226         curP = parseSpace(curP, endP);
00227         if(!curP) return 0;
00228         startP = curP++;
00229         curP = parseToChar(startP, endP, ';', true);
00230         // Do not allow @import statements after explicity inlined
00231         // declarations.  They should simply be ignored per CSS-1
00232         // specification section 3.0.
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         // ### check if at the beginning of the stylesheet (no style rule
00242         //     before the import rule)
00243 #ifdef CSS_DEBUG
00244         kdDebug( 6080 ) << "import rule = " << url.string() << ", mediaList = "
00245                         << mediaList.string() << endl;
00246 #endif
00247         // ignore block following @import rule
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         // ### invoke decoder
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         //qDebug("mediaList = '%s'", mediaList.latin1() );
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     //QString selecString( curP, endP - curP );
00316     //kdDebug( 6080 ) << "getValue = \"" << selecString << "\"" << endl;
00317     endVal = curP;
00318     endVal++; // ignore first char (could be the ':' form the pseudo classes)
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         // pseudo attributes (:link, :hover, ...), they are case insensitive.
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                 // pseudo attributes (:link, :hover, ...), they are case insensitive.
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                     // ### fixme we ignore everything after [..]
00421                     if( endVal == endP )
00422                         endVal = 0;
00423                 }
00424                 else
00425                 {
00426                     // check relation: = / ~= / |=
00427                     // CSS3: ^= / $= / *=
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                         // this case should never happen - only when loading
00477                         // the default stylesheet - which must not contain unknown attributes
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                     // ### fixme we ignore everything after [..]
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             //kdDebug( 6080 ) << "found '*' selector" << endl;
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                 // this case should never happen - only when loading
00555                 // the default stylesheet - which must not contain unknown tags
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    //stack->print();
00570    if( endVal ) {
00571        // lets be recursive
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             //if(selecStack)
00639             //    selecStack->print();
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             // invalid selector, delete
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     // Get rid of space in front of the declaration
00700 
00701     curP = parseSpace(curP, endP);
00702     if (!curP)
00703         return;
00704 
00705     // Search for the required colon or white space
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     // May have only reached white space before
00716     if (*colon != ':')
00717     {
00718         // Search for the required colon
00719         colon = parseToChar(curP, endP, ':', false);
00720         if (!colon)
00721             return;
00722     }
00723     curP = colon+1;
00724     // remove space in front of the value
00725     while(curP < endP && *curP == ' ')
00726         curP++;
00727     if ( curP >= endP )
00728         return;
00729 
00730     // search for !important
00731     const QChar *exclam = parseToChar(curP, endP, '!', false);
00732     if(exclam)
00733     {
00734         //const QChar *imp = parseSpace(exclam+1, endP);
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     // remove space after the value;
00748     while (endP > curP)
00749     {
00750         //if (!isspace(*(endP-1)))
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 // ------------------- begin font property ---------------------
00831 /*
00832   Parser for the font property of CSS.  See
00833   http://www.w3.org/TR/REC-CSS2/fonts.html#propdef-font for details.
00834 
00835   Written by Jasmin Blanchette (jasmin@trolltech.com) on 2000-08-16.
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         // accept quoted "serif" only in non strict mode.
00951         *ffamily = m_yyStr;
00952         // unquoted courier new should return courier new
00953         while( (m_yyTok = getToken()) == TOK_SYMBOL ) {
00954           *ffamily += " " + m_yyStr;
00955         }
00956         matched = true;
00957       } else if ( m_yyTok == TOK_STRING ) {
00958           //  kdDebug( 6080 ) << "[" << m_yyStr << "]" << endl;
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   //kdDebug( 6080 ) << str << endl;
01084   const struct css_value *cssval = findValue(fontParser.m_yyIn.latin1(), fontParser.m_yyIn.length());
01085 
01086   if (cssval) {
01087       //kdDebug( 6080 ) << "System fonts requested: [" << str << "]" << endl;
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 //   kdDebug(6080) << "[" << fstyle << "] [" << fvariant << "] [" << fweight << "] ["
01125 //              << fsize << "] / [" << lheight << "] [" << ffamily << "]" << endl;
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 // ---------------- end font property --------------------------
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; /* e.g.: width="" */}
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   // We are using this so often
01168   const struct css_value *cssval = findValue(val, len);
01169   if (cssval && cssval->id == CSS_VAL_INHERIT) {
01170       parsedValue = new CSSInheritedValueImpl(); // inherited value
01171   } else {
01172       switch(propId)
01173       {
01174           /* The comment to the left defines all valid value of this properties as defined
01175            * in CSS 2, Appendix F. Property index
01176            */
01177 
01178           /* All the CSS properties are not supported by the renderer at the moment.
01179            * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
01180            * (see parseAuralValues). As we don't support them at all this seems reasonable.
01181            */
01182 
01183       case CSS_PROP_SIZE:                 // <length>{1,2} | auto | portrait | landscape | inherit
01184       case CSS_PROP_QUOTES:               // [<string> <string>]+ | none | inherit
01185       case CSS_PROP_UNICODE_BIDI:         // normal | embed | bidi-override | inherit
01186       case CSS_PROP_PAGE:                 // <identifier> | auto // ### CHECK
01187       case CSS_PROP_PAGE_BREAK_AFTER:     // auto | always | avoid | left | right | inherit
01188       case CSS_PROP_PAGE_BREAK_BEFORE:    // auto | always | avoid | left | right | inherit
01189       case CSS_PROP_PAGE_BREAK_INSIDE:    // avoid | auto | inherit
01190       case CSS_PROP_POSITION:             // static | relative | absolute | fixed | inherit
01191       case CSS_PROP_EMPTY_CELLS:          // show | hide | inherit
01192         {
01193           const struct css_value *cssval = findValue(val, len);
01194           if (cssval)
01195             {
01196               parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01197             }
01198           // ### To be done
01199           break;
01200         }
01201 
01202       case CSS_PROP_CONTENT:              // [ <string> | <uri> | <counter> | attr(X) | open-quote |
01203         // close-quote | no-open-quote | no-close-quote ]+ | inherit
01204         parsedValue = parseContent(curP,endP);
01205         break;
01206       case CSS_PROP_WHITE_SPACE:          // normal | pre | nowrap | inherit
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:                 // <shape> | auto | inherit
01212       {
01213           int i;
01214           if ( cssval && cssval->id == CSS_VAL_AUTO )
01215               parsedValue = new CSSPrimitiveValueImpl( cssval->id );
01216           else {
01217               // only shape in CSS2 is rect( top right bottom left )
01218               QString str = QConstString( const_cast<QChar*>( curP ), endP - curP ).string();
01219               // the CSS specs are not really clear if there should be commas in here or not. We accept both spaces and commas.
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               //qDebug("rect = '%s'", str.latin1() );
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                   //qDebug("part: from=%d, to=%d", pos, space );
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               //qDebug(" passed rectangle parsing");
01275               break;
01276 
01277           cleanup:
01278               //qDebug(" rectangle parsing failed, i=%d", i);
01279               delete rect;
01280           }
01281           break;
01282       }
01283 
01284       /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
01285        * correctly and allows optimization in khtml::applyRule(..)
01286        */
01287       case CSS_PROP_CAPTION_SIDE:         // top | bottom | left | right | inherit
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:      // collapse | separate | inherit
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:           // visible | hidden | collapse | inherit
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:             // visible | hidden | scroll | auto | inherit
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:  // inside | outside | inherit
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         // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
01333         // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
01334         // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
01335         // katakana | hiragana-iroha | katakana-iroha | none | inherit
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         // inline | block | list-item | run-in | inline-block | -konq-ruler | table |
01347         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
01348         // table-column-group | table-column | table-cell | table-caption | none | inherit
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:            // ltr | rtl | inherit
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:       // capitalize | uppercase | lowercase | none | inherit
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:                // left | right | none | inherit + center for buggy CSS
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:                // none | left | right | both | inherit
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         // left | right | center | justify | konq_center | <string> | inherit
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:        // <border-style> | inherit
01416       case CSS_PROP_BORDER_TOP_STYLE:     
01417       case CSS_PROP_BORDER_RIGHT_STYLE:   //   Defined as:    none | hidden | dotted | dashed |
01418       case CSS_PROP_BORDER_BOTTOM_STYLE:  //   solid | double | groove | ridge | inset | outset
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:  // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 |
01430         // 500 | 600 | 700 | 800 | 900 | inherit
01431         {
01432           if (cssval) {
01433             int id = cssval->id;
01434             if (id) {
01435               if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_LIGHTER) {
01436                 // Allready correct id
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:    // repeat | repeat-x | repeat-y | no-repeat | inherit
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: // scroll | fixed
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           /* Problem: center is ambigous
01479            * In case of 'center' center defines X and Y coords
01480            * In case of 'center top', center defines the Y coord
01481            * in case of 'center left', center defines the X coord
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           // id1 will influence X and id2 will influence Y
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           /* CSS 14.2
01535            * Keywords cannot be combined with percentage values or length values.
01536            * -> No mix between keywords and other units.
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           // ### should be able to have two values
01559           parsedValue = parseUnit(curP, endP, LENGTH | NONNEGATIVE);
01560           break;
01561         }
01562       case CSS_PROP_OUTLINE_COLOR:        // <color> | invert | inherit
01563         {
01564 #ifdef CSS_DEBUG
01565           kdDebug( 6080 ) << "CSS_PROP_OUTLINE_COLOR: " << val << endl;
01566 #endif
01567           // outline has "invert" as additional keyword. we handle
01568           if (cssval && cssval->id == CSS_VAL_INVERT) {
01569             parsedValue = new CSSPrimitiveValueImpl( khtml::invertedColor );
01570             break;
01571           }
01572           // Break is explictly missing, looking for <color>
01573         }
01574       case CSS_PROP_BACKGROUND_COLOR:     // <color> | transparent | inherit
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           // Break is explictly missing, looking for <color>
01584         }
01585       case CSS_PROP_COLOR:                // <color> | inherit
01586       case CSS_PROP_BORDER_TOP_COLOR:     // <color> | inherit
01587       case CSS_PROP_BORDER_RIGHT_COLOR:   // <color> | inherit
01588       case CSS_PROP_BORDER_BOTTOM_COLOR:  // <color> | inherit
01589       case CSS_PROP_BORDER_LEFT_COLOR:    // <color> | inherit
01590       case CSS_PROP_TEXT_DECORATION_COLOR:        //
01591       case CSS_PROP_SCROLLBAR_FACE_COLOR:         // IE5.5
01592       case CSS_PROP_SCROLLBAR_SHADOW_COLOR:       // IE5.5
01593       case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:    // IE5.5
01594       case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:      // IE5.5
01595       case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:   // IE5.5
01596       case CSS_PROP_SCROLLBAR_TRACK_COLOR:        // IE5.5
01597       case CSS_PROP_SCROLLBAR_ARROW_COLOR:        // IE5.5
01598       case CSS_PROP_SCROLLBAR_BASE_COLOR:         // IE5.5
01599         {
01600           const QString val2( value.stripWhiteSpace() );
01601           //kdDebug(6080) << "parsing color " << val2 << endl;
01602           QRgb c = khtml::parseColor(val2, !m_bnonCSSHint);
01603           if(c == khtml::invalidColor) return false;
01604           //kdDebug( 6080 ) << "color is: " << c.red() << ", " << c.green() << ", " << c.blue() << endl;
01605           parsedValue = new CSSPrimitiveValueImpl(c);
01606           break;
01607         }
01608       case CSS_PROP_CURSOR:
01609           //  [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
01610           // nw-resize | // n-resize | se-resize | sw-resize | s-resize | w-resize | text |
01611           // wait | help ] ] | inherit
01612           if (cssval) {
01613               // MSIE 5 compatibility :/
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:     // <uri> | none | inherit
01621       case CSS_PROP_LIST_STYLE_IMAGE:     // <uri> | none | inherit
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()); // ### Optimize
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:        // <border-width> | inherit
01644       case CSS_PROP_BORDER_TOP_WIDTH:     
01645       case CSS_PROP_BORDER_RIGHT_WIDTH:   //   Which is defined as
01646       case CSS_PROP_BORDER_BOTTOM_WIDTH:  //   thin | medium | thick | <length>
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:        // <length> | auto | inherit
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:       // normal | <length> | inherit
01669       case CSS_PROP_WORD_SPACING:         // normal | <length> | inherit
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:        //   Which is defined as
01682       case CSS_PROP_PADDING_BOTTOM:       //   <length> | <percentage>
01683       case CSS_PROP_PADDING_LEFT:         
01684         {
01685           parsedValue = parseUnit(curP, endP, LENGTH | PERCENT|NONNEGATIVE);
01686           break;
01687         }
01688       case CSS_PROP_TEXT_INDENT:          // <length> | <percentage> | inherit
01689       case CSS_PROP_MIN_HEIGHT:           // <length> | <percentage> | inherit
01690       case CSS_PROP_MIN_WIDTH:            // <length> | <percentage> | inherit
01691         {
01692           parsedValue = parseUnit(curP, endP, LENGTH | PERCENT);
01693           break;
01694         }
01695       case CSS_PROP_FONT_SIZE:
01696         // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
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:           // normal | italic | oblique | inherit
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:         // normal | small-caps | inherit
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         // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
01731         // <percentage> | <length> | inherit
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:           // <length> | <percentage> | none | inherit
01744       case CSS_PROP_MAX_WIDTH:            // <length> | <percentage> | none | inherit
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:               // <length> | <percentage> | auto | inherit
01754       case CSS_PROP_WIDTH:                // <length> | <percentage> | auto | inherit
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:               // <length> | <percentage> | auto | inherit
01764       case CSS_PROP_LEFT:                 // <length> | <percentage> | auto | inherit
01765       case CSS_PROP_RIGHT:                // <length> | <percentage> | auto | inherit
01766       case CSS_PROP_TOP:                  // <length> | <percentage> | auto | inherit
01767       case CSS_PROP_MARGIN_TOP:           
01768       case CSS_PROP_MARGIN_RIGHT:         //   Which is defined as
01769       case CSS_PROP_MARGIN_BOTTOM:        //   <length> | <percentage> | auto | inherit
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:              // auto | <integer> | inherit
01780         {
01781           if (cssval && cssval->id == CSS_VAL_AUTO) {
01782             parsedValue = new CSSPrimitiveValueImpl(cssval->id);
01783             break;
01784           }
01785           // break explicitly missing, looking for <number>
01786         }
01787       case CSS_PROP_ORPHANS:              // <integer> | inherit
01788       case CSS_PROP_WIDOWS:               // <integer> | inherit
01789         // ### not supported later on
01790         {
01791           parsedValue = parseUnit(curP, endP, INTEGER);
01792           break;
01793         }
01794       case CSS_PROP_LINE_HEIGHT:          // normal | <number> | <length> | <percentage> | inherit
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:    // [ <identifier> <integer>? ]+ | none | inherit
01804       case CSS_PROP_COUNTER_RESET:        // [ <identifier> <integer>? ]+ | none | inherit
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                 // ### single quoted is missing...
01818                 if(face[0] == '\"') face.remove(0, 1);
01819                 if(face[face.length()-1] == '\"') face = face.left(face.length()-1);
01820                 //kdDebug( 6080 ) << "found face '" << face << "'" << endl;
01821                 list->append(new CSSPrimitiveValueImpl(DOMString(face), CSSPrimitiveValue::CSS_STRING));
01822                 pos = pos2 + 1;
01823                 if(pos2 == -1) break;
01824               }
01825             //kdDebug( 6080 ) << "got " << list->length() << " faces" << endl;
01826             if(list->length())
01827               parsedValue = list;
01828             else
01829               delete list;
01830             break;
01831           }
01832         }
01833       case CSS_PROP_FONT_FAMILY:
01834         // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
01835         {
01836           // css2 compatible parsing...
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               //kdDebug() << "StyleBaseImpl::parsefont: family='" << *it << "'" << endl;
01847             }
01848           }
01849           //kdDebug( 6080 ) << "got " << list->length() << " faces" << endl;
01850           if(list->length())
01851             parsedValue = list;
01852           else
01853             delete list;
01854           break;
01855         }
01856       case CSS_PROP_TEXT_DECORATION:
01857         // none | [ underline || overline || line-through || blink ] | inherit
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               //kdDebug( 6080 ) << "text-decoration: '" << value << "'" << endl;
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                   //kdDebug( 6080 ) << "found decoration '" << decoration << "'" << endl;
01873                   const struct css_value *cssval = findValue(decoration.lower().ascii(),
01874                                                              decoration.length());
01875                   //cerr << "KEYWORD: " << decoration.lower().left(decoration.length()).latin1() << endl;
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               //kdDebug( 6080 ) << "got " << list->length() << "d decorations" << endl;
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:         // auto | fixed | inherit
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       /* shorthand properties */
01920       case CSS_PROP_BACKGROUND:
01921         // ['background-color' || 'background-image' ||'background-repeat' ||
01922         // 'background-attachment' || 'background-position'] | inherit
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           //return parseBackground(curP, endP);
01933         }
01934       case CSS_PROP_BORDER:
01935         // [ 'border-width' || 'border-style' || <color> ] | inherit
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         // [ 'border-top-width' || 'border-style' || <color> ] | inherit
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         // [ 'border-right-width' || 'border-style' || <color> ] | inherit
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         // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
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         // [ 'border-left-width' || 'border-style' || <color> ] | inherit
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         // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
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         // <color>{1,4} | transparent | inherit
01978         {
01979           const struct css_value *cssval = findValue(val, len);
01980           if (cssval && cssval->id == CSS_VAL_TRANSPARENT)
01981             {
01982               // set border colors to invalid
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         // <border-width>{1,4} | inherit
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         // <border-style>{1,4} | inherit
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         // <margin-width>{1,4} | inherit
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         // <padding-width>{1,4} | inherit
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         // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
02020         // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
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 /* parseAuralValue */
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     /* AURAL Properies */
02064     switch(propId)
02065     {
02066     case CSS_PROP_AZIMUTH:              // <angle> | [[ left-side | far-left | left | center-left | center |
02067                                         // center-right | right | far-right | right-side ] || behind ] |
02068                                         // leftwards | rightwards | inherit
02069     case CSS_PROP_PAUSE_AFTER:          // <time> | <percentage> | inherit
02070     case CSS_PROP_PAUSE_BEFORE:         // <time> | <percentage> | inherit
02071     case CSS_PROP_PAUSE:                // [ [<time> | <percentage>]{1,2} ] | inherit
02072     case CSS_PROP_PLAY_DURING:          // <uri> mix? repeat? | auto | none | inherit
02073     case CSS_PROP_VOICE_FAMILY:         // [[<specific-voice> | <generic-voice> ],]*
02074                                         // [<specific-voice> | <generic-voice> ] | inherit
02075     {
02076       // ### TO BE DONE
02077         break;
02078     }
02079     case CSS_PROP_CUE:                  // [ 'cue-before' || 'cue-after' ] | inherit
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:            // <uri> | none | inherit
02087     case CSS_PROP_CUE_BEFORE:           // <uri> | none | inherit
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:            // <angle> | below | level | above | higher | lower
02104                                         // | inherit
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:          // <number> | x-slow | slow | medium | fast |
02119                                         // x-fast | faster | slower | inherit
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:               // <number> | <percentage> | silent | x-soft | soft |
02136                                         // medium | loud | x-loud | inherit
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:                 // <frequency> | x-low | low | medium | high | x-high | inherit
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:                // normal | none | spell-out | inherit
02165     case CSS_PROP_SPEAK_HEADER:         // once | always | inherit
02166     case CSS_PROP_SPEAK_NUMERAL:        // digits | continuous | inherit
02167     case CSS_PROP_SPEAK_PUNCTUATION:    // code | none | inherit
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:          // <number> | inherit
02177     case CSS_PROP_RICHNESS:             // <number> | inherit
02178     case CSS_PROP_STRESS:               // <number> | inherit
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(); // just remove the top one - not sure what should happen if we have multiple instances of the property
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                     // non implemented yet << ", value: " << parsedValue->cssText().string()
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     /* We try to match as many properties as possible
02234      * We setup an array of booleans to mark which property has been found,
02235      * and we try to search for properties until it makes no longer any sense
02236      */
02237 
02238     bool isLast = false;
02239     bool foundAnything = false;
02240     bool fnd[6]; //Trust me ;)
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         //kdDebug(6080) << "in PSH: \"" << QString(curP, nextP - curP) << "\"" << endl;
02251         foundAnything = false;
02252         for (int propIndex = 0; propIndex < num; ++propIndex) {
02253             if (!fnd[propIndex]) {
02254                 // We have to tread this seperately
02255                 //kdDebug(6080) << "LOOKING FOR: " << getPropertyName(properties[propIndex]).string() << endl;
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         // if we didn't find at least one match, this is an
02273         // invalid shorthand and we have to ignore it
02274         if (!foundAnything)
02275             return foundAnything;
02276 
02277         do {
02278             nextP++;
02279             curP = nextP;
02280 
02281             // oh, less parameteres than we expected
02282             if (curP >= endP)
02283                 return foundAnything;
02284         } while (curP->isSpace());
02285     }
02286     return foundAnything;
02287 }
02288 
02289 /*
02290  * Problem (again): the ambiguity of 'background-position'
02291  * from: http://www.w3.org/Style/CSS/Test/current/sec537.htm
02292 
02293         BODY {background: green url(oransqr.gif) repeat-x center top fixed;}
02294         .one {background: lime url(oransqr.gif) repeat-y 100% 0%;}
02295         .two {background: lime url(oransqr.gif) repeat-y center top;}
02296         .three {background: lime url(oransqr.gif) repeat-x left top;}
02297 */
02298 
02299 bool StyleBaseImpl::parseBackgroundPosition(const QChar *curP, const QChar *&nextP, const QChar *endP)
02300 {
02301     // We first need to check if the property has two values.
02302     // if this fails we try one value only.
02303 
02304     const QChar *bckgrNextP = nextP;
02305     while (bckgrNextP->isSpace() && bckgrNextP < endP) { bckgrNextP++; }
02306     bool dummy;
02307     bckgrNextP = getNext(bckgrNextP, endP, dummy);
02308     //kdDebug(6080) << "BKCGR: 2: \"" << QString(curP, bckgrNextP - curP) << "\"" << endl;
02309 
02310     bool found = parseValue(curP, bckgrNextP, CSS_PROP_BACKGROUND_POSITION);
02311     if (!found) {
02312         // We have not found a pair of Background-Positions, see if we have a single value
02313 
02314         //kdDebug(6080) << "BKCGR: Single: \"" << QString(curP, nextP - curP) << "\"" << endl;
02315         found = parseValue(curP, nextP, CSS_PROP_BACKGROUND_POSITION);
02316     } else {
02317         // Moving on
02318         nextP = bckgrNextP;
02319     }
02320     //kdDebug(6080) << "found background property!" << endl;
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             // url
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             // attr
02367         }
02368         else if (str.startsWith("open-quote"))
02369         {
02370             // open-quote
02371         }
02372         else if (str.startsWith("close-quote"))
02373         {
02374             // open-quote
02375         }
02376         else if (str.startsWith("no-open-quote"))
02377         {
02378             // no-open-quote
02379         }
02380         else if (str.startsWith("no-close-quote"))
02381         {
02382             // no-close-quote
02383         }
02384         else if (str.length() && (str[0] == '\'' || str[0] == '"'))
02385         {
02386             // string
02387             int l = str.length();
02388             QString strstr;
02389             // skip first character (which is ' or " !)
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         // skip over whitespace
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()) { // skip over WS between tokens
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 // used for shorthand properties xxx{1,2}
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 // used for shorthand properties xxx{1,4}
02489 bool StyleBaseImpl::parse4Values( const QChar *curP, const QChar *endP, const int *properties)
02490 {
02491     /* From the CSS 2 specs, 8.3
02492      * If there is only one value, it applies to all sides. If there are two values, the top and
02493      * bottom margins are set to the first value and the right and left margins are set to the second.
02494      * If there are three values, the top is set to the first value, the left and right are set to the
02495      * second, and the bottom is set to the third. If there are four values, they apply to the top,
02496      * right, bottom, and left, respectively.
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     /* e.g.: width=""  length="ffffff" */
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     // splt up number and unit
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) // no unit
02561     {
02562         if(allowedUnits & NUMBER)
02563             return new CSSPrimitiveValueImpl(value, CSSPrimitiveValue::CSS_NUMBER);
02564 
02565         if(allowedUnits & INTEGER && isInt) // ### DOM CSS doesn't seem to define something for integer
02566             return new CSSPrimitiveValueImpl(value, CSSPrimitiveValue::CSS_NUMBER);
02567 
02568         // ### according to the css specs only 0 is allowed without unit.
02569         // there are however too many web pages out there using CSS without units
02570         // cause ie and ns allow them. We do so if the document is not using a strict dtd
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     //kdDebug( 6080 ) << "style rule is \'" << QString(curP, endP-curP) << "\'" << endl;
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++; // need to get past the '{' from above
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++; // need to get past the '}' from above
02729 
02730     if (!plist || !slist)
02731     {
02732         // Useless rule
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     // return the newly created rule
02742     CSSStyleRuleImpl *rule = new CSSStyleRuleImpl(this);
02743     CSSStyleDeclarationImpl *decl = new CSSStyleDeclarationImpl(rule, plist);
02744 
02745     rule->setSelector(slist);
02746     rule->setDeclaration(decl);
02747     // ### set selector and value
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         // allow ; between rules (not part of spec)
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;  // set flag to true iff we have a valid inlined decl.
02781     }
02782 
02783     if(curP) curP++;
02784     return rule;
02785 }
02786 
02787 /* Generate a sort of Normal Form for CSS.
02788  * Remove comments, it is guaranteed that there will not be more then one space between
02789  * tokens and all the tokens within curly braces are lower case (except text
02790  * within quotes and url tags). Space is replaced with QChar(' ') and removed where
02791  * it's not necessary.
02792  *
02793  * 4.1.3 Characters and case
02794  *
02795  * The following rules always hold:
02796  *
02797  *  All CSS style sheets are case-insensitive, except for parts that are not under
02798  *  the control of CSS. For example, the case-sensitivity of values of the HTML
02799  *  attributes "id" and "class", of font names, and of URIs lies outside the scope
02800  *  of this specification. Note in particular that element names are case-insensitive
02801  *  in HTML, but case-sensitive in XML.
02802  */
02803 
02804 const QString StyleBaseImpl::preprocess(const QString &str, bool justOneRule)
02805 {
02806   // ### use DOMString here to avoid coversions
02807   QString processed;
02808 
02809   bool sq = false;      // Within single quote
02810   bool dq = false;      // Within double quote
02811   bool bracket = false; // Within brackets, e.g. url(ThisIsStupid)
02812   bool comment = false; // Within comment
02813   bool skipgarbage = !justOneRule; // skip <!-- and ---> only in specifc places
02814   bool firstChar = false; // Beginning of comment either /* or */
02815   bool space = true;    // Last token was space
02816   int curlyBracket = 0; // Within curlyBrackets -> lower
02817   hasInlinedDecl = false; // reset the inlined decl. flag
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 //       qDebug("current: *%s*, sq=%d dq=%d b=%d c=%d fC=%d space=%d cB=%d sg=%d",
02831 //              QConstString(ch, kMin(last-ch, 10)).string().latin1(), sq, dq, bracket, comment, firstChar, space, curlyBracket, skipgarbage);
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;  // Explictly true
02845       skipgarbage = false;
02846     } else if ( !comment && !dq && !sq && *ch == ')') {
02847       bracket = false;
02848       processed += *ch;
02849       processed += QChar(' '); // Adding a space after this token
02850       space = true;
02851       skipgarbage = false;
02852     } else if ( !comment && !dq && !sq && *ch == '{') {
02853       ++curlyBracket;
02854       processed += *ch;
02855       space = true;  // Explictly true
02856       skipgarbage = true;
02857     } else if ( !comment && !dq && !sq && *ch == '}') {
02858       --curlyBracket;
02859       processed += *ch;
02860       processed += QChar(' '); // Adding a space after this token
02861       space = true;
02862       skipgarbage = true;
02863     } else if ( !comment && skipgarbage && !dq && !sq && (*ch == '-') && ((ch+2) < last)  /* SGML Comment */
02864                 && (*(ch+1) == '-') && (*(ch+2) == '>')) {
02865         ch += 2; // skip -->
02866     } else if ( !comment && skipgarbage && !dq && !sq && (*ch == '<') && ((ch+3) < last)  /* SGML Comment */
02867                 && (*(ch+1) == '!') && (*(ch+2) == '-') && (*(ch+3) == '-')) {
02868         ch += 3; // skip <!--
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       // check for comment
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; // Slash added only if next is not '*'
02890       } else if ( *ch == ',' || *ch == ';') {
02891         processed += *ch;
02892         processed += QChar(' '); // Adding a space after these tokens
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())) { // Don't add more than one space
02922       if (ch->isSpace()) {
02923         processed += QChar(' '); // Normalize whitespace
02924       } else {
02925           processed += *ch;
02926       }
02927     }
02928     space = ch->isSpace();
02929   } else {
02930     processed += *ch; // We're within quotes or brackets, leave untouched
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     // make sure it doesn't overflow
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         // optional attribute
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; // the ":" is provided by selectorText()
03093         else // Descendant
03094             str = tagHistoryText + " " + str;
03095     }
03096     return str;
03097 }
03098 
03099 // ----------------------------------------------------------------------------
03100 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:33:34 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001