css_stylesheetimpl.cpp

00001 
00024 //#define CSS_STYLESHEET_DEBUG
00025 
00026 #include "dom/dom_string.h"
00027 #include "dom/dom_exception.h"
00028 #include "dom/css_stylesheet.h"
00029 #include "dom/css_rule.h"
00030 
00031 #include "css/css_ruleimpl.h"
00032 #include "css/css_valueimpl.h"
00033 #include "css/cssparser.h"
00034 #include "css/css_stylesheetimpl.h"
00035 
00036 #include "xml/dom_nodeimpl.h"
00037 #include "html/html_documentimpl.h"
00038 #include "misc/loader.h"
00039 
00040 #include <kdebug.h>
00041 
00042 using namespace DOM;
00043 using namespace khtml;
00044 // --------------------------------------------------------------------------------
00045 
00046 StyleSheetImpl::StyleSheetImpl(StyleSheetImpl *parentSheet, DOMString href)
00047     : StyleListImpl(parentSheet)
00048 {
00049     m_disabled = false;
00050     m_media = 0;
00051     m_parentNode = 0;
00052     m_strHref = href;
00053 }
00054 
00055 
00056 StyleSheetImpl::StyleSheetImpl(DOM::NodeImpl *parentNode, DOMString href)
00057     : StyleListImpl()
00058 {
00059     m_parentNode = parentNode;
00060     m_disabled = false;
00061     m_media = 0;
00062     m_strHref = href;
00063 }
00064 
00065 StyleSheetImpl::StyleSheetImpl(StyleBaseImpl *owner, DOMString href)
00066     : StyleListImpl(owner)
00067 {
00068     m_disabled = false;
00069     m_media = 0;
00070     m_parentNode = 0;
00071     m_strHref = href;
00072 }
00073 
00074 StyleSheetImpl::~StyleSheetImpl()
00075 {
00076     if(m_media) {
00077     m_media->setParent( 0 );
00078     m_media->deref();
00079     }
00080 }
00081 
00082 StyleSheetImpl *StyleSheetImpl::parentStyleSheet() const
00083 {
00084     if( !m_parent ) return 0;
00085     if( m_parent->isStyleSheet() ) return static_cast<StyleSheetImpl *>(m_parent);
00086     return 0;
00087 }
00088 
00089 void StyleSheetImpl::setMedia( MediaListImpl *media )
00090 {
00091     if( media )
00092     media->ref();
00093     if( m_media )
00094     m_media->deref();
00095     m_media = media;
00096 }
00097 
00098 void StyleSheetImpl::setDisabled( bool disabled )
00099 {
00100     bool updateStyle = isCSSStyleSheet() && m_parentNode && disabled != m_disabled;
00101     m_disabled = disabled;
00102     if (updateStyle)
00103         m_parentNode->getDocument()->updateStyleSelector();
00104 }
00105 
00106 // -----------------------------------------------------------------------
00107 
00108 
00109 CSSStyleSheetImpl::CSSStyleSheetImpl(CSSStyleSheetImpl *parentSheet, DOMString href)
00110     : StyleSheetImpl(parentSheet, href)
00111 {
00112     m_lstChildren = new QPtrList<StyleBaseImpl>;
00113     m_doc = 0;
00114     m_implicit = false;
00115     m_namespaces = 0;
00116 }
00117 
00118 CSSStyleSheetImpl::CSSStyleSheetImpl(DOM::NodeImpl *parentNode, DOMString href, bool _implicit)
00119     : StyleSheetImpl(parentNode, href)
00120 {
00121     m_lstChildren = new QPtrList<StyleBaseImpl>;
00122     m_doc = parentNode->getDocument();
00123     m_implicit = _implicit;
00124     m_namespaces = 0;
00125 }
00126 
00127 CSSStyleSheetImpl::CSSStyleSheetImpl(CSSRuleImpl *ownerRule, DOMString href)
00128     : StyleSheetImpl(ownerRule, href)
00129 {
00130     m_lstChildren = new QPtrList<StyleBaseImpl>;
00131     m_doc = 0;
00132     m_implicit = false;
00133     m_namespaces = 0;
00134 }
00135 
00136 CSSStyleSheetImpl::CSSStyleSheetImpl(DOM::NodeImpl *parentNode, CSSStyleSheetImpl *orig)
00137     : StyleSheetImpl(parentNode, orig->m_strHref)
00138 {
00139     m_lstChildren = new QPtrList<StyleBaseImpl>;
00140     StyleBaseImpl *rule;
00141     for ( rule = orig->m_lstChildren->first(); rule != 0; rule = orig->m_lstChildren->next() )
00142     {
00143         m_lstChildren->append(rule);
00144         rule->setParent(this);
00145     }
00146     m_doc = parentNode->getDocument();
00147     m_implicit = false;
00148     m_namespaces = 0;
00149 }
00150 
00151 CSSStyleSheetImpl::CSSStyleSheetImpl(CSSRuleImpl *ownerRule, CSSStyleSheetImpl *orig)
00152     : StyleSheetImpl(ownerRule, orig->m_strHref)
00153 {
00154     // m_lstChildren is deleted in StyleListImpl
00155     m_lstChildren = new QPtrList<StyleBaseImpl>;
00156     StyleBaseImpl *rule;
00157     for ( rule = orig->m_lstChildren->first(); rule != 0; rule = orig->m_lstChildren->next() )
00158     {
00159         m_lstChildren->append(rule);
00160         rule->setParent(this);
00161     }
00162     m_doc  = 0;
00163     m_implicit = false;
00164     m_namespaces = 0;
00165 }
00166 
00167 CSSRuleImpl *CSSStyleSheetImpl::ownerRule() const
00168 {
00169     if( !m_parent ) return 0;
00170     if( m_parent->isRule() ) return static_cast<CSSRuleImpl *>(m_parent);
00171     return 0;
00172 }
00173 
00174 unsigned long CSSStyleSheetImpl::insertRule( const DOMString &rule, unsigned long index, int &exceptioncode )
00175 {
00176     exceptioncode = 0;
00177     if(index > m_lstChildren->count()) {
00178         exceptioncode = DOMException::INDEX_SIZE_ERR;
00179         return 0;
00180     }
00181     CSSParser p( strictParsing );
00182     CSSRuleImpl *r = p.parseRule( this, rule );
00183 
00184     if(!r) {
00185         exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
00186         return 0;
00187     }
00188     // ###
00189     // HIERARCHY_REQUEST_ERR: Raised if the rule cannot be inserted at the specified index e.g. if an
00190     //@import rule is inserted after a standard rule set or other at-rule.
00191     m_lstChildren->insert(index, r);
00192     return index;
00193 }
00194 
00195 CSSRuleList CSSStyleSheetImpl::cssRules()
00196 {
00197     return this;
00198 }
00199 
00200 void CSSStyleSheetImpl::deleteRule( unsigned long index, int &exceptioncode )
00201 {
00202     exceptioncode = 0;
00203     StyleBaseImpl *b = m_lstChildren->take(index);
00204     if(!b) {
00205         exceptioncode = DOMException::INDEX_SIZE_ERR;
00206         return;
00207     }
00208     b->deref();
00209 }
00210 
00211 void CSSStyleSheetImpl::addNamespace(CSSParser* p, const DOM::DOMString& prefix, const DOM::DOMString& uri)
00212 {
00213     int exceptioncode = 0;
00214     if (uri.isEmpty())
00215         return;
00216 
00217     m_namespaces = new CSSNamespace(prefix, uri, m_namespaces);
00218 
00219     if (prefix.isEmpty())
00220         // Set the default namespace on the parser so that selectors that omit namespace info will
00221         // be able to pick it up easily.
00222         p->defaultNamespace = m_doc->getId(NodeImpl::NamespaceId, uri.implementation(), false, false, &exceptioncode);
00223 }
00224 
00225 void CSSStyleSheetImpl::determineNamespace(Q_UINT32& id, const DOM::DOMString& prefix)
00226 {
00227     // If the stylesheet has no namespaces we can just return.  There won't be any need to ever check
00228     // namespace values in selectors.
00229     if (!m_namespaces)
00230         return;
00231 
00232     if (prefix.isEmpty())
00233          id = makeId(noNamespace, localNamePart(id)); // No namespace. If an element/attribute has a namespace, e won't match it.
00234     else if (prefix == "*")
00235         id = makeId(anyNamespace, localNamePart(id)); // We'll match any namespace.
00236     else {
00237         int exceptioncode = 0;
00238         CSSNamespace* ns = m_namespaces->namespaceForPrefix(prefix);
00239         if (ns)
00240             // Look up the id for this namespace URI.
00241             id = makeId(m_doc->getId(NodeImpl::NamespaceId, ns->uri().implementation(), false, false, &exceptioncode), localNamePart(id));
00242     }
00243 }
00244 
00245 bool CSSStyleSheetImpl::parseString(const DOMString &string, bool strict)
00246 {
00247 #ifdef CSS_STYLESHEET_DEBUG
00248     kdDebug( 6080 ) << "parsing sheet, len=" << string.length() << ", sheet is " << string.string() << endl;
00249 #endif
00250 
00251     strictParsing = strict;
00252     CSSParser p( strict );
00253     p.parseSheet( this, string );
00254     return true;
00255 }
00256 
00257 bool CSSStyleSheetImpl::isLoading() const
00258 {
00259     StyleBaseImpl *rule;
00260     for ( rule = m_lstChildren->first(); rule != 0; rule = m_lstChildren->next() )
00261     {
00262         if(rule->isImportRule())
00263         {
00264             CSSImportRuleImpl *import = static_cast<CSSImportRuleImpl *>(rule);
00265 #ifdef CSS_STYLESHEET_DEBUG
00266             kdDebug( 6080 ) << "found import" << endl;
00267 #endif
00268             if(import->isLoading())
00269             {
00270 #ifdef CSS_STYLESHEET_DEBUG
00271                 kdDebug( 6080 ) << "--> not loaded" << endl;
00272 #endif
00273                 return true;
00274             }
00275         }
00276     }
00277     return false;
00278 }
00279 
00280 void CSSStyleSheetImpl::checkLoaded() const
00281 {
00282     if(isLoading()) return;
00283     if(m_parent) m_parent->checkLoaded();
00284     if(m_parentNode) m_parentNode->sheetLoaded();
00285 }
00286 
00287 void CSSStyleSheetImpl::setNonCSSHints()
00288 {
00289     StyleBaseImpl *rule = m_lstChildren->first();
00290     while(rule) {
00291         if(rule->isStyleRule()) {
00292             static_cast<CSSStyleRuleImpl *>(rule)->setNonCSSHints();
00293         }
00294         rule = m_lstChildren->next();
00295     }
00296 }
00297 
00298 
00299 // ---------------------------------------------------------------------------
00300 
00301 
00302 StyleSheetListImpl::~StyleSheetListImpl()
00303 {
00304     for ( QPtrListIterator<StyleSheetImpl> it ( styleSheets ); it.current(); ++it )
00305         it.current()->deref();
00306 }
00307 
00308 void StyleSheetListImpl::add( StyleSheetImpl* s )
00309 {
00310     if ( !styleSheets.containsRef( s ) ) {
00311         s->ref();
00312         styleSheets.append( s );
00313     }
00314 }
00315 
00316 void StyleSheetListImpl::remove( StyleSheetImpl* s )
00317 {
00318     if ( styleSheets.removeRef( s ) )
00319         s->deref();
00320 }
00321 
00322 unsigned long StyleSheetListImpl::length() const
00323 {
00324     // hack so implicit BODY stylesheets don't get counted here
00325     unsigned long l = 0;
00326     QPtrListIterator<StyleSheetImpl> it(styleSheets);
00327     for (; it.current(); ++it) {
00328         if (!it.current()->isCSSStyleSheet() || !static_cast<CSSStyleSheetImpl*>(it.current())->implicit())
00329             ++l;
00330     }
00331     return l;
00332 }
00333 
00334 StyleSheetImpl *StyleSheetListImpl::item ( unsigned long index )
00335 {
00336     unsigned long l = 0;
00337     QPtrListIterator<StyleSheetImpl> it(styleSheets);
00338     for (; it.current(); ++it) {
00339         if (!it.current()->isCSSStyleSheet() || !static_cast<CSSStyleSheetImpl*>(it.current())->implicit()) {
00340             if (l == index)
00341                 return it.current();
00342             ++l;
00343         }
00344     }
00345     return 0;
00346 }
00347 
00348 // --------------------------------------------------------------------------------------------
00349 
00350 MediaListImpl::MediaListImpl( CSSStyleSheetImpl *parentSheet,
00351                               const DOMString &media )
00352     : StyleBaseImpl( parentSheet )
00353 {
00354     setMediaText( media );
00355 }
00356 
00357 MediaListImpl::MediaListImpl( CSSRuleImpl *parentRule, const DOMString &media )
00358     : StyleBaseImpl(parentRule)
00359 {
00360     setMediaText( media );
00361 }
00362 
00363 bool MediaListImpl::contains( const DOMString &medium ) const
00364 {
00365     return m_lstMedia.empty() || m_lstMedia.contains( medium ) ||
00366             m_lstMedia.contains( "all" );
00367 }
00368 
00369 CSSStyleSheetImpl *MediaListImpl::parentStyleSheet() const
00370 {
00371     if( m_parent->isCSSStyleSheet() ) return static_cast<CSSStyleSheetImpl *>(m_parent);
00372     return 0;
00373 }
00374 
00375 CSSRuleImpl *MediaListImpl::parentRule() const
00376 {
00377     if( m_parent->isRule() ) return static_cast<CSSRuleImpl *>(m_parent);
00378     return 0;
00379 }
00380 
00381 void MediaListImpl::deleteMedium( const DOMString &oldMedium )
00382 {
00383     const QValueList<DOMString>::Iterator itEnd = m_lstMedia.end();
00384 
00385     for ( QValueList<DOMString>::Iterator it = m_lstMedia.begin(); it != itEnd; ++it ) {
00386         if( (*it) == oldMedium ) {
00387             m_lstMedia.remove( it );
00388             return;
00389         }
00390     }
00391 }
00392 
00393 DOM::DOMString MediaListImpl::mediaText() const
00394 {
00395     DOMString text;
00396     const QValueList<DOMString>::ConstIterator itEnd = m_lstMedia.end();
00397 
00398     for ( QValueList<DOMString>::ConstIterator it = m_lstMedia.begin(); it != itEnd; ++it ) {
00399         text += *it;
00400         text += ", ";
00401     }
00402     return text;
00403 }
00404 
00405 void MediaListImpl::setMediaText(const DOM::DOMString &value)
00406 {
00407     m_lstMedia.clear();
00408     const QString val = value.string();
00409     const QStringList list = QStringList::split( ',', val );
00410 
00411     const QStringList::ConstIterator itEnd = list.end();
00412 
00413     for ( QStringList::ConstIterator it = list.begin(); it != itEnd; ++it )
00414     {
00415         const DOMString medium = (*it).stripWhiteSpace();
00416         if( !medium.isEmpty() )
00417             m_lstMedia.append( medium );
00418     }
00419 }
KDE Home | KDE Accessibility Home | Description of Access Keys