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