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  * Copyright (C) 2002 Apple Computer, Inc.
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Library General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Library General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Library General Public License
00021  * along with this library; see the file COPYING.LIB.  If not, write to
00022  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00023  * Boston, MA 02111-1307, USA.
00024  */
00025 
00026 //#define CSS_DEBUG
00027 
00028 #include <assert.h>
00029 #include <kdebug.h>
00030 
00031 #include "css_base.h"
00032 
00033 #ifdef CSS_DEBUG
00034 #include "cssproperties.h"
00035 #endif
00036 
00037 #include "css_stylesheetimpl.h"
00038 #include "xml/dom_docimpl.h"
00039 #include "misc/htmlhashes.h"
00040 #include "css_valueimpl.h"
00041 using namespace DOM;
00042 
00043 void StyleBaseImpl::checkLoaded() const
00044 {
00045     if(m_parent) m_parent->checkLoaded();
00046 }
00047 
00048 StyleSheetImpl* StyleBaseImpl::stylesheet()
00049 {
00050     StyleBaseImpl* b = this;
00051     while(b && !b->isStyleSheet())
00052         b = b->m_parent;
00053     return static_cast<StyleSheetImpl *>(b);
00054 }
00055 
00056 KURL StyleBaseImpl::baseURL()
00057 {
00058     // try to find the style sheet. If found look for its url.
00059     // If it has none, look for the parentsheet, or the parentNode and
00060     // try to find out about their url
00061 
00062     StyleSheetImpl *sheet = stylesheet();
00063 
00064     if(!sheet) return KURL();
00065 
00066     if(!sheet->href().isNull())
00067         return KURL( sheet->href().string() );
00068 
00069     // find parent
00070     if(sheet->parent()) return sheet->parent()->baseURL();
00071 
00072     if(!sheet->ownerNode()) return KURL();
00073 
00074     return sheet->ownerNode()->getDocument()->baseURL();
00075 }
00076 
00077 void StyleBaseImpl::setParsedValue(int propId, const CSSValueImpl *parsedValue,
00078                    bool important, bool nonCSSHint, QPtrList<CSSProperty> *propList)
00079 {
00080     QPtrListIterator<CSSProperty> propIt(*propList);
00081     propIt.toLast(); // just remove the top one - not sure what should happen if we have multiple instances of the property
00082     while (propIt.current() &&
00083            ( propIt.current()->m_id != propId || propIt.current()->nonCSSHint != nonCSSHint ||
00084              propIt.current()->m_bImportant != important) )
00085         --propIt;
00086     if (propIt.current())
00087         propList->removeRef(propIt.current());
00088 
00089     CSSProperty *prop = new CSSProperty();
00090     prop->m_id = propId;
00091     prop->setValue((CSSValueImpl *) parsedValue);
00092     prop->m_bImportant = important;
00093     prop->nonCSSHint = nonCSSHint;
00094 
00095     propList->append(prop);
00096 #ifdef CSS_DEBUG
00097     kdDebug( 6080 ) << "added property: " << getPropertyName(propId).string()
00098                     // non implemented yet << ", value: " << parsedValue->cssText().string()
00099                     << " important: " << prop->m_bImportant
00100                     << " nonCSS: " << prop->nonCSSHint << endl;
00101 #endif
00102 }
00103 
00104 // ------------------------------------------------------------------------------
00105 
00106 StyleListImpl::~StyleListImpl()
00107 {
00108     StyleBaseImpl *n;
00109 
00110     if(!m_lstChildren) return;
00111 
00112     for( n = m_lstChildren->first(); n != 0; n = m_lstChildren->next() )
00113     {
00114         n->setParent(0);
00115         if( !n->refCount() ) delete n;
00116     }
00117     delete m_lstChildren;
00118 }
00119 
00120 // --------------------------------------------------------------------------------
00121 
00122 void CSSSelector::print(void)
00123 {
00124     kdDebug( 6080 ) << "[Selector: tag = " <<       QString::number(tag,16) << ", attr = \"" << attr << "\", match = \"" << match
00125             << "\" value = \"" << value.string().latin1() << "\" relation = " << (int)relation
00126             << "]" << endl;
00127     if ( tagHistory )
00128         tagHistory->print();
00129     kdDebug( 6080 ) << "    specificity = " << specificity() << endl;
00130 }
00131 
00132 unsigned int CSSSelector::specificity() const
00133 {
00134     if ( nonCSSHint )
00135         return 0;
00136 
00137     int s = ((( tag & NodeImpl_IdLocalMask ) == 0xffff) ? 0 : 1);
00138     switch(match)
00139     {
00140     case Id:
00141     s += 0x10000;
00142     break;
00143     case Exact:
00144     case Set:
00145     case List:
00146     case Hyphen:
00147     case Pseudo:
00148     case Contain:
00149     case Begin:
00150     case End:
00151         s += 0x100;
00152     case None:
00153         break;
00154     }
00155     if(tagHistory)
00156         s += tagHistory->specificity();
00157     // make sure it doesn't overflow
00158     return s & 0xffffff;
00159 }
00160 
00161 void CSSSelector::extractPseudoType() const
00162 {
00163     if (match != Pseudo)
00164         return;
00165     _pseudoType = PseudoOther;
00166     if (!value.isEmpty()) {
00167         value = value.lower();
00168         switch (value[0]) {
00169             case 'a':
00170                 if (value == "active")
00171                     _pseudoType = PseudoActive;
00172                 else if (value == "after")
00173                     _pseudoType = PseudoAfter;
00174                 break;
00175             case 'b':
00176                 if (value == "before")
00177                     _pseudoType = PseudoBefore;
00178                 break;
00179             case 'e':
00180                 if (value == "empty")
00181                     _pseudoType = PseudoEmpty;
00182                 break;
00183             case 'f':
00184                 if (value == "first-child")
00185                     _pseudoType = PseudoFirstChild;
00186                 else if (value == "first-letter")
00187                     _pseudoType = PseudoFirstLetter;
00188                 else if (value == "first-line")
00189                     _pseudoType = PseudoFirstLine;
00190                 else if (value == "focus")
00191                     _pseudoType = PseudoFocus;
00192                 break;
00193             case 'h':
00194                 if (value == "hover")
00195                     _pseudoType = PseudoHover;
00196                 break;
00197             case 'l':
00198                 if (value == "link")
00199                     _pseudoType = PseudoLink;
00200                 else if (value == "lang(")
00201                     _pseudoType = PseudoLang;
00202                 else if (value == "last-child")
00203                     _pseudoType = PseudoLastChild;
00204                 break;
00205             case 'n':
00206                 if (value == "not(")
00207                     _pseudoType = PseudoNot;
00208                 break;
00209             case 'o':
00210                 if (value == "only-child")
00211                     _pseudoType = PseudoOnlyChild;
00212                 break;
00213             case 'r':
00214                 if (value == "root")
00215                     _pseudoType = PseudoRoot;
00216                 break;
00217             case 's':
00218                 if (value == "selection")
00219                     _pseudoType = PseudoSelection;
00220                 break;
00221             case 't':
00222                 if (value == "target")
00223                     _pseudoType = PseudoTarget;
00224                 break;
00225             case 'v':
00226                 if (value == "visited")
00227                     _pseudoType = PseudoVisited;
00228                 break;
00229         }
00230     }
00231 
00232     value = DOMString();
00233 }
00234 
00235 
00236 bool CSSSelector::operator == ( const CSSSelector &other ) const
00237 {
00238     const CSSSelector *sel1 = this;
00239     const CSSSelector *sel2 = &other;
00240 
00241     while ( sel1 && sel2 ) {
00242         //assert(sel1->_pseudoType != PseudoNotParsed);
00243         //assert(sel2->_pseudoType != PseudoNotParsed);
00244     if ( sel1->tag != sel2->tag || sel1->attr != sel2->attr ||
00245          sel1->relation != sel2->relation || sel1->match != sel2->match ||
00246          sel1->nonCSSHint != sel2->nonCSSHint ||
00247          sel1->value != sel2->value ||
00248              sel1->pseudoType() != sel2->pseudoType())
00249         return false;
00250     sel1 = sel1->tagHistory;
00251     sel2 = sel2->tagHistory;
00252     }
00253     if ( sel1 || sel2 )
00254     return false;
00255     return true;
00256 }
00257 
00258 DOMString CSSSelector::selectorText() const
00259 {
00260     // #### fix namespace
00261     DOMString str;
00262     const CSSSelector* cs = this;
00263     if ( cs->tag == 0xffff && cs->attr == ATTR_ID && cs->match == CSSSelector::Exact )
00264     {
00265         str = "#";
00266         str += cs->value;
00267     }
00268     else if ( cs->tag == 0xffff && cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
00269     {
00270         str = ".";
00271         str += cs->value;
00272     }
00273     else if ( cs->tag == 0xffff && cs->match == CSSSelector::Pseudo )
00274     {
00275         str = ":";
00276         str += cs->value;
00277     }
00278     else
00279     {
00280         if ( cs->tag == 0xffff )
00281             str = "*";
00282         else
00283             str = getTagName( cs->tag );
00284         if ( cs->attr == ATTR_ID && cs->match == CSSSelector::Exact )
00285         {
00286             str += "#";
00287             str += cs->value;
00288         }
00289         else if ( cs->attr == ATTR_CLASS && cs->match == CSSSelector::List )
00290         {
00291             str += ".";
00292             str += cs->value;
00293         }
00294         else if ( cs->match == CSSSelector::Pseudo )
00295         {
00296             str += ":";
00297             str += cs->value;
00298         }
00299         // optional attribute
00300         if ( cs->attr ) {
00301             DOMString attrName = getAttrName( cs->attr );
00302             str += "[";
00303             str += attrName;
00304             switch (cs->match) {
00305             case CSSSelector::Exact:
00306                 str += "=";
00307                 break;
00308             case CSSSelector::Set:
00309                 str += " "; // ## correct?
00310                 break;
00311             case CSSSelector::List:
00312                 str += "~=";
00313                 break;
00314             case CSSSelector::Hyphen:
00315                 str += "|=";
00316                 break;
00317             case CSSSelector::Begin:
00318                 str += "^=";
00319                 break;
00320             case CSSSelector::End:
00321                 str += "$=";
00322                 break;
00323             case CSSSelector::Contain:
00324                 str += "*=";
00325                 break;
00326             default:
00327                 kdWarning(6080) << "Unhandled case in CSSStyleRuleImpl::selectorText : match=" << cs->match << endl;
00328             }
00329             str += "\"";
00330             str += cs->value;
00331             str += "\"]";
00332         }
00333     }
00334     if ( cs->tagHistory ) {
00335         DOMString tagHistoryText = cs->tagHistory->selectorText();
00336         if ( cs->relation == Sibling )
00337             str = tagHistoryText + " + " + str;
00338         else if ( cs->relation == Child )
00339             str = tagHistoryText + " > " + str;
00340         else if ( cs->relation == SubSelector )
00341             str += tagHistoryText; // the ":" is provided by selectorText()
00342         else // Descendant
00343             str = tagHistoryText + " " + str;
00344     }
00345     return str;
00346 }
00347 
00348 // ----------------------------------------------------------------------------
KDE Logo
This file is part of the documentation for khtml Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Aug 4 05:28:51 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2003