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