File indexing completed on 2024-04-28 15:22:40

0001 /**
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright 1999-2003 Lars Knoll (knoll@kde.org)
0005  * Copyright 2002-2003 Dirk Mueller (mueller@kde.org)
0006  * Copyright 2002-2008 Apple Computer, Inc.
0007  *
0008  * This library is free software; you can redistribute it and/or
0009  * modify it under the terms of the GNU Library General Public
0010  * License as published by the Free Software Foundation; either
0011  * version 2 of the License, or (at your option) any later version.
0012  *
0013  * This library is distributed in the hope that it will be useful,
0014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016  * Library General Public License for more details.
0017  *
0018  * You should have received a copy of the GNU Library General Public License
0019  * along with this library; see the file COPYING.LIB.  If not, write to
0020  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021  * Boston, MA 02110-1301, USA.
0022  */
0023 
0024 #include "css_ruleimpl.h"
0025 #include "css_stylesheetimpl.h"
0026 #include "css_valueimpl.h"
0027 #include "cssparser.h"
0028 
0029 #include <dom/css_rule.h>
0030 #include <dom/css_stylesheet.h>
0031 #include <dom/dom_exception.h>
0032 #include <dom/dom_string.h>
0033 
0034 #include <xml/dom_docimpl.h>
0035 
0036 using namespace DOM;
0037 
0038 CSSStyleSheetImpl *CSSRuleImpl::parentStyleSheet() const
0039 {
0040     return (m_parent && m_parent->isCSSStyleSheet())  ?
0041            static_cast<CSSStyleSheetImpl *>(m_parent) : nullptr;
0042 }
0043 
0044 CSSRuleImpl *CSSRuleImpl::parentRule() const
0045 {
0046     return (m_parent && m_parent->isRule())  ?
0047            static_cast<CSSRuleImpl *>(m_parent) : nullptr;
0048 }
0049 
0050 DOM::DOMString CSSRuleImpl::cssText() const
0051 {
0052     // ###
0053     return DOMString();
0054 }
0055 
0056 void CSSRuleImpl::setCssText(DOM::DOMString /*str*/)
0057 {
0058     // ###
0059 }
0060 
0061 // ---------------------------------------------------------------------------
0062 
0063 CSSFontFaceRuleImpl::CSSFontFaceRuleImpl(StyleBaseImpl *parent)
0064     : CSSRuleImpl(parent)
0065 {
0066     m_type = CSSRule::FONT_FACE_RULE;
0067     m_style = nullptr;
0068 }
0069 
0070 CSSFontFaceRuleImpl::~CSSFontFaceRuleImpl()
0071 {
0072     if (m_style) {
0073         m_style->deref();
0074     }
0075 }
0076 
0077 void CSSFontFaceRuleImpl::setDeclaration(CSSStyleDeclarationImpl *decl)
0078 {
0079     assert(!m_style);
0080     m_style = decl;
0081     if (m_style) {
0082         m_style->ref();
0083     }
0084 }
0085 
0086 DOMString CSSFontFaceRuleImpl::cssText() const
0087 {
0088     DOMString result("@font-face");
0089 
0090     result += " { ";
0091     result += m_style->cssText();
0092     result += "}";
0093 
0094     return result;
0095 }
0096 
0097 // --------------------------------------------------------------------------
0098 
0099 CSSImportRuleImpl::CSSImportRuleImpl(StyleBaseImpl *parent,
0100                                      const DOM::DOMString &href,
0101                                      MediaListImpl *media)
0102     : CSSRuleImpl(parent)
0103 {
0104     m_type = CSSRule::IMPORT_RULE;
0105 
0106     m_lstMedia = media;
0107     if (!m_lstMedia) {
0108         m_lstMedia = new MediaListImpl(this, DOMString());
0109     }
0110     m_lstMedia->setParent(this);
0111     m_lstMedia->ref();
0112 
0113     m_strHref = href;
0114     m_styleSheet = nullptr;
0115 
0116     m_cachedSheet = nullptr;
0117 
0118     init();
0119 }
0120 CSSImportRuleImpl::CSSImportRuleImpl(StyleBaseImpl *parent,
0121                                      const DOM::DOMString &href,
0122                                      const DOM::DOMString &media)
0123     : CSSRuleImpl(parent)
0124 {
0125     m_type = CSSRule::IMPORT_RULE;
0126 
0127     m_lstMedia = new MediaListImpl(this, media);
0128     m_lstMedia->ref();
0129 
0130     m_strHref = href;
0131     m_styleSheet = nullptr;
0132 
0133     m_cachedSheet = nullptr;
0134 
0135     init();
0136 }
0137 
0138 CSSImportRuleImpl::~CSSImportRuleImpl()
0139 {
0140     if (m_lstMedia) {
0141         m_lstMedia->setParent(nullptr);
0142         m_lstMedia->deref();
0143     }
0144     if (m_styleSheet) {
0145         m_styleSheet->setParent(nullptr);
0146         m_styleSheet->deref();
0147     }
0148 
0149     if (m_cachedSheet) {
0150         m_cachedSheet->deref(this);
0151     }
0152 }
0153 
0154 void CSSImportRuleImpl::checkLoaded() const
0155 {
0156     if (isLoading()) {
0157         return;
0158     }
0159     CSSRuleImpl::checkLoaded();
0160 }
0161 
0162 void CSSImportRuleImpl::setStyleSheet(const DOM::DOMString &url, const DOM::DOMString &sheetStr, const DOM::DOMString &charset, const DOM::DOMString &mimetype)
0163 {
0164     if (m_styleSheet) {
0165         m_styleSheet->setParent(nullptr);
0166         m_styleSheet->deref();
0167     }
0168     m_styleSheet = new CSSStyleSheetImpl(this, url);
0169     m_styleSheet->setCharset(charset);
0170     m_styleSheet->ref();
0171 
0172     CSSStyleSheetImpl *parent = parentStyleSheet();
0173     bool strict = parent ? parent->useStrictParsing() : true;
0174     DOMString sheet = sheetStr;
0175     if (strict && !khtml::isAcceptableCSSMimetype(mimetype)) {
0176         sheet = "";
0177     }
0178     m_styleSheet->parseString(sheet, strict);
0179     m_loading = false;
0180     m_done = true;
0181 
0182     checkLoaded();
0183 }
0184 
0185 void CSSImportRuleImpl::error(int /*err*/, const QString &/*text*/)
0186 {
0187     if (m_styleSheet) {
0188         m_styleSheet->setParent(nullptr);
0189         m_styleSheet->deref();
0190     }
0191     m_styleSheet = nullptr;
0192 
0193     m_loading = false;
0194     m_done = true;
0195 
0196     checkLoaded();
0197 }
0198 
0199 bool CSSImportRuleImpl::isLoading() const
0200 {
0201     return (m_loading || (m_styleSheet && m_styleSheet->isLoading()));
0202 }
0203 
0204 void CSSImportRuleImpl::init()
0205 {
0206     m_loading = 0;
0207     m_done = false;
0208     khtml::DocLoader *docLoader = nullptr;
0209     StyleBaseImpl *root = this;
0210     StyleBaseImpl *parent;
0211     while ((parent = root->parent())) {
0212         root = parent;
0213     }
0214     if (root->isCSSStyleSheet()) {
0215         docLoader = static_cast<CSSStyleSheetImpl *>(root)->docLoader();
0216     }
0217 
0218     DOMString absHref = m_strHref;
0219     CSSStyleSheetImpl *parentSheet = parentStyleSheet();
0220     if (!parentSheet->href().isNull()) {
0221         // use parent styleheet's URL as the base URL
0222         absHref = QUrl(parentSheet->href().string()).resolved(QUrl(m_strHref.string())).toString();
0223     }
0224     /*
0225         else {
0226           // use documents's URL as the base URL
0227           DocumentImpl *doc = static_cast<CSSStyleSheetImpl*>(root)->doc();
0228           absHref = QUrl(doc->URL()).resolved(QUrl(m_strHref.string())).toString();
0229         }
0230     */
0231     // Check for a cycle in our import chain.  If we encounter a stylesheet
0232     // in our parent chain with the same URL, then just bail.
0233     for (parent = static_cast<StyleBaseImpl *>(this)->parent();
0234             parent;
0235             parent = parent->parent())
0236         if (absHref == parent->baseURL().url()) {
0237             return;
0238         }
0239 
0240     m_cachedSheet = docLoader->requestStyleSheet(absHref, parentStyleSheet()->charset().string());
0241 
0242     if (m_cachedSheet) {
0243         // if the import rule is issued dynamically, the sheet may have already been
0244         // removed from the pending sheet count, so let the doc know
0245         // the sheet being imported is pending.
0246         checkPending();
0247 
0248         m_loading = true;
0249         m_cachedSheet->ref(this);
0250     }
0251 }
0252 
0253 DOMString CSSImportRuleImpl::cssText() const
0254 {
0255     DOMString result = "@import url(\"";
0256     result += m_strHref;
0257     result += "\")";
0258 
0259     if (m_lstMedia) {
0260         result += " ";
0261         result += m_lstMedia->mediaText();
0262     }
0263     result += ";";
0264 
0265     return result;
0266 }
0267 
0268 // --------------------------------------------------------------------------
0269 CSSMediaRuleImpl::CSSMediaRuleImpl(StyleBaseImpl *parent, MediaListImpl *mediaList, CSSRuleListImpl *ruleList)
0270     :   CSSRuleImpl(parent)
0271 {
0272     m_type = CSSRule::MEDIA_RULE;
0273     m_lstMedia = mediaList;
0274     if (m_lstMedia) {
0275         m_lstMedia->ref();
0276     }
0277     m_lstCSSRules = ruleList;
0278     m_lstCSSRules->ref();
0279 }
0280 
0281 CSSMediaRuleImpl::CSSMediaRuleImpl(StyleBaseImpl *parent)
0282     :   CSSRuleImpl(parent)
0283 {
0284     m_type = CSSRule::MEDIA_RULE;
0285     m_lstMedia = nullptr;
0286     m_lstCSSRules = new CSSRuleListImpl();
0287     m_lstCSSRules->ref();
0288 }
0289 
0290 CSSMediaRuleImpl::CSSMediaRuleImpl(StyleBaseImpl *parent, const DOM::DOMString &media)
0291     :   CSSRuleImpl(parent)
0292 {
0293     m_type = CSSRule::MEDIA_RULE;
0294     m_lstMedia = new MediaListImpl(this, media);
0295     m_lstMedia->ref();
0296     m_lstCSSRules = new CSSRuleListImpl();
0297     m_lstCSSRules->ref();
0298 }
0299 
0300 CSSMediaRuleImpl::~CSSMediaRuleImpl()
0301 {
0302     if (m_lstMedia) {
0303         m_lstMedia->setParent(nullptr);
0304         m_lstMedia->deref();
0305     }
0306     for (unsigned int i = 0; i < m_lstCSSRules->length(); ++i) {
0307         m_lstCSSRules->item(i)->setParent(nullptr);
0308     }
0309     m_lstCSSRules->deref();
0310 }
0311 
0312 unsigned long CSSMediaRuleImpl::append(CSSRuleImpl *rule)
0313 {
0314     return rule ? m_lstCSSRules->insertRule(rule, m_lstCSSRules->length()) : 0;
0315 }
0316 
0317 unsigned long CSSMediaRuleImpl::insertRule(const DOMString &rule,
0318         unsigned long index)
0319 {
0320     CSSParser p(strictParsing);
0321     CSSRuleImpl *newRule = p.parseRule(parentStyleSheet(), rule);
0322 
0323     return newRule ? m_lstCSSRules->insertRule(newRule, index) : 0;
0324 }
0325 
0326 DOM::DOMString CSSMediaRuleImpl::cssText() const
0327 {
0328     DOMString result("@media ");
0329     if (m_lstMedia) {
0330         result += m_lstMedia->mediaText();
0331         result += " ";
0332     }
0333     result += "{ \n";
0334 
0335     if (m_lstCSSRules) {
0336         unsigned len = m_lstCSSRules->length();
0337         for (unsigned i = 0; i < len; i++) {
0338             result += "  ";
0339             result += m_lstCSSRules->item(i)->cssText();
0340             result += "\n";
0341         }
0342     }
0343 
0344     result += "}";
0345     return result;
0346 }
0347 
0348 // ---------------------------------------------------------------------------
0349 
0350 CSSPageRuleImpl::CSSPageRuleImpl(StyleBaseImpl *parent)
0351     : CSSRuleImpl(parent)
0352 {
0353     m_type = CSSRule::PAGE_RULE;
0354     m_style = nullptr;
0355 }
0356 
0357 CSSPageRuleImpl::~CSSPageRuleImpl()
0358 {
0359     if (m_style) {
0360         m_style->deref();
0361     }
0362 }
0363 
0364 DOM::DOMString CSSPageRuleImpl::selectorText() const
0365 {
0366     // ###
0367     return DOMString();
0368 }
0369 
0370 void CSSPageRuleImpl::setSelectorText(DOM::DOMString /*str*/)
0371 {
0372     // ###
0373 }
0374 
0375 // --------------------------------------------------------------------------
0376 
0377 CSSStyleRuleImpl::CSSStyleRuleImpl(StyleBaseImpl *parent)
0378     : CSSRuleImpl(parent)
0379 {
0380     m_type = CSSRule::STYLE_RULE;
0381     m_style = nullptr;
0382     m_selector = nullptr;
0383 }
0384 
0385 CSSStyleRuleImpl::~CSSStyleRuleImpl()
0386 {
0387     if (m_style) {
0388         m_style->setParent(nullptr);
0389         m_style->deref();
0390     }
0391     qDeleteAll(*m_selector);
0392     delete m_selector;
0393 }
0394 
0395 DOMString CSSStyleRuleImpl::cssText() const
0396 {
0397     DOMString result(selectorText());
0398 
0399     result += " { ";
0400     result += m_style->cssText();
0401     result += "}";
0402 
0403     return result;
0404 }
0405 
0406 DOM::DOMString CSSStyleRuleImpl::selectorText() const
0407 {
0408     if (m_selector) {
0409         DOMString str;
0410         foreach (CSSSelector *s, *m_selector) {
0411             if (s != m_selector->at(0)) {
0412                 str += ", ";
0413             }
0414             str += s->selectorText();
0415         }
0416         return str;
0417     }
0418     return DOMString();
0419 }
0420 
0421 void CSSStyleRuleImpl::setSelectorText(DOM::DOMString /*str*/)
0422 {
0423     // ###
0424 }
0425 
0426 bool CSSStyleRuleImpl::parseString(const DOMString &/*string*/, bool)
0427 {
0428     // ###
0429     return false;
0430 }
0431 
0432 void CSSStyleRuleImpl::setDeclaration(CSSStyleDeclarationImpl *style)
0433 {
0434     if (m_style != style) {
0435         if (m_style) {
0436             m_style->deref();
0437         }
0438         m_style = style;
0439         if (m_style) {
0440             m_style->ref();
0441         }
0442     }
0443 }
0444 
0445 // --------------------------------------------------------------------
0446 
0447 CSSNamespaceRuleImpl::CSSNamespaceRuleImpl(StyleBaseImpl *parent, const DOMString &prefix, const DOMString &ns)
0448     : CSSRuleImpl(parent)
0449 {
0450     m_type      = CSSRule::NAMESPACE_RULE;
0451     m_prefix    = prefix;
0452     m_namespace = ns;
0453 }
0454 
0455 // --------------------------------------------------------------------
0456 
0457 CSSRuleListImpl::CSSRuleListImpl(StyleListImpl *const list, bool omitCharsetRules)
0458 {
0459     m_list = list;
0460     if (list && omitCharsetRules) {
0461         m_list = nullptr;
0462         unsigned len = list->length();
0463         for (unsigned i = 0; i < len; ++i) {
0464             StyleBaseImpl *rule = list->item(i);
0465             if (rule->isRule() && !rule->isCharsetRule()) {
0466                 append(static_cast<CSSRuleImpl *>(rule));
0467             }
0468         }
0469     } else if (m_list) {
0470         m_list->ref();
0471     }
0472 }
0473 
0474 CSSRuleListImpl::~CSSRuleListImpl()
0475 {
0476     CSSRuleImpl *rule;
0477     while (!m_lstCSSRules.isEmpty() && (rule = m_lstCSSRules.takeFirst())) {
0478         rule->deref();
0479     }
0480     if (m_list) {
0481         m_list->deref();
0482     }
0483 }
0484 
0485 unsigned long CSSRuleListImpl::length() const
0486 {
0487     return m_list ? m_list->length() : m_lstCSSRules.count();
0488 }
0489 
0490 CSSRuleImpl *CSSRuleListImpl::item(unsigned long index)
0491 {
0492     if (m_list) {
0493         StyleBaseImpl *rule = m_list->item(index);
0494         assert(!rule || rule->isRule());
0495         return static_cast<CSSRuleImpl *>(rule);
0496     }
0497     return index < length() ? m_lstCSSRules.at(index) : nullptr;
0498 }
0499 
0500 void CSSRuleListImpl::deleteRule(unsigned long index)
0501 {
0502     assert(!m_list);
0503     if (index + 1 > (unsigned) m_lstCSSRules.size()) {
0504         return;
0505         // ### Throw INDEX_SIZE_ERR exception here (TODO)
0506     }
0507     CSSRuleImpl *rule = m_lstCSSRules.takeAt(index);
0508     rule->deref();
0509 }
0510 
0511 void CSSRuleListImpl::append(CSSRuleImpl *rule)
0512 {
0513     assert(!m_list);
0514     rule->ref();
0515     m_lstCSSRules.append(rule);
0516 }
0517 
0518 unsigned long CSSRuleListImpl::insertRule(CSSRuleImpl *rule,
0519         unsigned long index)
0520 {
0521     assert(!m_list);
0522     if (index > (unsigned) m_lstCSSRules.size()) {
0523         return 0;
0524         // ### Throw INDEX_SIZE_ERR exception here (TODO)
0525     }
0526 
0527     if (rule) {
0528         m_lstCSSRules.insert(index, rule);
0529         rule->ref();
0530         return index;
0531     }
0532 
0533     return 0;
0534 }
0535