File indexing completed on 2024-05-05 16:10:09
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) 2010 Maksim Orlovich (maksim@kde.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 #include "html/html_documentimpl.h" 0026 #include "html/html_imageimpl.h" 0027 #include "html/html_headimpl.h" 0028 #include "html/html_baseimpl.h" 0029 #include "html/htmltokenizer.h" 0030 #include "html/html_formimpl.h" 0031 0032 #include "khtmlview.h" 0033 #include "khtml_part.h" 0034 #include "khtmlpart_p.h" 0035 #include "khtml_settings.h" 0036 0037 #include "xml/xml_tokenizer.h" 0038 #include "xml/dom2_eventsimpl.h" 0039 0040 #include <khtml_global.h> 0041 #include "rendering/render_object.h" 0042 #include "dom/dom_exception.h" 0043 0044 #include "khtml_debug.h" 0045 #include <QDBusConnection> 0046 #include <kcookiejar_interface.h> 0047 0048 #include "css/cssproperties.h" 0049 #include "css/cssstyleselector.h" 0050 #include "css/css_stylesheetimpl.h" 0051 #include <stdlib.h> 0052 0053 using namespace DOM; 0054 using namespace khtml; 0055 0056 HTMLDocumentImpl::HTMLDocumentImpl(KHTMLView *v) 0057 : DocumentImpl(v) 0058 { 0059 // qCDebug(KHTML_LOG) << "HTMLDocumentImpl constructor this = " << this; 0060 htmlElement = nullptr; 0061 0062 m_doAutoFill = false; 0063 m_determineParseMode = false; 0064 0065 /* dynamic history stuff to be fixed later (pfeiffer) 0066 connect( KHTMLGlobal::vLinks(), SIGNAL(removed(QString)), 0067 SLOT(slotHistoryChanged())); 0068 */ 0069 connect(KHTMLGlobal::vLinks(), SIGNAL(inserted(QString)), 0070 SLOT(slotHistoryChanged())); 0071 connect(KHTMLGlobal::vLinks(), SIGNAL(cleared()), 0072 SLOT(slotHistoryChanged())); 0073 } 0074 0075 HTMLDocumentImpl::~HTMLDocumentImpl() 0076 { 0077 } 0078 0079 DOMString HTMLDocumentImpl::referrer() const 0080 { 0081 if (part()) { 0082 return part()->pageReferrer(); 0083 } 0084 return DOMString(); 0085 } 0086 0087 DOMString HTMLDocumentImpl::lastModified() const 0088 { 0089 if (part()) { 0090 return part()->lastModified(); 0091 } 0092 return DOMString(); 0093 } 0094 0095 DOMString HTMLDocumentImpl::cookie() const 0096 { 0097 WId windowId = 0; 0098 KHTMLView *v = view(); 0099 0100 if (v && v->topLevelWidget()) { 0101 windowId = v->topLevelWidget()->winId(); 0102 } 0103 0104 org::kde::KCookieServer kcookiejar("org.kde.kded5", "/modules/kcookiejar", QDBusConnection::sessionBus()); 0105 QDBusReply<QString> reply = kcookiejar.findDOMCookies(URL().url(), qlonglong(windowId)); 0106 0107 if (!reply.isValid()) { 0108 qCWarning(KHTML_LOG) << "Can't communicate with cookiejar!"; 0109 return DOMString(); 0110 } 0111 0112 return DOMString(reply.value()); 0113 } 0114 0115 void HTMLDocumentImpl::setCookie(const DOMString &value) 0116 { 0117 WId windowId = 0; 0118 KHTMLView *v = view(); 0119 0120 if (v && v->topLevelWidget()) { 0121 windowId = v->topLevelWidget()->winId(); 0122 } 0123 0124 QByteArray fake_header("Set-Cookie: "); 0125 fake_header.append(value.string().toLatin1().constData()); 0126 fake_header.append("\n"); 0127 // Note that kded modules are autoloaded so we don't need to call loadModule ourselves. 0128 org::kde::KCookieServer kcookiejar("org.kde.kded5", "/modules/kcookiejar", QDBusConnection::sessionBus()); 0129 // Can't use kcookiejar.addCookies because then we can't pass NoBlock... 0130 kcookiejar.call(QDBus::NoBlock, "addCookies", 0131 URL().url(), fake_header, qlonglong(windowId)); 0132 } 0133 0134 void HTMLDocumentImpl::setBody(HTMLElementImpl *_body, int &exceptioncode) 0135 { 0136 HTMLElementImpl *b = body(); 0137 if (!_body) { 0138 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR; 0139 return; 0140 } 0141 if (!b) { 0142 documentElement()->appendChild(_body, exceptioncode); 0143 } else { 0144 documentElement()->replaceChild(_body, b, exceptioncode); 0145 } 0146 } 0147 0148 Tokenizer *HTMLDocumentImpl::createTokenizer() 0149 { 0150 return new HTMLTokenizer(docPtr(), m_view); 0151 } 0152 0153 // -------------------------------------------------------------------------- 0154 // not part of the DOM 0155 // -------------------------------------------------------------------------- 0156 0157 bool HTMLDocumentImpl::childAllowed(NodeImpl *newChild) 0158 { 0159 // ### support comments. etc as a child 0160 return (newChild->id() == ID_HTML || newChild->id() == ID_COMMENT || newChild->nodeType() == Node::DOCUMENT_TYPE_NODE); 0161 } 0162 0163 ElementImpl *HTMLDocumentImpl::createElement(const DOMString &name, int *pExceptioncode) 0164 { 0165 if (pExceptioncode && !Element::khtmlValidQualifiedName(name)) { 0166 *pExceptioncode = DOMException::INVALID_CHARACTER_ERR; 0167 return nullptr; 0168 } 0169 0170 return createHTMLElement(name, hMode != XHtml); 0171 } 0172 0173 ElementImpl *HTMLDocumentImpl::activeElement() const 0174 { 0175 NodeImpl *fn = focusNode(); 0176 if (!fn || !fn->isElementNode()) { 0177 return body(); 0178 } else { 0179 return static_cast<ElementImpl *>(fn); 0180 } 0181 } 0182 0183 void HTMLDocumentImpl::slotHistoryChanged() 0184 { 0185 if (true || !m_render) { 0186 return; 0187 } 0188 0189 recalcStyle(Force); 0190 m_render->repaint(); 0191 } 0192 0193 HTMLMapElementImpl *HTMLDocumentImpl::getMap(const DOMString &_url) 0194 { 0195 QString url = _url.string(); 0196 QString s; 0197 int pos = url.indexOf('#'); 0198 //qCDebug(KHTML_LOG) << "map pos of #:" << pos; 0199 s = QString(_url.unicode() + pos + 1, _url.length() - pos - 1); 0200 0201 QMap<QString, HTMLMapElementImpl *>::const_iterator it = mapMap.constFind(s); 0202 0203 if (it != mapMap.constEnd()) { 0204 return *it; 0205 } else { 0206 return nullptr; 0207 } 0208 } 0209 0210 void HTMLDocumentImpl::contentLoaded() 0211 { 0212 // auto fill: walk the tree and try to fill in login credentials 0213 if (view() && m_doAutoFill) { 0214 for (NodeImpl *n = this; n; n = n->traverseNextNode()) 0215 if (n->id() == ID_FORM) { 0216 static_cast<HTMLFormElementImpl *>(n)->doAutoFill(); 0217 } 0218 m_doAutoFill = false; 0219 } 0220 } 0221 0222 void HTMLDocumentImpl::close() 0223 { 0224 bool doload = !parsing() && m_tokenizer; 0225 0226 DocumentImpl::close(); 0227 0228 if (doload) { 0229 0230 if (title().isEmpty()) { // ensure setTitle is called at least once 0231 setTitle(DOMString()); 0232 } 0233 0234 // According to dom the load event must not bubble 0235 // but other browsers execute in a frameset document 0236 // the first(IE)/last(Moz/Konq) registered onload on a <frame> and the 0237 // first(IE)/last(Moz/Konq) registered onload on a <frameset>. 0238 0239 //qCDebug(KHTML_LOG) << "dispatching LOAD_EVENT on document " << document() << " " << (view()?view()->part()->name():0); 0240 0241 //Make sure to flush any pending image events now, as we want them out before the document's load event 0242 dispatchImageLoadEventsNow(); 0243 document()->dispatchWindowEvent(EventImpl::LOAD_EVENT, false, false); 0244 0245 // don't update rendering if we're going to redirect anyway 0246 if (part() && (part()->d->m_redirectURL.isEmpty() || 0247 part()->d->m_delayRedirect > 1)) { 0248 updateRendering(); 0249 } 0250 } 0251 } 0252 0253 void HTMLDocumentImpl::determineParseMode() 0254 { 0255 m_determineParseMode = true; 0256 if (m_doctype == nullptr) { 0257 // Currently we haven't got any doctype, so default to quirks mode and Html4 0258 changeModes(Compat, Html4); 0259 } 0260 } 0261 0262 void HTMLDocumentImpl::changeModes(ParseMode newPMode, HTMLMode newHMode) 0263 { 0264 if (!m_determineParseMode) { // change mode only when KHTMLPart called determineParseMode 0265 return; 0266 } 0267 ParseMode oldPMode = pMode; 0268 pMode = newPMode; 0269 hMode = newHMode; 0270 // This needs to be done last, see tests/parser/compatmode_xhtml_mixed.html 0271 if (hMode == Html4 && !m_htmlRequested) { 0272 // this part is still debatable and possibly UA dependent 0273 hMode = XHtml; 0274 pMode = Transitional; 0275 } 0276 m_htmlCompat = (hMode != XHtml); 0277 0278 m_styleSelector->strictParsing = !inCompatMode(); 0279 0280 #if 0 0281 qCDebug(KHTML_LOG) << "DocumentImpl::determineParseMode: publicId =" << publicID << " systemId = " << systemID; 0282 qCDebug(KHTML_LOG) << "DocumentImpl::determineParseMode: htmlMode = " << hMode; 0283 if (pMode == Strict) { 0284 qCDebug(KHTML_LOG) << " using strict parseMode"; 0285 } else if (pMode == Compat) { 0286 qCDebug(KHTML_LOG) << " using compatibility parseMode"; 0287 } else { 0288 qCDebug(KHTML_LOG) << " using transitional parseMode"; 0289 } 0290 #endif 0291 0292 if (pMode != oldPMode && styleSelector()) { 0293 updateStyleSelector(true/*shallow*/); 0294 } 0295 } 0296 0297 NodeListImpl *HTMLDocumentImpl::getElementsByName(const DOMString &elementName) 0298 { 0299 return new NameNodeListImpl(this, elementName); 0300 } 0301 0302 HTMLCollectionImpl *HTMLDocumentImpl::images() 0303 { 0304 return new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_IMAGES); 0305 } 0306 0307 HTMLCollectionImpl *HTMLDocumentImpl::applets() 0308 { 0309 return new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_APPLETS); 0310 } 0311 0312 HTMLCollectionImpl *HTMLDocumentImpl::links() 0313 { 0314 return new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_LINKS); 0315 } 0316 0317 HTMLCollectionImpl *HTMLDocumentImpl::forms() 0318 { 0319 return new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_FORMS); 0320 } 0321 0322 HTMLCollectionImpl *HTMLDocumentImpl::layers() 0323 { 0324 return new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_LAYERS); 0325 } 0326 0327 HTMLCollectionImpl *HTMLDocumentImpl::anchors() 0328 { 0329 return new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_ANCHORS); 0330 } 0331 0332 HTMLCollectionImpl *HTMLDocumentImpl::all() 0333 { 0334 return new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_ALL); 0335 } 0336 0337 HTMLCollectionImpl *HTMLDocumentImpl::scripts() 0338 { 0339 return new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_SCRIPTS); 0340 } 0341 0342 // -------------------------------------------------------------------------- 0343 // Support for displaying plaintext 0344 // -------------------------------------------------------------------------- 0345 0346 class HTMLTextTokenizer: public khtml::Tokenizer 0347 { 0348 public: 0349 HTMLTextTokenizer(DOM::HTMLDocumentImpl *doc): m_doc(doc) 0350 {} 0351 0352 void begin() override; 0353 void write(const TokenizerString &str, bool appendData) override; 0354 0355 void end() override 0356 { 0357 emit finishedParsing(); 0358 }; 0359 void finish() override 0360 { 0361 end(); 0362 }; 0363 0364 // We don't support any inline scripts here 0365 bool isWaitingForScripts() const override 0366 { 0367 return false; 0368 } 0369 bool isExecutingScript() const override 0370 { 0371 return false; 0372 } 0373 void executeScriptsWaitingForStylesheets() override {}; 0374 private: 0375 DOM::HTMLDocumentImpl *m_doc; 0376 }; 0377 0378 void HTMLTextTokenizer::begin() 0379 { 0380 int dummy; 0381 DOM::ElementImpl *html = m_doc->createElement("html", &dummy); 0382 DOM::ElementImpl *head = m_doc->createElement("head", &dummy); 0383 DOM::ElementImpl *body = m_doc->createElement("body", &dummy); 0384 DOM::ElementImpl *pre = m_doc->createElement("pre", &dummy); 0385 0386 m_doc->appendChild(html, dummy); 0387 html->appendChild(head, dummy); 0388 html->appendChild(body, dummy); 0389 body->appendChild(pre, dummy); 0390 } 0391 0392 void HTMLTextTokenizer::write(const TokenizerString &str, bool /*appendData*/) 0393 { 0394 // A potential worry here is the document being modified by 0395 // a script while we're still loading. To handle that, we always look up 0396 // the pre again, and append to it, even for document.write mess 0397 // and the like. 0398 RefPtr<NodeListImpl> coll = m_doc->getElementsByTagName("pre"); 0399 if (coll->length() >= 1ul) { 0400 int dummy; 0401 coll->item(0)->appendChild(m_doc->createTextNode(str.toString()), dummy); 0402 } 0403 } 0404 0405 HTMLTextDocumentImpl::HTMLTextDocumentImpl(KHTMLView *v): HTMLDocumentImpl(v) 0406 {} 0407 0408 khtml::Tokenizer *HTMLTextDocumentImpl::createTokenizer() 0409 { 0410 return new HTMLTextTokenizer(this); 0411 } 0412 0413 #include "moc_html_documentimpl.cpp"