| # khtml Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# cssparser.cpp

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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:33:34 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001