File indexing completed on 2024-05-05 16:10:12
0001 /** 0002 * This file is part of the DOM implementation for KDE. 0003 * 0004 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 0005 * (C) 1999 Antti Koivisto (koivisto@kde.org) 0006 * (C) 2001 Dirk Mueller (mueller@kde.org) 0007 * (C) 2003, 2004, 2005, 2006, 2007 Apple Computer, Inc. 0008 * 0009 * This library is free software; you can redistribute it and/or 0010 * modify it under the terms of the GNU Library General Public 0011 * License as published by the Free Software Foundation; either 0012 * version 2 of the License, or (at your option) any later version. 0013 * 0014 * This library is distributed in the hope that it will be useful, 0015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 * Library General Public License for more details. 0018 * 0019 * You should have received a copy of the GNU Library General Public License 0020 * along with this library; see the file COPYING.LIB. If not, write to 0021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0022 * Boston, MA 02110-1301, USA. 0023 */ 0024 // ------------------------------------------------------------------------- 0025 0026 #include "html/html_headimpl.h" 0027 #include "html/html_documentimpl.h" 0028 #include "xml/dom_textimpl.h" 0029 #include "xml/dom2_eventsimpl.h" 0030 0031 #include "khtmlview.h" 0032 #include "khtml_part.h" 0033 0034 #include "misc/loader.h" 0035 0036 #include "css/cssstyleselector.h" 0037 #include "css/css_mediaquery.h" 0038 0039 #include "ecma/kjs_proxy.h" 0040 0041 #include <QUrl> 0042 #include "khtml_debug.h" 0043 0044 using namespace khtml; 0045 using namespace DOM; 0046 0047 NodeImpl::Id HTMLBaseElementImpl::id() const 0048 { 0049 return ID_BASE; 0050 } 0051 0052 void HTMLBaseElementImpl::parseAttribute(AttributeImpl *attr) 0053 { 0054 switch (attr->id()) { 0055 case ATTR_HREF: 0056 m_href = attr->value().trimSpaces().string(); 0057 process(); 0058 break; 0059 case ATTR_TARGET: 0060 m_target = attr->value(); 0061 process(); 0062 break; 0063 default: 0064 HTMLElementImpl::parseAttribute(attr); 0065 } 0066 } 0067 0068 void HTMLBaseElementImpl::insertedIntoDocument() 0069 { 0070 HTMLElementImpl::insertedIntoDocument(); 0071 process(); 0072 } 0073 0074 void HTMLBaseElementImpl::removedFromDocument() 0075 { 0076 HTMLElementImpl::removedFromDocument(); 0077 0078 // Since the document doesn't have a base element... 0079 // (This will break in the case of multiple base elements, but that's not valid anyway (?)) 0080 document()->setBaseURL(QUrl()); 0081 document()->setBaseTarget(QString()); 0082 } 0083 0084 void HTMLBaseElementImpl::process() 0085 { 0086 if (!inDocument()) { 0087 return; 0088 } 0089 0090 if (!m_href.isEmpty() && document()->part()) { 0091 document()->setBaseURL(QUrl(document()->part()->url()).resolved(QUrl(m_href))); 0092 } 0093 0094 if (!m_target.isEmpty()) { 0095 document()->setBaseTarget(m_target.string()); 0096 } 0097 0098 // ### should changing a document's base URL dynamically automatically update all images, stylesheets etc? 0099 } 0100 0101 // ------------------------------------------------------------------------- 0102 0103 HTMLLinkElementImpl::~HTMLLinkElementImpl() 0104 { 0105 if (m_sheet) { 0106 m_sheet->deref(); 0107 } 0108 if (m_cachedSheet) { 0109 m_cachedSheet->deref(this); 0110 } 0111 } 0112 0113 NodeImpl::Id HTMLLinkElementImpl::id() const 0114 { 0115 return ID_LINK; 0116 } 0117 0118 void HTMLLinkElementImpl::parseAttribute(AttributeImpl *attr) 0119 { 0120 switch (attr->id()) { 0121 case ATTR_HREF: { 0122 const DOMString hrefUrl = attr->value().trimSpaces(); 0123 if (!hrefUrl.isEmpty()) { 0124 m_url = document()->completeURL(hrefUrl.string()); 0125 } 0126 process(); 0127 break; 0128 } 0129 case ATTR_REL: 0130 case ATTR_TYPE: 0131 process(); 0132 break; 0133 case ATTR_TITLE: 0134 // ### when title changes we have to reconsider our alternative 0135 // stylesheet choice 0136 if (m_sheet) { 0137 m_sheet->setTitle(attr->value()); 0138 } 0139 break; 0140 case ATTR_MEDIA: 0141 m_media = attr->value().string().toLower(); 0142 process(); 0143 break; 0144 case ATTR_DISABLED: { 0145 bool m_oldisDisabled = m_isDisabled; 0146 m_isDisabled = attr->val(); 0147 if (m_oldisDisabled != m_isDisabled) { 0148 if (isLoading()) { 0149 if (m_oldisDisabled) { 0150 document()->addPendingSheet(); 0151 } else if (!m_alternate) { 0152 document()->styleSheetLoaded(); 0153 } 0154 } 0155 if (m_oldisDisabled) { 0156 // enabling: if it's an alternate sheet, pretend it's not. 0157 m_alternate = false; 0158 } else if (!m_alternate) { 0159 // disabling: recheck alternate status 0160 QString rel = getAttribute(ATTR_REL).string().toLower(); 0161 QString type = getAttribute(ATTR_TYPE).string().toLower(); 0162 m_alternate = (type.contains("text/css") || rel.contains("stylesheet")) && rel.contains("alternate"); 0163 } 0164 if (isLoading()) { 0165 break; 0166 } 0167 if (!m_sheet && !m_isDisabled) { 0168 process(); 0169 if (isLoading() && m_alternate) { 0170 document()->addPendingSheet(); 0171 } 0172 m_alternate = false; 0173 } else { 0174 document()->updateStyleSelector(); // Update the style selector. 0175 } 0176 } 0177 break; 0178 } 0179 default: 0180 HTMLElementImpl::parseAttribute(attr); 0181 } 0182 } 0183 0184 static inline bool isIconLink(const QString &relAttribute) 0185 { 0186 // https://www.w3.org/TR/html5/links.html#linkTypes: 0187 // split rel attribute on spaces and search for "icon" keyword. 0188 // note: relAttribute is supposed to be a lower case string 0189 const QLatin1String icon("icon"); 0190 int iconPos = relAttribute.indexOf(icon); 0191 while (iconPos != -1) { 0192 const bool found = (iconPos == 0 || relAttribute.at(iconPos - 1).isSpace()) && 0193 (((iconPos + 4) == relAttribute.length()) || relAttribute.at(iconPos + 4).isSpace()); 0194 if (found) { 0195 return true; 0196 } 0197 iconPos = relAttribute.indexOf(icon, iconPos + 5); 0198 } 0199 0200 return false; 0201 } 0202 0203 void HTMLLinkElementImpl::process() 0204 { 0205 if (!inDocument()) { 0206 return; 0207 } 0208 0209 //QString type = getAttribute(ATTR_TYPE).string().toLower(); 0210 const QString rel = getAttribute(ATTR_REL).string().toLower(); 0211 0212 KHTMLPart *part = document()->part(); 0213 0214 // Location of small icon for locationbar / bookmarks (aka "favicon") 0215 if (isIconLink(rel) && !m_url.isEmpty() && part && !part->parentPart()) { 0216 part->browserExtension()->setIconUrl(QUrl(m_url.string())); 0217 } // Stylesheet 0218 else if (rel.contains("stylesheet") && !m_url.isEmpty() && !m_isDisabled) { 0219 // no need to load style sheets which aren't for the screen output 0220 // ### there may be in some situations e.g. for an editor or script to manipulate 0221 khtml::MediaQueryEvaluator allEval(true); 0222 khtml::MediaQueryEvaluator screenEval("screen", true); 0223 khtml::MediaQueryEvaluator printEval("print", true); 0224 MediaListImpl *media = new MediaListImpl((CSSStyleSheetImpl *)nullptr, m_media, true); 0225 media->ref(); 0226 if (allEval.eval(media) || screenEval.eval(media) || printEval.eval(media)) { 0227 // Add ourselves as a pending sheet, but only if we aren't an alternate 0228 // stylesheet. Alternate stylesheets don't hold up render tree construction. 0229 m_alternate = rel.contains("alternate"); 0230 if (!isAlternate()) { 0231 document()->addPendingSheet(); 0232 } 0233 0234 QString chset = getAttribute(ATTR_CHARSET).string(); 0235 // set chset to charset of referring document when attribute CHARSET is absent. 0236 // https://www.w3.org/TR/CSS21/syndata.html(4.4) 0237 if (chset.isEmpty() && part) { 0238 chset = part->encoding(); 0239 } 0240 if (m_cachedSheet) { 0241 if (m_loading) { 0242 document()->styleSheetLoaded(); 0243 } 0244 m_cachedSheet->deref(this); 0245 } 0246 m_loading = true; 0247 m_cachedSheet = document()->docLoader()->requestStyleSheet(m_url, chset); 0248 if (m_cachedSheet) { 0249 m_isCSSSheet = true; 0250 m_cachedSheet->ref(this); 0251 } else if (!isAlternate()) { 0252 // Error requesting sheet; decrement pending sheet count 0253 m_loading = false; 0254 document()->styleSheetLoaded(); 0255 } 0256 } 0257 media->deref(); 0258 } else if (m_sheet) { 0259 // we no longer contain a stylesheet, e.g. perhaps rel or type was changed 0260 m_sheet->deref(); 0261 m_sheet = nullptr; 0262 m_isCSSSheet = false; 0263 document()->updateStyleSelector(); 0264 } 0265 } 0266 0267 void HTMLLinkElementImpl::insertedIntoDocument() 0268 { 0269 HTMLElementImpl::insertedIntoDocument(); 0270 process(); 0271 } 0272 0273 void HTMLLinkElementImpl::removedFromDocument() 0274 { 0275 HTMLElementImpl::removedFromDocument(); 0276 document()->updateStyleSelector(); 0277 } 0278 0279 void HTMLLinkElementImpl::setStyleSheet(const DOM::DOMString &url, const DOM::DOMString &sheetStr, const DOM::DOMString &charset, const DOM::DOMString &mimetype) 0280 { 0281 if (m_sheet) { 0282 m_sheet->deref(); 0283 } 0284 bool strict = !document()->inCompatMode(); 0285 DOMString sheet = sheetStr; 0286 if (strict && !khtml::isAcceptableCSSMimetype(mimetype)) { 0287 sheet = ""; 0288 } 0289 m_sheet = new CSSStyleSheetImpl(this, url); 0290 m_sheet->ref(); 0291 m_sheet->setCharset(charset); 0292 m_sheet->parseString(sheet, strict); 0293 m_sheet->setTitle(getAttribute(ATTR_TITLE)); 0294 0295 MediaListImpl *media = new MediaListImpl((CSSStyleSheetImpl *)nullptr, m_media); 0296 m_sheet->setMedia(media); 0297 0298 finished(); 0299 } 0300 0301 void HTMLLinkElementImpl::finished() 0302 { 0303 m_loading = false; 0304 0305 // Tell the doc about the sheet. 0306 if (!isLoading() && !isDisabled() && !isAlternate()) { 0307 document()->styleSheetLoaded(); 0308 } 0309 0310 // ### major inefficiency, but currently necessary for proper 0311 // alternate styles support. don't recalc the styleselector 0312 // when nothing actually changed! 0313 if (isAlternate() && m_sheet && !isDisabled()) { 0314 document()->updateStyleSelector(); 0315 } 0316 } 0317 0318 void HTMLLinkElementImpl::error(int, const QString &) 0319 { 0320 finished(); 0321 } 0322 0323 bool HTMLLinkElementImpl::isLoading() const 0324 { 0325 // qCDebug(KHTML_LOG) << "link: checking if loading!"; 0326 if (m_loading) { 0327 return true; 0328 } 0329 if (!m_sheet) { 0330 return false; 0331 } 0332 //if(!m_sheet->isCSSStyleSheet()) return false; 0333 return static_cast<CSSStyleSheetImpl *>(m_sheet)->isLoading(); 0334 } 0335 0336 bool HTMLLinkElementImpl::checkAddPendingSheet() 0337 { 0338 if (!isLoading() && !isDisabled() && !isAlternate()) { 0339 document()->addPendingSheet(); 0340 return true; 0341 } 0342 return false; 0343 } 0344 0345 bool HTMLLinkElementImpl::checkRemovePendingSheet() 0346 { 0347 if (!isLoading() && !isDisabled() && !isAlternate()) { 0348 document()->styleSheetLoaded(); 0349 return true; 0350 } 0351 return false; 0352 } 0353 0354 // ------------------------------------------------------------------------- 0355 0356 NodeImpl::Id HTMLMetaElementImpl::id() const 0357 { 0358 return ID_META; 0359 } 0360 0361 void HTMLMetaElementImpl::parseAttribute(AttributeImpl *attr) 0362 { 0363 switch (attr->id()) { 0364 case ATTR_HTTP_EQUIV: 0365 m_equiv = attr->value(); 0366 process(); 0367 break; 0368 case ATTR_CONTENT: 0369 m_content = attr->value(); 0370 process(); 0371 break; 0372 default: 0373 HTMLElementImpl::parseAttribute(attr); 0374 } 0375 } 0376 0377 void HTMLMetaElementImpl::insertedIntoDocument() 0378 { 0379 HTMLElementImpl::insertedIntoDocument(); 0380 process(); 0381 } 0382 0383 void HTMLMetaElementImpl::process() 0384 { 0385 // Get the document to process the tag, but only if we're actually part of DOM tree (changing a meta tag while 0386 // it's not in the tree shouldn't have any effect on the document) 0387 if (inDocument() && !m_equiv.isNull() && !m_content.isNull()) { 0388 document()->processHttpEquiv(m_equiv, m_content); 0389 } 0390 } 0391 0392 // ------------------------------------------------------------------------- 0393 0394 HTMLScriptElementImpl::HTMLScriptElementImpl(DocumentImpl *doc) 0395 : HTMLElementImpl(doc), m_cachedScript(nullptr), m_createdByParser(false), m_evaluated(false), m_hasNonEmptyForAttribute(false) 0396 { 0397 } 0398 0399 HTMLScriptElementImpl::~HTMLScriptElementImpl() 0400 { 0401 if (m_cachedScript) { 0402 m_cachedScript->deref(this); 0403 } 0404 } 0405 0406 NodeImpl::Id HTMLScriptElementImpl::id() const 0407 { 0408 return ID_SCRIPT; 0409 } 0410 0411 void HTMLScriptElementImpl::parseAttribute(AttributeImpl *attr) 0412 { 0413 switch (attr->id()) { 0414 case ATTR_ONLOAD: 0415 setHTMLEventListener(EventImpl::LOAD_EVENT, 0416 document()->createHTMLEventListener(attr->value().string(), "onload", this)); 0417 break; 0418 case ATTR_SRC: { 0419 // We want to evaluate scripts on src attr change when a fresh script element 0420 // is inserted into document, and then has its source changed -after-. 0421 // If the source is manipulated while we're outside the document, 0422 // we'll only start doing things once we get insertedIntoDocument() 0423 if (m_evaluated || m_cachedScript || m_createdByParser || !inDocument()) { 0424 return; 0425 } 0426 const DOMString url = attr->value().trimSpaces(); 0427 if (!url.isEmpty()) { 0428 loadFromUrl(url); 0429 } 0430 break; 0431 } 0432 case ATTR_FOR: { 0433 m_hasNonEmptyForAttribute = !attr->value().isEmpty(); 0434 break; 0435 } 0436 default: 0437 HTMLElementImpl::parseAttribute(attr); 0438 } 0439 } 0440 0441 bool HTMLScriptElementImpl::isURLAttribute(AttributeImpl *attr) const 0442 { 0443 return attr->id() == ATTR_SRC; 0444 } 0445 0446 bool HTMLScriptElementImpl::isValidScript() const 0447 { 0448 // HTML5 draft 4.3.1 : script elements with non-empty for attribute 0449 // must not be executed. 0450 if (m_hasNonEmptyForAttribute) { 0451 return false; 0452 } 0453 0454 // Check type before language, since language is deprecated 0455 /* 0456 Mozilla 1.5 doesn't accept the text/javascript1.x formats, but WinIE 6 does. 0457 Mozilla 1.5 doesn't accept text/jscript, text/ecmascript, and text/livescript, but WinIE 6 does. 0458 Mozilla 1.5 accepts application/x-javascript, WinIE 6 doesn't. 0459 Mozilla 1.5 allows leading and trailing whitespace, but WinIE 6 doesn't. 0460 Mozilla 1.5 and WinIE 6 both accept the empty string, but neither accept a whitespace-only string. 0461 We want to accept all the values that either of these browsers accept, but not other values. 0462 */ 0463 QString type = getAttribute(ATTR_TYPE).string().toLower(); 0464 0465 // Gecko accepts initial/trailing whitespace around the mimetype. 0466 // Whitespace only, however, musn't trigger execution. 0467 int length = type.length(); 0468 type = type.trimmed(); 0469 if (length) 0470 return !(type.compare("text/javascript") != 0 && 0471 type.compare("text/javascript1.0") != 0 && 0472 type.compare("text/javascript1.1") != 0 && 0473 type.compare("text/javascript1.2") != 0 && 0474 type.compare("text/javascript1.3") != 0 && 0475 type.compare("text/javascript1.4") != 0 && 0476 type.compare("text/javascript1.5") != 0 && 0477 type.compare("text/jscript") != 0 && 0478 type.compare("text/ecmascript") != 0 && 0479 type.compare("text/livescript") != 0 && 0480 type.compare("application/x-javascript") != 0 && 0481 type.compare("application/x-ecmascript") != 0 && 0482 type.compare("application/javascript") != 0 && 0483 type.compare("application/ecmascript") != 0); 0484 0485 /* 0486 Mozilla 1.5 doesn't accept jscript or ecmascript, but WinIE 6 does. 0487 Mozilla 1.5 accepts javascript1.0, javascript1.4, and javascript1.5, but WinIE 6 accepts only 1.1 - 1.3. 0488 Neither Mozilla 1.5 nor WinIE 6 accept leading or trailing whitespace. 0489 We want to accept all the values that either of these browsers accept, but not other values. 0490 */ 0491 QString lang = getAttribute(ATTR_LANGUAGE).string().toLower(); 0492 if (!lang.isEmpty()) 0493 return !(lang.compare("javascript") != 0 && 0494 lang.compare("javascript1.0") != 0 && 0495 lang.compare("javascript1.1") != 0 && 0496 lang.compare("javascript1.2") != 0 && 0497 lang.compare("javascript1.3") != 0 && 0498 lang.compare("javascript1.4") != 0 && 0499 lang.compare("javascript1.5") != 0 && 0500 lang.compare("ecmascript") != 0 && 0501 lang.compare("livescript") != 0 && 0502 lang.compare("jscript")); 0503 0504 return true; 0505 } 0506 0507 void HTMLScriptElementImpl::childrenChanged() 0508 { 0509 // If a node is inserted as a child of the script element 0510 // and the script element has been inserted in the document 0511 // we evaluate the script. 0512 if (!m_createdByParser && inDocument() && firstChild()) { 0513 evaluateScript(document()->URL().url(), text()); 0514 } 0515 } 0516 0517 void HTMLScriptElementImpl::loadFromUrl(const DOMString &url) 0518 { 0519 QString charset = getAttribute(ATTR_CHARSET).string(); 0520 m_cachedScript = document()->docLoader()->requestScript(url, charset); 0521 if (m_cachedScript) { 0522 m_cachedScript->ref(this); 0523 } 0524 } 0525 0526 void HTMLScriptElementImpl::insertedIntoDocument() 0527 { 0528 HTMLElementImpl::insertedIntoDocument(); 0529 0530 assert(!m_cachedScript); 0531 0532 if (m_createdByParser) { 0533 return; 0534 } 0535 0536 const DOMString url = getAttribute(ATTR_SRC).trimSpaces(); 0537 if (!url.isEmpty()) { 0538 loadFromUrl(url); 0539 return; 0540 } 0541 0542 // If there's an empty script node, we shouldn't evaluate the script 0543 // because if a script is inserted afterwards (by setting text or innerText) 0544 // it should be evaluated, and evaluateScript only evaluates a script once. 0545 DOMString scriptString = text(); 0546 if (!scriptString.isEmpty()) { 0547 evaluateScript(document()->URL().url(), scriptString); 0548 } 0549 } 0550 0551 void HTMLScriptElementImpl::removedFromDocument() 0552 { 0553 HTMLElementImpl::removedFromDocument(); 0554 0555 if (m_cachedScript) { 0556 m_cachedScript->deref(this); 0557 m_cachedScript = nullptr; 0558 } 0559 } 0560 0561 void HTMLScriptElementImpl::notifyFinished(CachedObject *o) 0562 { 0563 CachedScript *cs = static_cast<CachedScript *>(o); 0564 0565 assert(cs == m_cachedScript); 0566 0567 QString URL = cs->url().string(); 0568 DOMString script = cs->script(); 0569 cs->deref(this); 0570 m_cachedScript = nullptr; 0571 0572 ref(); // Pin so we don't destroy oursleves. 0573 if (!cs->hadError()) { 0574 evaluateScript(URL, script); 0575 dispatchHTMLEvent(EventImpl::LOAD_EVENT, false, false); 0576 } 0577 deref(); 0578 } 0579 0580 void HTMLScriptElementImpl::evaluateScript(const QString &URL, const DOMString &script) 0581 { 0582 if (m_evaluated || !isValidScript()) { 0583 return; 0584 } 0585 0586 KHTMLPart *part = document()->part(); 0587 if (part) { 0588 KJSProxy *proxy = KJSProxy::proxy(part); 0589 if (proxy) { 0590 m_evaluated = true; 0591 proxy->evaluate(URL, 0, script.string(), nullptr); 0592 DocumentImpl::updateDocumentsRendering(); 0593 } 0594 } 0595 } 0596 0597 DOMString HTMLScriptElementImpl::text() const 0598 { 0599 DOMString val = ""; 0600 0601 for (NodeImpl *n = firstChild(); n; n = n->nextSibling()) { 0602 if (n->isTextNode()) { 0603 val += static_cast<TextImpl *>(n)->data(); 0604 } 0605 } 0606 0607 return val; 0608 } 0609 0610 void HTMLScriptElementImpl::setText(const DOMString &value) 0611 { 0612 int exceptioncode = 0; 0613 int numChildren = childNodeCount(); 0614 0615 if (numChildren == 1 && firstChild()->isTextNode()) { 0616 static_cast<DOM::TextImpl *>(firstChild())->setData(value, exceptioncode); 0617 return; 0618 } 0619 0620 if (numChildren > 0) { 0621 removeChildren(); 0622 } 0623 0624 appendChild(document()->createTextNode(value.implementation()), exceptioncode); 0625 } 0626 0627 DOMString HTMLScriptElementImpl::htmlFor() const 0628 { 0629 // DOM Level 1 says: reserved for future use. 0630 return DOMString(); 0631 } 0632 0633 void HTMLScriptElementImpl::setHtmlFor(const DOMString &/*value*/) 0634 { 0635 // DOM Level 1 says: reserved for future use. 0636 } 0637 0638 DOMString HTMLScriptElementImpl::event() const 0639 { 0640 // DOM Level 1 says: reserved for future use. 0641 return DOMString(); 0642 } 0643 0644 void HTMLScriptElementImpl::setEvent(const DOMString &/*value*/) 0645 { 0646 // DOM Level 1 says: reserved for future use. 0647 } 0648 0649 DOMString HTMLScriptElementImpl::charset() const 0650 { 0651 return getAttribute(ATTR_CHARSET); 0652 } 0653 0654 void HTMLScriptElementImpl::setCharset(const DOMString &value) 0655 { 0656 setAttribute(ATTR_CHARSET, value); 0657 } 0658 0659 bool HTMLScriptElementImpl::defer() const 0660 { 0661 return !getAttribute(ATTR_DEFER).isNull(); 0662 } 0663 0664 void HTMLScriptElementImpl::setDefer(bool defer) 0665 { 0666 setAttribute(ATTR_DEFER, defer ? "" : nullptr); 0667 } 0668 0669 DOMString HTMLScriptElementImpl::src() const 0670 { 0671 return document()->completeURL(getAttribute(ATTR_SRC).trimSpaces().string()); 0672 } 0673 0674 void HTMLScriptElementImpl::setSrc(const DOMString &value) 0675 { 0676 setAttribute(ATTR_SRC, value); 0677 } 0678 0679 DOMString HTMLScriptElementImpl::type() const 0680 { 0681 return getAttribute(ATTR_TYPE); 0682 } 0683 0684 void HTMLScriptElementImpl::setType(const DOMString &value) 0685 { 0686 setAttribute(ATTR_TYPE, value); 0687 } 0688 0689 // ------------------------------------------------------------------------- 0690 0691 HTMLStyleElementImpl::~HTMLStyleElementImpl() 0692 { 0693 if (m_sheet) { 0694 m_sheet->deref(); 0695 } 0696 } 0697 0698 NodeImpl::Id HTMLStyleElementImpl::id() const 0699 { 0700 return ID_STYLE; 0701 } 0702 0703 // other stuff... 0704 void HTMLStyleElementImpl::parseAttribute(AttributeImpl *attr) 0705 { 0706 switch (attr->id()) { 0707 case ATTR_TYPE: 0708 m_type = attr->value().lower(); 0709 break; 0710 case ATTR_MEDIA: 0711 m_media = attr->value().string().toLower(); 0712 break; 0713 case ATTR_TITLE: 0714 if (m_sheet) { 0715 m_sheet->setTitle(attr->value()); 0716 } 0717 break; 0718 default: 0719 HTMLElementImpl::parseAttribute(attr); 0720 } 0721 } 0722 0723 void HTMLStyleElementImpl::insertedIntoDocument() 0724 { 0725 HTMLElementImpl::insertedIntoDocument(); 0726 0727 // If we're empty, we have to call parseText here, since we won't get childrenChanged(); 0728 // but we still want a CSSOM object 0729 if (!firstChild()) { 0730 parseText(); 0731 } 0732 0733 if (m_sheet) { 0734 document()->updateStyleSelector(); 0735 } 0736 } 0737 0738 void HTMLStyleElementImpl::removedFromDocument() 0739 { 0740 HTMLElementImpl::removedFromDocument(); 0741 if (m_sheet) { 0742 document()->updateStyleSelector(); 0743 } 0744 } 0745 0746 void HTMLStyleElementImpl::childrenChanged() 0747 { 0748 HTMLElementImpl::childrenChanged(); 0749 0750 parseText(); 0751 } 0752 0753 void HTMLStyleElementImpl::parseText() 0754 { 0755 DOMString text = ""; 0756 0757 for (NodeImpl *c = firstChild(); c != nullptr; c = c->nextSibling()) { 0758 if ((c->nodeType() == Node::TEXT_NODE) || 0759 (c->nodeType() == Node::CDATA_SECTION_NODE) || 0760 (c->nodeType() == Node::COMMENT_NODE)) { 0761 text += c->nodeValue(); 0762 } 0763 } 0764 0765 if (m_sheet) { 0766 m_sheet->deref(); 0767 m_sheet = nullptr; 0768 } 0769 0770 m_loading = false; 0771 if (m_type.isEmpty() || m_type == "text/css") { // Type must be empty or CSS 0772 MediaListImpl *media = new MediaListImpl((CSSStyleSheetImpl *)nullptr, m_media, true); 0773 media->ref(); 0774 khtml::MediaQueryEvaluator screenEval("screen", true); 0775 khtml::MediaQueryEvaluator printEval("print", true); 0776 if (screenEval.eval(media) || printEval.eval(media)) { 0777 document()->addPendingSheet(); 0778 m_loading = true; 0779 m_sheet = new CSSStyleSheetImpl(this); 0780 m_sheet->ref(); 0781 m_sheet->parseString(text, !document()->inCompatMode()); 0782 m_sheet->setMedia(media); 0783 m_sheet->setTitle(getAttribute(ATTR_TITLE)); 0784 m_loading = false; 0785 } 0786 media->deref(); 0787 } 0788 0789 if (!isLoading() && m_sheet) { 0790 document()->styleSheetLoaded(); 0791 } 0792 } 0793 0794 bool HTMLStyleElementImpl::isLoading() const 0795 { 0796 if (m_loading) { 0797 return true; 0798 } 0799 if (!m_sheet) { 0800 return false; 0801 } 0802 return static_cast<CSSStyleSheetImpl *>(m_sheet)->isLoading(); 0803 } 0804 0805 bool HTMLStyleElementImpl::checkRemovePendingSheet() 0806 { 0807 if (!isLoading()) { 0808 document()->styleSheetLoaded(); 0809 return true; 0810 } 0811 return false; 0812 } 0813 0814 bool HTMLStyleElementImpl::checkAddPendingSheet() 0815 { 0816 if (!isLoading()) { 0817 document()->addPendingSheet(); 0818 return true; 0819 } 0820 return false; 0821 } 0822 0823 // ------------------------------------------------------------------------- 0824 0825 NodeImpl::Id HTMLTitleElementImpl::id() const 0826 { 0827 return ID_TITLE; 0828 } 0829 0830 void HTMLTitleElementImpl::childrenChanged() 0831 { 0832 HTMLElementImpl::childrenChanged(); 0833 0834 m_title = ""; 0835 for (NodeImpl *c = firstChild(); c != nullptr; c = c->nextSibling()) { 0836 if ((c->nodeType() == Node::TEXT_NODE) || (c->nodeType() == Node::CDATA_SECTION_NODE)) { 0837 m_title += c->nodeValue(); 0838 } 0839 } 0840 if (!m_title.isEmpty() && inDocument()) { 0841 document()->setTitle(m_title); 0842 } 0843 } 0844 0845 DOMString HTMLTitleElementImpl::text() 0846 { 0847 if (firstChild() && firstChild()->nodeType() == Node::TEXT_NODE) { 0848 return firstChild()->nodeValue(); 0849 } 0850 return ""; 0851 } 0852 0853 void HTMLTitleElementImpl::setText(const DOMString &str) 0854 { 0855 int exceptioncode = 0; 0856 RefPtr<DOM::NodeListImpl> nl = childNodes(); 0857 const unsigned int length = nl->length(); 0858 for (unsigned int i = 0; i < length; ++i) { 0859 if (nl->item(i)->nodeType() == DOM::Node::TEXT_NODE) { 0860 static_cast<DOM::TextImpl *>(nl->item(i))->setData(str, exceptioncode); 0861 return; 0862 } 0863 } 0864 0865 // No child text node found, creating one 0866 DOM::TextImpl *t = document()->createTextNode(str.implementation()); 0867 appendChild(t, exceptioncode); 0868 }