khtml Library API Documentation

css_base.cpp

00001 /*
00002  * This file is part of the DOM implementation for KDE.
00003  *
00004  * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
00005  *               1999 Waldo Bastian (bastian@kde.org)
00006  *               2001 Andreas Schlapbach (schlpbch@iam.unibe.ch)
00007  *               2001-2003 Dirk Mueller (mueller@kde.org)
00008  *               2002 Apple Computer, Inc.
00009  *               2004 Allan Sandfeld Jensen (kde@carewolf.com)
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 
00029 #include <assert.h>
00030 #include <kdebug.h>
00031 
00032 #include "css_base.h"
00033 
00034 #ifdef CSS_DEBUG
00035 #include "cssproperties.h"
00036 #endif
00037 
00038 #include "css_stylesheetimpl.h"
00039 #include "xml/dom_docimpl.h"
00040 #include "misc/htmlhashes.h"
00041 #include "css_valueimpl.h"
00042 using namespace DOM;
00043 
00044 void StyleBaseImpl::checkLoaded() const
00045 {
00046     if(m_parent) m_parent->checkLoaded();
00047 }
00048 
00049 StyleSheetImpl* StyleBaseImpl::stylesheet()
00050 {
00051     StyleBaseImpl* b = this;
00052     while(b && !b->isStyleSheet())
00053         b = b->m_parent;
00054     return static_cast<StyleSheetImpl *>(b);
00055 }
00056 
00057 KURL StyleBaseImpl::baseURL()
00058 {
00059     // try to find the style sheet. If found look for its url.
00060     // If it has none, look for the parentsheet, or the parentNode and
00061     // try to find out about their url
00062 
00063     StyleSheetImpl *sheet = stylesheet();
00064 
00065     if(!sheet) return KURL();
00066 
00067     if(!sheet->href().isNull())
00068         return KURL( sheet->href().string() );
00069 
00070     // find parent
00071     if(sheet->parent()) return sheet->parent()->baseURL();
00072 
00073     if(!sheet->ownerNode()) return KURL();
00074 
00075     return sheet->ownerNode()->getDocument()->baseURL();
00076 }
00077 
00078 void StyleBaseImpl::setParsedValue(int propId, const CSSValueImpl *parsedValue,
00079                    bool important, bool nonCSSHint, QPtrList<CSSProperty> *propList)
00080 {
00081     QPtrListIterator<CSSProperty> propIt(*propList);
00082     propIt.toLast(); // just remove the top one - not sure what should happen if we have multiple instances of the property
00083     while (propIt.current() &&
00084            ( propIt.current()->m_id != propId || propIt.current()->nonCSSHint != nonCSSHint ||
00085              propIt.current()->m_bImportant != important) )
00086         --propIt;
00087     if (propIt.current())
00088         propList->removeRef(propIt.current());
00089 
00090     CSSProperty *prop = new CSSProperty();
00091     prop->m_id = propId;
00092     prop->setValue((CSSValueImpl *) parsedValue);
00093     prop->m_bImportant = important;
00094     prop->nonCSSHint = nonCSSHint;
00095 
00096     propList->append(prop);
00097 #ifdef CSS_DEBUG
00098     kdDebug( 6080 ) << "added property: " << getPropertyName(propId).string()
00099                     // non implemented yet << ", value: " << parsedValue->cssText().string()
00100                     << " important: " << prop->m_bImportant
00101                     << " nonCSS: " << prop->nonCSSHint << endl;
00102 #endif
00103 }
00104 
00105 // ------------------------------------------------------------------------------
00106 
00107 StyleListImpl::~StyleListImpl()
00108 {
00109     StyleBaseImpl *n;
00110 
00111     if(!m_lstChildren) return;
00112 
00113     for( n = m_lstChildren->first(); n != 0; n = m_lstChildren->next() )
00114     {
00115         n->setParent(0);
00116         if( !n->refCount() ) delete n;
00117     }
00118     delete m_lstChildren;
00119 }
00120 
00121 // --------------------------------------------------------------------------------
00122 
00123 void CSSSelector::print(void)
00124 {
00125     kdDebug( 6080 ) << "[Selector: tag = " <<       QString::number(tag,16) << ", attr = \"" << attr << "\", match = \"" << match
00126             << "\" value = \"" << value.string().latin1() << "\" relation = " << (int)relation
00127             << "]" << endl;
00128     if ( tagHistory )
00129         tagHistory->print();
00130     kdDebug( 6080 ) << "    specificity = " << specificity() << endl;
00131 }
00132 
00133 unsigned int CSSSelector::specificity() const
00134 {
00135     if ( nonCSSHint )
00136         return 0;
00137 
00138     int s = ((( tag & NodeImpl_IdLocalMask ) == 0xffff) ? 0 : 1);
00139     switch(match)
00140     {
00141     case Id:
00142     s += 0x10000;
00143     break;
00144     case Exact:
00145     case Set:
00146     case List:
00147     case Hyphen:
00148     case PseudoClass:
00149     case PseudoElement:
00150     case Contain:
00151     case Begin:
00152     case End:
00153         s += 0x100;
00154     case None:
00155         break;
00156     }
00157     if(tagHistory)
00158         s += tagHistory->specificity();
00159     // make sure it doesn't overflow
00160     return s & 0xffffff;
00161 }
00162 
00163 void CSSSelector::extractPseudoType() const
00164 {
00165     if (match != PseudoClass && match != PseudoElement)
00166         return;
00167     _pseudoType = PseudoOther;
00168     bool element = false;
00169     bool compat = false;
00170     if (!value.isEmpty()) {
00171         value = value.lower();
00172         switch (value[0]) {
00173             case 'a':
00174                 if (value == "active")
00175                     _pseudoType = PseudoActive;
00176                 else if (value == "after") {
00177                     _pseudoType = PseudoAfter;
00178                     element = compat = true;
00179                 }
00180                 break;
00181             case 'b':
00182                 if (value == "before") {
00183                     _pseudoType = PseudoBefore;
00184                     element = compat = true;
00185                 }
00186                 break;
00187             case 'c':
00188                 if (value == "checked")
00189                     _pseudoType = PseudoChecked;
00190                 else if (value == "contains(")
00191                     _pseudoType = PseudoContains;
00192                 break;
00193             case 'd':
00194                 if (value == "disabled")
00195                     _pseudoType = PseudoDisabled;
00196                 break;
00197             case 'e':
00198                 if (value == "empty")
00199                     _pseudoType = PseudoEmpty;
00200                 else if (value == "enabled")
00201                     _pseudoType = PseudoEnabled;
00202                 break;
00203             case 'f':
00204                 if (value == "first-child")
00205                     _pseudoType = PseudoFirstChild;
00206                 else if (value == "first-letter") {
00207                     _pseudoType = PseudoFirstLetter;
00208                     element = compat = true;
00209                 }
00210                 else if (value == "first-line") {
00211                     _pseudoType = PseudoFirstLine;
00212                     element = compat = true;
00213                 }
00214                 else if (value == "first-of-type")
00215                     _pseudoType = PseudoFirstOfType;
00216                 else if (value == "focus")
00217                     _pseudoType = PseudoFocus;
00218                 break;
00219             case 'h':
00220                 if (value == "hover")
00221                     _pseudoType = PseudoHover;
00222                 break;
00223             case 'i':
00224                 if (value == "indeterminate")
00225                     _pseudoType = PseudoIndeterminate;
00226                 break;
00227             case 'l':
00228                 if (value == "link")
00229                     _pseudoType = PseudoLink;
00230                 else if (value == "lang(")
00231                     _pseudoType = PseudoLang;
00232                 else if (value == "last-child")
00233                     _pseudoType = PseudoLastChild;
00234                 else if (value == "last-of-type")
00235                     _pseudoType = PseudoLastOfType;
00236                 break;
00237             case 'n':
00238                 if (value == "not(")
00239                     _pseudoType = PseudoNot;
00240                 else if (value == "nth-child(")
00241                     _pseudoType = PseudoNthChild;
00242                 else if (value == "nth-last-child(")
00243                     _pseudoType = PseudoNthLastChild;
00244                 else if (value == "nth-of-type(")
00245                     _pseudoType = PseudoNthOfType;
00246                 else if (value == "nth-last-of-type(")
00247                     _pseudoType = PseudoNthLastOfType;
00248                 break;
00249             case 'o':
00250                 if (value == "only-child")
00251                     _pseudoType = PseudoOnlyChild;
00252                 else if (value == "only-of-type")
00253                     _pseudoType = PseudoOnlyOfType;
00254                 break;
00255             case 'r':
00256                 if (value == "root")
00257                     _pseudoType = PseudoRoot;
00258                 break;
00259             case 's':
00260                 if (value == "selection") {
00261                     _pseudoType = PseudoSelection;
00262                     element = true;
00263                 }
00264                 break;
00265             case 't':
00266                 if (value == "target")
00267                     _pseudoType = PseudoTarget;
00268                 break;
00269             case 'v':
00270                 if (value == "visited")
00271                     _pseudoType = PseudoVisited;
00272                 break;
00273         }
00274     }
00275     if (match == PseudoClass && element)
00276         if (!compat) _pseudoType = PseudoOther;
00277         else match = PseudoElement;
00278     else
00279     if (match == PseudoElement && !element)
00280         _pseudoType = PseudoOther;
00281     value = DOMString();
00282 }
00283 
00284 
00285 bool CSSSelector::operator == ( const CSSSelector &other ) const
00286 {
00287     const CSSSelector *sel1 = this;
00288     const CSSSelector *sel2 = &other;
00289 
00290     while ( sel1 && sel2 ) {
00291         //assert(sel1->_pseudoType != PseudoNotParsed);
00292         //assert(sel2->_pseudoType != PseudoNotParsed);
00293     if ( sel1->tag != sel2->tag || sel1->attr != sel2->attr ||
00294          sel1->relation != sel2->relation || sel1->match != sel2->match ||
00295          sel1->nonCSSHint != sel2->nonCSSHint ||
00296          sel1->value != sel2->value ||
00297              sel1->pseudoType() != sel2->pseudoType() ||
00298              sel1->string_arg != sel2->string_arg)
00299         return false;
00300     sel1 = sel1->tagHistory;
00301     sel2 = sel2->tagHistory;
00302     }
00303     if ( sel1 || sel2 )
00304     return false;
00305     return true;
00306 }
00307 
00308 DOMString CSSSelector::selectorText() const
00309 {
00310     // #### fix namespace
00311     DOMString str;
00312     const CSSSelector* cs = this;
00313     if ( cs->tag == 0xffffffff && cs->attr == ATTR_ID && cs->match == CSSSelector::Id )
00314     {
00315         str = "#";
00316         str += cs->value;
00317     }
00318     else if ( cs->tag == 0xffffffff && cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
00319     {
00320         str = ".";
00321         str += cs->value;
00322     }
00323     else if ( cs->tag == 0xffffffff && cs->match == CSSSelector::PseudoClass )
00324     {
00325         str = ":";
00326         str += cs->value;
00327     }
00328     else if ( cs->tag == 0xffffffff && cs->match == CSSSelector::PseudoElement )
00329     {
00330         str = "::";
00331         str += cs->value;
00332     }
00333     else
00334     {
00335         if ( cs->tag == 0xffffffff )
00336             str = "*";
00337         else if ( cs->tag != 0xffff )
00338             str = getTagName( cs->tag );
00339         if ( cs->attr == ATTR_ID && cs->match == CSSSelector::Id )
00340         {
00341             str += "#";
00342             str += cs->value;
00343         }
00344         else if ( cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
00345         {
00346             str += ".";
00347             str += cs->value;
00348         }
00349         else if ( cs->match == CSSSelector::PseudoClass )
00350         {
00351             str += ":";
00352             str += cs->value;
00353         }
00354         else if ( cs->match == CSSSelector::PseudoElement )
00355         {
00356             str += "::";
00357             str += cs->value;
00358         }
00359         // optional attribute
00360         else if ( cs->attr ) {
00361             DOMString attrName = getAttrName( cs->attr );
00362             str += "[";
00363             str += attrName;
00364             switch (cs->match) {
00365             case CSSSelector::Exact:
00366                 str += "=";
00367                 break;
00368             case CSSSelector::Set:
00369                 str += " "; // ## correct?
00370                 break;
00371             case CSSSelector::List:
00372                 str += "~=";
00373                 break;
00374             case CSSSelector::Hyphen:
00375                 str += "|=";
00376                 break;
00377             case CSSSelector::Begin:
00378                 str += "^=";
00379                 break;
00380             case CSSSelector::End:
00381                 str += "$=";
00382                 break;
00383             case CSSSelector::Contain:
00384                 str += "*=";
00385                 break;
00386             default:
00387                 kdWarning(6080) << "Unhandled case in CSSStyleRuleImpl::selectorText : match=" << cs->match << endl;
00388             }
00389             str += "\"";
00390             str += cs->value;
00391             str += "\"]";
00392         }
00393     }
00394     if ( cs->tagHistory ) {
00395         DOMString tagHistoryText = cs->tagHistory->selectorText();
00396         if ( cs->relation == DirectAdjacent )
00397             str = tagHistoryText + " + " + str;
00398         else if ( cs->relation == IndirectAdjacent )
00399             str = tagHistoryText + " ~ " + str;
00400         else if ( cs->relation == Child )
00401             str = tagHistoryText + " > " + str;
00402         else if ( cs->relation == SubSelector )
00403             str += tagHistoryText; // the ":" is provided by selectorText()
00404         else // Descendant
00405             str = tagHistoryText + " " + str;
00406     }
00407     return str;
00408 }
00409 
00410 // ----------------------------------------------------------------------------
KDE Logo
This file is part of the documentation for khtml Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Sep 16 07:10:13 2005 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003