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 Pseudo:
00149     case Contain:
00150     case Begin:
00151     case End:
00152         s += 0x100;
00153     case None:
00154         break;
00155     }
00156     if(tagHistory)
00157         s += tagHistory->specificity();
00158     // make sure it doesn't overflow
00159     return s & 0xffffff;
00160 }
00161 
00162 void CSSSelector::extractPseudoType() const
00163 {
00164     if (match != Pseudo)
00165         return;
00166     _pseudoType = PseudoOther;
00167     if (!value.isEmpty()) {
00168         value = value.lower();
00169         switch (value[0]) {
00170             case 'a':
00171                 if (value == "active")
00172                     _pseudoType = PseudoActive;
00173                 else if (value == "after")
00174                     _pseudoType = PseudoAfter;
00175                 break;
00176             case 'b':
00177                 if (value == "before")
00178                     _pseudoType = PseudoBefore;
00179                 break;
00180             case 'c':
00181                 if (value == "checked")
00182                     _pseudoType = PseudoChecked;
00183                 else if (value == "contains(")
00184                     _pseudoType = PseudoContains;
00185                 break;
00186             case 'd':
00187                 if (value == "disabled")
00188                     _pseudoType = PseudoDisabled;
00189                 break;
00190             case 'e':
00191                 if (value == "empty")
00192                     _pseudoType = PseudoEmpty;
00193                 else if (value == "enabled")
00194                     _pseudoType = PseudoEnabled;
00195                 break;
00196             case 'f':
00197                 if (value == "first-child")
00198                     _pseudoType = PseudoFirstChild;
00199                 else if (value == "first-letter")
00200                     _pseudoType = PseudoFirstLetter;
00201                 else if (value == "first-line")
00202                     _pseudoType = PseudoFirstLine;
00203                 else if (value == "first-of-type")
00204                     _pseudoType = PseudoFirstOfType;
00205                 else if (value == "focus")
00206                     _pseudoType = PseudoFocus;
00207                 break;
00208             case 'h':
00209                 if (value == "hover")
00210                     _pseudoType = PseudoHover;
00211                 break;
00212             case 'i':
00213                 if (value == "indeterminate")
00214                     _pseudoType = PseudoIndeterminate;
00215                 break;
00216             case 'l':
00217                 if (value == "link")
00218                     _pseudoType = PseudoLink;
00219                 else if (value == "lang(")
00220                     _pseudoType = PseudoLang;
00221                 else if (value == "last-child")
00222                     _pseudoType = PseudoLastChild;
00223                 else if (value == "last-of-type")
00224                     _pseudoType = PseudoLastOfType;
00225                 break;
00226             case 'n':
00227                 if (value == "not(")
00228                     _pseudoType = PseudoNot;
00229                 else if (value == "nth-child(")
00230                     _pseudoType = PseudoNthChild;
00231                 else if (value == "nth-last-child(")
00232                     _pseudoType = PseudoNthLastChild;
00233                 else if (value == "nth-of-type(")
00234                     _pseudoType = PseudoNthOfType;
00235                 else if (value == "nth-last-of-type(")
00236                     _pseudoType = PseudoNthLastOfType;
00237                 break;
00238             case 'o':
00239                 if (value == "only-child")
00240                     _pseudoType = PseudoOnlyChild;
00241                 else if (value == "only-of-type")
00242                     _pseudoType = PseudoOnlyOfType;
00243                 break;
00244             case 'r':
00245                 if (value == "root")
00246                     _pseudoType = PseudoRoot;
00247                 break;
00248             case 's':
00249                 if (value == "selection")
00250                     _pseudoType = PseudoSelection;
00251                 break;
00252             case 't':
00253                 if (value == "target")
00254                     _pseudoType = PseudoTarget;
00255                 break;
00256             case 'v':
00257                 if (value == "visited")
00258                     _pseudoType = PseudoVisited;
00259                 break;
00260         }
00261     }
00262 
00263     value = DOMString();
00264 }
00265 
00266 
00267 bool CSSSelector::operator == ( const CSSSelector &other ) const
00268 {
00269     const CSSSelector *sel1 = this;
00270     const CSSSelector *sel2 = &other;
00271 
00272     while ( sel1 && sel2 ) {
00273         //assert(sel1->_pseudoType != PseudoNotParsed);
00274         //assert(sel2->_pseudoType != PseudoNotParsed);
00275     if ( sel1->tag != sel2->tag || sel1->attr != sel2->attr ||
00276          sel1->relation != sel2->relation || sel1->match != sel2->match ||
00277          sel1->nonCSSHint != sel2->nonCSSHint ||
00278          sel1->value != sel2->value ||
00279              sel1->pseudoType() != sel2->pseudoType() ||
00280              sel1->string_arg != sel2->string_arg)
00281         return false;
00282     sel1 = sel1->tagHistory;
00283     sel2 = sel2->tagHistory;
00284     }
00285     if ( sel1 || sel2 )
00286     return false;
00287     return true;
00288 }
00289 
00290 DOMString CSSSelector::selectorText() const
00291 {
00292     // #### fix namespace
00293     DOMString str;
00294     const CSSSelector* cs = this;
00295     if ( cs->tag == 0xffffffff && cs->attr == ATTR_ID && cs->match == CSSSelector::Id )
00296     {
00297         str = "#";
00298         str += cs->value;
00299     }
00300     else if ( cs->tag == 0xffffffff && cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
00301     {
00302         str = ".";
00303         str += cs->value;
00304     }
00305     else if ( cs->tag == 0xffffffff && cs->match == CSSSelector::Pseudo )
00306     {
00307         str = ":";
00308         str += cs->value;
00309     }
00310     else
00311     {
00312         if ( cs->tag == 0xffffffff )
00313             str = "*";
00314         else if ( cs->tag != 0xffff )
00315             str = getTagName( cs->tag );
00316         if ( cs->attr == ATTR_ID && cs->match == CSSSelector::Id )
00317         {
00318             str += "#";
00319             str += cs->value;
00320         }
00321         else if ( cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
00322         {
00323             str += ".";
00324             str += cs->value;
00325         }
00326         else if ( cs->match == CSSSelector::Pseudo )
00327         {
00328             str += ":";
00329             str += cs->value;
00330         }
00331         // optional attribute
00332         else if ( cs->attr ) {
00333             DOMString attrName = getAttrName( cs->attr );
00334             str += "[";
00335             str += attrName;
00336             switch (cs->match) {
00337             case CSSSelector::Exact:
00338                 str += "=";
00339                 break;
00340             case CSSSelector::Set:
00341                 str += " "; // ## correct?
00342                 break;
00343             case CSSSelector::List:
00344                 str += "~=";
00345                 break;
00346             case CSSSelector::Hyphen:
00347                 str += "|=";
00348                 break;
00349             case CSSSelector::Begin:
00350                 str += "^=";
00351                 break;
00352             case CSSSelector::End:
00353                 str += "$=";
00354                 break;
00355             case CSSSelector::Contain:
00356                 str += "*=";
00357                 break;
00358             default:
00359                 kdWarning(6080) << "Unhandled case in CSSStyleRuleImpl::selectorText : match=" << cs->match << endl;
00360             }
00361             str += "\"";
00362             str += cs->value;
00363             str += "\"]";
00364         }
00365     }
00366     if ( cs->tagHistory ) {
00367         DOMString tagHistoryText = cs->tagHistory->selectorText();
00368         if ( cs->relation == DirectAdjacent )
00369             str = tagHistoryText + " + " + str;
00370         else if ( cs->relation == IndirectAdjacent )
00371             str = tagHistoryText + " ~ " + str;
00372         else if ( cs->relation == Child )
00373             str = tagHistoryText + " > " + str;
00374         else if ( cs->relation == SubSelector )
00375             str += tagHistoryText; // the ":" is provided by selectorText()
00376         else // Descendant
00377             str = tagHistoryText + " " + str;
00378     }
00379     return str;
00380 }
00381 
00382 // ----------------------------------------------------------------------------
KDE Logo
This file is part of the documentation for khtml Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 4 07:16:00 2005 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003