File indexing completed on 2024-04-28 11:37:27
0001 /** 0002 * This file is part of the DOM implementation for KDE. 0003 * 0004 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) 0005 * (C) 2004 Apple Computer, Inc. 0006 * (C) 2008 Germain Garand <germain@ebooksfrance.org> 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 0025 //#define CSS_STYLESHEET_DEBUG 0026 0027 #include "css_stylesheetimpl.h" 0028 #include "css_ruleimpl.h" 0029 #include "css_valueimpl.h" 0030 #include "cssparser.h" 0031 #include "css_mediaquery.h" 0032 0033 #include <dom/dom_string.h> 0034 #include <dom/dom_exception.h> 0035 #include <dom/css_stylesheet.h> 0036 #include <dom/css_rule.h> 0037 #include <dom/dom_exception.h> 0038 0039 #include <xml/dom_nodeimpl.h> 0040 #include <html/html_documentimpl.h> 0041 #include <misc/loader.h> 0042 0043 #include "khtml_debug.h" 0044 0045 using namespace DOM; 0046 using namespace khtml; 0047 // -------------------------------------------------------------------------------- 0048 0049 StyleSheetImpl::StyleSheetImpl(StyleSheetImpl *parentSheet, DOMString href) 0050 : StyleListImpl(parentSheet) 0051 { 0052 m_disabled = false; 0053 m_media = nullptr; 0054 m_parentNode = nullptr; 0055 m_strHref = href; 0056 } 0057 0058 StyleSheetImpl::StyleSheetImpl(DOM::NodeImpl *parentNode, DOMString href) 0059 : StyleListImpl() 0060 { 0061 m_parentNode = parentNode; 0062 m_disabled = false; 0063 m_media = nullptr; 0064 m_strHref = href; 0065 } 0066 0067 StyleSheetImpl::StyleSheetImpl(StyleBaseImpl *owner, DOMString href) 0068 : StyleListImpl(owner) 0069 { 0070 m_disabled = false; 0071 m_media = nullptr; 0072 m_parentNode = nullptr; 0073 m_strHref = href; 0074 } 0075 0076 StyleSheetImpl::~StyleSheetImpl() 0077 { 0078 if (m_media) { 0079 m_media->setParent(nullptr); 0080 m_media->deref(); 0081 } 0082 } 0083 0084 StyleSheetImpl *StyleSheetImpl::parentStyleSheet() const 0085 { 0086 if (!m_parent) { 0087 return nullptr; 0088 } 0089 if (m_parent->isStyleSheet()) { 0090 return static_cast<StyleSheetImpl *>(m_parent); 0091 } 0092 if (m_parent->isRule()) { 0093 return m_parent->stylesheet(); 0094 } 0095 return nullptr; 0096 } 0097 0098 void StyleSheetImpl::setMedia(MediaListImpl *media) 0099 { 0100 if (media) { 0101 media->ref(); 0102 } 0103 if (m_media) { 0104 m_media->setParent(nullptr); 0105 m_media->deref(); 0106 } 0107 m_media = media; 0108 if (m_media) { 0109 m_media->setParent(this); 0110 } 0111 } 0112 0113 void StyleSheetImpl::setDisabled(bool disabled) 0114 { 0115 bool updateStyle = isCSSStyleSheet() && m_parentNode && disabled != m_disabled; 0116 m_disabled = disabled; 0117 if (updateStyle) { 0118 m_parentNode->document()->updateStyleSelector(); 0119 } 0120 } 0121 0122 // ----------------------------------------------------------------------- 0123 0124 CSSStyleSheetImpl::CSSStyleSheetImpl(CSSStyleSheetImpl *parentSheet, DOMString href) 0125 : StyleSheetImpl(parentSheet, href) 0126 { 0127 m_lstChildren = new QList<StyleBaseImpl *>; 0128 m_doc = parentSheet ? parentSheet->doc() : nullptr; 0129 m_implicit = false; 0130 m_namespaces = nullptr; 0131 m_defaultNamespace = NamespaceName::fromId(anyNamespace); 0132 m_loadedHint = false; 0133 } 0134 0135 CSSStyleSheetImpl::CSSStyleSheetImpl(DOM::NodeImpl *parentNode, DOMString href, bool _implicit) 0136 : StyleSheetImpl(parentNode, href) 0137 { 0138 m_lstChildren = new QList<StyleBaseImpl *>; 0139 m_doc = parentNode->document(); 0140 m_implicit = _implicit; 0141 m_namespaces = nullptr; 0142 m_defaultNamespace = NamespaceName::fromId(anyNamespace); 0143 m_loadedHint = false; 0144 } 0145 0146 CSSStyleSheetImpl::CSSStyleSheetImpl(CSSRuleImpl *ownerRule, DOMString href) 0147 : StyleSheetImpl(ownerRule, href) 0148 { 0149 m_lstChildren = new QList<StyleBaseImpl *>; 0150 m_doc = static_cast<CSSStyleSheetImpl *>(ownerRule->stylesheet())->doc(); 0151 m_implicit = false; 0152 m_namespaces = nullptr; 0153 m_defaultNamespace = NamespaceName::fromId(anyNamespace); 0154 m_loadedHint = false; 0155 } 0156 0157 CSSStyleSheetImpl::CSSStyleSheetImpl(DOM::NodeImpl *parentNode, CSSStyleSheetImpl *orig) 0158 : StyleSheetImpl(parentNode, orig->m_strHref) 0159 { 0160 m_lstChildren = new QList<StyleBaseImpl *>; 0161 StyleBaseImpl *rule; 0162 QListIterator<StyleBaseImpl *> it(*orig->m_lstChildren); 0163 while (it.hasNext()) { 0164 rule = it.next(); 0165 m_lstChildren->append(rule); 0166 rule->setParent(this); 0167 } 0168 m_doc = parentNode->document(); 0169 m_implicit = false; 0170 m_namespaces = nullptr; 0171 m_defaultNamespace = NamespaceName::fromId(anyNamespace); 0172 m_loadedHint = false; 0173 0174 recomputeNamespaceInfo(); // as we cloned kids 0175 } 0176 0177 CSSStyleSheetImpl::CSSStyleSheetImpl(CSSRuleImpl *ownerRule, CSSStyleSheetImpl *orig) 0178 : StyleSheetImpl(ownerRule, orig->m_strHref) 0179 { 0180 // m_lstChildren is deleted in StyleListImpl 0181 m_lstChildren = new QList<StyleBaseImpl *>; 0182 StyleBaseImpl *rule; 0183 QListIterator<StyleBaseImpl *> it(*orig->m_lstChildren); 0184 while (it.hasNext()) { 0185 rule = it.next(); 0186 m_lstChildren->append(rule); 0187 rule->setParent(this); 0188 } 0189 m_doc = static_cast<CSSStyleSheetImpl *>(ownerRule->stylesheet())->doc(); 0190 m_implicit = false; 0191 m_namespaces = nullptr; 0192 m_defaultNamespace = NamespaceName::fromId(anyNamespace); 0193 m_loadedHint = false; 0194 0195 recomputeNamespaceInfo(); // as we cloned kids 0196 } 0197 0198 CSSRuleImpl *CSSStyleSheetImpl::ownerRule() const 0199 { 0200 if (!m_parent) { 0201 return nullptr; 0202 } 0203 if (m_parent->isRule()) { 0204 return static_cast<CSSRuleImpl *>(m_parent); 0205 } 0206 return nullptr; 0207 } 0208 0209 unsigned long CSSStyleSheetImpl::insertRule(const DOMString &rule, unsigned long index, int &exceptioncode) 0210 { 0211 exceptioncode = 0; 0212 if (index > (unsigned) m_lstChildren->count()) { 0213 exceptioncode = DOMException::INDEX_SIZE_ERR; 0214 return 0; 0215 } 0216 CSSParser p(strictParsing); 0217 CSSRuleImpl *r = p.parseRule(this, rule); 0218 0219 if (!r) { 0220 exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET; 0221 return 0; 0222 } 0223 // ### 0224 // HIERARCHY_REQUEST_ERR: Raised if the rule cannot be inserted at the specified index e.g. if an 0225 //@import rule is inserted after a standard rule set or other at-rule. 0226 m_lstChildren->insert(index, r); 0227 if (m_doc) { 0228 m_doc->updateStyleSelector(true /*shallow*/); 0229 } 0230 0231 if (r->type() == DOM::CSSRule::NAMESPACE_RULE) { 0232 dirtyNamespaceInfo(); 0233 if (static_cast<CSSNamespaceRuleImpl *>(r)->isDefault()) { 0234 recomputeNamespaceInfo(); // default may have changed 0235 } 0236 // ### too late for some rules? 0237 } 0238 0239 return index; 0240 } 0241 0242 void CSSStyleSheetImpl::appendNamespaceRule(CSSNamespaceRuleImpl *ns) 0243 { 0244 append(ns); 0245 dirtyNamespaceInfo(); 0246 if (ns->isDefault()) { 0247 recomputeNamespaceInfo(); 0248 } 0249 } 0250 0251 CSSRuleListImpl *CSSStyleSheetImpl::cssRules(bool omitCharsetRules) 0252 { 0253 return new CSSRuleListImpl(this, omitCharsetRules); 0254 } 0255 0256 void CSSStyleSheetImpl::deleteRule(unsigned long index, int &exceptioncode) 0257 { 0258 exceptioncode = 0; 0259 if (index + 1 > (unsigned) m_lstChildren->count()) { 0260 exceptioncode = DOMException::INDEX_SIZE_ERR; 0261 return; 0262 } 0263 StyleBaseImpl *b = m_lstChildren->takeAt(index); 0264 0265 if (b->isRule() && static_cast<CSSRuleImpl *>(b)->type() == DOM::CSSRule::NAMESPACE_RULE) { 0266 dirtyNamespaceInfo(); 0267 if (static_cast<CSSNamespaceRuleImpl *>(b)->isDefault()) { 0268 recomputeNamespaceInfo(); // default may have changed 0269 } 0270 // ### too late for some rules? 0271 } 0272 0273 // TreeShared requires delete not deref when removed from tree 0274 b->setParent(nullptr); 0275 if (!b->refCount()) { 0276 delete b; 0277 } 0278 if (m_doc) { 0279 m_doc->updateStyleSelector(true /*shallow*/); 0280 } 0281 } 0282 0283 void CSSStyleSheetImpl::recomputeNamespaceInfo() 0284 { 0285 assert(!m_namespaces); 0286 0287 m_namespaces = new QList<CSSNamespaceRuleImpl *>; 0288 m_defaultNamespace = NamespaceName::fromId(anyNamespace); 0289 0290 // Compute list of all the @namespace nodes, as well as the default one. 0291 for (int i = 0; i < m_lstChildren->count(); ++i) { 0292 StyleBaseImpl *b = m_lstChildren->at(i); 0293 if (b->isRule() && static_cast<CSSRuleImpl *>(b)->type() == DOM::CSSRule::NAMESPACE_RULE) { 0294 CSSNamespaceRuleImpl *nr = static_cast<CSSNamespaceRuleImpl *>(b); 0295 DOM::DOMString prefix = nr->prefix(); 0296 DOM::DOMString uri = nr->namespaceURI(); 0297 0298 if (uri.isNull()) { 0299 continue; 0300 } 0301 0302 if (nr->isDefault()) { 0303 m_defaultNamespace = NamespaceName::fromString(uri); 0304 } 0305 0306 m_namespaces->append(nr); 0307 } 0308 } 0309 } 0310 0311 void CSSStyleSheetImpl::determineNamespace(NamespaceName &namespacename, const DOM::DOMString &prefix) 0312 { 0313 if (prefix.isEmpty()) { 0314 namespacename = NamespaceName::fromId(emptyNamespace); // No namespace. If an element/attribute has a namespace, we won't match it. 0315 } else if (prefix == "*") { 0316 namespacename = NamespaceName::fromId(anyNamespace); // We'll match any namespace. 0317 } else { 0318 if (!m_namespaces) { 0319 recomputeNamespaceInfo(); 0320 } 0321 0322 // To lookup the name, we go backwards, so the latest one wins 0323 for (int p = m_namespaces->count() - 1; p >= 0; --p) { 0324 CSSNamespaceRuleImpl *ns = m_namespaces->at(p); 0325 if (ns->prefix() == prefix) { 0326 namespacename = NamespaceName::fromString(ns->namespaceURI()); 0327 return; 0328 } 0329 } 0330 } 0331 } 0332 0333 bool CSSStyleSheetImpl::parseString(const DOMString &string, bool strict) 0334 { 0335 #ifdef CSS_STYLESHEET_DEBUG 0336 qCDebug(KHTML_LOG) << "parsing sheet, len=" << string.length() << ", sheet is " << string.string(); 0337 #endif 0338 0339 strictParsing = strict; 0340 CSSParser p(strict); 0341 p.parseSheet(this, string); 0342 return true; 0343 } 0344 0345 bool CSSStyleSheetImpl::isLoading() const 0346 { 0347 StyleBaseImpl *rule; 0348 QListIterator<StyleBaseImpl *> it(*m_lstChildren); 0349 while (it.hasNext()) { 0350 rule = it.next(); 0351 if (rule->isImportRule()) { 0352 CSSImportRuleImpl *import = static_cast<CSSImportRuleImpl *>(rule); 0353 #ifdef CSS_STYLESHEET_DEBUG 0354 qCDebug(KHTML_LOG) << "found import"; 0355 #endif 0356 if (import->isLoading()) { 0357 #ifdef CSS_STYLESHEET_DEBUG 0358 qCDebug(KHTML_LOG) << "--> not loaded"; 0359 #endif 0360 m_loadedHint = false; 0361 return true; 0362 } 0363 } 0364 } 0365 m_loadedHint = true; 0366 return false; 0367 } 0368 0369 void CSSStyleSheetImpl::checkLoaded() const 0370 { 0371 if (isLoading()) { 0372 return; 0373 } 0374 if (m_parent) { 0375 m_parent->checkLoaded(); 0376 } 0377 if (m_parentNode) { 0378 m_loadedHint = m_parentNode->checkRemovePendingSheet(); 0379 } else if (parentStyleSheet() && parentStyleSheet()->isCSSStyleSheet()) { 0380 m_loadedHint = static_cast<CSSStyleSheetImpl *>(parentStyleSheet())->loadedHint(); 0381 } else { 0382 m_loadedHint = true; 0383 } 0384 } 0385 0386 void CSSStyleSheetImpl::checkPending() const 0387 { 0388 if (!m_loadedHint) { 0389 return; 0390 } 0391 if (m_parent) { 0392 m_parent->checkPending(); 0393 } else if (m_parentNode) { 0394 m_parentNode->checkAddPendingSheet(); 0395 } 0396 } 0397 0398 // --------------------------------------------------------------------------- 0399 0400 StyleSheetListImpl::~StyleSheetListImpl() 0401 { 0402 foreach (StyleSheetImpl *sh, styleSheets) { 0403 sh->deref(); 0404 } 0405 } 0406 0407 void StyleSheetListImpl::add(StyleSheetImpl *s) 0408 { 0409 if (managerDocument) { 0410 managerDocument->ensureStyleSheetListUpToDate(); 0411 } 0412 0413 // ### in cases this is document.styleSheets, maybe 0414 // we should route to DocumentImpl::addStyleSheets? 0415 0416 if (!styleSheets.contains(s)) { 0417 s->ref(); 0418 styleSheets.append(s); 0419 } 0420 } 0421 0422 void StyleSheetListImpl::remove(StyleSheetImpl *s) 0423 { 0424 if (managerDocument) { 0425 managerDocument->ensureStyleSheetListUpToDate(); 0426 } 0427 0428 if (styleSheets.removeAll(s)) { 0429 s->deref(); 0430 } 0431 } 0432 0433 unsigned long StyleSheetListImpl::length() const 0434 { 0435 if (managerDocument) { 0436 managerDocument->ensureStyleSheetListUpToDate(); 0437 } 0438 0439 // hack so implicit BODY stylesheets don't get counted here 0440 unsigned long l = 0; 0441 foreach (StyleSheetImpl *sh, styleSheets) { 0442 if (!sh->isCSSStyleSheet() || !static_cast<CSSStyleSheetImpl *>(sh)->implicit()) { 0443 ++l; 0444 } 0445 } 0446 return l; 0447 } 0448 0449 StyleSheetImpl *StyleSheetListImpl::item(unsigned long index) 0450 { 0451 if (managerDocument) { 0452 managerDocument->ensureStyleSheetListUpToDate(); 0453 } 0454 0455 unsigned long l = 0; 0456 foreach (StyleSheetImpl *sh, styleSheets) { 0457 if (!sh->isCSSStyleSheet() || !static_cast<CSSStyleSheetImpl *>(sh)->implicit()) { 0458 if (l == index) { 0459 return sh; 0460 } 0461 ++l; 0462 } 0463 } 0464 return nullptr; 0465 } 0466 0467 // -------------------------------------------------------------------------------------------- 0468 0469 /* MediaList is used to store 3 types of media related entities which mean the same: 0470 * Media Queries, Media Types and Media Descriptors. 0471 * Currently MediaList always tries to parse media queries and if parsing fails, 0472 * tries to fallback to Media Descriptors if m_fallback flag is set. 0473 * Slight problem with syntax error handling: 0474 * CSS 2.1 Spec (https://www.w3.org/TR/CSS21/media.html) 0475 * specifies that failing media type parsing is a syntax error 0476 * CSS 3 Media Queries Spec (https://www.w3.org/TR/css3-mediaqueries/) 0477 * specifies that failing media query is a syntax error 0478 * HTML 4.01 spec (https://www.w3.org/TR/REC-html40/present/styles.html#adef-media) 0479 * specifies that Media Descriptors should be parsed with forward-compatible syntax 0480 * DOM Level 2 Style Sheet spec (https://www.w3.org/TR/DOM-Level-2-Style/) 0481 * talks about MediaList.mediaText and refers 0482 * - to Media Descriptors of HTML 4.0 in context of StyleSheet 0483 * - to Media Types of CSS 2.0 in context of CSSMediaRule and CSSImportRule 0484 * 0485 * These facts create situation where same (illegal) media specification may result in 0486 * different parses depending on whether it is media attr of style element or part of 0487 * css @media rule. 0488 * <style media="screen and resolution > 40dpi"> ..</style> will be enabled on screen devices where as 0489 * @media screen and resolution > 40dpi {..} will not. 0490 * This gets more counter-intuitive in JavaScript: 0491 * document.styleSheets[0].media.mediaText = "screen and resolution > 40dpi" will be ok and 0492 * enabled, while 0493 * document.styleSheets[0].cssRules[0].media.mediaText = "screen and resolution > 40dpi" will 0494 * throw SYNTAX_ERR exception. 0495 */ 0496 0497 MediaListImpl::MediaListImpl(CSSStyleSheetImpl *parentSheet, 0498 const DOMString &media, bool fallbackToDescriptor) 0499 : StyleBaseImpl(parentSheet) 0500 , m_fallback(fallbackToDescriptor) 0501 { 0502 int ec = 0; 0503 setMediaText(media, ec); 0504 // FIXME: parsing can fail. The problem with failing constructor is that 0505 // we would need additional flag saying MediaList is not valid 0506 // Parse can fail only when fallbackToDescriptor == false, i.e when HTML4 media descriptor 0507 // forward-compatible syntax is not in use. 0508 // DOMImplementationCSS seems to mandate that media descriptors are used 0509 // for both html and svg, even though svg:style doesn't use media descriptors 0510 // Currently the only places where parsing can fail are 0511 // creating <svg:style>, creating css media / import rules from js 0512 if (ec) { 0513 setMediaText("invalid", ec); 0514 } 0515 } 0516 0517 MediaListImpl::MediaListImpl(CSSRuleImpl *parentRule, const DOMString &media, bool fallbackToDescriptor) 0518 : StyleBaseImpl(parentRule) 0519 , m_fallback(fallbackToDescriptor) 0520 { 0521 int ec = 0; 0522 setMediaText(media, ec); 0523 // FIXME: parsing can fail. The problem with failing constructor is that 0524 // we would need additional flag saying MediaList is not valid 0525 // Parse can fail only when fallbackToDescriptor == false, i.e when HTML4 media descriptor 0526 // forward-compatible syntax is not in use. 0527 // DOMImplementationCSS seems to mandate that media descriptors are used 0528 // for both html and svg, even though svg:style doesn't use media descriptors 0529 // Currently the only places where parsing can fail are 0530 // creating <svg:style>, creating css media / import rules from js 0531 if (ec) { 0532 setMediaText("invalid", ec); 0533 } 0534 } 0535 0536 MediaListImpl::~MediaListImpl() 0537 { 0538 qDeleteAll(m_queries); 0539 } 0540 0541 CSSStyleSheetImpl *MediaListImpl::parentStyleSheet() const 0542 { 0543 if (m_parent->isCSSStyleSheet()) { 0544 return static_cast<CSSStyleSheetImpl *>(m_parent); 0545 } 0546 return nullptr; 0547 } 0548 0549 CSSRuleImpl *MediaListImpl::parentRule() const 0550 { 0551 if (m_parent->isRule()) { 0552 return static_cast<CSSRuleImpl *>(m_parent); 0553 } 0554 return nullptr; 0555 } 0556 0557 static DOMString parseMediaDescriptor(const DOMString &s) 0558 { 0559 int len = s.length(); 0560 0561 // https://www.w3.org/TR/REC-html40/types.html#type-media-descriptors 0562 // "Each entry is truncated just before the first character that isn't a 0563 // US ASCII letter [a-zA-Z] (ISO 10646 hex 41-5a, 61-7a), digit [0-9] (hex 30-39), 0564 // or hyphen (hex 2d)." 0565 int i; 0566 unsigned short c; 0567 for (i = 0; i < len; ++i) { 0568 c = s[i].unicode(); 0569 if (!((c >= 'a' && c <= 'z') 0570 || (c >= 'A' && c <= 'Z') 0571 || (c >= '1' && c <= '9') 0572 || (c == '-'))) { 0573 break; 0574 } 0575 } 0576 return s.implementation()->substring(0, i); 0577 } 0578 0579 void MediaListImpl::deleteMedium(const DOMString &oldMedium, int &ec) 0580 { 0581 MediaListImpl tempMediaList; 0582 CSSParser p(true); 0583 0584 MediaQuery *oldQuery = nullptr; 0585 bool deleteOldQuery = false; 0586 0587 if (p.parseMediaQuery(&tempMediaList, oldMedium)) { 0588 if (tempMediaList.m_queries.size() > 0) { 0589 oldQuery = tempMediaList.m_queries[0]; 0590 } 0591 } else if (m_fallback) { 0592 DOMString medium = parseMediaDescriptor(oldMedium); 0593 if (!medium.isNull()) { 0594 oldQuery = new MediaQuery(MediaQuery::None, medium, nullptr); 0595 deleteOldQuery = true; 0596 } 0597 } 0598 0599 // DOM Style Sheets spec doesn't allow SYNTAX_ERR to be thrown in deleteMedium 0600 ec = DOMException::NOT_FOUND_ERR; 0601 0602 if (oldQuery) { 0603 for (int i = 0; i < m_queries.size(); ++i) { 0604 MediaQuery *a = m_queries[i]; 0605 if (*a == *oldQuery) { 0606 m_queries.removeAt(i); 0607 delete a; 0608 ec = 0; 0609 break; 0610 } 0611 } 0612 if (deleteOldQuery) { 0613 delete oldQuery; 0614 } 0615 } 0616 } 0617 0618 DOM::DOMString MediaListImpl::mediaText() const 0619 { 0620 DOMString text; 0621 bool first = true; 0622 const QList<MediaQuery *>::ConstIterator itEnd = m_queries.end(); 0623 0624 for (QList<MediaQuery *>::ConstIterator it = m_queries.begin(); it != itEnd; ++it) { 0625 if (!first) { 0626 text += ", "; 0627 } 0628 text += (*it)->cssText(); 0629 first = false; 0630 } 0631 return text; 0632 } 0633 0634 void MediaListImpl::setMediaText(const DOM::DOMString &value, int &ec) 0635 { 0636 MediaListImpl tempMediaList; 0637 CSSParser p(true); 0638 0639 const QString val = value.string(); 0640 const QStringList list = val.split(','); 0641 0642 const QStringList::ConstIterator itEnd = list.end(); 0643 0644 for (QStringList::ConstIterator it = list.begin(); it != itEnd; ++it) { 0645 const DOMString medium = (*it).trimmed(); 0646 if (!medium.isEmpty()) { 0647 if (!p.parseMediaQuery(&tempMediaList, medium)) { 0648 if (m_fallback) { 0649 DOMString mediaDescriptor = parseMediaDescriptor(medium); 0650 if (!mediaDescriptor.isNull()) { 0651 tempMediaList.m_queries.append(new MediaQuery(MediaQuery::None, mediaDescriptor, nullptr)); 0652 } 0653 } else { 0654 ec = CSSException::SYNTAX_ERR; 0655 return; 0656 } 0657 } 0658 } else if (!m_fallback) { 0659 ec = CSSException::SYNTAX_ERR; 0660 return; 0661 } 0662 } 0663 // ",,,," falls straight through, but is not valid unless fallback 0664 if (!m_fallback && list.begin() == list.end()) { 0665 DOMString s = value.string().trimmed(); 0666 if (!s.isEmpty()) { 0667 ec = CSSException::SYNTAX_ERR; 0668 return; 0669 } 0670 } 0671 0672 ec = 0; 0673 qDeleteAll(m_queries); 0674 m_queries = tempMediaList.m_queries; 0675 tempMediaList.m_queries.clear(); 0676 } 0677 0678 DOMString MediaListImpl::item(unsigned long index) const 0679 { 0680 if (index < (unsigned)m_queries.size()) { 0681 MediaQuery *query = m_queries[index]; 0682 return query->cssText(); 0683 } 0684 0685 return DOMString(); 0686 } 0687 0688 void MediaListImpl::appendMedium(const DOMString &newMedium, int &ec) 0689 { 0690 ec = DOMException::INVALID_CHARACTER_ERR; 0691 CSSParser p(true); 0692 if (p.parseMediaQuery(this, newMedium)) { 0693 ec = 0; 0694 } else if (m_fallback) { 0695 DOMString medium = parseMediaDescriptor(newMedium); 0696 if (!medium.isNull()) { 0697 m_queries.append(new MediaQuery(MediaQuery::None, medium, nullptr)); 0698 ec = 0; 0699 } 0700 } 0701 } 0702 0703 void MediaListImpl::appendMediaQuery(MediaQuery *mediaQuery) 0704 { 0705 m_queries.append(mediaQuery); 0706 } 0707