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     m_defaultNamespace = anyNamespace;
00117 }
00118 
00119 CSSStyleSheetImpl::CSSStyleSheetImpl(DOM::NodeImpl *parentNode, DOMString href, bool _implicit)
00120     : StyleSheetImpl(parentNode, href)
00121 {
00122     m_lstChildren = new QPtrList<StyleBaseImpl>;
00123     m_doc = parentNode->getDocument();
00124     m_implicit = _implicit;
00125     m_namespaces = 0;
00126     m_defaultNamespace = anyNamespace;
00127 }
00128 
00129 CSSStyleSheetImpl::CSSStyleSheetImpl(CSSRuleImpl *ownerRule, DOMString href)
00130     : StyleSheetImpl(ownerRule, href)
00131 {
00132     m_lstChildren = new QPtrList<StyleBaseImpl>;
00133     m_doc = 0;
00134     m_implicit = false;
00135     m_namespaces = 0;
00136     m_defaultNamespace = anyNamespace;
00137 }
00138 
00139 CSSStyleSheetImpl::CSSStyleSheetImpl(DOM::NodeImpl *parentNode, CSSStyleSheetImpl *orig)
00140     : StyleSheetImpl(parentNode, orig->m_strHref)
00141 {
00142     m_lstChildren = new QPtrList<StyleBaseImpl>;
00143     StyleBaseImpl *rule;
00144     for ( rule = orig->m_lstChildren->first(); rule != 0; rule = orig->m_lstChildren->next() )
00145     {
00146         m_lstChildren->append(rule);
00147         rule->setParent(this);
00148     }
00149     m_doc = parentNode->getDocument();
00150     m_implicit = false;
00151     m_namespaces = 0;
00152     m_defaultNamespace = anyNamespace;
00153 }
00154 
00155 CSSStyleSheetImpl::CSSStyleSheetImpl(CSSRuleImpl *ownerRule, CSSStyleSheetImpl *orig)
00156     : StyleSheetImpl(ownerRule, orig->m_strHref)
00157 {
00158     // m_lstChildren is deleted in StyleListImpl
00159     m_lstChildren = new QPtrList<StyleBaseImpl>;
00160     StyleBaseImpl *rule;
00161     for ( rule = orig->m_lstChildren->first(); rule != 0; rule = orig->m_lstChildren->next() )
00162     {
00163         m_lstChildren->append(rule);
00164         rule->setParent(this);
00165     }
00166     m_doc  = 0;
00167     m_implicit = false;
00168     m_namespaces = 0;
00169     m_defaultNamespace = anyNamespace;
00170 }
00171 
00172 CSSRuleImpl *CSSStyleSheetImpl::ownerRule() const
00173 {
00174     if( !m_parent ) return 0;
00175     if( m_parent->isRule() ) return static_cast<CSSRuleImpl *>(m_parent);
00176     return 0;
00177 }
00178 
00179 unsigned long CSSStyleSheetImpl::insertRule( const DOMString &rule, unsigned long index, int &exceptioncode )
00180 {
00181     exceptioncode = 0;
00182     if(index > m_lstChildren->count()) {
00183         exceptioncode = DOMException::INDEX_SIZE_ERR;
00184         return 0;
00185     }
00186     CSSParser p( strictParsing );
00187     CSSRuleImpl *r = p.parseRule( this, rule );
00188 
00189     if(!r) {
00190         exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
00191         return 0;
00192     }
00193     // ###
00194     // HIERARCHY_REQUEST_ERR: Raised if the rule cannot be inserted at the specified index e.g. if an
00195     //@import rule is inserted after a standard rule set or other at-rule.
00196     m_lstChildren->insert(index, r);
00197     return index;
00198 }
00199 
00200 CSSRuleList CSSStyleSheetImpl::cssRules()
00201 {
00202     return this;
00203 }
00204 
00205 void CSSStyleSheetImpl::deleteRule( unsigned long index, int &exceptioncode )
00206 {
00207     exceptioncode = 0;
00208     StyleBaseImpl *b = m_lstChildren->take(index);
00209     if(!b) {
00210         exceptioncode = DOMException::INDEX_SIZE_ERR;
00211         return;
00212     }
00213     b->deref();
00214 }
00215 
00216 void CSSStyleSheetImpl::addNamespace(CSSParser* p, const DOM::DOMString& prefix, const DOM::DOMString& uri)
00217 {
00218     int exceptioncode = 0;
00219     if (uri.isEmpty())
00220         return;
00221 
00222     m_namespaces = new CSSNamespace(prefix, uri, m_namespaces);
00223 
00224     if (prefix.isEmpty()) {
00225         Q_ASSERT(m_doc != 0);
00226 
00227         m_defaultNamespace = m_doc->getId(NodeImpl::NamespaceId, uri.implementation(), false, false, &exceptioncode);
00228     }
00229 }
00230 
00231 void CSSStyleSheetImpl::determineNamespace(Q_UINT32& id, const DOM::DOMString& prefix)
00232 {
00233     // If the stylesheet has no namespaces we can just return.  There won't be any need to ever check
00234     // namespace values in selectors.
00235     if (!m_namespaces)
00236         return;
00237 
00238     if (prefix.isEmpty())
00239          id = makeId(emptyNamespace, localNamePart(id)); // No namespace. If an element/attribute has a namespace, we won't match it.
00240     else if (prefix == "*")
00241         id = makeId(anyNamespace, localNamePart(id)); // We'll match any namespace.
00242     else {
00243         int exceptioncode = 0;
00244         CSSNamespace* ns = m_namespaces->namespaceForPrefix(prefix);
00245         if (ns) {
00246             Q_ASSERT(m_doc != 0);
00247 
00248             // Look up the id for this namespace URI.
00249             Q_UINT16 nsid = m_doc->getId(NodeImpl::NamespaceId, 0, 0, ns->uri().implementation(), false, false, &exceptioncode);
00250             id = makeId(nsid, localNamePart(id));
00251         }
00252     }
00253 }
00254 
00255 bool CSSStyleSheetImpl::parseString(const DOMString &string, bool strict)
00256 {
00257 #ifdef CSS_STYLESHEET_DEBUG
00258     kdDebug( 6080 ) << "parsing sheet, len=" << string.length() << ", sheet is " << string.string() << endl;
00259 #endif
00260 
00261     strictParsing = strict;
00262     CSSParser p( strict );
00263     p.parseSheet( this, string );
00264     return true;
00265 }
00266 
00267 bool CSSStyleSheetImpl::isLoading() const
00268 {
00269     StyleBaseImpl *rule;
00270     for ( rule = m_lstChildren->first(); rule != 0; rule = m_lstChildren->next() )
00271     {
00272         if(rule->isImportRule())
00273         {
00274             CSSImportRuleImpl *import = static_cast<CSSImportRuleImpl *>(rule);
00275 #ifdef CSS_STYLESHEET_DEBUG
00276             kdDebug( 6080 ) << "found import" << endl;
00277 #endif
00278             if(import->isLoading())
00279             {
00280 #ifdef CSS_STYLESHEET_DEBUG
00281                 kdDebug( 6080 ) << "--> not loaded" << endl;
00282 #endif
00283                 return true;
00284             }
00285         }
00286     }
00287     return false;
00288 }
00289 
00290 void CSSStyleSheetImpl::checkLoaded() const
00291 {
00292     if(isLoading()) return;
00293     if(m_parent) m_parent->checkLoaded();
00294     if(m_parentNode) m_parentNode->sheetLoaded();
00295 }
00296 
00297 void CSSStyleSheetImpl::setNonCSSHints()
00298 {
00299     StyleBaseImpl *rule = m_lstChildren->first();
00300     while(rule) {
00301         if(rule->isStyleRule()) {
00302             static_cast<CSSStyleRuleImpl *>(rule)->setNonCSSHints();
00303         }
00304         rule = m_lstChildren->next();
00305     }
00306 }
00307 
00308 
00309 // ---------------------------------------------------------------------------
00310 
00311 
00312 StyleSheetListImpl::~StyleSheetListImpl()
00313 {
00314     for ( QPtrListIterator<StyleSheetImpl> it ( styleSheets ); it.current(); ++it )
00315         it.current()->deref();
00316 }
00317 
00318 void StyleSheetListImpl::add( StyleSheetImpl* s )
00319 {
00320     if ( !styleSheets.containsRef( s ) ) {
00321         s->ref();
00322         styleSheets.append( s );
00323     }
00324 }
00325 
00326 void StyleSheetListImpl::remove( StyleSheetImpl* s )
00327 {
00328     if ( styleSheets.removeRef( s ) )
00329         s->deref();
00330 }
00331 
00332 unsigned long StyleSheetListImpl::length() const
00333 {
00334     // hack so implicit BODY stylesheets don't get counted here
00335     unsigned long l = 0;
00336     QPtrListIterator<StyleSheetImpl> it(styleSheets);
00337     for (; it.current(); ++it) {
00338         if (!it.current()->isCSSStyleSheet() || !static_cast<CSSStyleSheetImpl*>(it.current())->implicit())
00339             ++l;
00340     }
00341     return l;
00342 }
00343 
00344 StyleSheetImpl *StyleSheetListImpl::item ( unsigned long index )
00345 {
00346     unsigned long l = 0;
00347     QPtrListIterator<StyleSheetImpl> it(styleSheets);
00348     for (; it.current(); ++it) {
00349         if (!it.current()->isCSSStyleSheet() || !static_cast<CSSStyleSheetImpl*>(it.current())->implicit()) {
00350             if (l == index)
00351                 return it.current();
00352             ++l;
00353         }
00354     }
00355     return 0;
00356 }
00357 
00358 // --------------------------------------------------------------------------------------------
00359 
00360 MediaListImpl::MediaListImpl( CSSStyleSheetImpl *parentSheet,
00361                               const DOMString &media )
00362     : StyleBaseImpl( parentSheet )
00363 {
00364     setMediaText( media );
00365 }
00366 
00367 MediaListImpl::MediaListImpl( CSSRuleImpl *parentRule, const DOMString &media )
00368     : StyleBaseImpl(parentRule)
00369 {
00370     setMediaText( media );
00371 }
00372 
00373 bool MediaListImpl::contains( const DOMString &medium ) const
00374 {
00375     return m_lstMedia.empty() || m_lstMedia.contains( medium ) ||
00376             m_lstMedia.contains( "all" );
00377 }
00378 
00379 CSSStyleSheetImpl *MediaListImpl::parentStyleSheet() const
00380 {
00381     if( m_parent->isCSSStyleSheet() ) return static_cast<CSSStyleSheetImpl *>(m_parent);
00382     return 0;
00383 }
00384 
00385 CSSRuleImpl *MediaListImpl::parentRule() const
00386 {
00387     if( m_parent->isRule() ) return static_cast<CSSRuleImpl *>(m_parent);
00388     return 0;
00389 }
00390 
00391 void MediaListImpl::deleteMedium( const DOMString &oldMedium )
00392 {
00393     const QValueList<DOMString>::Iterator itEnd = m_lstMedia.end();
00394 
00395     for ( QValueList<DOMString>::Iterator it = m_lstMedia.begin(); it != itEnd; ++it ) {
00396         if( (*it) == oldMedium ) {
00397             m_lstMedia.remove( it );
00398             return;
00399         }
00400     }
00401 }
00402 
00403 DOM::DOMString MediaListImpl::mediaText() const
00404 {
00405     DOMString text;
00406     const QValueList<DOMString>::ConstIterator itEnd = m_lstMedia.end();
00407 
00408     for ( QValueList<DOMString>::ConstIterator it = m_lstMedia.begin(); it != itEnd; ++it ) {
00409         text += *it;
00410         text += ", ";
00411     }
00412     return text;
00413 }
00414 
00415 void MediaListImpl::setMediaText(const DOM::DOMString &value)
00416 {
00417     m_lstMedia.clear();
00418     const QString val = value.string();
00419     const QStringList list = QStringList::split( ',', val );
00420 
00421     const QStringList::ConstIterator itEnd = list.end();
00422 
00423     for ( QStringList::ConstIterator it = list.begin(); it != itEnd; ++it )
00424     {
00425         const DOMString medium = (*it).stripWhiteSpace();
00426         if( !medium.isEmpty() )
00427             m_lstMedia.append( medium );
00428     }
00429 }
KDE Home | KDE Accessibility Home | Description of Access Keys