File indexing completed on 2023-05-30 09:09:55
0001 /* This file is part of the KDE project 0002 * 0003 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 0004 * 1999 Lars Knoll <knoll@kde.org> 0005 * 1999 Antti Koivisto <koivisto@kde.org> 0006 * 2000 Simon Hausmann <hausmann@kde.org> 0007 * 2000 Stefan Schimanski <1Stein@gmx.de> 0008 * 2001-2005 George Staikos <staikos@kde.org> 0009 * 2001-2003 Dirk Mueller <mueller@kde.org> 0010 * 2000-2005 David Faure <faure@kde.org> 0011 * 2002 Apple Computer, Inc. 0012 * 2010 Maksim Orlovich (maksim@kde.org) 0013 * 0014 * This library is free software; you can redistribute it and/or 0015 * modify it under the terms of the GNU Library General Public 0016 * License as published by the Free Software Foundation; either 0017 * version 2 of the License, or (at your option) any later version. 0018 * 0019 * This library is distributed in the hope that it will be useful, 0020 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0022 * Library General Public License for more details. 0023 * 0024 * You should have received a copy of the GNU Library General Public License 0025 * along with this library; see the file COPYING.LIB. If not, write to 0026 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0027 * Boston, MA 02110-1301, USA. 0028 */ 0029 0030 //#define SPEED_DEBUG 0031 #include "khtml_part.h" 0032 0033 #include "ui_htmlpageinfo.h" 0034 0035 #include "khtmlviewbar.h" 0036 #include "khtml_pagecache.h" 0037 0038 #include "dom/dom_string.h" 0039 #include "dom/dom_element.h" 0040 #include "dom/dom_exception.h" 0041 #include "dom/html_document.h" 0042 #include "editing/editor.h" 0043 #include "html/html_documentimpl.h" 0044 #include "html/html_baseimpl.h" 0045 #include "html/html_objectimpl.h" 0046 #include "html/html_miscimpl.h" 0047 #include "html/html_imageimpl.h" 0048 #include "imload/imagemanager.h" 0049 #include "rendering/render_text.h" 0050 #include "rendering/render_frames.h" 0051 #include "rendering/render_layer.h" 0052 #include "rendering/render_position.h" 0053 #include "misc/loader.h" 0054 #include "misc/khtml_partaccessor.h" 0055 #include "xml/dom2_eventsimpl.h" 0056 #include "xml/dom2_rangeimpl.h" 0057 #include "xml/xml_tokenizer.h" 0058 #include "css/cssstyleselector.h" 0059 using namespace DOM; 0060 0061 #include "khtmlview.h" 0062 #include <kparts/partmanager.h> 0063 #include <kparts/browseropenorsavequestion.h> 0064 #include <kparts/guiactivateevent.h> 0065 0066 #include <kacceleratormanager.h> 0067 #include "ecma/kjs_proxy.h" 0068 #include "ecma/kjs_window.h" 0069 #include "ecma/kjs_events.h" 0070 #include "khtml_settings.h" 0071 #include "kjserrordlg.h" 0072 0073 #include <kjs/function.h> 0074 #include <kjs/interpreter.h> 0075 0076 #include <sys/types.h> 0077 #include <assert.h> 0078 0079 #include <kstringhandler.h> 0080 #include <kio/job.h> 0081 #include <kio/jobuidelegate.h> 0082 #include <kio/global.h> 0083 #include <kio/pixmaploader.h> 0084 #include <kio/hostinfo.h> 0085 #include <kprotocolmanager.h> 0086 #include "khtml_debug.h" 0087 #include <kjobwidgets.h> 0088 #include <kmessagebox.h> 0089 #include <kstandardaction.h> 0090 #include <kstandardguiitem.h> 0091 #include <kactioncollection.h> 0092 #include <kmimetypetrader.h> 0093 #include <qtemporaryfile.h> 0094 #include <ktoolinvocation.h> 0095 #include <kurlauthorized.h> 0096 #include <kparts/browserinterface.h> 0097 #include <kparts/scriptableextension.h> 0098 #include <kparts/liveconnectextension.h> 0099 #include <kactionmenu.h> 0100 #include <ktoggleaction.h> 0101 #include <kcodecaction.h> 0102 #include <kselectaction.h> 0103 0104 #include <QDBusConnection> 0105 #include <ksslinfodialog.h> 0106 #include <ksslsettings.h> 0107 0108 #include <QDBusInterface> 0109 #include <QMimeData> 0110 #include <kfileitem.h> 0111 #include <kurifilter.h> 0112 #include <kurllabel.h> 0113 #include <kurlmimedata.h> 0114 0115 #include <QClipboard> 0116 #include <QLocale> 0117 #include <QMenu> 0118 #include <QToolTip> 0119 #include <QDrag> 0120 #include <QMouseEvent> 0121 #include <QFile> 0122 #include <QMetaEnum> 0123 #include <QTextDocument> 0124 #include <QDate> 0125 #include <QtNetwork/QSslCertificate> 0126 #include <QStatusBar> 0127 #include <QStyle> 0128 #include <qmimedatabase.h> 0129 #include <qplatformdefs.h> 0130 #include <QFileInfo> 0131 0132 #include "khtmlpart_p.h" 0133 #include "khtml_iface.h" 0134 0135 #include "kpassivepopup.h" 0136 #include "rendering/render_form.h" 0137 #include <kwindowsystem.h> 0138 #include <kconfiggroup.h> 0139 #include <ksharedconfig.h> 0140 0141 #ifdef KJS_DEBUGGER 0142 #include "ecma/debugger/debugwindow.h" 0143 #endif 0144 0145 // SVG 0146 #include <svg/SVGDocument.h> 0147 #include <qstandardpaths.h> 0148 0149 bool KHTMLPartPrivate::s_dnsInitialised = false; 0150 0151 // DNS prefetch settings 0152 static const int sMaxDNSPrefetchPerPage = 42; 0153 static const int sDNSPrefetchTimerDelay = 200; 0154 static const int sDNSTTLSeconds = 400; 0155 static const int sDNSCacheSize = 500; 0156 0157 namespace khtml 0158 { 0159 0160 class PartStyleSheetLoader : public CachedObjectClient 0161 { 0162 public: 0163 PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader *dl) 0164 { 0165 m_part = part; 0166 m_cachedSheet = dl->requestStyleSheet(url, QString(), "text/css", 0167 true /* "user sheet" */); 0168 if (m_cachedSheet) { 0169 m_cachedSheet->ref(this); 0170 } 0171 } 0172 virtual ~PartStyleSheetLoader() 0173 { 0174 if (m_cachedSheet) { 0175 m_cachedSheet->deref(this); 0176 } 0177 } 0178 void setStyleSheet(const DOM::DOMString &, const DOM::DOMString &sheet, const DOM::DOMString &, const DOM::DOMString &/*mimetype*/) override 0179 { 0180 if (m_part) { 0181 m_part->setUserStyleSheet(sheet.string()); 0182 } 0183 0184 delete this; 0185 } 0186 void error(int, const QString &) override 0187 { 0188 delete this; 0189 } 0190 QPointer<KHTMLPart> m_part; 0191 khtml::CachedCSSStyleSheet *m_cachedSheet; 0192 }; 0193 } 0194 0195 KHTMLPart::KHTMLPart(QWidget *parentWidget, QObject *parent, GUIProfile prof) 0196 : KParts::ReadOnlyPart(parent) 0197 { 0198 d = nullptr; 0199 KHTMLGlobal::registerPart(this); 0200 setComponentData(KHTMLGlobal::aboutData(), false); 0201 init(new KHTMLView(this, parentWidget), prof); 0202 } 0203 0204 KHTMLPart::KHTMLPart(KHTMLView *view, QObject *parent, GUIProfile prof) 0205 : KParts::ReadOnlyPart(parent) 0206 { 0207 d = nullptr; 0208 KHTMLGlobal::registerPart(this); 0209 setComponentData(KHTMLGlobal::aboutData(), false); 0210 assert(view); 0211 if (!view->part()) { 0212 view->setPart(this); 0213 } 0214 init(view, prof); 0215 } 0216 0217 void KHTMLPart::init(KHTMLView *view, GUIProfile prof) 0218 { 0219 if (prof == DefaultGUI) { 0220 setXMLFile("khtml.rc"); 0221 } else if (prof == BrowserViewGUI) { 0222 setXMLFile("khtml_browser.rc"); 0223 } 0224 0225 d = new KHTMLPartPrivate(this, parent()); 0226 0227 d->m_view = view; 0228 0229 if (!parentPart()) { 0230 QWidget *widget = new QWidget(view->parentWidget()); 0231 widget->setObjectName("khtml_part_widget"); 0232 QVBoxLayout *layout = new QVBoxLayout(widget); 0233 layout->setContentsMargins(0, 0, 0, 0); 0234 layout->setSpacing(0); 0235 widget->setLayout(layout); 0236 0237 d->m_topViewBar = new KHTMLViewBar(KHTMLViewBar::Top, d->m_view, widget); 0238 d->m_bottomViewBar = new KHTMLViewBar(KHTMLViewBar::Bottom, d->m_view, widget); 0239 0240 layout->addWidget(d->m_topViewBar); 0241 layout->addWidget(d->m_view); 0242 layout->addWidget(d->m_bottomViewBar); 0243 setWidget(widget); 0244 widget->setFocusProxy(d->m_view); 0245 } else { 0246 setWidget(view); 0247 } 0248 0249 d->m_guiProfile = prof; 0250 d->m_extension = new KHTMLPartBrowserExtension(this); 0251 d->m_extension->setObjectName("KHTMLBrowserExtension"); 0252 d->m_hostExtension = new KHTMLPartBrowserHostExtension(this); 0253 d->m_statusBarExtension = new KParts::StatusBarExtension(this); 0254 d->m_scriptableExtension = new KJS::KHTMLPartScriptable(this); 0255 new KHTMLTextExtension(this); 0256 new KHTMLHtmlExtension(this); 0257 d->m_statusBarPopupLabel = nullptr; 0258 d->m_openableSuppressedPopups = 0; 0259 0260 d->m_paLoadImages = nullptr; 0261 d->m_paDebugScript = nullptr; 0262 d->m_bMousePressed = false; 0263 d->m_bRightMousePressed = false; 0264 d->m_bCleared = false; 0265 0266 if (prof == BrowserViewGUI) { 0267 d->m_paViewDocument = new QAction(i18n("View Do&cument Source"), this); 0268 actionCollection()->addAction("viewDocumentSource", d->m_paViewDocument); 0269 connect(d->m_paViewDocument, SIGNAL(triggered(bool)), this, SLOT(slotViewDocumentSource())); 0270 if (!parentPart()) { 0271 actionCollection()->setDefaultShortcut(d->m_paViewDocument,QKeySequence(Qt::CTRL | Qt::Key_U)); 0272 } 0273 0274 d->m_paViewFrame = new QAction(i18n("View Frame Source"), this); 0275 actionCollection()->addAction("viewFrameSource", d->m_paViewFrame); 0276 connect(d->m_paViewFrame, SIGNAL(triggered(bool)), this, SLOT(slotViewFrameSource())); 0277 if (!parentPart()) { 0278 actionCollection()->setDefaultShortcut(d->m_paViewFrame,QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_U)); 0279 } 0280 0281 d->m_paViewInfo = new QAction(i18n("View Document Information"), this); 0282 actionCollection()->addAction("viewPageInfo", d->m_paViewInfo); 0283 if (!parentPart()) { 0284 actionCollection()->setDefaultShortcut(d->m_paViewInfo, QKeySequence(Qt::CTRL | Qt::Key_I)); 0285 } 0286 connect(d->m_paViewInfo, SIGNAL(triggered(bool)), this, SLOT(slotViewPageInfo())); 0287 0288 d->m_paSaveBackground = new QAction(i18n("Save &Background Image As..."), this); 0289 actionCollection()->addAction("saveBackground", d->m_paSaveBackground); 0290 connect(d->m_paSaveBackground, SIGNAL(triggered(bool)), this, SLOT(slotSaveBackground())); 0291 0292 d->m_paSaveDocument = actionCollection()->addAction(KStandardAction::SaveAs, "saveDocument", 0293 this, SLOT(slotSaveDocument())); 0294 if (parentPart()) { 0295 d->m_paSaveDocument->setShortcuts(QList<QKeySequence>()); // avoid clashes 0296 } 0297 0298 d->m_paSaveFrame = new QAction(i18n("Save &Frame As..."), this); 0299 actionCollection()->addAction("saveFrame", d->m_paSaveFrame); 0300 connect(d->m_paSaveFrame, SIGNAL(triggered(bool)), this, SLOT(slotSaveFrame())); 0301 } else { 0302 d->m_paViewDocument = nullptr; 0303 d->m_paViewFrame = nullptr; 0304 d->m_paViewInfo = nullptr; 0305 d->m_paSaveBackground = nullptr; 0306 d->m_paSaveDocument = nullptr; 0307 d->m_paSaveFrame = nullptr; 0308 } 0309 0310 d->m_paSecurity = new QAction(i18n("SSL"), this); 0311 actionCollection()->addAction("security", d->m_paSecurity); 0312 connect(d->m_paSecurity, SIGNAL(triggered(bool)), this, SLOT(slotSecurity())); 0313 0314 d->m_paDebugRenderTree = new QAction(i18n("Print Rendering Tree to STDOUT"), this); 0315 actionCollection()->addAction("debugRenderTree", d->m_paDebugRenderTree); 0316 connect(d->m_paDebugRenderTree, SIGNAL(triggered(bool)), this, SLOT(slotDebugRenderTree())); 0317 0318 d->m_paDebugDOMTree = new QAction(i18n("Print DOM Tree to STDOUT"), this); 0319 actionCollection()->addAction("debugDOMTree", d->m_paDebugDOMTree); 0320 connect(d->m_paDebugDOMTree, SIGNAL(triggered(bool)), this, SLOT(slotDebugDOMTree())); 0321 0322 QAction *paDebugFrameTree = new QAction(i18n("Print frame tree to STDOUT"), this); 0323 actionCollection()->addAction("debugFrameTree", paDebugFrameTree); 0324 connect(paDebugFrameTree, SIGNAL(triggered(bool)), this, SLOT(slotDebugFrameTree())); 0325 0326 d->m_paStopAnimations = new QAction(i18n("Stop Animated Images"), this); 0327 actionCollection()->addAction("stopAnimations", d->m_paStopAnimations); 0328 connect(d->m_paStopAnimations, SIGNAL(triggered(bool)), this, SLOT(slotStopAnimations())); 0329 0330 d->m_paSetEncoding = new KCodecAction(QIcon::fromTheme("character-set"), i18n("Set &Encoding"), this, true); 0331 actionCollection()->addAction("setEncoding", d->m_paSetEncoding); 0332 // d->m_paSetEncoding->setDelayed( false ); 0333 0334 connect(d->m_paSetEncoding, &KSelectAction::textTriggered, this, &KHTMLPart::slotSetEncoding); 0335 connect(d->m_paSetEncoding, &KCodecAction::encodingProberTriggered, this, &KHTMLPart::slotAutomaticDetectionLanguage); 0336 0337 if (KSharedConfig::openConfig()->hasGroup("HTML Settings")) { 0338 KConfigGroup config(KSharedConfig::openConfig(), "HTML Settings"); 0339 0340 d->m_autoDetectLanguage = static_cast<KEncodingProber::ProberType>(config.readEntry("AutomaticDetectionLanguage", /*static_cast<int>(language) */0)); 0341 if (d->m_autoDetectLanguage == KEncodingProber::None) { 0342 const QByteArray name = QTextCodec::codecForLocale()->name().toLower(); 0343 // qCWarning(KHTML_LOG) << "00000000 "; 0344 if (name.endsWith("1251") || name.startsWith("koi") || name == "iso-8859-5") { 0345 d->m_autoDetectLanguage = KEncodingProber::Cyrillic; 0346 } else if (name.endsWith("1256") || name == "iso-8859-6") { 0347 d->m_autoDetectLanguage = KEncodingProber::Arabic; 0348 } else if (name.endsWith("1257") || name == "iso-8859-13" || name == "iso-8859-4") { 0349 d->m_autoDetectLanguage = KEncodingProber::Baltic; 0350 } else if (name.endsWith("1250") || name == "ibm852" || name == "iso-8859-2" || name == "iso-8859-3") { 0351 d->m_autoDetectLanguage = KEncodingProber::CentralEuropean; 0352 } else if (name.endsWith("1253") || name == "iso-8859-7") { 0353 d->m_autoDetectLanguage = KEncodingProber::Greek; 0354 } else if (name.endsWith("1255") || name == "iso-8859-8" || name == "iso-8859-8-i") { 0355 d->m_autoDetectLanguage = KEncodingProber::Hebrew; 0356 } else if (name == "jis7" || name == "eucjp" || name == "sjis") { 0357 d->m_autoDetectLanguage = KEncodingProber::Japanese; 0358 } else if (name == "gb2312" || name == "gbk" || name == "gb18030") { 0359 d->m_autoDetectLanguage = KEncodingProber::ChineseSimplified; 0360 } else if (name == "big5") { 0361 d->m_autoDetectLanguage = KEncodingProber::ChineseTraditional; 0362 } else if (name == "euc-kr") { 0363 d->m_autoDetectLanguage = KEncodingProber::Korean; 0364 } else if (name.endsWith("1254") || name == "iso-8859-9") { 0365 d->m_autoDetectLanguage = KEncodingProber::Turkish; 0366 } else if (name.endsWith("1252") || name == "iso-8859-1" || name == "iso-8859-15") { 0367 d->m_autoDetectLanguage = KEncodingProber::WesternEuropean; 0368 } else { 0369 d->m_autoDetectLanguage = KEncodingProber::Universal; 0370 } 0371 // qCWarning(KHTML_LOG) << "0000000end " << d->m_autoDetectLanguage << " " << QTextCodec::codecForLocale()->mibEnum(); 0372 } 0373 d->m_paSetEncoding->setCurrentProberType(d->m_autoDetectLanguage); 0374 } 0375 0376 d->m_paUseStylesheet = new KSelectAction(i18n("Use S&tylesheet"), this); 0377 actionCollection()->addAction("useStylesheet", d->m_paUseStylesheet); 0378 connect(d->m_paUseStylesheet, SIGNAL(triggered(int)), this, SLOT(slotUseStylesheet())); 0379 0380 if (prof == BrowserViewGUI) { 0381 d->m_paIncZoomFactor = new KHTMLZoomFactorAction(this, true, "format-font-size-more", i18n("Enlarge Font"), this); 0382 actionCollection()->addAction("incFontSizes", d->m_paIncZoomFactor); 0383 connect(d->m_paIncZoomFactor, SIGNAL(triggered(bool)), SLOT(slotIncFontSizeFast())); 0384 d->m_paIncZoomFactor->setWhatsThis(i18n("<qt>Enlarge Font<br /><br />" 0385 "Make the font in this window bigger. " 0386 "Click and hold down the mouse button for a menu with all available font sizes.</qt>")); 0387 0388 d->m_paDecZoomFactor = new KHTMLZoomFactorAction(this, false, "format-font-size-less", i18n("Shrink Font"), this); 0389 actionCollection()->addAction("decFontSizes", d->m_paDecZoomFactor); 0390 connect(d->m_paDecZoomFactor, SIGNAL(triggered(bool)), SLOT(slotDecFontSizeFast())); 0391 d->m_paDecZoomFactor->setWhatsThis(i18n("<qt>Shrink Font<br /><br />" 0392 "Make the font in this window smaller. " 0393 "Click and hold down the mouse button for a menu with all available font sizes.</qt>")); 0394 if (!parentPart()) { 0395 // For framesets, this action also affects frames, so only 0396 // the frameset needs to define a shortcut for the action. 0397 0398 // TODO: Why also CTRL+=? Because of http://trolltech.com/developer/knowledgebase/524/? 0399 // Nobody else does it... 0400 actionCollection()->setDefaultShortcut(d->m_paIncZoomFactor, QKeySequence("CTRL++; CTRL+=")); 0401 actionCollection()->setDefaultShortcut(d->m_paDecZoomFactor, QKeySequence(Qt::CTRL | Qt::Key_Minus)); 0402 } 0403 } 0404 0405 d->m_paFind = actionCollection()->addAction(KStandardAction::Find, "find", this, SLOT(slotFind())); 0406 d->m_paFind->setWhatsThis(i18n("<qt>Find text<br /><br />" 0407 "Shows a dialog that allows you to find text on the displayed page.</qt>")); 0408 0409 d->m_paFindNext = actionCollection()->addAction(KStandardAction::FindNext, "findNext", this, SLOT(slotFindNext())); 0410 d->m_paFindNext->setWhatsThis(i18n("<qt>Find next<br /><br />" 0411 "Find the next occurrence of the text that you " 0412 "have found using the <b>Find Text</b> function.</qt>")); 0413 0414 d->m_paFindPrev = actionCollection()->addAction(KStandardAction::FindPrev, "findPrevious", 0415 this, SLOT(slotFindPrev())); 0416 d->m_paFindPrev->setWhatsThis(i18n("<qt>Find previous<br /><br />" 0417 "Find the previous occurrence of the text that you " 0418 "have found using the <b>Find Text</b> function.</qt>")); 0419 0420 // These two actions aren't visible in the menus, but exist for the (configurable) shortcut 0421 d->m_paFindAheadText = new QAction(i18n("Find Text as You Type"), this); 0422 actionCollection()->addAction("findAheadText", d->m_paFindAheadText); 0423 actionCollection()->setDefaultShortcut(d->m_paFindAheadText, QKeySequence("/")); 0424 d->m_paFindAheadText->setToolTip(i18n("This shortcut shows the find bar, for finding text in the displayed page. It cancels the effect of \"Find Links as You Type\", which sets the \"Find links only\" option.")); 0425 d->m_paFindAheadText->setStatusTip(d->m_paFindAheadText->toolTip()); 0426 connect(d->m_paFindAheadText, SIGNAL(triggered(bool)), this, SLOT(slotFindAheadText())); 0427 0428 d->m_paFindAheadLinks = new QAction(i18n("Find Links as You Type"), this); 0429 actionCollection()->addAction("findAheadLink", d->m_paFindAheadLinks); 0430 // The issue is that it sets the (sticky) option FindLinksOnly, so 0431 // if you trigger this shortcut once by mistake, Esc and Ctrl+F will still have the option set. 0432 // Better let advanced users configure a shortcut for this advanced option 0433 //d->m_paFindAheadLinks->setShortcut( QKeySequence("\'") ); 0434 d->m_paFindAheadLinks->setToolTip(i18n("This shortcut shows the find bar, and sets the option \"Find links only\".")); 0435 d->m_paFindAheadLinks->setStatusTip(d->m_paFindAheadLinks->toolTip()); 0436 connect(d->m_paFindAheadLinks, SIGNAL(triggered(bool)), this, SLOT(slotFindAheadLink())); 0437 0438 if (parentPart()) { 0439 d->m_paFind->setShortcuts(QList<QKeySequence>()); // avoid clashes 0440 d->m_paFindNext->setShortcuts(QList<QKeySequence>()); // avoid clashes 0441 d->m_paFindPrev->setShortcuts(QList<QKeySequence>()); // avoid clashes 0442 d->m_paFindAheadText->setShortcuts(QList<QKeySequence>()); 0443 d->m_paFindAheadLinks->setShortcuts(QList<QKeySequence>()); 0444 } 0445 0446 d->m_paPrintFrame = new QAction(i18n("Print Frame..."), this); 0447 actionCollection()->addAction("printFrame", d->m_paPrintFrame); 0448 d->m_paPrintFrame->setIcon(QIcon::fromTheme("document-print-frame")); 0449 connect(d->m_paPrintFrame, SIGNAL(triggered(bool)), this, SLOT(slotPrintFrame())); 0450 d->m_paPrintFrame->setWhatsThis(i18n("<qt>Print Frame<br /><br />" 0451 "Some pages have several frames. To print only a single frame, click " 0452 "on it and then use this function.</qt>")); 0453 0454 // Warning: The name selectAll is used hardcoded by some 3rd parties to remove the 0455 // shortcut for selectAll so they do not get ambigous shortcuts. Renaming it 0456 // will either crash or render useless that workaround. It would be better 0457 // to use the name KStandardAction::name(KStandardAction::SelectAll) but we 0458 // can't for the same reason. 0459 d->m_paSelectAll = actionCollection()->addAction(KStandardAction::SelectAll, "selectAll", 0460 this, SLOT(slotSelectAll())); 0461 if (parentPart()) { // Only the frameset has the shortcut, but the slot uses the current frame. 0462 d->m_paSelectAll->setShortcuts(QList<QKeySequence>()); // avoid clashes 0463 } 0464 0465 d->m_paToggleCaretMode = new KToggleAction(i18n("Toggle Caret Mode"), this); 0466 actionCollection()->addAction("caretMode", d->m_paToggleCaretMode); 0467 actionCollection()->setDefaultShortcut(d->m_paToggleCaretMode, QKeySequence(Qt::Key_F7)); 0468 connect(d->m_paToggleCaretMode, SIGNAL(triggered(bool)), this, SLOT(slotToggleCaretMode())); 0469 d->m_paToggleCaretMode->setChecked(isCaretMode()); 0470 if (parentPart()) { 0471 d->m_paToggleCaretMode->setShortcuts(QList<QKeySequence>()); // avoid clashes 0472 } 0473 0474 // set the default java(script) flags according to the current host. 0475 d->m_bOpenMiddleClick = d->m_settings->isOpenMiddleClickEnabled(); 0476 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(); 0477 setDebugScript(d->m_settings->isJavaScriptDebugEnabled()); 0478 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(); 0479 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(); 0480 0481 // Set the meta-refresh flag... 0482 d->m_metaRefreshEnabled = d->m_settings->isAutoDelayedActionsEnabled(); 0483 0484 KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling(); 0485 if (ssm == KHTMLSettings::KSmoothScrollingDisabled) { 0486 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled); 0487 } else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient) { 0488 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient); 0489 } else { 0490 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled); 0491 } 0492 0493 if (d->m_bDNSPrefetchIsDefault && !onlyLocalReferences()) { 0494 KHTMLSettings::KDNSPrefetch dpm = d->m_settings->dnsPrefetch(); 0495 if (dpm == KHTMLSettings::KDNSPrefetchDisabled) { 0496 d->m_bDNSPrefetch = DNSPrefetchDisabled; 0497 } else if (dpm == KHTMLSettings::KDNSPrefetchOnlyWWWAndSLD) { 0498 d->m_bDNSPrefetch = DNSPrefetchOnlyWWWAndSLD; 0499 } else { 0500 d->m_bDNSPrefetch = DNSPrefetchEnabled; 0501 } 0502 } 0503 0504 if (!KHTMLPartPrivate::s_dnsInitialised && d->m_bDNSPrefetch != DNSPrefetchDisabled) { 0505 KIO::HostInfo::setCacheSize(sDNSCacheSize); 0506 KIO::HostInfo::setTTL(sDNSTTLSeconds); 0507 KHTMLPartPrivate::s_dnsInitialised = true; 0508 } 0509 0510 // all shortcuts should only be active, when this part has focus 0511 foreach (QAction *action, actionCollection()->actions()) { 0512 action->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0513 } 0514 actionCollection()->associateWidget(view); 0515 0516 connect(view, SIGNAL(zoomView(int)), SLOT(slotZoomView(int))); 0517 0518 connect(this, SIGNAL(completed()), 0519 this, SLOT(updateActions())); 0520 connect(this, SIGNAL(completed(bool)), 0521 this, SLOT(updateActions())); 0522 connect(this, SIGNAL(started(KIO::Job*)), 0523 this, SLOT(updateActions())); 0524 0525 // #### FIXME: the process wide loader is going to signal every part about every loaded object. 0526 // That's quite inefficient. Should be per-document-tree somehow. Even signaling to 0527 // child parts that a request from an ancestor has loaded is inefficent.. 0528 connect(khtml::Cache::loader(), SIGNAL(requestStarted(khtml::DocLoader*,khtml::CachedObject*)), 0529 this, SLOT(slotLoaderRequestStarted(khtml::DocLoader*,khtml::CachedObject*))); 0530 connect(khtml::Cache::loader(), SIGNAL(requestDone(khtml::DocLoader*,khtml::CachedObject*)), 0531 this, SLOT(slotLoaderRequestDone(khtml::DocLoader*,khtml::CachedObject*))); 0532 connect(khtml::Cache::loader(), SIGNAL(requestFailed(khtml::DocLoader*,khtml::CachedObject*)), 0533 this, SLOT(slotLoaderRequestDone(khtml::DocLoader*,khtml::CachedObject*))); 0534 0535 connect(&d->m_progressUpdateTimer, SIGNAL(timeout()), this, SLOT(slotProgressUpdate())); 0536 0537 findTextBegin(); //reset find variables 0538 0539 connect(&d->m_redirectionTimer, SIGNAL(timeout()), 0540 this, SLOT(slotRedirect())); 0541 0542 if (QDBusConnection::sessionBus().isConnected()) { 0543 new KHTMLPartIface(this); // our "adaptor" 0544 for (int i = 1;; ++i) 0545 if (QDBusConnection::sessionBus().registerObject(QString("/KHTML/%1/widget").arg(i), this)) { 0546 break; 0547 } else if (i == 0xffff) { 0548 qFatal("Something is very wrong in KHTMLPart!"); 0549 } 0550 } 0551 0552 if (prof == BrowserViewGUI && !parentPart()) { 0553 loadPlugins(); 0554 } 0555 } 0556 0557 KHTMLPart::~KHTMLPart() 0558 { 0559 // qCDebug(KHTML_LOG) << this; 0560 KConfigGroup config(KSharedConfig::openConfig(), "HTML Settings"); 0561 config.writeEntry("AutomaticDetectionLanguage", int(d->m_autoDetectLanguage)); 0562 0563 if (d->m_manager) { // the PartManager for this part's children 0564 d->m_manager->removePart(this); 0565 } 0566 0567 slotWalletClosed(); 0568 if (!parentPart()) { // only delete it if the top khtml_part closes 0569 removeJSErrorExtension(); 0570 } 0571 0572 stopAutoScroll(); 0573 d->m_redirectionTimer.stop(); 0574 0575 if (!d->m_bComplete) { 0576 closeUrl(); 0577 } 0578 0579 disconnect(khtml::Cache::loader(), SIGNAL(requestStarted(khtml::DocLoader*,khtml::CachedObject*)), 0580 this, SLOT(slotLoaderRequestStarted(khtml::DocLoader*,khtml::CachedObject*))); 0581 disconnect(khtml::Cache::loader(), SIGNAL(requestDone(khtml::DocLoader*,khtml::CachedObject*)), 0582 this, SLOT(slotLoaderRequestDone(khtml::DocLoader*,khtml::CachedObject*))); 0583 disconnect(khtml::Cache::loader(), SIGNAL(requestFailed(khtml::DocLoader*,khtml::CachedObject*)), 0584 this, SLOT(slotLoaderRequestDone(khtml::DocLoader*,khtml::CachedObject*))); 0585 0586 clear(); 0587 hide(); 0588 0589 if (d->m_view) { 0590 d->m_view->m_part = nullptr; 0591 } 0592 0593 // Have to delete this here since we forward declare it in khtmlpart_p and 0594 // at least some compilers won't call the destructor in this case. 0595 delete d->m_jsedlg; 0596 d->m_jsedlg = nullptr; 0597 0598 if (!parentPart()) { // only delete d->m_frame if the top khtml_part closes 0599 delete d->m_frame; 0600 } else if (d->m_frame && d->m_frame->m_run) { // for kids, they may get detached while 0601 d->m_frame->m_run.data()->abort(); // resolving mimetype; cancel that if needed 0602 } 0603 delete d; d = nullptr; 0604 KHTMLGlobal::deregisterPart(this); 0605 } 0606 0607 bool KHTMLPart::restoreURL(const QUrl &url) 0608 { 0609 // qCDebug(KHTML_LOG) << url; 0610 0611 d->m_redirectionTimer.stop(); 0612 0613 /* 0614 * That's not a good idea as it will call closeUrl() on all 0615 * child frames, preventing them from further loading. This 0616 * method gets called from restoreState() in case of a full frameset 0617 * restoral, and restoreState() calls closeUrl() before restoring 0618 * anyway. 0619 // qCDebug(KHTML_LOG) << "closing old URL"; 0620 closeUrl(); 0621 */ 0622 0623 d->m_bComplete = false; 0624 d->m_bLoadEventEmitted = false; 0625 d->m_workingURL = url; 0626 0627 // set the java(script) flags according to the current host. 0628 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host()); 0629 setDebugScript(KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled()); 0630 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host()); 0631 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host()); 0632 0633 setUrl(url); 0634 0635 d->m_restoreScrollPosition = true; 0636 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 0637 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 0638 0639 KHTMLPageCache::self()->fetchData(d->m_cacheId, this, SLOT(slotRestoreData(QByteArray))); 0640 0641 emit started(nullptr); 0642 0643 return true; 0644 } 0645 0646 static bool areUrlsForSamePage(const QUrl &url1, const QUrl &url2) 0647 { 0648 QUrl u1 = url1.adjusted(QUrl::StripTrailingSlash); 0649 u1.setFragment(QString()); 0650 if (u1.path() == QLatin1String("/")) { 0651 u1.setPath(QString()); 0652 } 0653 QUrl u2 = url2.adjusted(QUrl::StripTrailingSlash); 0654 u2.setFragment(QString()); 0655 if (u2.path() == QLatin1String("/")) { 0656 u2.setPath(QString()); 0657 } 0658 return u1 == u2; 0659 } 0660 0661 bool KHTMLPartPrivate::isLocalAnchorJump(const QUrl &url) 0662 { 0663 // kio_help actually uses fragments to identify different pages, so 0664 // always reload with it. 0665 if (url.scheme() == QLatin1String("help")) { 0666 return false; 0667 } 0668 0669 return url.hasFragment() && areUrlsForSamePage(url, q->url()); 0670 } 0671 0672 void KHTMLPartPrivate::executeAnchorJump(const QUrl &url, bool lockHistory) 0673 { 0674 DOM::HashChangeEventImpl *hashChangeEvImpl = nullptr; 0675 const QString &oldRef = q->url().fragment(QUrl::FullyEncoded); 0676 const QString &newRef = url.fragment(QUrl::FullyEncoded); 0677 const bool hashChanged = (oldRef != newRef) || (oldRef.isNull() && newRef.isEmpty()); 0678 0679 if (hashChanged) { 0680 // Note: we want to emit openUrlNotify first thing to make the history capture the old state, 0681 // however do not update history if a lock was explicitly requested, e.g. Location.replace() 0682 if (!lockHistory) { 0683 emit m_extension->openUrlNotify(); 0684 } 0685 // Create hashchange event 0686 hashChangeEvImpl = new DOM::HashChangeEventImpl(); 0687 hashChangeEvImpl->initHashChangeEvent("hashchange", 0688 true, //bubble 0689 false, //cancelable 0690 q->url().toString(), //oldURL 0691 url.toString() //newURL 0692 ); 0693 } 0694 0695 if (!q->gotoAnchor(newRef)) { // encoded fragment 0696 q->gotoAnchor(url.fragment(QUrl::FullyDecoded)); // not encoded fragment 0697 } 0698 0699 q->setUrl(url); 0700 emit m_extension->setLocationBarUrl(url.toDisplayString()); 0701 0702 if (hashChangeEvImpl) { 0703 m_doc->dispatchWindowEvent(hashChangeEvImpl); 0704 } 0705 } 0706 0707 bool KHTMLPart::openUrl(const QUrl &url) 0708 { 0709 // qCDebug(KHTML_LOG) << this << "opening" << url; 0710 0711 #ifndef KHTML_NO_WALLET 0712 // Wallet forms are per page, so clear it when loading a different page if we 0713 // are not an iframe (because we store walletforms only on the topmost part). 0714 if (!parentPart()) { 0715 d->m_walletForms.clear(); 0716 } 0717 #endif 0718 d->m_redirectionTimer.stop(); 0719 0720 // check to see if this is an "error://" URL. This is caused when an error 0721 // occurs before this part was loaded (e.g. KonqRun), and is passed to 0722 // khtmlpart so that it can display the error. 0723 if (url.scheme() == "error") { 0724 closeUrl(); 0725 0726 if (d->m_bJScriptEnabled) { 0727 d->m_statusBarText[BarOverrideText].clear(); 0728 d->m_statusBarText[BarDefaultText].clear(); 0729 } 0730 0731 /** 0732 * The format of the error url is that two variables are passed in the query: 0733 * error = int kio error code, errText = QString error text from kio 0734 * and the URL where the error happened is passed as a sub URL. 0735 */ 0736 const QUrl mainURL(url.fragment()); 0737 //qCDebug(KHTML_LOG) << "Handling error URL. URL count:" << urls.count(); 0738 0739 if (mainURL.isValid()) { 0740 QString query = url.query(QUrl::FullyDecoded); 0741 QRegularExpression pattern("error=(\\d+)&errText=(.*)"); 0742 QRegularExpressionMatch match = pattern.match(query); 0743 int error = match.captured(1).toInt(); 0744 // error=0 isn't a valid error code, so 0 means it's missing from the URL 0745 if (error == 0) { 0746 error = KIO::ERR_UNKNOWN; 0747 } 0748 const QString errorText = match.captured(2); 0749 d->m_workingURL = mainURL; 0750 //qCDebug(KHTML_LOG) << "Emitting fixed URL " << d->m_workingURL; 0751 emit d->m_extension->setLocationBarUrl(d->m_workingURL.toDisplayString()); 0752 htmlError(error, errorText, d->m_workingURL); 0753 return true; 0754 } 0755 } 0756 0757 if (!parentPart()) { // only do it for toplevel part 0758 QString host = url.isLocalFile() ? "localhost" : url.host(); 0759 QString userAgent = KProtocolManager::userAgentForHost(host); 0760 if (userAgent != KProtocolManager::userAgentForHost(QString())) { 0761 if (!d->m_statusBarUALabel) { 0762 d->m_statusBarUALabel = new KUrlLabel(d->m_statusBarExtension->statusBar()); 0763 d->m_statusBarUALabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); 0764 d->m_statusBarUALabel->setUseCursor(false); 0765 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarUALabel, 0, false); 0766 d->m_statusBarUALabel->setPixmap(SmallIcon("preferences-web-browser-identification")); 0767 } 0768 d->m_statusBarUALabel->setToolTip(i18n("The fake user-agent '%1' is in use.", userAgent)); 0769 } else if (d->m_statusBarUALabel) { 0770 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarUALabel); 0771 delete d->m_statusBarUALabel; 0772 d->m_statusBarUALabel = nullptr; 0773 } 0774 } 0775 0776 KParts::BrowserArguments browserArgs(d->m_extension->browserArguments()); 0777 KParts::OpenUrlArguments args(arguments()); 0778 0779 // in case 0780 // a) we have no frameset (don't test m_frames.count(), iframes get in there) 0781 // b) the url is identical with the currently displayed one (except for the htmlref!) 0782 // c) the url request is not a POST operation and 0783 // d) the caller did not request to reload the page 0784 // e) there was no HTTP redirection meanwhile (testcase: webmin's software/tree.cgi) 0785 // => we don't reload the whole document and 0786 // we just jump to the requested html anchor 0787 bool isFrameSet = false; 0788 if (d->m_doc && d->m_doc->isHTMLDocument()) { 0789 HTMLDocumentImpl *htmlDoc = static_cast<HTMLDocumentImpl *>(d->m_doc); 0790 isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET); 0791 } 0792 0793 if (isFrameSet && d->isLocalAnchorJump(url) && browserArgs.softReload) { 0794 QList<khtml::ChildFrame *>::Iterator it = d->m_frames.begin(); 0795 const QList<khtml::ChildFrame *>::Iterator end = d->m_frames.end(); 0796 for (; it != end; ++it) { 0797 KHTMLPart *const part = qobject_cast<KHTMLPart *>((*it)->m_part.data()); 0798 if (part) { 0799 // We are reloading frames to make them jump into offsets. 0800 KParts::OpenUrlArguments partargs(part->arguments()); 0801 partargs.setReload(true); 0802 part->setArguments(partargs); 0803 0804 part->openUrl(part->url()); 0805 } 0806 }/*next it*/ 0807 return true; 0808 } 0809 0810 if (url.hasFragment() && !isFrameSet) { 0811 bool noReloadForced = !args.reload() && !browserArgs.redirectedRequest() && !browserArgs.doPost(); 0812 if (noReloadForced && d->isLocalAnchorJump(url)) { 0813 // qCDebug(KHTML_LOG) << "jumping to anchor. m_url = " << url; 0814 setUrl(url); 0815 emit started(nullptr); 0816 0817 if (!gotoAnchor(url.fragment(QUrl::FullyEncoded))) { 0818 gotoAnchor(url.fragment(QUrl::FullyDecoded)); 0819 } 0820 0821 d->m_bComplete = true; 0822 if (d->m_doc) { 0823 d->m_doc->setParsing(false); 0824 } 0825 0826 // qCDebug(KHTML_LOG) << "completed..."; 0827 emit completed(); 0828 return true; 0829 } 0830 } 0831 0832 // Save offset of viewport when page is reloaded to be compliant 0833 // to every other capable browser out there. 0834 if (args.reload()) { 0835 args.setXOffset(d->m_view->contentsX()); 0836 args.setYOffset(d->m_view->contentsY()); 0837 setArguments(args); 0838 } 0839 0840 if (!d->m_restored) { 0841 closeUrl(); 0842 } 0843 0844 d->m_restoreScrollPosition = d->m_restored; 0845 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 0846 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 0847 0848 // Classify the mimetype. Some, like images and plugins are handled 0849 // by wrapping things up in tags, so we want to plain output the HTML, 0850 // and not start the job and all that (since we would want the 0851 // KPart or whatever to load it). 0852 // This is also the only place we need to do this, as it's for 0853 // internal iframe use, not any other clients. 0854 MimeType type = d->classifyMimeType(args.mimeType()); 0855 0856 if (type == MimeImage || type == MimeOther) { 0857 begin(url, args.xOffset(), args.yOffset()); 0858 write(QString::fromLatin1("<html><head></head><body>")); 0859 if (type == MimeImage) { 0860 write(QString::fromLatin1("<img ")); 0861 } else { 0862 write(QString::fromLatin1("<embed ")); 0863 } 0864 write(QString::fromLatin1("src=\"")); 0865 0866 assert(url.toString().indexOf('"') == -1); 0867 write(url.toString()); 0868 0869 write(QString::fromLatin1("\">")); 0870 end(); 0871 return true; 0872 } 0873 0874 // initializing m_url to the new url breaks relative links when opening such a link after this call and _before_ begin() is called (when the first 0875 // data arrives) (Simon) 0876 d->m_workingURL = url; 0877 if (url.scheme().startsWith("http") && !url.host().isEmpty() && 0878 url.path().isEmpty()) { 0879 d->m_workingURL.setPath("/"); 0880 emit d->m_extension->setLocationBarUrl(d->m_workingURL.toDisplayString()); 0881 } 0882 setUrl(d->m_workingURL); 0883 0884 QMap<QString, QString> &metaData = args.metaData(); 0885 metaData.insert("main_frame_request", parentPart() == nullptr ? "TRUE" : "FALSE"); 0886 metaData.insert("ssl_parent_ip", d->m_ssl_parent_ip); 0887 metaData.insert("ssl_parent_cert", d->m_ssl_parent_cert); 0888 metaData.insert("PropagateHttpHeader", "true"); 0889 metaData.insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE"); 0890 metaData.insert("ssl_activate_warnings", "TRUE"); 0891 metaData.insert("cross-domain", toplevelURL().toString()); 0892 0893 if (d->m_restored) { 0894 metaData.insert("referrer", d->m_pageReferrer); 0895 d->m_cachePolicy = KIO::CC_Cache; 0896 } else if (args.reload() && !browserArgs.softReload) { 0897 d->m_cachePolicy = KIO::CC_Reload; 0898 } else { 0899 d->m_cachePolicy = KProtocolManager::cacheControl(); 0900 } 0901 0902 if (browserArgs.doPost() && (url.scheme().startsWith("http"))) { 0903 d->m_job = KIO::http_post(url, browserArgs.postData, KIO::HideProgressInfo); 0904 d->m_job->addMetaData("content-type", browserArgs.contentType()); 0905 } else { 0906 d->m_job = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo); 0907 d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy)); 0908 } 0909 0910 if (widget()) { 0911 KJobWidgets::setWindow(d->m_job, widget()->topLevelWidget()); 0912 } 0913 d->m_job->addMetaData(metaData); 0914 0915 connect(d->m_job, SIGNAL(result(KJob*)), 0916 SLOT(slotFinished(KJob*))); 0917 connect(d->m_job, SIGNAL(data(KIO::Job*,QByteArray)), 0918 SLOT(slotData(KIO::Job*,QByteArray))); 0919 connect(d->m_job, SIGNAL(infoMessage(KJob*,QString,QString)), 0920 SLOT(slotInfoMessage(KJob*,QString))); 0921 connect(d->m_job, SIGNAL(redirection(KIO::Job*,QUrl)), 0922 SLOT(slotRedirection(KIO::Job*,QUrl))); 0923 0924 d->m_bComplete = false; 0925 d->m_bLoadEventEmitted = false; 0926 0927 // delete old status bar msg's from kjs (if it _was_ activated on last URL) 0928 if (d->m_bJScriptEnabled) { 0929 d->m_statusBarText[BarOverrideText].clear(); 0930 d->m_statusBarText[BarDefaultText].clear(); 0931 } 0932 0933 // set the javascript flags according to the current url 0934 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host()); 0935 setDebugScript(KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled()); 0936 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host()); 0937 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host()); 0938 0939 connect(d->m_job, SIGNAL(speed(KJob*,ulong)), 0940 this, SLOT(slotJobSpeed(KJob*,ulong))); 0941 0942 connect(d->m_job, SIGNAL(percent(KJob*,ulong)), 0943 this, SLOT(slotJobPercent(KJob*,ulong))); 0944 0945 connect(d->m_job, SIGNAL(result(KJob*)), 0946 this, SLOT(slotJobDone(KJob*))); 0947 0948 d->m_jobspeed = 0; 0949 0950 // If this was an explicit reload and the user style sheet should be used, 0951 // do a stat to see whether the stylesheet was changed in the meanwhile. 0952 if (args.reload() && !settings()->userStyleSheet().isEmpty()) { 0953 QUrl userStyleSheetUrl(settings()->userStyleSheet()); 0954 KIO::StatJob *job = KIO::stat(userStyleSheetUrl, KIO::HideProgressInfo); 0955 connect(job, SIGNAL(result(KJob*)), 0956 this, SLOT(slotUserSheetStatDone(KJob*))); 0957 } 0958 startingJob(d->m_job); 0959 emit started(nullptr); 0960 0961 return true; 0962 } 0963 0964 bool KHTMLPart::closeUrl() 0965 { 0966 if (d->m_job) { 0967 KHTMLPageCache::self()->cancelEntry(d->m_cacheId); 0968 d->m_job->kill(); 0969 d->m_job = nullptr; 0970 } 0971 0972 if (d->m_doc && d->m_doc->isHTMLDocument()) { 0973 HTMLDocumentImpl *hdoc = static_cast<HTMLDocumentImpl *>(d->m_doc); 0974 0975 if (hdoc->body() && d->m_bLoadEventEmitted) { 0976 hdoc->body()->dispatchWindowEvent(EventImpl::UNLOAD_EVENT, false, false); 0977 if (d->m_doc) { 0978 d->m_doc->updateRendering(); 0979 } 0980 d->m_bLoadEventEmitted = false; 0981 } 0982 } 0983 0984 d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David) 0985 d->m_bLoadEventEmitted = true; // don't want that one either 0986 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy 0987 0988 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 0989 0990 KHTMLPageCache::self()->cancelFetch(this); 0991 if (d->m_doc && d->m_doc->parsing()) { 0992 // qCDebug(KHTML_LOG) << " was still parsing... calling end "; 0993 slotFinishedParsing(); 0994 d->m_doc->setParsing(false); 0995 } 0996 0997 if (!d->m_workingURL.isEmpty()) { 0998 // Aborted before starting to render 0999 // qCDebug(KHTML_LOG) << "Aborted before starting to render, reverting location bar to " << url(); 1000 emit d->m_extension->setLocationBarUrl(url().toDisplayString()); 1001 } 1002 1003 d->m_workingURL = QUrl(); 1004 1005 if (d->m_doc && d->m_doc->docLoader()) { 1006 khtml::Cache::loader()->cancelRequests(d->m_doc->docLoader()); 1007 } 1008 1009 // tell all subframes to stop as well 1010 { 1011 ConstFrameIt it = d->m_frames.constBegin(); 1012 const ConstFrameIt end = d->m_frames.constEnd(); 1013 for (; it != end; ++it) { 1014 if ((*it)->m_run) { 1015 (*it)->m_run.data()->abort(); 1016 } 1017 if (!(*it)->m_part.isNull()) { 1018 (*it)->m_part.data()->closeUrl(); 1019 } 1020 } 1021 } 1022 // tell all objects to stop as well 1023 { 1024 ConstFrameIt it = d->m_objects.constBegin(); 1025 const ConstFrameIt end = d->m_objects.constEnd(); 1026 for (; it != end; ++it) { 1027 if (!(*it)->m_part.isNull()) { 1028 (*it)->m_part.data()->closeUrl(); 1029 } 1030 } 1031 } 1032 // Stop any started redirections as well!! (DA) 1033 if (d && d->m_redirectionTimer.isActive()) { 1034 d->m_redirectionTimer.stop(); 1035 } 1036 1037 // null node activated. 1038 emit nodeActivated(Node()); 1039 1040 // make sure before clear() runs, we pop out of a dialog's message loop 1041 if (d->m_view) { 1042 d->m_view->closeChildDialogs(); 1043 } 1044 1045 return true; 1046 } 1047 1048 DOM::HTMLDocument KHTMLPart::htmlDocument() const 1049 { 1050 if (d->m_doc && d->m_doc->isHTMLDocument()) { 1051 return static_cast<HTMLDocumentImpl *>(d->m_doc); 1052 } else { 1053 return static_cast<HTMLDocumentImpl *>(nullptr); 1054 } 1055 } 1056 1057 DOM::Document KHTMLPart::document() const 1058 { 1059 return d->m_doc; 1060 } 1061 1062 QString KHTMLPart::documentSource() const 1063 { 1064 QString sourceStr; 1065 if (!(url().isLocalFile()) && KHTMLPageCache::self()->isComplete(d->m_cacheId)) { 1066 QByteArray sourceArray; 1067 QDataStream dataStream(&sourceArray, QIODevice::WriteOnly); 1068 KHTMLPageCache::self()->saveData(d->m_cacheId, &dataStream); 1069 QTextStream stream(sourceArray, QIODevice::ReadOnly); 1070 stream.setCodec(QTextCodec::codecForName(encoding().toLatin1().constData())); 1071 sourceStr = stream.readAll(); 1072 } else { 1073 QTemporaryFile tmpFile; 1074 if (!tmpFile.open()) { 1075 return sourceStr; 1076 } 1077 1078 KIO::FileCopyJob *job = KIO::file_copy(url(), QUrl::fromLocalFile(tmpFile.fileName()), KIO::Overwrite); 1079 if (job->exec()) { 1080 QTextStream stream(&tmpFile); 1081 stream.setCodec(QTextCodec::codecForName(encoding().toLatin1().constData())); 1082 sourceStr = stream.readAll(); 1083 } 1084 } 1085 1086 return sourceStr; 1087 } 1088 1089 KParts::BrowserExtension *KHTMLPart::browserExtension() const 1090 { 1091 return d->m_extension; 1092 } 1093 1094 KParts::BrowserHostExtension *KHTMLPart::browserHostExtension() const 1095 { 1096 return d->m_hostExtension; 1097 } 1098 1099 KHTMLView *KHTMLPart::view() const 1100 { 1101 return d->m_view; 1102 } 1103 1104 KHTMLViewBar *KHTMLPart::pTopViewBar() const 1105 { 1106 if (const_cast<KHTMLPart *>(this)->parentPart()) { 1107 return const_cast<KHTMLPart *>(this)->parentPart()->pTopViewBar(); 1108 } 1109 return d->m_topViewBar; 1110 } 1111 1112 KHTMLViewBar *KHTMLPart::pBottomViewBar() const 1113 { 1114 if (const_cast<KHTMLPart *>(this)->parentPart()) { 1115 return const_cast<KHTMLPart *>(this)->parentPart()->pBottomViewBar(); 1116 } 1117 return d->m_bottomViewBar; 1118 } 1119 1120 void KHTMLPart::setStatusMessagesEnabled(bool enable) 1121 { 1122 d->m_statusMessagesEnabled = enable; 1123 } 1124 1125 KJS::Interpreter *KHTMLPart::jScriptInterpreter() 1126 { 1127 KJSProxy *proxy = jScript(); 1128 if (!proxy || proxy->paused()) { 1129 return nullptr; 1130 } 1131 1132 return proxy->interpreter(); 1133 } 1134 1135 bool KHTMLPart::statusMessagesEnabled() const 1136 { 1137 return d->m_statusMessagesEnabled; 1138 } 1139 1140 void KHTMLPart::setJScriptEnabled(bool enable) 1141 { 1142 if (!enable && jScriptEnabled() && d->m_frame && d->m_frame->m_jscript) { 1143 d->m_frame->m_jscript->clear(); 1144 } 1145 d->m_bJScriptForce = enable; 1146 d->m_bJScriptOverride = true; 1147 } 1148 1149 bool KHTMLPart::jScriptEnabled() const 1150 { 1151 if (onlyLocalReferences()) { 1152 return false; 1153 } 1154 1155 if (d->m_bJScriptOverride) { 1156 return d->m_bJScriptForce; 1157 } 1158 return d->m_bJScriptEnabled; 1159 } 1160 1161 void KHTMLPart::setDNSPrefetch(DNSPrefetch pmode) 1162 { 1163 d->m_bDNSPrefetch = pmode; 1164 d->m_bDNSPrefetchIsDefault = false; 1165 } 1166 1167 KHTMLPart::DNSPrefetch KHTMLPart::dnsPrefetch() const 1168 { 1169 if (onlyLocalReferences()) { 1170 return DNSPrefetchDisabled; 1171 } 1172 return d->m_bDNSPrefetch; 1173 } 1174 1175 void KHTMLPart::setMetaRefreshEnabled(bool enable) 1176 { 1177 d->m_metaRefreshEnabled = enable; 1178 } 1179 1180 bool KHTMLPart::metaRefreshEnabled() const 1181 { 1182 return d->m_metaRefreshEnabled; 1183 } 1184 1185 KJSProxy *KHTMLPart::jScript() 1186 { 1187 if (!jScriptEnabled()) { 1188 return nullptr; 1189 } 1190 1191 if (!d->m_frame) { 1192 KHTMLPart *p = parentPart(); 1193 if (!p) { 1194 d->m_frame = new khtml::ChildFrame; 1195 d->m_frame->m_part = this; 1196 } else { 1197 ConstFrameIt it = p->d->m_frames.constBegin(); 1198 const ConstFrameIt end = p->d->m_frames.constEnd(); 1199 for (; it != end; ++it) 1200 if ((*it)->m_part.data() == this) { 1201 d->m_frame = *it; 1202 break; 1203 } 1204 } 1205 if (!d->m_frame) { 1206 return nullptr; 1207 } 1208 } 1209 if (!d->m_frame->m_jscript) { 1210 d->m_frame->m_jscript = new KJSProxy(d->m_frame); 1211 } 1212 d->m_frame->m_jscript->setDebugEnabled(d->m_bJScriptDebugEnabled); 1213 1214 return d->m_frame->m_jscript; 1215 } 1216 1217 QVariant KHTMLPart::crossFrameExecuteScript(const QString &target, const QString &script) 1218 { 1219 KHTMLPart *destpart = this; 1220 1221 QString trg = target.toLower(); 1222 1223 if (target == "_top") { 1224 while (destpart->parentPart()) { 1225 destpart = destpart->parentPart(); 1226 } 1227 } else if (target == "_parent") { 1228 if (parentPart()) { 1229 destpart = parentPart(); 1230 } 1231 } else if (target == "_self" || target == "_blank") { 1232 // we always allow these 1233 } else { 1234 destpart = findFrame(target); 1235 if (!destpart) { 1236 destpart = this; 1237 } 1238 } 1239 1240 // easy way out? 1241 if (destpart == this) { 1242 return executeScript(DOM::Node(), script); 1243 } 1244 1245 // now compare the domains 1246 if (destpart->checkFrameAccess(this)) { 1247 return destpart->executeScript(DOM::Node(), script); 1248 } 1249 1250 // eww, something went wrong. better execute it in our frame 1251 return executeScript(DOM::Node(), script); 1252 } 1253 1254 //Enable this to see all JS scripts being executed 1255 //#define KJS_VERBOSE 1256 1257 KJSErrorDlg *KHTMLPart::jsErrorExtension() 1258 { 1259 if (!d->m_settings->jsErrorsEnabled()) { 1260 return nullptr; 1261 } 1262 1263 if (parentPart()) { 1264 return parentPart()->jsErrorExtension(); 1265 } 1266 1267 if (!d->m_statusBarJSErrorLabel) { 1268 d->m_statusBarJSErrorLabel = new KUrlLabel(d->m_statusBarExtension->statusBar()); 1269 d->m_statusBarJSErrorLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); 1270 d->m_statusBarJSErrorLabel->setUseCursor(false); 1271 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarJSErrorLabel, 0, false); 1272 d->m_statusBarJSErrorLabel->setToolTip(i18n("This web page contains coding errors.")); 1273 d->m_statusBarJSErrorLabel->setPixmap(SmallIcon("script-error")); 1274 connect(d->m_statusBarJSErrorLabel, SIGNAL(leftClickedUrl()), SLOT(launchJSErrorDialog())); 1275 connect(d->m_statusBarJSErrorLabel, SIGNAL(rightClickedUrl()), SLOT(jsErrorDialogContextMenu())); 1276 } 1277 if (!d->m_jsedlg) { 1278 d->m_jsedlg = new KJSErrorDlg; 1279 d->m_jsedlg->setURL(url().toDisplayString()); 1280 } 1281 return d->m_jsedlg; 1282 } 1283 1284 void KHTMLPart::removeJSErrorExtension() 1285 { 1286 if (parentPart()) { 1287 parentPart()->removeJSErrorExtension(); 1288 return; 1289 } 1290 if (d->m_statusBarJSErrorLabel != nullptr) { 1291 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarJSErrorLabel); 1292 delete d->m_statusBarJSErrorLabel; 1293 d->m_statusBarJSErrorLabel = nullptr; 1294 } 1295 delete d->m_jsedlg; 1296 d->m_jsedlg = nullptr; 1297 } 1298 1299 void KHTMLPart::disableJSErrorExtension() 1300 { 1301 removeJSErrorExtension(); 1302 // These two lines are really kind of hacky, and it sucks to do this inside 1303 // KHTML but I don't know of anything that's reasonably easy as an alternative 1304 // right now. It makes me wonder if there should be a more clean way to 1305 // contact all running "KHTML" instance as opposed to Konqueror instances too. 1306 d->m_settings->setJSErrorsEnabled(false); 1307 emit configurationChanged(); 1308 } 1309 1310 void KHTMLPart::jsErrorDialogContextMenu() 1311 { 1312 QMenu *m = new QMenu(nullptr); 1313 m->addAction(i18n("&Hide Errors"), this, SLOT(removeJSErrorExtension())); 1314 m->addAction(i18n("&Disable Error Reporting"), this, SLOT(disableJSErrorExtension())); 1315 m->popup(QCursor::pos()); 1316 } 1317 1318 void KHTMLPart::launchJSErrorDialog() 1319 { 1320 KJSErrorDlg *dlg = jsErrorExtension(); 1321 if (dlg) { 1322 dlg->show(); 1323 dlg->raise(); 1324 } 1325 } 1326 1327 void KHTMLPart::launchJSConfigDialog() 1328 { 1329 QStringList args; 1330 args << "khtml_java_js"; 1331 KToolInvocation::kdeinitExec("kcmshell5", args); 1332 } 1333 1334 QVariant KHTMLPart::executeScript(const QString &filename, int baseLine, const DOM::Node &n, const QString &script) 1335 { 1336 #ifdef KJS_VERBOSE 1337 // The script is now printed by KJS's Parser::parse 1338 qCDebug(KHTML_LOG) << "executeScript: caller='" << objectName() << "' filename=" << filename << " baseLine=" << baseLine /*<< " script=" << script*/; 1339 #endif 1340 KJSProxy *proxy = jScript(); 1341 1342 if (!proxy || proxy->paused()) { 1343 return QVariant(); 1344 } 1345 1346 KJS::Completion comp; 1347 QVariant ret = proxy->evaluate(filename, baseLine, script, n, &comp); 1348 1349 /* 1350 * Error handling 1351 */ 1352 if (comp.complType() == KJS::Throw && comp.value()) { 1353 KJSErrorDlg *dlg = jsErrorExtension(); 1354 if (dlg) { 1355 QString msg = KJS::exceptionToString( 1356 proxy->interpreter()->globalExec(), comp.value()); 1357 dlg->addError(i18n("<qt><b>Error</b>: %1: %2</qt>", 1358 filename.toHtmlEscaped(), msg.toHtmlEscaped())); 1359 } 1360 } 1361 1362 // Handle immediate redirects now (e.g. location='foo') 1363 if (!d->m_redirectURL.isEmpty() && d->m_delayRedirect == -1) { 1364 // qCDebug(KHTML_LOG) << "executeScript done, handling immediate redirection NOW"; 1365 // Must abort tokenizer, no further script must execute. 1366 khtml::Tokenizer *t = d->m_doc->tokenizer(); 1367 if (t) { 1368 t->abort(); 1369 } 1370 d->m_redirectionTimer.setSingleShot(true); 1371 d->m_redirectionTimer.start(0); 1372 } 1373 1374 return ret; 1375 } 1376 1377 QVariant KHTMLPart::executeScript(const QString &script) 1378 { 1379 return executeScript(DOM::Node(), script); 1380 } 1381 1382 QVariant KHTMLPart::executeScript(const DOM::Node &n, const QString &script) 1383 { 1384 #ifdef KJS_VERBOSE 1385 qCDebug(KHTML_LOG) << "caller=" << objectName() << "node=" << n.nodeName().string().toLatin1().constData() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " /* << script */; 1386 #endif 1387 KJSProxy *proxy = jScript(); 1388 1389 if (!proxy || proxy->paused()) { 1390 return QVariant(); 1391 } 1392 1393 ++(d->m_runningScripts); 1394 KJS::Completion comp; 1395 const QVariant ret = proxy->evaluate(QString(), 1, script, n, &comp); 1396 --(d->m_runningScripts); 1397 1398 /* 1399 * Error handling 1400 */ 1401 if (comp.complType() == KJS::Throw && comp.value()) { 1402 KJSErrorDlg *dlg = jsErrorExtension(); 1403 if (dlg) { 1404 QString msg = KJS::exceptionToString( 1405 proxy->interpreter()->globalExec(), comp.value()); 1406 dlg->addError(i18n("<qt><b>Error</b>: node %1: %2</qt>", 1407 n.nodeName().string(), msg.toHtmlEscaped())); 1408 } 1409 } 1410 1411 if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm) { 1412 submitFormAgain(); 1413 } 1414 1415 #ifdef KJS_VERBOSE 1416 qCDebug(KHTML_LOG) << "done"; 1417 #endif 1418 return ret; 1419 } 1420 1421 void KHTMLPart::setJavaEnabled(bool enable) 1422 { 1423 d->m_bJavaForce = enable; 1424 d->m_bJavaOverride = true; 1425 } 1426 1427 bool KHTMLPart::javaEnabled() const 1428 { 1429 if (onlyLocalReferences()) { 1430 return false; 1431 } 1432 1433 if (d->m_bJavaOverride) { 1434 return d->m_bJavaForce; 1435 } 1436 return d->m_bJavaEnabled; 1437 } 1438 1439 void KHTMLPart::setPluginsEnabled(bool enable) 1440 { 1441 d->m_bPluginsForce = enable; 1442 d->m_bPluginsOverride = true; 1443 } 1444 1445 bool KHTMLPart::pluginsEnabled() const 1446 { 1447 if (onlyLocalReferences()) { 1448 return false; 1449 } 1450 1451 if (d->m_bPluginsOverride) { 1452 return d->m_bPluginsForce; 1453 } 1454 return d->m_bPluginsEnabled; 1455 } 1456 1457 static int s_DOMTreeIndentLevel = 0; 1458 1459 void KHTMLPart::slotDebugDOMTree() 1460 { 1461 if (d->m_doc) { 1462 qDebug("%s", d->m_doc->toString().string().toLatin1().constData()); 1463 } 1464 1465 // Now print the contents of the frames that contain HTML 1466 1467 const int indentLevel = s_DOMTreeIndentLevel++; 1468 1469 ConstFrameIt it = d->m_frames.constBegin(); 1470 const ConstFrameIt end = d->m_frames.constEnd(); 1471 for (; it != end; ++it) 1472 if (!(*it)->m_part.isNull() && (*it)->m_part.data()->inherits("KHTMLPart")) { 1473 KParts::ReadOnlyPart *const p = (*it)->m_part.data(); 1474 // qCDebug(KHTML_LOG) << QString().leftJustified(s_DOMTreeIndentLevel*4,' ') << "FRAME " << p->objectName() << " "; 1475 static_cast<KHTMLPart *>(p)->slotDebugDOMTree(); 1476 } 1477 s_DOMTreeIndentLevel = indentLevel; 1478 } 1479 1480 void KHTMLPart::slotDebugScript() 1481 { 1482 if (jScript()) { 1483 jScript()->showDebugWindow(); 1484 } 1485 } 1486 1487 void KHTMLPart::slotDebugRenderTree() 1488 { 1489 #ifndef NDEBUG 1490 if (d->m_doc) { 1491 d->m_doc->renderer()->printTree(); 1492 // dump out the contents of the rendering & DOM trees 1493 // QString dumps; 1494 // QTextStream outputStream(&dumps,QIODevice::WriteOnly); 1495 // d->m_doc->renderer()->layer()->dump( outputStream ); 1496 // qCDebug(KHTML_LOG) << "dump output:" << "\n" + dumps; 1497 // d->m_doc->renderer()->printLineBoxTree(); 1498 } 1499 #endif 1500 } 1501 1502 void KHTMLPart::slotDebugFrameTree() 1503 { 1504 khtml::ChildFrame::dumpFrameTree(this); 1505 } 1506 1507 void KHTMLPart::slotStopAnimations() 1508 { 1509 stopAnimations(); 1510 } 1511 1512 void KHTMLPart::setAutoloadImages(bool enable) 1513 { 1514 if (d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable) { 1515 return; 1516 } 1517 1518 if (d->m_doc) { 1519 d->m_doc->docLoader()->setAutoloadImages(enable); 1520 } 1521 1522 unplugActionList("loadImages"); 1523 1524 if (enable) { 1525 delete d->m_paLoadImages; 1526 d->m_paLoadImages = nullptr; 1527 } else if (!d->m_paLoadImages) { 1528 d->m_paLoadImages = new QAction(i18n("Display Images on Page"), this); 1529 actionCollection()->addAction("loadImages", d->m_paLoadImages); 1530 d->m_paLoadImages->setIcon(QIcon::fromTheme("image-loading")); 1531 connect(d->m_paLoadImages, SIGNAL(triggered(bool)), this, SLOT(slotLoadImages())); 1532 } 1533 1534 if (d->m_paLoadImages) { 1535 QList<QAction *> lst; 1536 lst.append(d->m_paLoadImages); 1537 plugActionList("loadImages", lst); 1538 } 1539 } 1540 1541 bool KHTMLPart::autoloadImages() const 1542 { 1543 if (d->m_doc) { 1544 return d->m_doc->docLoader()->autoloadImages(); 1545 } 1546 1547 return true; 1548 } 1549 1550 void KHTMLPart::clear() 1551 { 1552 if (d->m_bCleared) { 1553 return; 1554 } 1555 1556 d->m_bCleared = true; 1557 1558 d->m_bClearing = true; 1559 1560 { 1561 ConstFrameIt it = d->m_frames.constBegin(); 1562 const ConstFrameIt end = d->m_frames.constEnd(); 1563 for (; it != end; ++it) { 1564 // Stop HTMLRun jobs for frames 1565 if ((*it)->m_run) { 1566 (*it)->m_run.data()->abort(); 1567 } 1568 } 1569 } 1570 1571 { 1572 ConstFrameIt it = d->m_objects.constBegin(); 1573 const ConstFrameIt end = d->m_objects.constEnd(); 1574 for (; it != end; ++it) { 1575 // Stop HTMLRun jobs for objects 1576 if ((*it)->m_run) { 1577 (*it)->m_run.data()->abort(); 1578 } 1579 } 1580 } 1581 1582 findTextBegin(); // resets d->m_findNode and d->m_findPos 1583 d->m_mousePressNode = DOM::Node(); 1584 1585 if (d->m_doc) { 1586 if (d->m_doc->attached()) { //the view may have detached it already 1587 d->m_doc->detach(); 1588 } 1589 } 1590 1591 // Moving past doc so that onUnload works. 1592 if (d->m_frame && d->m_frame->m_jscript) { 1593 d->m_frame->m_jscript->clear(); 1594 } 1595 1596 // stopping marquees 1597 if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->layer()) { 1598 d->m_doc->renderer()->layer()->suspendMarquees(); 1599 } 1600 1601 if (d->m_view) { 1602 d->m_view->clear(); 1603 } 1604 1605 // do not dereference the document before the jscript and view are cleared, as some destructors 1606 // might still try to access the document. 1607 if (d->m_doc) { 1608 d->m_doc->deref(); 1609 } 1610 d->m_doc = nullptr; 1611 1612 delete d->m_decoder; 1613 d->m_decoder = nullptr; 1614 1615 // We don't want to change between parts if we are going to delete all of them anyway 1616 if (partManager()) { 1617 disconnect(partManager(), SIGNAL(activePartChanged(KParts::Part*)), 1618 this, SLOT(slotActiveFrameChanged(KParts::Part*))); 1619 } 1620 1621 if (d->m_frames.count()) { 1622 const KHTMLFrameList frames = d->m_frames; 1623 d->m_frames.clear(); 1624 ConstFrameIt it = frames.begin(); 1625 const ConstFrameIt end = frames.end(); 1626 for (; it != end; ++it) { 1627 if ((*it)->m_part) { 1628 partManager()->removePart((*it)->m_part.data()); 1629 delete(*it)->m_part.data(); 1630 } 1631 delete *it; 1632 } 1633 } 1634 d->m_suppressedPopupOriginParts.clear(); 1635 1636 if (d->m_objects.count()) { 1637 KHTMLFrameList objects = d->m_objects; 1638 d->m_objects.clear(); 1639 ConstFrameIt oi = objects.constBegin(); 1640 const ConstFrameIt oiEnd = objects.constEnd(); 1641 1642 for (; oi != oiEnd; ++oi) { 1643 delete(*oi)->m_part.data(); 1644 delete *oi; 1645 } 1646 } 1647 1648 // Listen to part changes again 1649 if (partManager()) { 1650 connect(partManager(), SIGNAL(activePartChanged(KParts::Part*)), 1651 this, SLOT(slotActiveFrameChanged(KParts::Part*))); 1652 } 1653 1654 d->clearRedirection(); 1655 d->m_redirectLockHistory = true; 1656 d->m_bClearing = false; 1657 d->m_frameNameId = 1; 1658 d->m_bFirstData = true; 1659 1660 d->m_bMousePressed = false; 1661 1662 if (d->editor_context.m_caretBlinkTimer >= 0) { 1663 killTimer(d->editor_context.m_caretBlinkTimer); 1664 } 1665 d->editor_context.reset(); 1666 #ifndef QT_NO_CLIPBOARD 1667 connect(qApp->clipboard(), SIGNAL(selectionChanged()), SLOT(slotClearSelection())); 1668 #endif 1669 1670 d->m_jobPercent = 0; 1671 1672 if (!d->m_haveEncoding) { 1673 d->m_encoding.clear(); 1674 } 1675 1676 d->m_DNSPrefetchQueue.clear(); 1677 if (d->m_DNSPrefetchTimer > 0) { 1678 killTimer(d->m_DNSPrefetchTimer); 1679 } 1680 d->m_DNSPrefetchTimer = -1; 1681 d->m_lookedupHosts.clear(); 1682 if (d->m_DNSTTLTimer > 0) { 1683 killTimer(d->m_DNSTTLTimer); 1684 } 1685 d->m_DNSTTLTimer = -1; 1686 d->m_numDNSPrefetchedNames = 0; 1687 1688 #ifdef SPEED_DEBUG 1689 d->m_parsetime.restart(); 1690 #endif 1691 } 1692 1693 bool KHTMLPart::openFile() 1694 { 1695 return true; 1696 } 1697 1698 DOM::HTMLDocumentImpl *KHTMLPart::docImpl() const 1699 { 1700 if (d && d->m_doc && d->m_doc->isHTMLDocument()) { 1701 return static_cast<HTMLDocumentImpl *>(d->m_doc); 1702 } 1703 return nullptr; 1704 } 1705 1706 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const 1707 { 1708 if (d) { 1709 return d->m_doc; 1710 } 1711 return nullptr; 1712 } 1713 1714 void KHTMLPart::slotInfoMessage(KJob *kio_job, const QString &msg) 1715 { 1716 assert(d->m_job == kio_job); 1717 Q_ASSERT(kio_job); 1718 Q_UNUSED(kio_job); 1719 1720 if (!parentPart()) { 1721 setStatusBarText(msg, BarDefaultText); 1722 } 1723 } 1724 1725 void KHTMLPart::setPageSecurity(PageSecurity sec) 1726 { 1727 emit d->m_extension->setPageSecurity(sec); 1728 } 1729 1730 void KHTMLPart::slotData(KIO::Job *kio_job, const QByteArray &data) 1731 { 1732 assert(d->m_job == kio_job); 1733 Q_ASSERT(kio_job); 1734 Q_UNUSED(kio_job); 1735 1736 //qCDebug(KHTML_LOG) << "slotData: " << data.size(); 1737 // The first data ? 1738 if (!d->m_workingURL.isEmpty()) { 1739 //qCDebug(KHTML_LOG) << "begin!"; 1740 1741 // We must suspend KIO while we're inside begin() because it can cause 1742 // crashes if a window (such as kjsdebugger) goes back into the event loop, 1743 // more data arrives, and begin() gets called again (re-entered). 1744 d->m_job->suspend(); 1745 begin(d->m_workingURL, arguments().xOffset(), arguments().yOffset()); 1746 d->m_job->resume(); 1747 1748 // CC_Refresh means : always send the server an If-Modified-Since conditional request. 1749 // This is the default cache setting and correspond to the KCM's "Keep cache in sync". 1750 // CC_Verify means : only send a conditional request if the cache expiry date is passed. 1751 // It doesn't have a KCM setter. 1752 // We override the first to the second, except when doing a soft-reload. 1753 if (d->m_cachePolicy == KIO::CC_Refresh && !d->m_extension->browserArguments().softReload) { 1754 d->m_doc->docLoader()->setCachePolicy(KIO::CC_Verify); 1755 } else { 1756 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy); 1757 } 1758 1759 d->m_workingURL = QUrl(); 1760 1761 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry(); 1762 1763 // When the first data arrives, the metadata has just been made available 1764 d->m_httpHeaders = d->m_job->queryMetaData("HTTP-Headers"); 1765 QDateTime cacheCreationDate = QDateTime::fromTime_t(d->m_job->queryMetaData("cache-creation-date").toLong()); 1766 d->m_doc->docLoader()->setCacheCreationDate(cacheCreationDate); 1767 1768 d->m_pageServices = d->m_job->queryMetaData("PageServices"); 1769 d->m_pageReferrer = d->m_job->queryMetaData("referrer"); 1770 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE"); 1771 1772 { 1773 KHTMLPart *p = parentPart(); 1774 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) { 1775 while (p->parentPart()) { 1776 p = p->parentPart(); 1777 } 1778 1779 p->setPageSecurity(NotCrypted); 1780 } 1781 } 1782 1783 setPageSecurity(d->m_ssl_in_use ? Encrypted : NotCrypted); 1784 1785 // Shouldn't all of this be done only if ssl_in_use == true ? (DF) 1786 d->m_ssl_parent_ip = d->m_job->queryMetaData("ssl_parent_ip"); 1787 d->m_ssl_parent_cert = d->m_job->queryMetaData("ssl_parent_cert"); 1788 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain"); 1789 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip"); 1790 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher"); 1791 d->m_ssl_protocol_version = d->m_job->queryMetaData("ssl_protocol_version"); 1792 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits"); 1793 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits"); 1794 d->m_ssl_cert_errors = d->m_job->queryMetaData("ssl_cert_errors"); 1795 1796 // Check for charset meta-data 1797 QString qData = d->m_job->queryMetaData("charset"); 1798 if (!qData.isEmpty() && !d->m_haveEncoding) { // only use information if the user didn't override the settings 1799 d->m_encoding = qData; 1800 } 1801 1802 // Support for http-refresh 1803 qData = d->m_job->queryMetaData("http-refresh"); 1804 if (!qData.isEmpty()) { 1805 d->m_doc->processHttpEquiv("refresh", qData); 1806 } 1807 1808 // DISABLED: Support Content-Location per section 14.14 of RFC 2616. 1809 // See BR# 51185,BR# 82747 1810 /* 1811 QString baseURL = d->m_job->queryMetaData ("content-location"); 1812 if (!baseURL.isEmpty()) 1813 d->m_doc->setBaseURL(QUrl( d->m_doc->completeURL(baseURL) )); 1814 */ 1815 1816 // Support for Content-Language 1817 QString language = d->m_job->queryMetaData("content-language"); 1818 if (!language.isEmpty()) { 1819 d->m_doc->setContentLanguage(language); 1820 } 1821 1822 if (!url().isLocalFile()) { 1823 // Support for http last-modified 1824 d->m_lastModified = d->m_job->queryMetaData("modified"); 1825 } else { 1826 d->m_lastModified.clear(); // done on-demand by lastModified() 1827 } 1828 } 1829 1830 KHTMLPageCache::self()->addData(d->m_cacheId, data); 1831 write(data.data(), data.size()); 1832 } 1833 1834 void KHTMLPart::slotRestoreData(const QByteArray &data) 1835 { 1836 // The first data ? 1837 if (!d->m_workingURL.isEmpty()) { 1838 long saveCacheId = d->m_cacheId; 1839 QString savePageReferrer = d->m_pageReferrer; 1840 QString saveEncoding = d->m_encoding; 1841 begin(d->m_workingURL, arguments().xOffset(), arguments().yOffset()); 1842 d->m_encoding = saveEncoding; 1843 d->m_pageReferrer = savePageReferrer; 1844 d->m_cacheId = saveCacheId; 1845 d->m_workingURL = QUrl(); 1846 } 1847 1848 //qCDebug(KHTML_LOG) << data.size(); 1849 write(data.data(), data.size()); 1850 1851 if (data.size() == 0) { 1852 //qCDebug(KHTML_LOG) << "<<end of data>>"; 1853 // End of data. 1854 if (d->m_doc && d->m_doc->parsing()) { 1855 end(); //will emit completed() 1856 } 1857 } 1858 } 1859 1860 void KHTMLPart::showError(KJob *job) 1861 { 1862 // qCDebug(KHTML_LOG) << "d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete 1863 // << " d->m_bCleared=" << d->m_bCleared; 1864 1865 if (job->error() == KIO::ERR_NO_CONTENT) { 1866 return; 1867 } 1868 1869 if ((d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty()) { // if we got any data already 1870 job->uiDelegate()->showErrorMessage(); 1871 } else { 1872 htmlError(job->error(), job->errorText(), d->m_workingURL); 1873 } 1874 } 1875 1876 // This is a protected method, placed here because of it's relevance to showError 1877 void KHTMLPart::htmlError(int errorCode, const QString &text, const QUrl &reqUrl) 1878 { 1879 // qCDebug(KHTML_LOG) << "errorCode" << errorCode << "text" << text; 1880 // make sure we're not executing any embedded JS 1881 bool bJSFO = d->m_bJScriptForce; 1882 bool bJSOO = d->m_bJScriptOverride; 1883 d->m_bJScriptForce = false; 1884 d->m_bJScriptOverride = true; 1885 begin(); 1886 1887 QString errorName, techName, description; 1888 QStringList causes, solutions; 1889 1890 QByteArray raw = KIO::rawErrorDetail(errorCode, text, &reqUrl); 1891 QDataStream stream(raw); 1892 1893 stream >> errorName >> techName >> description >> causes >> solutions; 1894 1895 QString url, protocol, datetime; 1896 1897 // This is somewhat confusing, but we have to escape the externally- 1898 // controlled URL twice: once for i18n, and once for HTML. 1899 url = reqUrl.toDisplayString().toHtmlEscaped().toHtmlEscaped(); 1900 protocol = reqUrl.scheme(); 1901 datetime = QDateTime::currentDateTime().toString(Qt::DefaultLocaleLongDate); 1902 1903 QString filename(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/khtml/error.html")); 1904 QFile file(filename); 1905 bool isOpened = file.open(QIODevice::ReadOnly); 1906 if (!isOpened) { 1907 qCWarning(KHTML_LOG) << "Could not open error html template:" << filename; 1908 } 1909 1910 QString html = QString(QLatin1String(file.readAll())); 1911 1912 html.replace(QLatin1String("TITLE"), i18n("Error: %1 - %2", errorName, url)); 1913 html.replace(QLatin1String("DIRECTION"), QApplication::isRightToLeft() ? "rtl" : "ltr"); 1914 html.replace(QLatin1String("ICON_PATH"), QUrl::fromLocalFile(KIconLoader::global()->iconPath("dialog-warning", -KIconLoader::SizeHuge)).url()); 1915 1916 QString doc = QLatin1String("<h1>"); 1917 doc += i18n("The requested operation could not be completed"); 1918 doc += QLatin1String("</h1><h2>"); 1919 doc += errorName; 1920 doc += QLatin1String("</h2>"); 1921 if (!techName.isNull()) { 1922 doc += QLatin1String("<h2>"); 1923 doc += i18n("Technical Reason: "); 1924 doc += techName; 1925 doc += QLatin1String("</h2>"); 1926 } 1927 doc += QLatin1String("<br clear=\"all\">"); 1928 doc += QLatin1String("<h3>"); 1929 doc += i18n("Details of the Request:"); 1930 doc += QLatin1String("</h3><ul><li>"); 1931 doc += i18n("URL: %1", url); 1932 doc += QLatin1String("</li><li>"); 1933 if (!protocol.isNull()) { 1934 doc += i18n("Protocol: %1", protocol); 1935 doc += QLatin1String("</li><li>"); 1936 } 1937 doc += i18n("Date and Time: %1", datetime); 1938 doc += QLatin1String("</li><li>"); 1939 doc += i18n("Additional Information: %1", text); 1940 doc += QLatin1String("</li></ul><h3>"); 1941 doc += i18n("Description:"); 1942 doc += QLatin1String("</h3><p>"); 1943 doc += description; 1944 doc += QLatin1String("</p>"); 1945 if (causes.count()) { 1946 doc += QLatin1String("<h3>"); 1947 doc += i18n("Possible Causes:"); 1948 doc += QLatin1String("</h3><ul><li>"); 1949 doc += causes.join("</li><li>"); 1950 doc += QLatin1String("</li></ul>"); 1951 } 1952 if (solutions.count()) { 1953 doc += QLatin1String("<h3>"); 1954 doc += i18n("Possible Solutions:"); 1955 doc += QLatin1String("</h3><ul><li>"); 1956 doc += solutions.join("</li><li>"); 1957 doc += QLatin1String("</li></ul>"); 1958 } 1959 1960 html.replace(QLatin1String("TEXT"), doc); 1961 1962 write(html); 1963 end(); 1964 1965 d->m_bJScriptForce = bJSFO; 1966 d->m_bJScriptOverride = bJSOO; 1967 1968 // make the working url the current url, so that reload works and 1969 // emit the progress signals to advance one step in the history 1970 // (so that 'back' works) 1971 setUrl(reqUrl); // same as d->m_workingURL 1972 d->m_workingURL = QUrl(); 1973 emit started(nullptr); 1974 emit completed(); 1975 } 1976 1977 void KHTMLPart::slotFinished(KJob *job) 1978 { 1979 d->m_job = nullptr; 1980 d->m_jobspeed = 0L; 1981 1982 if (job->error()) { 1983 KHTMLPageCache::self()->cancelEntry(d->m_cacheId); 1984 1985 // The following catches errors that occur as a result of HTTP 1986 // to FTP redirections where the FTP URL is a directory. Since 1987 // KIO cannot change a redirection request from GET to LISTDIR, 1988 // we have to take care of it here once we know for sure it is 1989 // a directory... 1990 if (job->error() == KIO::ERR_IS_DIRECTORY) { 1991 emit canceled(job->errorString()); 1992 emit d->m_extension->openUrlRequest(d->m_workingURL); 1993 } else { 1994 emit canceled(job->errorString()); 1995 // TODO: what else ? 1996 checkCompleted(); 1997 showError(job); 1998 } 1999 2000 return; 2001 } 2002 KIO::TransferJob *tjob = ::qobject_cast<KIO::TransferJob *>(job); 2003 if (tjob && tjob->isErrorPage()) { 2004 HTMLPartContainerElementImpl *elt = d->m_frame ? 2005 d->m_frame->m_partContainerElement.data() : nullptr; 2006 2007 if (!elt) { 2008 return; 2009 } 2010 2011 elt->partLoadingErrorNotify(); 2012 checkCompleted(); 2013 if (d->m_bComplete) { 2014 return; 2015 } 2016 } 2017 2018 //qCDebug(KHTML_LOG) << "slotFinished"; 2019 2020 KHTMLPageCache::self()->endData(d->m_cacheId); 2021 2022 if (d->m_doc && d->m_doc->docLoader()->expireDate().isValid() && url().scheme().startsWith("http")) { 2023 KIO::http_update_cache(url(), false, d->m_doc->docLoader()->expireDate()); 2024 } 2025 2026 d->m_workingURL = QUrl(); 2027 2028 if (d->m_doc && d->m_doc->parsing()) { 2029 end(); //will emit completed() 2030 } 2031 } 2032 2033 MimeType KHTMLPartPrivate::classifyMimeType(const QString &mimeStr) 2034 { 2035 // See HTML5's "5.5.1 Navigating across documents" section. 2036 if (mimeStr == "application/xhtml+xml") { 2037 return MimeXHTML; 2038 } 2039 if (mimeStr == "image/svg+xml") { 2040 return MimeSVG; 2041 } 2042 if (mimeStr == "text/html" || mimeStr.isEmpty()) { 2043 return MimeHTML; 2044 } 2045 2046 QMimeDatabase db; 2047 QMimeType mime = db.mimeTypeForName(mimeStr); 2048 if (mime.inherits("text/xml") || mimeStr.endsWith("+xml")) { 2049 return MimeXML; 2050 } 2051 2052 if (mime.inherits("text/plain")) { 2053 return MimeText; 2054 } 2055 2056 if (khtmlImLoad::ImageManager::loaderDatabase()->supportedMimeTypes().contains(mimeStr)) { 2057 return MimeImage; 2058 } 2059 2060 // Sometimes our subclasses like to handle custom mimetypes. In that case, 2061 // we want to handle them as HTML. We do that in the following cases: 2062 // 1) We're at top-level, so we were forced to open something 2063 // 2) We're an object --- this again means we were forced to open something, 2064 // as an iframe-generating-an-embed case would have us as an iframe 2065 if (!q->parentPart() || (m_frame && m_frame->m_type == khtml::ChildFrame::Object)) { 2066 return MimeHTML; 2067 } 2068 2069 return MimeOther; 2070 } 2071 2072 void KHTMLPart::begin(const QUrl &url, int xOffset, int yOffset) 2073 { 2074 if (d->m_view->underMouse()) { 2075 QToolTip::hideText(); // in case a previous tooltip is still shown 2076 } 2077 2078 // No need to show this for a new page until an error is triggered 2079 if (!parentPart()) { 2080 removeJSErrorExtension(); 2081 setSuppressedPopupIndicator(false); 2082 d->m_openableSuppressedPopups = 0; 2083 foreach (KHTMLPart *part, d->m_suppressedPopupOriginParts) { 2084 if (part) { 2085 KJS::Window *w = KJS::Window::retrieveWindow(part); 2086 if (w) { 2087 w->forgetSuppressedWindows(); 2088 } 2089 } 2090 } 2091 } 2092 2093 d->m_bCleared = false; 2094 d->m_cacheId = 0; 2095 d->m_bComplete = false; 2096 d->m_bLoadEventEmitted = false; 2097 clear(); 2098 d->m_bCleared = false; 2099 2100 if (url.isValid()) { 2101 QString urlString = url.toString(); 2102 KHTMLGlobal::vLinks()->insert(urlString); 2103 QString urlString2 = url.toDisplayString(); 2104 if (urlString != urlString2) { 2105 KHTMLGlobal::vLinks()->insert(urlString2); 2106 } 2107 } 2108 2109 // ### 2110 //stopParser(); 2111 2112 KParts::OpenUrlArguments args = arguments(); 2113 args.setXOffset(xOffset); 2114 args.setYOffset(yOffset); 2115 setArguments(args); 2116 2117 d->m_pageReferrer.clear(); 2118 2119 d->m_referrer = url.scheme().startsWith("http") ? url.toString() : ""; 2120 2121 setUrl(url); 2122 2123 // Note: by now, any special mimetype besides plaintext would have been 2124 // handled specially inside openURL, so we handle their cases the same 2125 // as HTML. 2126 MimeType type = d->classifyMimeType(args.mimeType()); 2127 switch (type) { 2128 case MimeSVG: 2129 d->m_doc = DOMImplementationImpl::createSVGDocument(d->m_view); 2130 break; 2131 case MimeXML: // any XML derivative, except XHTML or SVG 2132 // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl 2133 d->m_doc = DOMImplementationImpl::createXMLDocument(d->m_view); 2134 break; 2135 case MimeText: 2136 d->m_doc = new HTMLTextDocumentImpl(d->m_view); 2137 break; 2138 case MimeXHTML: 2139 case MimeHTML: 2140 default: 2141 d->m_doc = DOMImplementationImpl::createHTMLDocument(d->m_view); 2142 // HTML or XHTML? (#86446) 2143 static_cast<HTMLDocumentImpl *>(d->m_doc)->setHTMLRequested(type != MimeXHTML); 2144 } 2145 2146 d->m_doc->ref(); 2147 d->m_doc->setURL(url.toString()); 2148 d->m_doc->open(); 2149 if (!d->m_doc->attached()) { 2150 d->m_doc->attach(); 2151 } 2152 d->m_doc->setBaseURL(QUrl()); 2153 d->m_doc->docLoader()->setShowAnimations(KHTMLGlobal::defaultHTMLSettings()->showAnimations()); 2154 emit docCreated(); 2155 2156 d->m_paUseStylesheet->setItems(QStringList()); 2157 d->m_paUseStylesheet->setEnabled(false); 2158 2159 setAutoloadImages(KHTMLGlobal::defaultHTMLSettings()->autoLoadImages()); 2160 QString userStyleSheet = KHTMLGlobal::defaultHTMLSettings()->userStyleSheet(); 2161 if (!userStyleSheet.isEmpty()) { 2162 setUserStyleSheet(QUrl(userStyleSheet)); 2163 } 2164 2165 d->m_doc->setRestoreState(d->m_extension->browserArguments().docState); 2166 connect(d->m_doc, SIGNAL(finishedParsing()), this, SLOT(slotFinishedParsing())); 2167 2168 emit d->m_extension->enableAction("print", true); 2169 2170 d->m_doc->setParsing(true); 2171 } 2172 2173 void KHTMLPart::write(const char *data, int len) 2174 { 2175 if (!d->m_decoder) { 2176 d->m_decoder = createDecoder(); 2177 } 2178 2179 if (len == -1) { 2180 len = strlen(data); 2181 } 2182 2183 if (len == 0) { 2184 return; 2185 } 2186 2187 QString decoded = d->m_decoder->decodeWithBuffering(data, len); 2188 2189 if (decoded.isEmpty()) { 2190 return; 2191 } 2192 2193 if (d->m_bFirstData) { 2194 onFirstData(); 2195 } 2196 2197 khtml::Tokenizer *t = d->m_doc->tokenizer(); 2198 if (t) { 2199 t->write(decoded, true); 2200 } 2201 } 2202 2203 // ### KDE5: remove 2204 void KHTMLPart::setAlwaysHonourDoctype(bool b) 2205 { 2206 d->m_bStrictModeQuirk = !b; 2207 } 2208 2209 void KHTMLPart::write(const QString &str) 2210 { 2211 if (str.isNull()) { 2212 return; 2213 } 2214 2215 if (d->m_bFirstData) { 2216 // determine the parse mode 2217 if (d->m_bStrictModeQuirk) { 2218 d->m_doc->setParseMode(DocumentImpl::Strict); 2219 d->m_bFirstData = false; 2220 } else { 2221 onFirstData(); 2222 } 2223 } 2224 khtml::Tokenizer *t = d->m_doc->tokenizer(); 2225 if (t) { 2226 t->write(str, true); 2227 } 2228 } 2229 2230 void KHTMLPart::end() 2231 { 2232 if (d->m_doc) { 2233 if (d->m_decoder) { 2234 QString decoded = d->m_decoder->flush(); 2235 if (d->m_bFirstData) { 2236 onFirstData(); 2237 } 2238 if (!decoded.isEmpty()) { 2239 write(decoded); 2240 } 2241 } 2242 d->m_doc->finishParsing(); 2243 } 2244 } 2245 2246 void KHTMLPart::onFirstData() 2247 { 2248 assert(d->m_bFirstData); 2249 2250 // determine the parse mode 2251 d->m_doc->determineParseMode(); 2252 d->m_bFirstData = false; 2253 2254 // ### this is still quite hacky, but should work a lot better than the old solution 2255 // Note: decoder may be null if only write(QString) is used. 2256 if (d->m_decoder && d->m_decoder->visuallyOrdered()) { 2257 d->m_doc->setVisuallyOrdered(); 2258 } 2259 // ensure part and view shares zoom-level before styling 2260 updateZoomFactor(); 2261 d->m_doc->recalcStyle(NodeImpl::Force); 2262 } 2263 2264 bool KHTMLPart::doOpenStream(const QString &mimeType) 2265 { 2266 QMimeDatabase db; 2267 QMimeType mime = db.mimeTypeForName(mimeType); 2268 if (mime.inherits("text/html") || mime.inherits("text/xml")) { 2269 begin(url()); 2270 return true; 2271 } 2272 return false; 2273 } 2274 2275 bool KHTMLPart::doWriteStream(const QByteArray &data) 2276 { 2277 write(data.data(), data.size()); 2278 return true; 2279 } 2280 2281 bool KHTMLPart::doCloseStream() 2282 { 2283 end(); 2284 return true; 2285 } 2286 2287 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more) 2288 { 2289 if (!d->m_view) { 2290 return; 2291 } 2292 d->m_view->paint(p, rc, yOff, more); 2293 } 2294 2295 void KHTMLPart::stopAnimations() 2296 { 2297 if (d->m_doc) { 2298 d->m_doc->docLoader()->setShowAnimations(KHTMLSettings::KAnimationDisabled); 2299 } 2300 2301 ConstFrameIt it = d->m_frames.constBegin(); 2302 const ConstFrameIt end = d->m_frames.constEnd(); 2303 for (; it != end; ++it) { 2304 if (KHTMLPart *p = qobject_cast<KHTMLPart *>((*it)->m_part.data())) { 2305 p->stopAnimations(); 2306 } 2307 } 2308 } 2309 2310 void KHTMLPart::resetFromScript() 2311 { 2312 closeUrl(); 2313 d->m_bComplete = false; 2314 d->m_bLoadEventEmitted = false; 2315 disconnect(d->m_doc, SIGNAL(finishedParsing()), this, SLOT(slotFinishedParsing())); 2316 connect(d->m_doc, SIGNAL(finishedParsing()), this, SLOT(slotFinishedParsing())); 2317 d->m_doc->setParsing(true); 2318 2319 emit started(nullptr); 2320 } 2321 2322 void KHTMLPart::slotFinishedParsing() 2323 { 2324 d->m_doc->setParsing(false); 2325 d->m_doc->dispatchHTMLEvent(EventImpl::KHTML_CONTENTLOADED_EVENT, true, false); 2326 checkEmitLoadEvent(); 2327 disconnect(d->m_doc, SIGNAL(finishedParsing()), this, SLOT(slotFinishedParsing())); 2328 2329 if (!d->m_view) { 2330 return; // We are probably being destructed. 2331 } 2332 2333 checkCompleted(); 2334 } 2335 2336 void KHTMLPart::slotLoaderRequestStarted(khtml::DocLoader *dl, khtml::CachedObject *obj) 2337 { 2338 if (obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl) { 2339 KHTMLPart *p = this; 2340 while (p) { 2341 KHTMLPart *const op = p; 2342 ++(p->d->m_totalObjectCount); 2343 p = p->parentPart(); 2344 if (!p && op->d->m_loadedObjects <= op->d->m_totalObjectCount 2345 && !op->d->m_progressUpdateTimer.isActive()) { 2346 op->d->m_progressUpdateTimer.setSingleShot(true); 2347 op->d->m_progressUpdateTimer.start(200); 2348 } 2349 } 2350 } 2351 } 2352 2353 static bool isAncestorOrSamePart(KHTMLPart *p1, KHTMLPart *p2) 2354 { 2355 KHTMLPart *p = p2; 2356 do { 2357 if (p == p1) { 2358 return true; 2359 } 2360 } while ((p = p->parentPart())); 2361 return false; 2362 } 2363 2364 void KHTMLPart::slotLoaderRequestDone(khtml::DocLoader *dl, khtml::CachedObject *obj) 2365 { 2366 if (obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl) { 2367 KHTMLPart *p = this; 2368 while (p) { 2369 KHTMLPart *const op = p; 2370 ++(p->d->m_loadedObjects); 2371 p = p->parentPart(); 2372 if (!p && op->d->m_loadedObjects <= op->d->m_totalObjectCount && op->d->m_jobPercent <= 100 2373 && !op->d->m_progressUpdateTimer.isActive()) { 2374 op->d->m_progressUpdateTimer.setSingleShot(true); 2375 op->d->m_progressUpdateTimer.start(200); 2376 } 2377 } 2378 } 2379 /// if we have no document, or the object is not a request of one of our children, 2380 // then our loading state can't possibly be affected : don't waste time checking for completion. 2381 if (!d->m_doc || !dl->doc()->part() || !isAncestorOrSamePart(this, dl->doc()->part())) { 2382 return; 2383 } 2384 checkCompleted(); 2385 } 2386 2387 void KHTMLPart::slotProgressUpdate() 2388 { 2389 int percent; 2390 if (d->m_loadedObjects < d->m_totalObjectCount) { 2391 percent = d->m_jobPercent / 4 + (d->m_loadedObjects * 300) / (4 * d->m_totalObjectCount); 2392 } else { 2393 percent = d->m_jobPercent; 2394 } 2395 2396 if (d->m_bComplete) { 2397 percent = 100; 2398 } 2399 2400 if (d->m_statusMessagesEnabled) { 2401 if (d->m_bComplete) { 2402 emit d->m_extension->infoMessage(i18n("Page loaded.")); 2403 } else if (d->m_loadedObjects < d->m_totalObjectCount && percent >= 75) { 2404 emit d->m_extension->infoMessage(i18np("%1 Image of %2 loaded.", "%1 Images of %2 loaded.", d->m_loadedObjects, d->m_totalObjectCount)); 2405 } 2406 } 2407 2408 emit d->m_extension->loadingProgress(percent); 2409 } 2410 2411 void KHTMLPart::slotJobSpeed(KJob * /*job*/, unsigned long speed) 2412 { 2413 d->m_jobspeed = speed; 2414 if (!parentPart()) { 2415 setStatusBarText(jsStatusBarText(), BarOverrideText); 2416 } 2417 } 2418 2419 void KHTMLPart::slotJobPercent(KJob * /*job*/, unsigned long percent) 2420 { 2421 d->m_jobPercent = percent; 2422 2423 if (!parentPart()) { 2424 d->m_progressUpdateTimer.setSingleShot(true); 2425 d->m_progressUpdateTimer.start(0); 2426 } 2427 } 2428 2429 void KHTMLPart::slotJobDone(KJob * /*job*/) 2430 { 2431 d->m_jobPercent = 100; 2432 2433 if (!parentPart()) { 2434 d->m_progressUpdateTimer.setSingleShot(true); 2435 d->m_progressUpdateTimer.start(0); 2436 } 2437 } 2438 2439 void KHTMLPart::slotUserSheetStatDone(KJob *_job) 2440 { 2441 using namespace KIO; 2442 2443 if (_job->error()) { 2444 showError(_job); 2445 return; 2446 } 2447 2448 const UDSEntry entry = dynamic_cast<KIO::StatJob *>(_job)->statResult(); 2449 const QDateTime lastModified = QDateTime::fromTime_t(entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1)); 2450 2451 // If the filesystem supports modification times, only reload the 2452 // user-defined stylesheet if necessary - otherwise always reload. 2453 if (lastModified.isValid()) { 2454 if (d->m_userStyleSheetLastModified >= lastModified) { 2455 return; 2456 } 2457 d->m_userStyleSheetLastModified = lastModified; 2458 } 2459 2460 setUserStyleSheet(QUrl(settings()->userStyleSheet())); 2461 } 2462 2463 bool KHTMLPartPrivate::isFullyLoaded(bool *pendingRedirections) const 2464 { 2465 *pendingRedirections = false; 2466 2467 // Any frame that hasn't completed yet ? 2468 ConstFrameIt it = m_frames.constBegin(); 2469 const ConstFrameIt end = m_frames.constEnd(); 2470 for (; it != end; ++it) { 2471 if (!(*it)->m_bCompleted || (*it)->m_run) { 2472 //qCDebug(KHTML_LOG) << this << " is waiting for " << (*it)->m_part; 2473 return false; 2474 } 2475 // Check for frames with pending redirections 2476 if ((*it)->m_bPendingRedirection) { 2477 *pendingRedirections = true; 2478 } 2479 } 2480 2481 // Any object that hasn't completed yet ? 2482 { 2483 ConstFrameIt oi = m_objects.constBegin(); 2484 const ConstFrameIt oiEnd = m_objects.constEnd(); 2485 2486 for (; oi != oiEnd; ++oi) 2487 if (!(*oi)->m_bCompleted) { 2488 return false; 2489 } 2490 } 2491 2492 // Are we still parsing 2493 if (m_doc && m_doc->parsing()) { 2494 return false; 2495 } 2496 2497 // Still waiting for images/scripts from the loader ? 2498 int requests = 0; 2499 if (m_doc && m_doc->docLoader()) { 2500 requests = khtml::Cache::loader()->numRequests(m_doc->docLoader()); 2501 } 2502 2503 if (requests > 0) { 2504 //qCDebug(KHTML_LOG) << "still waiting for images/scripts from the loader - requests:" << requests; 2505 return false; 2506 } 2507 2508 return true; 2509 } 2510 2511 void KHTMLPart::checkCompleted() 2512 { 2513 // qCDebug(KHTML_LOG) << this; 2514 // qCDebug(KHTML_LOG) << " parsing: " << (d->m_doc && d->m_doc->parsing()); 2515 // qCDebug(KHTML_LOG) << " complete: " << d->m_bComplete; 2516 2517 // restore the cursor position 2518 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored) { 2519 if (d->m_focusNodeNumber >= 0) { 2520 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber)); 2521 } 2522 2523 d->m_focusNodeRestored = true; 2524 } 2525 2526 bool fullyLoaded, pendingChildRedirections; 2527 fullyLoaded = d->isFullyLoaded(&pendingChildRedirections); 2528 2529 // Are we still loading, or already have done the relevant work? 2530 if (!fullyLoaded || d->m_bComplete) { 2531 return; 2532 } 2533 2534 // OK, completed. 2535 // Now do what should be done when we are really completed. 2536 d->m_bComplete = true; 2537 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy 2538 d->m_totalObjectCount = 0; 2539 d->m_loadedObjects = 0; 2540 2541 KHTMLPart *p = this; 2542 while (p) { 2543 KHTMLPart *op = p; 2544 p = p->parentPart(); 2545 if (!p && !op->d->m_progressUpdateTimer.isActive()) { 2546 op->d->m_progressUpdateTimer.setSingleShot(true); 2547 op->d->m_progressUpdateTimer.start(0); 2548 } 2549 } 2550 2551 checkEmitLoadEvent(); // if we didn't do it before 2552 2553 bool pendingAction = false; 2554 2555 if (!d->m_redirectURL.isEmpty()) { 2556 // DA: Do not start redirection for frames here! That action is 2557 // deferred until the parent emits a completed signal. 2558 if (parentPart() == nullptr) { 2559 //qCDebug(KHTML_LOG) << this << " starting redirection timer"; 2560 d->m_redirectionTimer.setSingleShot(true); 2561 d->m_redirectionTimer.start(qMax(0, 1000 * d->m_delayRedirect)); 2562 } else { 2563 //qCDebug(KHTML_LOG) << this << " not toplevel -> not starting redirection timer. Waiting for slotParentCompleted."; 2564 } 2565 2566 pendingAction = true; 2567 } else if (pendingChildRedirections) { 2568 pendingAction = true; 2569 } 2570 2571 // the view will emit completed on our behalf, 2572 // either now or at next repaint if one is pending 2573 2574 //qCDebug(KHTML_LOG) << this << " asks the view to emit completed. pendingAction=" << pendingAction; 2575 d->m_view->complete(pendingAction); 2576 2577 // find the alternate stylesheets 2578 QStringList sheets; 2579 if (d->m_doc) { 2580 sheets = d->m_doc->availableStyleSheets(); 2581 } 2582 sheets.prepend(i18n("Automatic Detection")); 2583 d->m_paUseStylesheet->setItems(sheets); 2584 2585 d->m_paUseStylesheet->setEnabled(sheets.count() > 2); 2586 if (sheets.count() > 2) { 2587 d->m_paUseStylesheet->setCurrentItem(qMax(sheets.indexOf(d->m_sheetUsed), 0)); 2588 slotUseStylesheet(); 2589 } 2590 2591 setJSDefaultStatusBarText(QString()); 2592 2593 #ifdef SPEED_DEBUG 2594 if (!parentPart()) { 2595 qCDebug(KHTML_LOG) << "DONE:" << d->m_parsetime.elapsed(); 2596 } 2597 #endif 2598 } 2599 2600 void KHTMLPart::checkEmitLoadEvent() 2601 { 2602 bool fullyLoaded, pendingChildRedirections; 2603 fullyLoaded = d->isFullyLoaded(&pendingChildRedirections); 2604 2605 // ### might want to wait on pendingChildRedirections here, too 2606 if (d->m_bLoadEventEmitted || !d->m_doc || !fullyLoaded) { 2607 return; 2608 } 2609 2610 d->m_bLoadEventEmitted = true; 2611 if (d->m_doc) { 2612 d->m_doc->close(); 2613 } 2614 } 2615 2616 const KHTMLSettings *KHTMLPart::settings() const 2617 { 2618 return d->m_settings; 2619 } 2620 2621 #ifndef KDE_NO_COMPAT // KDE5: remove this ifndef, keep the method (renamed to baseUrl) 2622 QUrl KHTMLPart::baseURL() const 2623 { 2624 if (!d->m_doc) { 2625 return QUrl(); 2626 } 2627 2628 return d->m_doc->baseURL(); 2629 } 2630 #endif 2631 2632 QUrl KHTMLPart::completeURL(const QString &url) 2633 { 2634 if (!d->m_doc) { 2635 return QUrl(url); 2636 } 2637 2638 #if 0 2639 if (d->m_decoder) { 2640 return QUrl(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum()); 2641 } 2642 #endif 2643 2644 return QUrl(d->m_doc->completeURL(url)); 2645 } 2646 2647 QString KHTMLPartPrivate::codeForJavaScriptURL(const QString &u) 2648 { 2649 return QUrl::fromPercentEncoding(u.right(u.length() - 11).toUtf8()); 2650 } 2651 2652 void KHTMLPartPrivate::executeJavascriptURL(const QString &u) 2653 { 2654 QString script = codeForJavaScriptURL(u); 2655 // qCDebug(KHTML_LOG) << "script=" << script; 2656 QVariant res = q->executeScript(DOM::Node(), script); 2657 if (res.type() == QVariant::String) { 2658 q->begin(q->url()); 2659 q->setAlwaysHonourDoctype(); // Disable public API compat; it messes with doctype 2660 q->write(res.toString()); 2661 q->end(); 2662 } 2663 emit q->completed(); 2664 } 2665 2666 bool KHTMLPartPrivate::isJavaScriptURL(const QString &url) 2667 { 2668 return url.indexOf(QLatin1String("javascript:"), 0, Qt::CaseInsensitive) == 0; 2669 } 2670 2671 // Called by ecma/kjs_window in case of redirections from Javascript, 2672 // and by xml/dom_docimpl.cpp in case of http-equiv meta refresh. 2673 void KHTMLPart::scheduleRedirection(int delay, const QString &url, bool doLockHistory) 2674 { 2675 // qCDebug(KHTML_LOG) << "delay=" << delay << " url=" << url << " from=" << this->url() << "parent=" << parentPart(); 2676 // qCDebug(KHTML_LOG) << "current redirectURL=" << d->m_redirectURL << " with delay " << d->m_delayRedirect; 2677 2678 // In case of JS redirections, some, such as jump to anchors, and javascript: 2679 // evaluation should actually be handled immediately, and not waiting until 2680 // the end of the script. (Besides, we don't want to abort the tokenizer for those) 2681 if (delay == -1 && d->isInPageURL(url)) { 2682 d->executeInPageURL(url, doLockHistory); 2683 return; 2684 } 2685 2686 if (delay < 24 * 60 * 60 && 2687 (d->m_redirectURL.isEmpty() || delay <= d->m_delayRedirect)) { 2688 d->m_delayRedirect = delay; 2689 d->m_redirectURL = url; 2690 d->m_redirectLockHistory = doLockHistory; 2691 // qCDebug(KHTML_LOG) << " d->m_bComplete=" << d->m_bComplete; 2692 2693 if (d->m_bComplete) { 2694 d->m_redirectionTimer.stop(); 2695 d->m_redirectionTimer.setSingleShot(true); 2696 d->m_redirectionTimer.start(qMax(0, 1000 * d->m_delayRedirect)); 2697 } 2698 } 2699 } 2700 2701 void KHTMLPartPrivate::clearRedirection() 2702 { 2703 m_delayRedirect = 0; 2704 m_redirectURL.clear(); 2705 m_redirectionTimer.stop(); 2706 } 2707 2708 void KHTMLPart::slotRedirect() 2709 { 2710 // qCDebug(KHTML_LOG) << this; 2711 QString u = d->m_redirectURL; 2712 QUrl url(u); 2713 d->clearRedirection(); 2714 2715 if (d->isInPageURL(u)) { 2716 d->executeInPageURL(u, d->m_redirectLockHistory); 2717 return; 2718 } 2719 2720 KParts::OpenUrlArguments args; 2721 QUrl cUrl(this->url()); 2722 2723 // handle windows opened by JS 2724 if (openedByJS() && d->m_opener) { 2725 cUrl = d->m_opener->url(); 2726 } 2727 2728 if (!KUrlAuthorized::authorizeUrlAction("redirect", cUrl, url)) { 2729 qCWarning(KHTML_LOG) << "KHTMLPart::scheduleRedirection: Redirection from " << cUrl << " to " << url << " REJECTED!"; 2730 emit completed(); 2731 return; 2732 } 2733 2734 if (areUrlsForSamePage(url, this->url())) { 2735 args.metaData().insert("referrer", d->m_pageReferrer); 2736 } 2737 2738 // For javascript and META-tag based redirections: 2739 // - We don't take cross-domain-ness in consideration if we are the 2740 // toplevel frame because the new URL may be in a different domain as the current URL 2741 // but that's ok. 2742 // - If we are not the toplevel frame then we check against the toplevelURL() 2743 if (parentPart()) { 2744 args.metaData().insert("cross-domain", toplevelURL().toString()); 2745 } 2746 2747 KParts::BrowserArguments browserArgs; 2748 browserArgs.setLockHistory(d->m_redirectLockHistory); 2749 // _self: make sure we don't use any <base target=>'s 2750 2751 if (!urlSelected(u, 0, 0, "_self", args, browserArgs)) { 2752 // urlSelected didn't open a url, so emit completed ourselves 2753 emit completed(); 2754 } 2755 } 2756 2757 void KHTMLPart::slotRedirection(KIO::Job *, const QUrl &url) 2758 { 2759 // the worker told us that we got redirected 2760 //qCDebug(KHTML_LOG) << "redirection by KIO to" << url; 2761 emit d->m_extension->setLocationBarUrl(url.toDisplayString()); 2762 d->m_workingURL = url; 2763 } 2764 2765 bool KHTMLPart::setEncoding(const QString &name, bool override) 2766 { 2767 d->m_encoding = name; 2768 d->m_haveEncoding = override; 2769 2770 if (!url().isEmpty()) { 2771 // reload document 2772 closeUrl(); 2773 QUrl oldUrl = url(); 2774 setUrl(QUrl()); 2775 d->m_restored = true; 2776 openUrl(oldUrl); 2777 d->m_restored = false; 2778 } 2779 2780 return true; 2781 } 2782 2783 QString KHTMLPart::encoding() const 2784 { 2785 if (d->m_haveEncoding && !d->m_encoding.isEmpty()) { 2786 return d->m_encoding; 2787 } 2788 2789 if (d->m_decoder && d->m_decoder->encoding()) { 2790 return QString(d->m_decoder->encoding()); 2791 } 2792 2793 return defaultEncoding(); 2794 } 2795 2796 QString KHTMLPart::defaultEncoding() const 2797 { 2798 QString encoding = settings()->encoding(); 2799 if (!encoding.isEmpty()) { 2800 return encoding; 2801 } 2802 // HTTP requires the default encoding to be latin1, when neither 2803 // the user nor the page requested a particular encoding. 2804 if (url().scheme().startsWith("http")) { 2805 return "iso-8859-1"; 2806 } else { 2807 return QTextCodec::codecForLocale()->name().toLower(); 2808 } 2809 } 2810 2811 void KHTMLPart::setUserStyleSheet(const QUrl &url) 2812 { 2813 if (d->m_doc && d->m_doc->docLoader()) { 2814 (void) new khtml::PartStyleSheetLoader(this, url.toString(), d->m_doc->docLoader()); 2815 } 2816 } 2817 2818 void KHTMLPart::setUserStyleSheet(const QString &styleSheet) 2819 { 2820 if (d->m_doc) { 2821 d->m_doc->setUserStyleSheet(styleSheet); 2822 } 2823 } 2824 2825 bool KHTMLPart::gotoAnchor(const QString &name) 2826 { 2827 if (!d->m_doc) { 2828 return false; 2829 } 2830 2831 HTMLCollectionImpl *anchors = new HTMLCollectionImpl(d->m_doc, HTMLCollectionImpl::DOC_ANCHORS); 2832 anchors->ref(); 2833 NodeImpl *n = anchors->namedItem(name); 2834 anchors->deref(); 2835 2836 if (!n) { 2837 n = d->m_doc->getElementById(name); 2838 } 2839 2840 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target. 2841 2842 // Implement the rule that "" and "top" both mean top of page. 2843 bool top = !n && (name.isEmpty() || name.toLower() == "top"); 2844 2845 if (top) { 2846 d->m_view->setContentsPos(d->m_view->contentsX(), 0); 2847 return true; 2848 } else if (!n) { 2849 // qCDebug(KHTML_LOG) << name << "not found"; 2850 return false; 2851 } 2852 2853 int x = 0, y = 0; 2854 int gox, dummy; 2855 HTMLElementImpl *a = static_cast<HTMLElementImpl *>(n); 2856 2857 a->getUpperLeftCorner(x, y); 2858 if (x <= d->m_view->contentsX()) { 2859 gox = x - 10; 2860 } else { 2861 gox = d->m_view->contentsX(); 2862 if (x + 10 > d->m_view->contentsX() + d->m_view->visibleWidth()) { 2863 a->getLowerRightCorner(x, dummy); 2864 gox = x - d->m_view->visibleWidth() + 10; 2865 } 2866 } 2867 2868 d->m_view->setContentsPos(gox, y); 2869 2870 return true; 2871 } 2872 2873 bool KHTMLPart::nextAnchor() 2874 { 2875 if (!d->m_doc) { 2876 return false; 2877 } 2878 d->m_view->focusNextPrevNode(true); 2879 2880 return true; 2881 } 2882 2883 bool KHTMLPart::prevAnchor() 2884 { 2885 if (!d->m_doc) { 2886 return false; 2887 } 2888 d->m_view->focusNextPrevNode(false); 2889 2890 return true; 2891 } 2892 2893 void KHTMLPart::setStandardFont(const QString &name) 2894 { 2895 d->m_settings->setStdFontName(name); 2896 } 2897 2898 void KHTMLPart::setFixedFont(const QString &name) 2899 { 2900 d->m_settings->setFixedFontName(name); 2901 } 2902 2903 void KHTMLPart::setURLCursor(const QCursor &c) 2904 { 2905 d->m_linkCursor = c; 2906 } 2907 2908 QCursor KHTMLPart::urlCursor() const 2909 { 2910 return d->m_linkCursor; 2911 } 2912 2913 bool KHTMLPart::onlyLocalReferences() const 2914 { 2915 return d->m_onlyLocalReferences; 2916 } 2917 2918 void KHTMLPart::setOnlyLocalReferences(bool enable) 2919 { 2920 d->m_onlyLocalReferences = enable; 2921 } 2922 2923 bool KHTMLPart::forcePermitLocalImages() const 2924 { 2925 return d->m_forcePermitLocalImages; 2926 } 2927 2928 void KHTMLPart::setForcePermitLocalImages(bool enable) 2929 { 2930 d->m_forcePermitLocalImages = enable; 2931 } 2932 2933 void KHTMLPartPrivate::setFlagRecursively( 2934 bool KHTMLPartPrivate::*flag, bool value) 2935 { 2936 // first set it on the current one 2937 this->*flag = value; 2938 2939 // descend into child frames recursively 2940 { 2941 QList<khtml::ChildFrame *>::Iterator it = m_frames.begin(); 2942 const QList<khtml::ChildFrame *>::Iterator itEnd = m_frames.end(); 2943 for (; it != itEnd; ++it) { 2944 KHTMLPart *const part = qobject_cast<KHTMLPart *>((*it)->m_part.data()); 2945 if (part) { 2946 part->d->setFlagRecursively(flag, value); 2947 } 2948 }/*next it*/ 2949 } 2950 // do the same again for objects 2951 { 2952 QList<khtml::ChildFrame *>::Iterator it = m_objects.begin(); 2953 const QList<khtml::ChildFrame *>::Iterator itEnd = m_objects.end(); 2954 for (; it != itEnd; ++it) { 2955 KHTMLPart *const part = qobject_cast<KHTMLPart *>((*it)->m_part.data()); 2956 if (part) { 2957 part->d->setFlagRecursively(flag, value); 2958 } 2959 }/*next it*/ 2960 } 2961 } 2962 2963 void KHTMLPart::initCaret() 2964 { 2965 // initialize caret if not used yet 2966 if (d->editor_context.m_selection.state() == Selection::NONE) { 2967 if (d->m_doc) { 2968 NodeImpl *node; 2969 if (d->m_doc->isHTMLDocument()) { 2970 HTMLDocumentImpl *htmlDoc = static_cast<HTMLDocumentImpl *>(d->m_doc); 2971 node = htmlDoc->body(); 2972 } else { 2973 node = d->m_doc; 2974 } 2975 if (!node) { 2976 return; 2977 } 2978 d->editor_context.m_selection.moveTo(Position(node, 0)); 2979 d->editor_context.m_selection.setNeedsLayout(); 2980 d->editor_context.m_selection.needsCaretRepaint(); 2981 } 2982 } 2983 } 2984 2985 static void setCaretInvisibleIfNeeded(KHTMLPart *part) 2986 { 2987 // On contenteditable nodes, don't hide the caret 2988 if (!khtml::KHTMLPartAccessor::caret(part).caretPos().node()->isContentEditable()) { 2989 part->setCaretVisible(false); 2990 } 2991 } 2992 2993 void KHTMLPart::setCaretMode(bool enable) 2994 { 2995 // qCDebug(KHTML_LOG) << enable; 2996 if (isCaretMode() == enable) { 2997 return; 2998 } 2999 d->setFlagRecursively(&KHTMLPartPrivate::m_caretMode, enable); 3000 // FIXME: this won't work on frames as expected 3001 if (!isEditable()) { 3002 if (enable) { 3003 initCaret(); 3004 setCaretVisible(true); 3005 // view()->ensureCaretVisible(); 3006 } else { 3007 setCaretInvisibleIfNeeded(this); 3008 } 3009 } 3010 } 3011 3012 bool KHTMLPart::isCaretMode() const 3013 { 3014 return d->m_caretMode; 3015 } 3016 3017 void KHTMLPart::setEditable(bool enable) 3018 { 3019 if (isEditable() == enable) { 3020 return; 3021 } 3022 d->setFlagRecursively(&KHTMLPartPrivate::m_designMode, enable); 3023 // FIXME: this won't work on frames as expected 3024 if (!isCaretMode()) { 3025 if (enable) { 3026 initCaret(); 3027 setCaretVisible(true); 3028 // view()->ensureCaretVisible(); 3029 } else { 3030 setCaretInvisibleIfNeeded(this); 3031 } 3032 } 3033 } 3034 3035 bool KHTMLPart::isEditable() const 3036 { 3037 return d->m_designMode; 3038 } 3039 3040 khtml::EditorContext *KHTMLPart::editorContext() const 3041 { 3042 return &d->editor_context; 3043 } 3044 3045 void KHTMLPart::setCaretPosition(DOM::Node node, long offset, bool extendSelection) 3046 { 3047 Q_UNUSED(node); 3048 Q_UNUSED(offset); 3049 Q_UNUSED(extendSelection); 3050 #ifndef KHTML_NO_CARET 3051 #if 0 3052 qCDebug(KHTML_LOG) << "node: " << node.handle() << " nodeName: " 3053 << node.nodeName().string() << " offset: " << offset 3054 << " extendSelection " << extendSelection; 3055 if (view()->moveCaretTo(node.handle(), offset, !extendSelection)) { 3056 emitSelectionChanged(); 3057 } 3058 view()->ensureCaretVisible(); 3059 #endif 3060 #endif // KHTML_NO_CARET 3061 } 3062 3063 KHTMLPart::CaretDisplayPolicy KHTMLPart::caretDisplayPolicyNonFocused() const 3064 { 3065 #if 0 3066 #ifndef KHTML_NO_CARET 3067 return (CaretDisplayPolicy)view()->caretDisplayPolicyNonFocused(); 3068 #else // KHTML_NO_CARET 3069 return CaretInvisible; 3070 #endif // KHTML_NO_CARET 3071 #endif 3072 return CaretInvisible; 3073 } 3074 3075 void KHTMLPart::setCaretDisplayPolicyNonFocused(CaretDisplayPolicy policy) 3076 { 3077 Q_UNUSED(policy); 3078 #if 0 3079 #ifndef KHTML_NO_CARET 3080 view()->setCaretDisplayPolicyNonFocused(policy); 3081 #endif // KHTML_NO_CARET 3082 #endif 3083 } 3084 3085 void KHTMLPart::setCaretVisible(bool show) 3086 { 3087 if (show) { 3088 NodeImpl *caretNode = d->editor_context.m_selection.caretPos().node(); 3089 if (isCaretMode() || (caretNode && caretNode->isContentEditable())) { 3090 invalidateSelection(); 3091 enableFindAheadActions(false); 3092 } 3093 } else { 3094 3095 if (d->editor_context.m_caretBlinkTimer >= 0) { 3096 killTimer(d->editor_context.m_caretBlinkTimer); 3097 } 3098 clearCaretRectIfNeeded(); 3099 3100 } 3101 } 3102 3103 void KHTMLPart::findTextBegin() 3104 { 3105 d->m_find.findTextBegin(); 3106 } 3107 3108 bool KHTMLPart::initFindNode(bool selection, bool reverse, bool fromCursor) 3109 { 3110 return d->m_find.initFindNode(selection, reverse, fromCursor); 3111 } 3112 3113 void KHTMLPart::slotFind() 3114 { 3115 KParts::ReadOnlyPart *part = currentFrame(); 3116 if (!part) { 3117 return; 3118 } 3119 if (!part->inherits("KHTMLPart")) { 3120 qCCritical(KHTML_LOG) << "part is a" << part->metaObject()->className() << ", can't do a search into it"; 3121 return; 3122 } 3123 static_cast<KHTMLPart *>(part)->findText(); 3124 } 3125 3126 void KHTMLPart::slotFindNext() 3127 { 3128 KParts::ReadOnlyPart *part = currentFrame(); 3129 if (!part) { 3130 return; 3131 } 3132 if (!part->inherits("KHTMLPart")) { 3133 qCCritical(KHTML_LOG) << "part is a" << part->metaObject()->className() << ", can't do a search into it"; 3134 return; 3135 } 3136 static_cast<KHTMLPart *>(part)->findTextNext(); 3137 } 3138 3139 void KHTMLPart::slotFindPrev() 3140 { 3141 KParts::ReadOnlyPart *part = currentFrame(); 3142 if (!part) { 3143 return; 3144 } 3145 if (!part->inherits("KHTMLPart")) { 3146 qCCritical(KHTML_LOG) << "part is a" << part->metaObject()->className() << ", can't do a search into it"; 3147 return; 3148 } 3149 static_cast<KHTMLPart *>(part)->findTextNext(true); // reverse 3150 } 3151 3152 void KHTMLPart::slotFindDone() 3153 { 3154 // ### remove me 3155 } 3156 3157 void KHTMLPart::slotFindAheadText() 3158 { 3159 KHTMLPart *part = qobject_cast<KHTMLPart *>(currentFrame()); 3160 if (!part) { 3161 return; 3162 } 3163 part->findText(); 3164 KHTMLFindBar *findBar = part->d->m_find.findBar(); 3165 findBar->setOptions(findBar->options() & ~FindLinksOnly); 3166 } 3167 3168 void KHTMLPart::slotFindAheadLink() 3169 { 3170 KHTMLPart *part = qobject_cast<KHTMLPart *>(currentFrame()); 3171 if (!part) { 3172 return; 3173 } 3174 part->findText(); 3175 KHTMLFindBar *findBar = part->d->m_find.findBar(); 3176 findBar->setOptions(findBar->options() | FindLinksOnly); 3177 } 3178 3179 void KHTMLPart::enableFindAheadActions(bool) 3180 { 3181 // ### remove me 3182 } 3183 3184 void KHTMLPart::slotFindDialogDestroyed() 3185 { 3186 // ### remove me 3187 } 3188 3189 void KHTMLPart::findText() 3190 { 3191 if (parentPart()) { 3192 return parentPart()->findText(); 3193 } 3194 d->m_find.activate(); 3195 } 3196 3197 void KHTMLPart::findText(const QString &str, long options, QWidget *parent, KFindDialog *findDialog) 3198 { 3199 if (parentPart()) { 3200 return parentPart()->findText(str, options, parent, findDialog); 3201 } 3202 d->m_find.createNewKFind(str, options, parent, findDialog); 3203 } 3204 3205 // New method 3206 bool KHTMLPart::findTextNext(bool reverse) 3207 { 3208 if (parentPart()) { 3209 return parentPart()->findTextNext(reverse); 3210 } 3211 return d->m_find.findTextNext(reverse); 3212 } 3213 3214 bool KHTMLPart::pFindTextNextInThisFrame(bool reverse) 3215 { 3216 return d->m_find.findTextNext(reverse); 3217 } 3218 3219 QString KHTMLPart::selectedTextAsHTML() const 3220 { 3221 const Selection &sel = d->editor_context.m_selection; 3222 if (!hasSelection()) { 3223 // qCDebug(KHTML_LOG) << "Selection is not valid. Returning empty selection"; 3224 return QString(); 3225 } 3226 if (sel.start().offset() < 0 || sel.end().offset() < 0) { 3227 // qCDebug(KHTML_LOG) << "invalid values for end/startOffset " << sel.start().offset() << " " << sel.end().offset(); 3228 return QString(); 3229 } 3230 DOM::Range r = selection(); 3231 if (r.isNull() || r.isDetached()) { 3232 return QString(); 3233 } 3234 int exceptioncode = 0; //ignore the result 3235 return r.handle()->toHTML(exceptioncode).string(); 3236 } 3237 3238 QString KHTMLPart::selectedText() const 3239 { 3240 bool hasNewLine = true; 3241 bool seenTDTag = false; 3242 QString text; 3243 const Selection &sel = d->editor_context.m_selection; 3244 DOM::Node n = sel.start().node(); 3245 while (!n.isNull()) { 3246 if (n.nodeType() == DOM::Node::TEXT_NODE && n.handle()->renderer()) { 3247 DOM::DOMStringImpl *dstr = static_cast<DOM::TextImpl *>(n.handle())->renderString(); 3248 QString str(dstr->s, dstr->l); 3249 if (!str.isEmpty()) { 3250 if (seenTDTag) { 3251 text += " "; 3252 seenTDTag = false; 3253 } 3254 hasNewLine = false; 3255 if (n == sel.start().node() && n == sel.end().node()) { 3256 int s = khtml::RenderPosition::fromDOMPosition(sel.start()).renderedOffset(); 3257 int e = khtml::RenderPosition::fromDOMPosition(sel.end()).renderedOffset(); 3258 text = str.mid(s, e - s); 3259 } else if (n == sel.start().node()) { 3260 text = str.mid(khtml::RenderPosition::fromDOMPosition(sel.start()).renderedOffset()); 3261 } else if (n == sel.end().node()) { 3262 text += str.left(khtml::RenderPosition::fromDOMPosition(sel.end()).renderedOffset()); 3263 } else { 3264 text += str; 3265 } 3266 } 3267 } else { 3268 // This is our simple HTML -> ASCII transformation: 3269 unsigned short id = n.elementId(); 3270 switch (id) { 3271 case ID_TEXTAREA: 3272 text += static_cast<HTMLTextAreaElementImpl *>(n.handle())->value().string(); 3273 break; 3274 case ID_INPUT: 3275 if (static_cast<HTMLInputElementImpl *>(n.handle())->inputType() != HTMLInputElementImpl::PASSWORD) { 3276 text += static_cast<HTMLInputElementImpl *>(n.handle())->value().string(); 3277 } 3278 break; 3279 case ID_SELECT: 3280 text += static_cast<HTMLSelectElementImpl *>(n.handle())->value().string(); 3281 break; 3282 case ID_BR: 3283 text += "\n"; 3284 hasNewLine = true; 3285 break; 3286 case ID_IMG: 3287 text += static_cast<HTMLImageElementImpl *>(n.handle())->altText().string(); 3288 break; 3289 case ID_TD: 3290 break; 3291 case ID_TH: 3292 case ID_HR: 3293 case ID_OL: 3294 case ID_UL: 3295 case ID_LI: 3296 case ID_DD: 3297 case ID_DL: 3298 case ID_DT: 3299 case ID_PRE: 3300 case ID_LISTING: 3301 case ID_BLOCKQUOTE: 3302 case ID_DIV: 3303 if (!hasNewLine) { 3304 text += "\n"; 3305 } 3306 hasNewLine = true; 3307 break; 3308 case ID_P: 3309 case ID_TR: 3310 case ID_H1: 3311 case ID_H2: 3312 case ID_H3: 3313 case ID_H4: 3314 case ID_H5: 3315 case ID_H6: 3316 if (!hasNewLine) { 3317 text += "\n"; 3318 } 3319 hasNewLine = true; 3320 break; 3321 } 3322 } 3323 if (n == sel.end().node()) { 3324 break; 3325 } 3326 DOM::Node next = n.firstChild(); 3327 if (next.isNull()) { 3328 next = n.nextSibling(); 3329 } 3330 while (next.isNull() && !n.parentNode().isNull()) { 3331 n = n.parentNode(); 3332 next = n.nextSibling(); 3333 unsigned short id = n.elementId(); 3334 switch (id) { 3335 case ID_TD: 3336 seenTDTag = true; //Add two spaces after a td if then followed by text. 3337 break; 3338 case ID_TH: 3339 case ID_HR: 3340 case ID_OL: 3341 case ID_UL: 3342 case ID_LI: 3343 case ID_DD: 3344 case ID_DL: 3345 case ID_DT: 3346 case ID_PRE: 3347 case ID_LISTING: 3348 case ID_BLOCKQUOTE: 3349 case ID_DIV: 3350 seenTDTag = false; 3351 if (!hasNewLine) { 3352 text += "\n"; 3353 } 3354 hasNewLine = true; 3355 break; 3356 case ID_P: 3357 case ID_TR: 3358 case ID_H1: 3359 case ID_H2: 3360 case ID_H3: 3361 case ID_H4: 3362 case ID_H5: 3363 case ID_H6: 3364 if (!hasNewLine) { 3365 text += "\n"; 3366 } 3367 // text += "\n"; 3368 hasNewLine = true; 3369 break; 3370 } 3371 } 3372 3373 n = next; 3374 } 3375 3376 if (text.isEmpty()) { 3377 return QString(); 3378 } 3379 3380 int start = 0; 3381 int end = text.length(); 3382 3383 // Strip leading LFs 3384 while ((start < end) && (text[start] == '\n')) { 3385 ++start; 3386 } 3387 3388 // Strip excessive trailing LFs 3389 while ((start < (end - 1)) && (text[end - 1] == '\n') && (text[end - 2] == '\n')) { 3390 --end; 3391 } 3392 3393 return text.mid(start, end - start); 3394 } 3395 3396 QString KHTMLPart::simplifiedSelectedText() const 3397 { 3398 QString text = selectedText(); 3399 text.replace(QChar(0xa0), ' '); 3400 // remove leading and trailing whitespace 3401 while (!text.isEmpty() && text[0].isSpace()) { 3402 text = text.mid(1); 3403 } 3404 while (!text.isEmpty() && text[text.length() - 1].isSpace()) { 3405 text.truncate(text.length() - 1); 3406 } 3407 return text; 3408 } 3409 3410 bool KHTMLPart::hasSelection() const 3411 { 3412 return !d->editor_context.m_selection.isEmpty() && !d->editor_context.m_selection.isCollapsed(); 3413 } 3414 3415 DOM::Range KHTMLPart::selection() const 3416 { 3417 return d->editor_context.m_selection.toRange(); 3418 } 3419 3420 void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const 3421 { 3422 DOM::Range r = d->editor_context.m_selection.toRange(); 3423 s = r.startContainer(); 3424 so = r.startOffset(); 3425 e = r.endContainer(); 3426 eo = r.endOffset(); 3427 } 3428 3429 void KHTMLPart::setSelection(const DOM::Range &r) 3430 { 3431 setCaret(r); 3432 } 3433 3434 const Selection &KHTMLPart::caret() const 3435 { 3436 return d->editor_context.m_selection; 3437 } 3438 3439 const Selection &KHTMLPart::dragCaret() const 3440 { 3441 return d->editor_context.m_dragCaret; 3442 } 3443 3444 void KHTMLPart::setCaret(const Selection &s, bool closeTyping) 3445 { 3446 if (d->editor_context.m_selection != s) { 3447 clearCaretRectIfNeeded(); 3448 setFocusNodeIfNeeded(s); 3449 d->editor_context.m_selection = s; 3450 notifySelectionChanged(closeTyping); 3451 } 3452 } 3453 3454 void KHTMLPart::setDragCaret(const DOM::Selection &dragCaret) 3455 { 3456 if (d->editor_context.m_dragCaret != dragCaret) { 3457 d->editor_context.m_dragCaret.needsCaretRepaint(); 3458 d->editor_context.m_dragCaret = dragCaret; 3459 d->editor_context.m_dragCaret.needsCaretRepaint(); 3460 } 3461 } 3462 3463 void KHTMLPart::clearSelection() 3464 { 3465 clearCaretRectIfNeeded(); 3466 setFocusNodeIfNeeded(d->editor_context.m_selection); 3467 #ifdef APPLE_CHANGES 3468 d->editor_context.m_selection.clear(); 3469 #else 3470 d->editor_context.m_selection.collapse(); 3471 #endif 3472 notifySelectionChanged(); 3473 } 3474 3475 void KHTMLPart::invalidateSelection() 3476 { 3477 clearCaretRectIfNeeded(); 3478 d->editor_context.m_selection.setNeedsLayout(); 3479 selectionLayoutChanged(); 3480 } 3481 3482 void KHTMLPart::setSelectionVisible(bool flag) 3483 { 3484 if (d->editor_context.m_caretVisible == flag) { 3485 return; 3486 } 3487 3488 clearCaretRectIfNeeded(); 3489 setFocusNodeIfNeeded(d->editor_context.m_selection); 3490 d->editor_context.m_caretVisible = flag; 3491 // notifySelectionChanged(); 3492 } 3493 3494 #if 1 3495 void KHTMLPart::slotClearSelection() 3496 { 3497 if (!isCaretMode() 3498 && d->editor_context.m_selection.state() != Selection::NONE 3499 && !d->editor_context.m_selection.caretPos().node()->isContentEditable()) { 3500 clearCaretRectIfNeeded(); 3501 } 3502 bool hadSelection = hasSelection(); 3503 #ifdef APPLE_CHANGES 3504 d->editor_context.m_selection.clear(); 3505 #else 3506 d->editor_context.m_selection.collapse(); 3507 #endif 3508 if (hadSelection) { 3509 notifySelectionChanged(); 3510 } 3511 } 3512 #endif 3513 3514 void KHTMLPart::clearCaretRectIfNeeded() 3515 { 3516 if (d->editor_context.m_caretPaint) { 3517 d->editor_context.m_caretPaint = false; 3518 d->editor_context.m_selection.needsCaretRepaint(); 3519 } 3520 } 3521 3522 void KHTMLPart::setFocusNodeIfNeeded(const Selection &s) 3523 { 3524 if (!xmlDocImpl() || s.state() == Selection::NONE) { 3525 return; 3526 } 3527 3528 NodeImpl *n = s.start().node(); 3529 NodeImpl *target = (n && n->isContentEditable()) ? n : nullptr; 3530 if (!target) { 3531 while (n && n != s.end().node()) { 3532 if (n->isContentEditable()) { 3533 target = n; 3534 break; 3535 } 3536 n = n->traverseNextNode(); 3537 } 3538 } 3539 assert(target == nullptr || target->isContentEditable()); 3540 3541 if (target) { 3542 for (; target && !target->isFocusable(); target = target->parentNode()) { 3543 } 3544 if (target && target->isMouseFocusable()) { 3545 xmlDocImpl()->setFocusNode(target); 3546 } else if (!target || !target->focused()) { 3547 xmlDocImpl()->setFocusNode(nullptr); 3548 } 3549 } 3550 } 3551 3552 void KHTMLPart::selectionLayoutChanged() 3553 { 3554 // kill any caret blink timer now running 3555 if (d->editor_context.m_caretBlinkTimer >= 0) { 3556 killTimer(d->editor_context.m_caretBlinkTimer); 3557 d->editor_context.m_caretBlinkTimer = -1; 3558 } 3559 3560 // see if a new caret blink timer needs to be started 3561 if (d->editor_context.m_caretVisible 3562 && d->editor_context.m_selection.state() != Selection::NONE) { 3563 d->editor_context.m_caretPaint = isCaretMode() 3564 || d->editor_context.m_selection.caretPos().node()->isContentEditable(); 3565 if (d->editor_context.m_caretBlinks && d->editor_context.m_caretPaint) { 3566 d->editor_context.m_caretBlinkTimer = startTimer(qApp->cursorFlashTime() / 2); 3567 } 3568 d->editor_context.m_selection.needsCaretRepaint(); 3569 // make sure that caret is visible 3570 QRect r(d->editor_context.m_selection.getRepaintRect()); 3571 if (d->editor_context.m_caretPaint) { 3572 d->m_view->ensureVisible(r.x(), r.y()); 3573 } 3574 } 3575 3576 if (d->m_doc) { 3577 d->m_doc->updateSelection(); 3578 } 3579 3580 // Always clear the x position used for vertical arrow navigation. 3581 // It will be restored by the vertical arrow navigation code if necessary. 3582 d->editor_context.m_xPosForVerticalArrowNavigation = d->editor_context.NoXPosForVerticalArrowNavigation; 3583 } 3584 3585 void KHTMLPart::notifySelectionChanged(bool closeTyping) 3586 { 3587 Editor *ed = d->editor_context.m_editor; 3588 selectionLayoutChanged(); 3589 if (ed) { 3590 ed->clearTypingStyle(); 3591 3592 if (closeTyping) { 3593 ed->closeTyping(); 3594 } 3595 } 3596 3597 emitSelectionChanged(); 3598 } 3599 3600 void KHTMLPart::timerEvent(QTimerEvent *e) 3601 { 3602 if (e->timerId() == d->editor_context.m_caretBlinkTimer) { 3603 if (d->editor_context.m_caretBlinks && 3604 d->editor_context.m_selection.state() != Selection::NONE) { 3605 d->editor_context.m_caretPaint = !d->editor_context.m_caretPaint; 3606 d->editor_context.m_selection.needsCaretRepaint(); 3607 } 3608 } else if (e->timerId() == d->m_DNSPrefetchTimer) { 3609 // qCDebug(KHTML_LOG) << "will lookup " << d->m_DNSPrefetchQueue.head() << d->m_numDNSPrefetchedNames; 3610 KIO::HostInfo::prefetchHost(d->m_DNSPrefetchQueue.dequeue()); 3611 if (d->m_DNSPrefetchQueue.isEmpty()) { 3612 killTimer(d->m_DNSPrefetchTimer); 3613 d->m_DNSPrefetchTimer = -1; 3614 } 3615 } else if (e->timerId() == d->m_DNSTTLTimer) { 3616 foreach (const QString &name, d->m_lookedupHosts) { 3617 d->m_DNSPrefetchQueue.enqueue(name); 3618 } 3619 if (d->m_DNSPrefetchTimer <= 0) { 3620 d->m_DNSPrefetchTimer = startTimer(sDNSPrefetchTimerDelay); 3621 } 3622 } 3623 } 3624 3625 bool KHTMLPart::mayPrefetchHostname(const QString &name) 3626 { 3627 if (d->m_bDNSPrefetch == DNSPrefetchDisabled) { 3628 return false; 3629 } 3630 3631 if (d->m_numDNSPrefetchedNames >= sMaxDNSPrefetchPerPage) { 3632 return false; 3633 } 3634 3635 if (d->m_bDNSPrefetch == DNSPrefetchOnlyWWWAndSLD) { 3636 int dots = name.count('.'); 3637 if (dots > 2 || (dots == 2 && !name.startsWith("www."))) { 3638 return false; 3639 } 3640 } 3641 3642 if (d->m_lookedupHosts.contains(name)) { 3643 return false; 3644 } 3645 3646 d->m_DNSPrefetchQueue.enqueue(name); 3647 d->m_lookedupHosts.insert(name); 3648 d->m_numDNSPrefetchedNames++; 3649 3650 if (d->m_DNSPrefetchTimer < 1) { 3651 d->m_DNSPrefetchTimer = startTimer(sDNSPrefetchTimerDelay); 3652 } 3653 if (d->m_DNSTTLTimer < 1) { 3654 d->m_DNSTTLTimer = startTimer(sDNSTTLSeconds * 1000 + 1); 3655 } 3656 3657 return true; 3658 } 3659 3660 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const 3661 { 3662 if (d->editor_context.m_caretPaint) { 3663 d->editor_context.m_selection.paintCaret(p, rect); 3664 } 3665 } 3666 3667 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const 3668 { 3669 d->editor_context.m_dragCaret.paintCaret(p, rect); 3670 } 3671 3672 DOM::Editor *KHTMLPart::editor() const 3673 { 3674 if (!d->editor_context.m_editor) { 3675 const_cast<KHTMLPart *>(this)->d->editor_context.m_editor = new DOM::Editor(const_cast<KHTMLPart *>(this)); 3676 } 3677 return d->editor_context.m_editor; 3678 } 3679 3680 void KHTMLPart::resetHoverText() 3681 { 3682 if (!d->m_overURL.isEmpty()) { // Only if we were showing a link 3683 d->m_overURL.clear(); 3684 d->m_overURLTarget.clear(); 3685 emit onURL(QString()); 3686 // revert to default statusbar text 3687 setStatusBarText(QString(), BarHoverText); 3688 emit d->m_extension->mouseOverInfo(KFileItem()); 3689 } 3690 } 3691 3692 void KHTMLPart::overURL(const QString &url, const QString &target, bool /*shiftPressed*/) 3693 { 3694 QUrl u = completeURL(url); 3695 3696 // special case for <a href=""> 3697 if (url.isEmpty()) { 3698 u = u.adjusted(QUrl::RemoveFilename); 3699 } 3700 3701 emit onURL(url); 3702 3703 if (url.isEmpty()) { 3704 setStatusBarText(u.toDisplayString().toHtmlEscaped(), BarHoverText); 3705 return; 3706 } 3707 3708 if (d->isJavaScriptURL(url)) { 3709 QString jscode = d->codeForJavaScriptURL(url); 3710 jscode = KStringHandler::rsqueeze(jscode, 80); // truncate if too long 3711 if (url.startsWith("javascript:window.open")) { 3712 jscode += i18n(" (In new window)"); 3713 } 3714 setStatusBarText(jscode.toHtmlEscaped(), BarHoverText); 3715 return; 3716 } 3717 3718 KFileItem item(u, QString(), KFileItem::Unknown); 3719 emit d->m_extension->mouseOverInfo(item); 3720 const QString com = item.mimeComment(); 3721 3722 if (!u.isValid()) { 3723 setStatusBarText(u.toDisplayString().toHtmlEscaped(), BarHoverText); 3724 return; 3725 } 3726 3727 if (u.isLocalFile()) { 3728 // TODO : use KIO::stat() and create a KFileItem out of its result, 3729 // to use KFileItem::statusBarText() 3730 3731 QFileInfo info(u.toLocalFile()); 3732 bool ok = info.exists(); 3733 3734 QString text = u.toDisplayString().toHtmlEscaped(); 3735 QString text2 = text; 3736 3737 if (info.isSymLink()) { 3738 QString tmp; 3739 if (com.isEmpty()) { 3740 tmp = i18n("Symbolic Link"); 3741 } else { 3742 tmp = i18n("%1 (Link)", com); 3743 } 3744 text += " -> "; 3745 QString target = info.symLinkTarget(); 3746 if (target.isEmpty()) { 3747 text2 += " "; 3748 text2 += tmp; 3749 setStatusBarText(text2, BarHoverText); 3750 return; 3751 } 3752 3753 text += target; 3754 text += " "; 3755 text += tmp; 3756 } else if (ok && info.isFile()) { 3757 if (info.size() < 1024) { 3758 text = i18np("%2 (%1 byte)", "%2 (%1 bytes)", (long) info.size(), text2); // always put the URL last, in case it contains '%' 3759 } else { 3760 float d = (float) info.size() / 1024.0; 3761 text = i18n("%2 (%1 K)", QLocale().toString(d, 'f', 2), text2); // was %.2f 3762 } 3763 text += " "; 3764 text += com; 3765 } else if (ok && info.isDir()) { 3766 text += " "; 3767 text += com; 3768 } else { 3769 text += " "; 3770 text += com; 3771 } 3772 setStatusBarText(text, BarHoverText); 3773 } else { 3774 QString extra; 3775 if (target.toLower() == "_blank") { 3776 extra = i18n(" (In new window)"); 3777 } else if (!target.isEmpty() && 3778 (target.toLower() != "_top") && 3779 (target.toLower() != "_self") && 3780 (target.toLower() != "_parent")) { 3781 KHTMLPart *p = this; 3782 while (p->parentPart()) { 3783 p = p->parentPart(); 3784 } 3785 if (!p->frameExists(target)) { 3786 extra = i18n(" (In new window)"); 3787 } else { 3788 extra = i18n(" (In other frame)"); 3789 } 3790 } 3791 3792 if (u.scheme() == QLatin1String("mailto")) { 3793 QString mailtoMsg /* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/; 3794 mailtoMsg += i18n("Email to: ") + QUrl::fromPercentEncoding(u.path().toLatin1()); 3795 const QStringList queries = u.query().mid(1).split('&'); 3796 QStringList::ConstIterator it = queries.begin(); 3797 const QStringList::ConstIterator itEnd = queries.end(); 3798 for (; it != itEnd; ++it) 3799 if ((*it).startsWith(QLatin1String("subject="))) { 3800 mailtoMsg += i18n(" - Subject: ") + QUrl::fromPercentEncoding((*it).mid(8).toLatin1()); 3801 } else if ((*it).startsWith(QLatin1String("cc="))) { 3802 mailtoMsg += i18n(" - CC: ") + QUrl::fromPercentEncoding((*it).mid(3).toLatin1()); 3803 } else if ((*it).startsWith(QLatin1String("bcc="))) { 3804 mailtoMsg += i18n(" - BCC: ") + QUrl::fromPercentEncoding((*it).mid(4).toLatin1()); 3805 } 3806 mailtoMsg = mailtoMsg.toHtmlEscaped(); 3807 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), QString()); 3808 setStatusBarText("<qt>" + mailtoMsg, BarHoverText); 3809 return; 3810 } 3811 // Is this check necessary at all? (Frerich) 3812 #if 0 3813 else if (u.scheme() == QLatin1String("http")) { 3814 DOM::Node hrefNode = nodeUnderMouse().parentNode(); 3815 while (hrefNode.nodeName().string() != QLatin1String("A") && !hrefNode.isNull()) { 3816 hrefNode = hrefNode.parentNode(); 3817 } 3818 3819 if (!hrefNode.isNull()) { 3820 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG"); 3821 if (!hreflangNode.isNull()) { 3822 QString countryCode = hreflangNode.nodeValue().string().toLower(); 3823 // Map the language code to an appropriate country code. 3824 if (countryCode == QLatin1String("en")) { 3825 countryCode = QLatin1String("gb"); 3826 } 3827 QString flagImg = QLatin1String("<img src=%1>").arg( 3828 locate("locale", QLatin1String("l10n/") 3829 + countryCode 3830 + QLatin1String("/kf5_flag.png"))); 3831 emit setStatusBarText(flagImg + u.toDisplayString() + extra); 3832 } 3833 } 3834 } 3835 #endif 3836 setStatusBarText(u.toDisplayString().toHtmlEscaped() + extra, BarHoverText); 3837 } 3838 } 3839 3840 // 3841 // This executes in the active part on a click or other url selection action in 3842 // that active part. 3843 // 3844 bool KHTMLPart::urlSelected(const QString &url, int button, int state, const QString &_target, const KParts::OpenUrlArguments &_args, const KParts::BrowserArguments &_browserArgs) 3845 { 3846 KParts::OpenUrlArguments args = _args; 3847 KParts::BrowserArguments browserArgs = _browserArgs; 3848 bool hasTarget = false; 3849 3850 QString target = _target; 3851 if (target.isEmpty() && d->m_doc) { 3852 target = d->m_doc->baseTarget(); 3853 } 3854 if (!target.isEmpty()) { 3855 hasTarget = true; 3856 } 3857 3858 if (d->isJavaScriptURL(url)) { 3859 crossFrameExecuteScript(target, d->codeForJavaScriptURL(url)); 3860 return false; 3861 } 3862 3863 QUrl cURL = completeURL(url); 3864 // special case for <a href=""> (IE removes filename, mozilla doesn't) 3865 if (url.isEmpty()) { 3866 cURL = cURL.adjusted(QUrl::RemoveFilename); 3867 } 3868 3869 if (!cURL.isValid()) 3870 // ### ERROR HANDLING 3871 { 3872 return false; 3873 } 3874 3875 // qCDebug(KHTML_LOG) << this << "complete URL:" << cURL << "target=" << target; 3876 3877 if (state & Qt::ControlModifier) { 3878 emit d->m_extension->createNewWindow(cURL, args, browserArgs); 3879 return true; 3880 } 3881 3882 if (button == Qt::LeftButton && (state & Qt::ShiftModifier)) { 3883 KIO::MetaData metaData; 3884 metaData.insert("referrer", d->m_referrer); 3885 KHTMLPopupGUIClient::saveURL(d->m_view, i18n("Save As"), cURL, metaData); 3886 return false; 3887 } 3888 3889 if (!checkLinkSecurity(cURL, 3890 ki18n("<qt>This untrusted page links to<br /><b>%1</b>.<br />Do you want to follow the link?</qt>"), 3891 i18n("Follow"))) { 3892 return false; 3893 } 3894 3895 browserArgs.frameName = target; 3896 3897 args.metaData().insert("main_frame_request", 3898 parentPart() == nullptr ? "TRUE" : "FALSE"); 3899 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip); 3900 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert); 3901 args.metaData().insert("PropagateHttpHeader", "true"); 3902 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE"); 3903 args.metaData().insert("ssl_activate_warnings", "TRUE"); 3904 3905 if (hasTarget && target != "_self" && target != "_top" && target != "_blank" && target != "_parent") { 3906 // unknown frame names should open in a new window. 3907 khtml::ChildFrame *frame = recursiveFrameRequest(this, cURL, args, browserArgs, false); 3908 if (frame) { 3909 args.metaData()["referrer"] = d->m_referrer; 3910 requestObject(frame, cURL, args, browserArgs); 3911 return true; 3912 } 3913 } 3914 3915 if (!d->m_referrer.isEmpty() && !args.metaData().contains("referrer")) { 3916 args.metaData()["referrer"] = d->m_referrer; 3917 } 3918 3919 if (button == Qt::NoButton && (state & Qt::ShiftModifier) && (state & Qt::ControlModifier)) { 3920 emit d->m_extension->createNewWindow(cURL, args, browserArgs); 3921 return true; 3922 } 3923 3924 if (state & Qt::ShiftModifier) { 3925 KParts::WindowArgs winArgs; 3926 winArgs.setLowerWindow(true); 3927 emit d->m_extension->createNewWindow(cURL, args, browserArgs, winArgs); 3928 return true; 3929 } 3930 3931 //If we're asked to open up an anchor in the current URL, in current window, 3932 //merely gotoanchor, and do not reload the new page. Note that this does 3933 //not apply if the URL is the same page, but without a ref 3934 if (cURL.hasFragment() && (!hasTarget || target == "_self")) { 3935 if (d->isLocalAnchorJump(cURL)) { 3936 d->executeAnchorJump(cURL, browserArgs.lockHistory()); 3937 return false; // we jumped, but we didn't open a URL 3938 } 3939 } 3940 3941 if (!d->m_bComplete && !hasTarget) { 3942 closeUrl(); 3943 } 3944 3945 view()->viewport()->unsetCursor(); 3946 emit d->m_extension->openUrlRequest(cURL, args, browserArgs); 3947 return true; 3948 } 3949 3950 void KHTMLPart::slotViewDocumentSource() 3951 { 3952 QUrl currentUrl(this->url()); 3953 KRun::RunFlags runFlags; 3954 if (!(currentUrl.isLocalFile()) && KHTMLPageCache::self()->isComplete(d->m_cacheId)) { 3955 QTemporaryFile sourceFile(QDir::tempPath() + QLatin1String("/XXXXXX") + defaultExtension()); 3956 sourceFile.setAutoRemove(false); 3957 if (sourceFile.open()) { 3958 QDataStream stream(&sourceFile); 3959 KHTMLPageCache::self()->saveData(d->m_cacheId, &stream); 3960 currentUrl = QUrl::fromLocalFile(sourceFile.fileName()); 3961 runFlags |= KRun::DeleteTemporaryFiles; 3962 } 3963 } 3964 3965 (void) KRun::runUrl(currentUrl, QLatin1String("text/plain"), view(), runFlags); 3966 } 3967 3968 void KHTMLPart::slotViewPageInfo() 3969 { 3970 Ui_KHTMLInfoDlg ui; 3971 3972 QDialog *dlg = new QDialog(nullptr); 3973 dlg->setAttribute(Qt::WA_DeleteOnClose); 3974 dlg->setObjectName("KHTML Page Info Dialog"); 3975 ui.setupUi(dlg); 3976 3977 KGuiItem::assign(ui._close, KStandardGuiItem::close()); 3978 connect(ui._close, SIGNAL(clicked()), dlg, SLOT(accept())); 3979 3980 if (d->m_doc) { 3981 ui._title->setText(d->m_doc->title().string().trimmed()); 3982 } 3983 3984 // If it's a frame, set the caption to "Frame Information" 3985 if (parentPart() && d->m_doc && d->m_doc->isHTMLDocument()) { 3986 dlg->setWindowTitle(i18n("Frame Information")); 3987 } 3988 3989 QString editStr; 3990 3991 if (!d->m_pageServices.isEmpty()) { 3992 editStr = i18n(" <a href=\"%1\">[Properties]</a>", d->m_pageServices); 3993 } 3994 3995 QString squeezedURL = KStringHandler::csqueeze(url().toDisplayString(), 80); 3996 ui._url->setText("<a href=\"" + url().toString() + "\">" + squeezedURL + "</a>" + editStr); 3997 if (lastModified().isEmpty()) { 3998 ui._lastModified->hide(); 3999 ui._lmLabel->hide(); 4000 } else { 4001 ui._lastModified->setText(lastModified()); 4002 } 4003 4004 const QString &enc = encoding(); 4005 if (enc.isEmpty()) { 4006 ui._eLabel->hide(); 4007 ui._encoding->hide(); 4008 } else { 4009 ui._encoding->setText(enc); 4010 } 4011 4012 if (!xmlDocImpl() || xmlDocImpl()->parseMode() == DOM::DocumentImpl::Unknown) { 4013 ui._mode->hide(); 4014 ui._modeLabel->hide(); 4015 } else { 4016 switch (xmlDocImpl()->parseMode()) { 4017 case DOM::DocumentImpl::Compat: 4018 ui._mode->setText(i18nc("HTML rendering mode (see https://en.wikipedia.org/wiki/Quirks_mode)", "Quirks")); 4019 break; 4020 case DOM::DocumentImpl::Transitional: 4021 ui._mode->setText(i18nc("HTML rendering mode (see https://en.wikipedia.org/wiki/Quirks_mode)", "Almost standards")); 4022 break; 4023 case DOM::DocumentImpl::Strict: 4024 default: // others handled above 4025 ui._mode->setText(i18nc("HTML rendering mode (see https://en.wikipedia.org/wiki/Quirks_mode)", "Strict")); 4026 break; 4027 } 4028 } 4029 4030 /* populate the list view now */ 4031 const QStringList headers = d->m_httpHeaders.split("\n"); 4032 4033 QStringList::ConstIterator it = headers.begin(); 4034 const QStringList::ConstIterator itEnd = headers.end(); 4035 4036 for (; it != itEnd; ++it) { 4037 const QStringList header = (*it).split(QRegExp(":[ ]+")); 4038 if (header.count() != 2) { 4039 continue; 4040 } 4041 QTreeWidgetItem *item = new QTreeWidgetItem(ui._headers); 4042 item->setText(0, header[0]); 4043 item->setText(1, header[1]); 4044 } 4045 4046 dlg->show(); 4047 /* put no code here */ 4048 } 4049 4050 void KHTMLPart::slotViewFrameSource() 4051 { 4052 KParts::ReadOnlyPart *frame = currentFrame(); 4053 if (!frame) { 4054 return; 4055 } 4056 4057 QUrl url = frame->url(); 4058 KRun::RunFlags runFlags; 4059 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart")) { 4060 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId; 4061 4062 if (KHTMLPageCache::self()->isComplete(cacheId)) { 4063 QTemporaryFile sourceFile(QDir::tempPath() + QLatin1String("/XXXXXX") + defaultExtension()); 4064 sourceFile.setAutoRemove(false); 4065 if (sourceFile.open()) { 4066 QDataStream stream(&sourceFile); 4067 KHTMLPageCache::self()->saveData(cacheId, &stream); 4068 url = QUrl(); 4069 url.setPath(sourceFile.fileName()); 4070 runFlags |= KRun::DeleteTemporaryFiles; 4071 } 4072 } 4073 } 4074 4075 (void) KRun::runUrl(url, QLatin1String("text/plain"), view(), runFlags); 4076 } 4077 4078 QUrl KHTMLPart::backgroundURL() const 4079 { 4080 // ### what about XML documents? get from CSS? 4081 if (!d->m_doc || !d->m_doc->isHTMLDocument()) { 4082 return QUrl(); 4083 } 4084 4085 QString relURL = static_cast<HTMLDocumentImpl *>(d->m_doc)->body()->getAttribute(ATTR_BACKGROUND).string(); 4086 4087 return url().resolved(QUrl(relURL)); 4088 } 4089 4090 void KHTMLPart::slotSaveBackground() 4091 { 4092 KIO::MetaData metaData; 4093 metaData["referrer"] = d->m_referrer; 4094 KHTMLPopupGUIClient::saveURL(d->m_view, i18n("Save Background Image As"), backgroundURL(), metaData); 4095 } 4096 4097 void KHTMLPart::slotSaveDocument() 4098 { 4099 QUrl srcURL(url()); 4100 4101 if (srcURL.fileName().isEmpty()) { 4102 srcURL.setPath(srcURL.path() + "index" + defaultExtension()); 4103 } 4104 4105 KIO::MetaData metaData; 4106 // Referre unknown? 4107 KHTMLPopupGUIClient::saveURL(d->m_view, i18n("Save As"), srcURL, metaData, "text/html", d->m_cacheId); 4108 } 4109 4110 void KHTMLPart::slotSecurity() 4111 { 4112 // qCDebug(KHTML_LOG) << "Meta Data:" << endl 4113 // << d->m_ssl_peer_cert_subject 4114 // << endl 4115 // << d->m_ssl_peer_cert_issuer 4116 // << endl 4117 // << d->m_ssl_cipher 4118 // << endl 4119 // << d->m_ssl_cipher_desc 4120 // << endl 4121 // << d->m_ssl_cipher_version 4122 // << endl 4123 // << d->m_ssl_good_from 4124 // << endl 4125 // << d->m_ssl_good_until 4126 // << endl 4127 // << d->m_ssl_cert_state 4128 // << endl; 4129 4130 //### reenable with new signature 4131 #if 0 4132 KSslInfoDialog *kid = new KSslInfoDialog(d->m_ssl_in_use, widget(), "kssl_info_dlg", true); 4133 4134 const QStringList sl = d->m_ssl_peer_chain.split('\n', QString::SkipEmptyParts); 4135 QList<QSslCertificate> certChain; 4136 bool certChainOk = d->m_ssl_in_use; 4137 if (certChainOk) { 4138 foreach (const QString &s, sl) { 4139 certChain.append(QSslCertificate(s.toLatin1())); //or is it toLocal8Bit or whatever? 4140 if (certChain.last().isNull()) { 4141 certChainOk = false; 4142 break; 4143 } 4144 } 4145 } 4146 if (certChainOk) { 4147 kid->setup(certChain, 4148 d->m_ssl_peer_ip, 4149 url().toString(), 4150 d->m_ssl_cipher, 4151 d->m_ssl_cipher_desc, 4152 d->m_ssl_cipher_version, 4153 d->m_ssl_cipher_used_bits.toInt(), 4154 d->m_ssl_cipher_bits.toInt(), 4155 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt()); 4156 } 4157 kid->exec(); 4158 //the dialog deletes itself on close 4159 #endif 4160 4161 KSslInfoDialog *kid = new KSslInfoDialog(nullptr); 4162 //### This is boilerplate code and it's copied from SlaveInterface. 4163 QStringList sl = d->m_ssl_peer_chain.split('\x01', QString::SkipEmptyParts); 4164 QList<QSslCertificate> certChain; 4165 bool decodedOk = true; 4166 foreach (const QString &s, sl) { 4167 certChain.append(QSslCertificate(s.toLatin1())); //or is it toLocal8Bit or whatever? 4168 if (certChain.last().isNull()) { 4169 decodedOk = false; 4170 break; 4171 } 4172 } 4173 4174 if (decodedOk || true /*H4X*/) { 4175 kid->setSslInfo(certChain, 4176 d->m_ssl_peer_ip, 4177 url().host(), 4178 d->m_ssl_protocol_version, 4179 d->m_ssl_cipher, 4180 d->m_ssl_cipher_used_bits.toInt(), 4181 d->m_ssl_cipher_bits.toInt(), 4182 KSslInfoDialog::errorsFromString(d->m_ssl_cert_errors)); 4183 // qCDebug(KHTML_LOG) << "Showing SSL Info dialog"; 4184 kid->exec(); 4185 // qCDebug(KHTML_LOG) << "SSL Info dialog closed"; 4186 } else { 4187 KMessageBox::information(nullptr, i18n("The peer SSL certificate chain " 4188 "appears to be corrupt."), 4189 i18n("SSL")); 4190 } 4191 } 4192 4193 void KHTMLPart::slotSaveFrame() 4194 { 4195 KParts::ReadOnlyPart *frame = currentFrame(); 4196 if (!frame) { 4197 return; 4198 } 4199 4200 QUrl srcURL(frame->url()); 4201 4202 if (srcURL.fileName().isEmpty()) { 4203 srcURL.setPath(srcURL.path() + "index" + defaultExtension()); 4204 } 4205 4206 KIO::MetaData metaData; 4207 // Referrer unknown? 4208 KHTMLPopupGUIClient::saveURL(d->m_view, i18n("Save Frame As"), srcURL, metaData, "text/html"); 4209 } 4210 4211 void KHTMLPart::slotSetEncoding(const QString &enc) 4212 { 4213 d->m_autoDetectLanguage = KEncodingProber::None; 4214 setEncoding(enc, true); 4215 } 4216 4217 void KHTMLPart::slotAutomaticDetectionLanguage(KEncodingProber::ProberType scri) 4218 { 4219 d->m_autoDetectLanguage = scri; 4220 setEncoding(QString(), false); 4221 } 4222 4223 void KHTMLPart::slotUseStylesheet() 4224 { 4225 if (d->m_doc) { 4226 bool autoselect = (d->m_paUseStylesheet->currentItem() == 0); 4227 d->m_sheetUsed = autoselect ? QString() : d->m_paUseStylesheet->currentText(); 4228 d->m_doc->updateStyleSelector(); 4229 } 4230 } 4231 4232 void KHTMLPart::updateActions() 4233 { 4234 bool frames = false; 4235 4236 QList<khtml::ChildFrame *>::ConstIterator it = d->m_frames.constBegin(); 4237 const QList<khtml::ChildFrame *>::ConstIterator end = d->m_frames.constEnd(); 4238 for (; it != end; ++it) 4239 if ((*it)->m_type == khtml::ChildFrame::Frame) { 4240 frames = true; 4241 break; 4242 } 4243 4244 if (d->m_paViewFrame) { 4245 d->m_paViewFrame->setEnabled(frames); 4246 } 4247 if (d->m_paSaveFrame) { 4248 d->m_paSaveFrame->setEnabled(frames); 4249 } 4250 4251 if (frames) { 4252 d->m_paFind->setText(i18n("&Find in Frame...")); 4253 } else { 4254 d->m_paFind->setText(i18n("&Find...")); 4255 } 4256 4257 KParts::Part *frame = nullptr; 4258 4259 if (frames) { 4260 frame = currentFrame(); 4261 } 4262 4263 bool enableFindAndSelectAll = true; 4264 4265 if (frame) { 4266 enableFindAndSelectAll = frame->inherits("KHTMLPart"); 4267 } 4268 4269 d->m_paFind->setEnabled(enableFindAndSelectAll); 4270 d->m_paSelectAll->setEnabled(enableFindAndSelectAll); 4271 4272 bool enablePrintFrame = false; 4273 4274 if (frame) { 4275 QObject *ext = KParts::BrowserExtension::childObject(frame); 4276 if (ext) { 4277 enablePrintFrame = ext->metaObject()->indexOfSlot("print()") != -1; 4278 } 4279 } 4280 4281 d->m_paPrintFrame->setEnabled(enablePrintFrame); 4282 4283 QString bgURL; 4284 4285 // ### frames 4286 if (d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl *>(d->m_doc)->body() && !d->m_bClearing) { 4287 bgURL = static_cast<HTMLDocumentImpl *>(d->m_doc)->body()->getAttribute(ATTR_BACKGROUND).string(); 4288 } 4289 4290 if (d->m_paSaveBackground) { 4291 d->m_paSaveBackground->setEnabled(!bgURL.isEmpty()); 4292 } 4293 4294 if (d->m_paDebugScript) { 4295 d->m_paDebugScript->setEnabled(d->m_frame ? d->m_frame->m_jscript : nullptr); 4296 } 4297 } 4298 4299 KParts::ScriptableExtension *KHTMLPart::scriptableExtension(const DOM::NodeImpl *frame) 4300 { 4301 const ConstFrameIt end = d->m_objects.constEnd(); 4302 for (ConstFrameIt it = d->m_objects.constBegin(); it != end; ++it) 4303 if ((*it)->m_partContainerElement.data() == frame) { 4304 return (*it)->m_scriptable.data(); 4305 } 4306 return nullptr; 4307 } 4308 4309 void KHTMLPart::loadFrameElement(DOM::HTMLPartContainerElementImpl *frame, const QString &url, 4310 const QString &frameName, const QStringList ¶ms, bool isIFrame) 4311 { 4312 //qCDebug(KHTML_LOG) << this << " requestFrame( ..., " << url << ", " << frameName << " )"; 4313 khtml::ChildFrame *child; 4314 4315 FrameIt it = d->m_frames.find(frameName); 4316 if (it == d->m_frames.end()) { 4317 child = new khtml::ChildFrame; 4318 //qCDebug(KHTML_LOG) << "inserting new frame into frame map " << frameName; 4319 child->m_name = frameName; 4320 d->m_frames.insert(d->m_frames.end(), child); 4321 } else { 4322 child = *it; 4323 } 4324 4325 child->m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame; 4326 child->m_partContainerElement = frame; 4327 child->m_params = params; 4328 4329 // If we do not have a part, make sure we create one. 4330 if (!child->m_part) { 4331 QStringList dummy; // the list of servicetypes handled by the part is now unused. 4332 QString khtml = QString::fromLatin1("khtml"); 4333 KParts::ReadOnlyPart *part = createPart(d->m_view->viewport(), this, 4334 QString::fromLatin1("text/html"), 4335 khtml, dummy, QStringList()); 4336 // We navigate it to about:blank to setup an empty one, but we do it 4337 // before hooking up the signals and extensions, so that any sync emit 4338 // of completed by the kid doesn't cause us to be marked as completed. 4339 // (async ones are discovered by the presence of the KHTMLRun) 4340 // ### load event on the kid? 4341 navigateLocalProtocol(child, part, QUrl("about:blank")); 4342 connectToChildPart(child, part, "text/html" /* mimetype of the part, not what's being loaded */); 4343 } 4344 4345 QUrl u = url.isEmpty() ? QUrl() : completeURL(url); 4346 4347 // Since we don't specify args here a KHTMLRun will be used to determine the 4348 // mimetype, which will then be passed down at the bottom of processObjectRequest 4349 // inside URLArgs to the part. In our particular case, this means that we can 4350 // use that inside KHTMLPart::openUrl to route things appropriately. 4351 child->m_bCompleted = false; 4352 if (!requestObject(child, u) && !child->m_run) { 4353 child->m_bCompleted = true; 4354 } 4355 } 4356 4357 QString KHTMLPart::requestFrameName() 4358 { 4359 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++); 4360 } 4361 4362 bool KHTMLPart::loadObjectElement(DOM::HTMLPartContainerElementImpl *frame, const QString &url, 4363 const QString &serviceType, const QStringList ¶ms) 4364 { 4365 //qCDebug(KHTML_LOG) << this << "frame=" << frame; 4366 khtml::ChildFrame *child = new khtml::ChildFrame; 4367 FrameIt it = d->m_objects.insert(d->m_objects.end(), child); 4368 (*it)->m_partContainerElement = frame; 4369 (*it)->m_type = khtml::ChildFrame::Object; 4370 (*it)->m_params = params; 4371 4372 KParts::OpenUrlArguments args; 4373 args.setMimeType(serviceType); 4374 if (!requestObject(*it, completeURL(url), args) && !(*it)->m_run) { 4375 (*it)->m_bCompleted = true; 4376 return false; 4377 } 4378 return true; 4379 } 4380 4381 bool KHTMLPart::requestObject(khtml::ChildFrame *child, const QUrl &url, const KParts::OpenUrlArguments &_args, 4382 const KParts::BrowserArguments &browserArgs) 4383 { 4384 // we always permit javascript: URLs here since they're basically just 4385 // empty pages (and checkLinkSecurity/KAuthorized doesn't know what to do with them) 4386 if (!d->isJavaScriptURL(url.toString()) && !checkLinkSecurity(url)) { 4387 // qCDebug(KHTML_LOG) << this << "checkLinkSecurity refused"; 4388 return false; 4389 } 4390 4391 if (d->m_bClearing) { 4392 return false; 4393 } 4394 4395 if (child->m_bPreloaded) { 4396 if (child->m_partContainerElement && child->m_part) { 4397 child->m_partContainerElement.data()->setWidget(child->m_part.data()->widget()); 4398 } 4399 4400 child->m_bPreloaded = false; 4401 return true; 4402 } 4403 4404 //qCDebug(KHTML_LOG) << "child=" << child << "child->m_part=" << child->m_part; 4405 4406 KParts::OpenUrlArguments args(_args); 4407 4408 if (child->m_run) { 4409 // qCDebug(KHTML_LOG) << "navigating ChildFrame while mimetype resolution was in progress..."; 4410 child->m_run.data()->abort(); 4411 } 4412 4413 // ### Dubious -- the whole dir/ vs. img thing 4414 if (child->m_part && !args.reload() && areUrlsForSamePage(child->m_part.data()->url(), url)) { 4415 args.setMimeType(child->m_serviceType); 4416 } 4417 4418 child->m_browserArgs = browserArgs; 4419 child->m_args = args; 4420 4421 // reload/soft-reload arguments are always inherited from parent 4422 child->m_args.setReload(arguments().reload()); 4423 child->m_browserArgs.softReload = d->m_extension->browserArguments().softReload; 4424 4425 child->m_serviceName.clear(); 4426 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains("referrer")) { 4427 child->m_args.metaData()["referrer"] = d->m_referrer; 4428 } 4429 4430 child->m_args.metaData().insert("PropagateHttpHeader", "true"); 4431 child->m_args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip); 4432 child->m_args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert); 4433 child->m_args.metaData().insert("main_frame_request", 4434 parentPart() == nullptr ? "TRUE" : "FALSE"); 4435 child->m_args.metaData().insert("ssl_was_in_use", 4436 d->m_ssl_in_use ? "TRUE" : "FALSE"); 4437 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE"); 4438 child->m_args.metaData().insert("cross-domain", toplevelURL().toString()); 4439 4440 // We know the frame will be text/html if the HTML says <frame src=""> or <frame src="about:blank">, 4441 // no need to KHTMLRun to figure out the mimetype" 4442 // ### What if we're inside an XML document? 4443 if ((url.isEmpty() || url.toString() == "about:blank" || url.scheme() == "javascript") && args.mimeType().isEmpty()) { 4444 args.setMimeType(QLatin1String("text/html")); 4445 } 4446 4447 if (args.mimeType().isEmpty()) { 4448 // qCDebug(KHTML_LOG) << "Running new KHTMLRun for" << this << "and child=" << child; 4449 child->m_run = new KHTMLRun(this, child, url, child->m_args, child->m_browserArgs, true); 4450 d->m_bComplete = false; // ensures we stop it in checkCompleted... 4451 return false; 4452 } else { 4453 return processObjectRequest(child, url, args.mimeType()); 4454 } 4455 } 4456 4457 void KHTMLPart::childLoadFailure(khtml::ChildFrame *child) 4458 { 4459 child->m_bCompleted = true; 4460 if (child->m_partContainerElement) { 4461 child->m_partContainerElement.data()->partLoadingErrorNotify(); 4462 } 4463 4464 checkCompleted(); 4465 } 4466 4467 bool KHTMLPart::processObjectRequest(khtml::ChildFrame *child, const QUrl &_url, const QString &mimetype) 4468 { 4469 // qCDebug(KHTML_LOG) << "trying to create part for" << mimetype << _url; 4470 4471 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given 4472 // by an emitting frame part (emit openUrlRequest( blahurl, ... ) . A few lines below we delete the part 4473 // though -> the reference becomes invalid -> crash is likely 4474 QUrl url(_url); 4475 4476 // khtmlrun called us with empty url + mimetype to indicate a loading error, 4477 // we obviosuly failed; but we can return true here since we don't want it 4478 // doing anything more, while childLoadFailure is enough to notify our kid. 4479 if (d->m_onlyLocalReferences || (url.isEmpty() && mimetype.isEmpty())) { 4480 childLoadFailure(child); 4481 return true; 4482 } 4483 4484 // we also want to ignore any spurious requests due to closing when parser is being cleared. These should be 4485 // ignored entirely --- the tail end of ::clear will clean things up. 4486 if (d->m_bClearing) { 4487 return false; 4488 } 4489 4490 if (child->m_bNotify) { 4491 child->m_bNotify = false; 4492 if (!child->m_browserArgs.lockHistory()) { 4493 emit d->m_extension->openUrlNotify(); 4494 } 4495 } 4496 4497 QMimeDatabase db; 4498 4499 // Now, depending on mimetype and current state of the world, we may have 4500 // to create a new part or ask the user to save things, etc. 4501 // 4502 // We need a new part if there isn't one at all (doh) or the one that's there 4503 // is not for the mimetype we're loading. 4504 // 4505 // For these new types, we may have to ask the user to save it or not 4506 // (we don't if it's navigating the same type). 4507 // Further, we will want to ask if content-disposition suggests we ask for 4508 // saving, even if we're re-navigating. 4509 if (!child->m_part || child->m_serviceType != mimetype || 4510 (child->m_run && child->m_run.data()->serverSuggestsSave())) { 4511 // We often get here if we didn't know the mimetype in advance, and had to rely 4512 // on KRun to figure it out. In this case, we let the element check if it wants to 4513 // handle this mimetype itself, for e.g. objects containing images. 4514 if (child->m_partContainerElement && 4515 child->m_partContainerElement.data()->mimetypeHandledInternally(mimetype)) { 4516 child->m_bCompleted = true; 4517 checkCompleted(); 4518 return true; 4519 } 4520 4521 // Before attempting to load a part, check if the user wants that. 4522 // Many don't like getting ZIP files embedded. 4523 // However we don't want to ask for flash and other plugin things. 4524 // 4525 // Note: this is fine for frames, since we will merely effectively ignore 4526 // the navigation if this happens 4527 if (child->m_type != khtml::ChildFrame::Object && child->m_type != khtml::ChildFrame::IFrame) { 4528 QString suggestedFileName; 4529 int disposition = 0; 4530 if (KHTMLRun *run = child->m_run.data()) { 4531 suggestedFileName = run->suggestedFileName(); 4532 disposition = run->serverSuggestsSave() ? 4533 KParts::BrowserRun::AttachmentDisposition : 4534 KParts::BrowserRun::InlineDisposition; 4535 } 4536 4537 KParts::BrowserOpenOrSaveQuestion dlg(widget(), url, mimetype); 4538 dlg.setSuggestedFileName(suggestedFileName); 4539 const KParts::BrowserOpenOrSaveQuestion::Result res = dlg.askEmbedOrSave(disposition); 4540 4541 switch (res) { 4542 case KParts::BrowserOpenOrSaveQuestion::Save: 4543 KHTMLPopupGUIClient::saveURL(widget(), i18n("Save As"), url, child->m_args.metaData(), QString(), 0, suggestedFileName); 4544 // fall-through 4545 case KParts::BrowserOpenOrSaveQuestion::Cancel: 4546 child->m_bCompleted = true; 4547 checkCompleted(); 4548 return true; // done 4549 default: // Embed 4550 break; 4551 } 4552 } 4553 4554 // Now, for frames and iframes, we always create a KHTMLPart anyway, 4555 // doing it in advance when registering the frame. So we want the 4556 // actual creation only for objects here. 4557 if (child->m_type == khtml::ChildFrame::Object) { 4558 QMimeType mime = db.mimeTypeForName(mimetype); 4559 if (mime.isValid()) { 4560 // Even for objects, however, we want to force a KHTMLPart for 4561 // html & xml, even if the normally preferred part is another one, 4562 // so that we can script the target natively via contentDocument method. 4563 if (mime.inherits("text/html") 4564 || mime.inherits("application/xml")) { // this includes xhtml and svg 4565 child->m_serviceName = "khtml"; 4566 } else { 4567 if (!pluginsEnabled()) { 4568 childLoadFailure(child); 4569 return false; 4570 } 4571 } 4572 } 4573 4574 QStringList dummy; // the list of servicetypes handled by the part is now unused. 4575 KParts::ReadOnlyPart *part = createPart(d->m_view->viewport(), this, mimetype, child->m_serviceName, dummy, child->m_params); 4576 4577 if (!part) { 4578 childLoadFailure(child); 4579 return false; 4580 } 4581 4582 connectToChildPart(child, part, mimetype); 4583 } 4584 } 4585 4586 checkEmitLoadEvent(); 4587 4588 // Some JS code in the load event may have destroyed the part 4589 // In that case, abort 4590 if (!child->m_part) { 4591 return false; 4592 } 4593 4594 if (child->m_bPreloaded) { 4595 if (child->m_partContainerElement && child->m_part) { 4596 child->m_partContainerElement.data()->setWidget(child->m_part.data()->widget()); 4597 } 4598 4599 child->m_bPreloaded = false; 4600 return true; 4601 } 4602 4603 // reload/soft-reload arguments are always inherited from parent 4604 child->m_args.setReload(arguments().reload()); 4605 child->m_browserArgs.softReload = d->m_extension->browserArguments().softReload; 4606 4607 // make sure the part has a way to find out about the mimetype. 4608 // we actually set it in child->m_args in requestObject already, 4609 // but it's useless if we had to use a KHTMLRun instance, as the 4610 // point the run object is to find out exactly the mimetype. 4611 child->m_args.setMimeType(mimetype); 4612 child->m_part.data()->setArguments(child->m_args); 4613 4614 // if not a frame set child as completed 4615 // ### dubious. 4616 child->m_bCompleted = child->m_type == khtml::ChildFrame::Object; 4617 4618 if (child->m_extension) { 4619 child->m_extension.data()->setBrowserArguments(child->m_browserArgs); 4620 } 4621 4622 return navigateChild(child, url); 4623 } 4624 4625 bool KHTMLPart::navigateLocalProtocol(khtml::ChildFrame * /*child*/, KParts::ReadOnlyPart *inPart, 4626 const QUrl &url) 4627 { 4628 if (!qobject_cast<KHTMLPart *>(inPart)) { 4629 return false; 4630 } 4631 4632 KHTMLPart *p = static_cast<KHTMLPart *>(static_cast<KParts::ReadOnlyPart *>(inPart)); 4633 4634 p->begin(); 4635 4636 // We may have to re-propagate the domain here if we go here due to navigation 4637 d->propagateInitialDomainAndBaseTo(p); 4638 4639 // Support for javascript: sources 4640 if (d->isJavaScriptURL(url.toString())) { 4641 // See if we want to replace content with javascript: output.. 4642 QVariant res = p->executeScript(DOM::Node(), 4643 d->codeForJavaScriptURL(url.toString())); 4644 if (res.type() == QVariant::String && p->d->m_redirectURL.isEmpty()) { 4645 p->begin(); 4646 p->setAlwaysHonourDoctype(); // Disable public API compat; it messes with doctype 4647 // We recreated the document, so propagate domain again. 4648 d->propagateInitialDomainAndBaseTo(p); 4649 p->write(res.toString()); 4650 p->end(); 4651 } 4652 } else { 4653 p->setUrl(url); 4654 // we need a body element. testcase: <iframe id="a"></iframe><script>alert(a.document.body);</script> 4655 p->write("<HTML><TITLE></TITLE><BODY></BODY></HTML>"); 4656 } 4657 p->end(); 4658 // we don't need to worry about child completion explicitly for KHTMLPart... 4659 // or do we? 4660 return true; 4661 } 4662 4663 bool KHTMLPart::navigateChild(khtml::ChildFrame *child, const QUrl &url) 4664 { 4665 if (url.scheme() == "javascript" || url.toString() == "about:blank") { 4666 return navigateLocalProtocol(child, child->m_part.data(), url); 4667 } else if (!url.isEmpty()) { 4668 // qCDebug(KHTML_LOG) << "opening" << url << "in frame" << child->m_part; 4669 bool b = child->m_part.data()->openUrl(url); 4670 if (child->m_bCompleted) { 4671 checkCompleted(); 4672 } 4673 return b; 4674 } else { 4675 // empty URL -> no need to navigate 4676 child->m_bCompleted = true; 4677 checkCompleted(); 4678 return true; 4679 } 4680 } 4681 4682 void KHTMLPart::connectToChildPart(khtml::ChildFrame *child, KParts::ReadOnlyPart *part, 4683 const QString &mimetype) 4684 { 4685 // qCDebug(KHTML_LOG) << "we:" << this << "kid:" << child << part << mimetype; 4686 4687 part->setObjectName(child->m_name); 4688 4689 // Cleanup any previous part for this childframe and its connections 4690 if (KParts::ReadOnlyPart *p = child->m_part.data()) { 4691 if (!qobject_cast<KHTMLPart *>(p) && child->m_jscript) { 4692 child->m_jscript->clear(); 4693 } 4694 partManager()->removePart(p); 4695 delete p; 4696 child->m_scriptable.clear(); 4697 } 4698 4699 child->m_part = part; 4700 4701 child->m_serviceType = mimetype; 4702 if (child->m_partContainerElement && part->widget()) { 4703 child->m_partContainerElement.data()->setWidget(part->widget()); 4704 } 4705 4706 if (child->m_type != khtml::ChildFrame::Object) { 4707 partManager()->addPart(part, false); 4708 } 4709 // else 4710 // qCDebug(KHTML_LOG) << "AH! NO FRAME!!!!!"; 4711 4712 if (qobject_cast<KHTMLPart *>(part)) { 4713 static_cast<KHTMLPart *>(part)->d->m_frame = child; 4714 } else if (child->m_partContainerElement) { 4715 // See if this can be scripted.. 4716 KParts::ScriptableExtension *scriptExt = KParts::ScriptableExtension::childObject(part); 4717 if (!scriptExt) { 4718 // Try to fall back to LiveConnectExtension compat 4719 KParts::LiveConnectExtension *lc = KParts::LiveConnectExtension::childObject(part); 4720 if (lc) { 4721 scriptExt = KParts::ScriptableExtension::adapterFromLiveConnect(part, lc); 4722 } 4723 } 4724 4725 if (scriptExt) { 4726 scriptExt->setHost(d->m_scriptableExtension); 4727 } 4728 child->m_scriptable = scriptExt; 4729 } 4730 KParts::StatusBarExtension *sb = KParts::StatusBarExtension::childObject(part); 4731 if (sb) { 4732 sb->setStatusBar(d->m_statusBarExtension->statusBar()); 4733 } 4734 4735 connect(part, SIGNAL(started(KIO::Job*)), 4736 this, SLOT(slotChildStarted(KIO::Job*))); 4737 connect(part, SIGNAL(completed()), 4738 this, SLOT(slotChildCompleted())); 4739 connect(part, SIGNAL(completed(bool)), 4740 this, SLOT(slotChildCompleted(bool))); 4741 connect(part, SIGNAL(setStatusBarText(QString)), 4742 this, SIGNAL(setStatusBarText(QString))); 4743 if (part->inherits("KHTMLPart")) { 4744 connect(this, SIGNAL(completed()), 4745 part, SLOT(slotParentCompleted())); 4746 connect(this, SIGNAL(completed(bool)), 4747 part, SLOT(slotParentCompleted())); 4748 // As soon as the child's document is created, we need to set its domain 4749 // (but we do so only once, so it can't be simply done in the child) 4750 connect(part, SIGNAL(docCreated()), 4751 this, SLOT(slotChildDocCreated())); 4752 } 4753 4754 child->m_extension = KParts::BrowserExtension::childObject(part); 4755 4756 if (KParts::BrowserExtension *kidBrowserExt = child->m_extension.data()) { 4757 connect(kidBrowserExt, SIGNAL(openUrlNotify()), 4758 d->m_extension, SIGNAL(openUrlNotify())); 4759 4760 connect(kidBrowserExt, SIGNAL(openUrlRequestDelayed(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)), 4761 this, SLOT(slotChildURLRequest(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments))); 4762 4763 connect(kidBrowserExt, SIGNAL(createNewWindow(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**)), 4764 d->m_extension, SIGNAL(createNewWindow(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**))); 4765 4766 connect(kidBrowserExt, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), 4767 d->m_extension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); 4768 connect(kidBrowserExt, SIGNAL(popupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), 4769 d->m_extension, SIGNAL(popupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); 4770 4771 connect(kidBrowserExt, SIGNAL(infoMessage(QString)), 4772 d->m_extension, SIGNAL(infoMessage(QString))); 4773 4774 connect(kidBrowserExt, SIGNAL(requestFocus(KParts::ReadOnlyPart*)), 4775 this, SLOT(slotRequestFocus(KParts::ReadOnlyPart*))); 4776 4777 kidBrowserExt->setBrowserInterface(d->m_extension->browserInterface()); 4778 } 4779 } 4780 4781 KParts::ReadOnlyPart *KHTMLPart::createPart(QWidget *parentWidget, 4782 QObject *parent, const QString &mimetype, 4783 QString &serviceName, QStringList &serviceTypes, 4784 const QStringList ¶ms) 4785 { 4786 QString constr; 4787 if (!serviceName.isEmpty()) { 4788 constr.append(QString::fromLatin1("DesktopEntryName == '%1'").arg(serviceName)); 4789 } 4790 4791 KService::List offers = KMimeTypeTrader::self()->query(mimetype, "KParts/ReadOnlyPart", constr); 4792 4793 if (offers.isEmpty()) { 4794 int pos = mimetype.indexOf("-plugin"); 4795 if (pos < 0) { 4796 return nullptr; 4797 } 4798 QString stripped_mime = mimetype.left(pos); 4799 offers = KMimeTypeTrader::self()->query(stripped_mime, "KParts/ReadOnlyPart", constr); 4800 if (offers.isEmpty()) { 4801 return nullptr; 4802 } 4803 } 4804 4805 KService::List::ConstIterator it = offers.constBegin(); 4806 const KService::List::ConstIterator itEnd = offers.constEnd(); 4807 for (; it != itEnd; ++it) { 4808 KService::Ptr service = (*it); 4809 4810 KPluginLoader loader(*service); 4811 KPluginFactory *const factory = loader.factory(); 4812 if (factory) { 4813 // Turn params into a QVariantList as expected by KPluginFactory 4814 QVariantList variantlist; 4815 Q_FOREACH (const QString &str, params) { 4816 variantlist << QVariant(str); 4817 } 4818 4819 if (service->serviceTypes().contains("Browser/View")) { 4820 variantlist << QString("Browser/View"); 4821 } 4822 4823 KParts::ReadOnlyPart *part = factory->create<KParts::ReadOnlyPart>(parentWidget, parent, QString(), variantlist); 4824 if (part) { 4825 serviceTypes = service->serviceTypes(); 4826 serviceName = service->name(); 4827 return part; 4828 } 4829 } else { 4830 // TODO KMessageBox::error and i18n, like in KonqFactory::createView? 4831 qCWarning(KHTML_LOG) << QString("There was an error loading the module %1.\nThe diagnostics is:\n%2") 4832 .arg(service->name()).arg(loader.errorString()); 4833 } 4834 } 4835 return nullptr; 4836 } 4837 4838 KParts::PartManager *KHTMLPart::partManager() 4839 { 4840 if (!d->m_manager && d->m_view) { 4841 d->m_manager = new KParts::PartManager(d->m_view->topLevelWidget(), this); 4842 d->m_manager->setObjectName("khtml part manager"); 4843 d->m_manager->setAllowNestedParts(true); 4844 connect(d->m_manager, SIGNAL(activePartChanged(KParts::Part*)), 4845 this, SLOT(slotActiveFrameChanged(KParts::Part*))); 4846 connect(d->m_manager, SIGNAL(partRemoved(KParts::Part*)), 4847 this, SLOT(slotPartRemoved(KParts::Part*))); 4848 } 4849 4850 return d->m_manager; 4851 } 4852 4853 void KHTMLPart::submitFormAgain() 4854 { 4855 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain())); 4856 if (d->m_doc && !d->m_doc->parsing() && d->m_submitForm) { 4857 KHTMLPart::submitForm(d->m_submitForm->submitAction, d->m_submitForm->submitUrl, d->m_submitForm->submitFormData, d->m_submitForm->target, d->m_submitForm->submitContentType, d->m_submitForm->submitBoundary); 4858 } 4859 4860 delete d->m_submitForm; 4861 d->m_submitForm = nullptr; 4862 } 4863 4864 void KHTMLPart::submitFormProxy(const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString &contentType, const QString &boundary) 4865 { 4866 submitForm(action, url, formData, _target, contentType, boundary); 4867 } 4868 4869 void KHTMLPart::submitForm(const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString &contentType, const QString &boundary) 4870 { 4871 // qCDebug(KHTML_LOG) << this << "target=" << _target << "url=" << url; 4872 if (d->m_formNotification == KHTMLPart::Only) { 4873 emit formSubmitNotification(action, url, formData, _target, contentType, boundary); 4874 return; 4875 } else if (d->m_formNotification == KHTMLPart::Before) { 4876 emit formSubmitNotification(action, url, formData, _target, contentType, boundary); 4877 } 4878 4879 QUrl u = completeURL(url); 4880 4881 if (!u.isValid()) { 4882 // ### ERROR HANDLING! 4883 return; 4884 } 4885 4886 // Form security checks 4887 // 4888 /* 4889 * If these form security checks are still in this place in a month or two 4890 * I'm going to simply delete them. 4891 */ 4892 4893 /* This is separate for a reason. It has to be _before_ all script, etc, 4894 * AND I don't want to break anything that uses checkLinkSecurity() in 4895 * other places. 4896 */ 4897 4898 if (!d->m_submitForm) { 4899 if (u.scheme() != "https" && u.scheme() != "mailto") { 4900 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL 4901 int rc = KMessageBox::warningContinueCancel(nullptr, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted." 4902 "\nA third party may be able to intercept and view this information." 4903 "\nAre you sure you wish to continue?"), 4904 i18n("Network Transmission"), KGuiItem(i18n("&Send Unencrypted"))); 4905 if (rc == KMessageBox::Cancel) { 4906 return; 4907 } 4908 } else { // Going from nonSSL -> nonSSL 4909 KSSLSettings kss(true); 4910 if (kss.warnOnUnencrypted()) { 4911 int rc = KMessageBox::warningContinueCancel(nullptr, 4912 i18n("Warning: Your data is about to be transmitted across the network unencrypted." 4913 "\nAre you sure you wish to continue?"), 4914 i18n("Network Transmission"), 4915 KGuiItem(i18n("&Send Unencrypted")), 4916 KStandardGuiItem::cancel(), 4917 "WarnOnUnencryptedForm"); 4918 // Move this setting into KSSL instead 4919 QString grpNotifMsgs = QLatin1String("Notification Messages"); 4920 KConfigGroup cg(KSharedConfig::openConfig(), grpNotifMsgs); 4921 4922 if (!cg.readEntry("WarnOnUnencryptedForm", true)) { 4923 cg.deleteEntry("WarnOnUnencryptedForm"); 4924 cg.sync(); 4925 kss.setWarnOnUnencrypted(false); 4926 kss.save(); 4927 } 4928 if (rc == KMessageBox::Cancel) { 4929 return; 4930 } 4931 } 4932 } 4933 } 4934 4935 if (u.scheme() == "mailto") { 4936 int rc = KMessageBox::warningContinueCancel(nullptr, 4937 i18n("This site is attempting to submit form data via email.\n" 4938 "Do you want to continue?"), 4939 i18n("Network Transmission"), 4940 KGuiItem(i18n("&Send Email")), 4941 KStandardGuiItem::cancel(), 4942 "WarnTriedEmailSubmit"); 4943 4944 if (rc == KMessageBox::Cancel) { 4945 return; 4946 } 4947 } 4948 } 4949 4950 // End form security checks 4951 // 4952 4953 QString urlstring = u.toString(); 4954 4955 if (d->isJavaScriptURL(urlstring)) { 4956 crossFrameExecuteScript(_target, d->codeForJavaScriptURL(urlstring)); 4957 return; 4958 } 4959 4960 if (!checkLinkSecurity(u, 4961 ki18n("<qt>The form will be submitted to <br /><b>%1</b><br />on your local filesystem.<br />Do you want to submit the form?</qt>"), 4962 i18n("Submit"))) { 4963 return; 4964 } 4965 4966 // OK. We're actually going to submit stuff. Clear any redirections, 4967 // we should win over them 4968 d->clearRedirection(); 4969 4970 KParts::OpenUrlArguments args; 4971 4972 if (!d->m_referrer.isEmpty()) { 4973 args.metaData()["referrer"] = d->m_referrer; 4974 } 4975 4976 args.metaData().insert("PropagateHttpHeader", "true"); 4977 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip); 4978 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert); 4979 args.metaData().insert("main_frame_request", 4980 parentPart() == nullptr ? "TRUE" : "FALSE"); 4981 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE"); 4982 args.metaData().insert("ssl_activate_warnings", "TRUE"); 4983 //WABA: When we post a form we should treat it as the main url 4984 //the request should never be considered cross-domain 4985 //args.metaData().insert("cross-domain", toplevelURL().toString()); 4986 KParts::BrowserArguments browserArgs; 4987 browserArgs.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target; 4988 4989 // Handle mailto: forms 4990 if (u.scheme() == "mailto") { 4991 // 1) Check for attach= and strip it 4992 QString q = u.query().mid(1); 4993 QStringList nvps = q.split("&"); 4994 bool triedToAttach = false; 4995 4996 QStringList::Iterator nvp = nvps.begin(); 4997 const QStringList::Iterator nvpEnd = nvps.end(); 4998 4999 // cannot be a for loop as if something is removed we don't want to do ++nvp, as 5000 // remove returns an iterator pointing to the next item 5001 5002 while (nvp != nvpEnd) { 5003 const QStringList pair = (*nvp).split("="); 5004 if (pair.count() >= 2) { 5005 if (pair.first().toLower() == "attach") { 5006 nvp = nvps.erase(nvp); 5007 triedToAttach = true; 5008 } else { 5009 ++nvp; 5010 } 5011 } else { 5012 ++nvp; 5013 } 5014 } 5015 5016 if (triedToAttach) { 5017 KMessageBox::information(nullptr, i18n("This site attempted to attach a file from your computer in the form submission. The attachment was removed for your protection."), i18n("KDE"), "WarnTriedAttach"); 5018 } 5019 5020 // 2) Append body= 5021 QString bodyEnc; 5022 if (contentType.toLower() == "multipart/form-data") { 5023 // FIXME: is this correct? I suspect not 5024 bodyEnc = QLatin1String(QUrl::toPercentEncoding(QString::fromLatin1(formData.data(), 5025 formData.size()))); 5026 } else if (contentType.toLower() == "text/plain") { 5027 // Convention seems to be to decode, and s/&/\n/ 5028 QString tmpbody = QString::fromLatin1(formData.data(), 5029 formData.size()); 5030 tmpbody.replace(QRegExp("[&]"), "\n"); 5031 tmpbody.replace(QRegExp("[+]"), " "); 5032 tmpbody = QUrl::fromPercentEncoding(tmpbody.toLatin1()); // Decode the rest of it 5033 bodyEnc = QLatin1String(QUrl::toPercentEncoding(tmpbody)); // Recode for the URL 5034 } else { 5035 bodyEnc = QLatin1String(QUrl::toPercentEncoding(QString::fromLatin1(formData.data(), 5036 formData.size()))); 5037 } 5038 5039 nvps.append(QString("body=%1").arg(bodyEnc)); 5040 q = nvps.join("&"); 5041 u.setQuery(q); 5042 } 5043 5044 if (strcmp(action, "get") == 0) { 5045 if (u.scheme() != "mailto") { 5046 u.setQuery(QString::fromLatin1(formData.data(), formData.size())); 5047 } 5048 browserArgs.setDoPost(false); 5049 } else { 5050 browserArgs.postData = formData; 5051 browserArgs.setDoPost(true); 5052 5053 // construct some user headers if necessary 5054 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded") { 5055 browserArgs.setContentType("Content-Type: application/x-www-form-urlencoded"); 5056 } else { // contentType must be "multipart/form-data" 5057 browserArgs.setContentType("Content-Type: " + contentType + "; boundary=" + boundary); 5058 } 5059 } 5060 5061 if (d->m_doc->parsing() || d->m_runningScripts > 0) { 5062 if (d->m_submitForm) { 5063 // qCDebug(KHTML_LOG) << "ABORTING!"; 5064 return; 5065 } 5066 d->m_submitForm = new KHTMLPartPrivate::SubmitForm; 5067 d->m_submitForm->submitAction = action; 5068 d->m_submitForm->submitUrl = url; 5069 d->m_submitForm->submitFormData = formData; 5070 d->m_submitForm->target = _target; 5071 d->m_submitForm->submitContentType = contentType; 5072 d->m_submitForm->submitBoundary = boundary; 5073 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain())); 5074 } else { 5075 emit d->m_extension->openUrlRequest(u, args, browserArgs); 5076 } 5077 } 5078 5079 void KHTMLPart::popupMenu(const QString &linkUrl) 5080 { 5081 QUrl popupURL; 5082 QUrl linkKUrl; 5083 KParts::OpenUrlArguments args; 5084 KParts::BrowserArguments browserArgs; 5085 QString referrer; 5086 KParts::BrowserExtension::PopupFlags itemflags = KParts::BrowserExtension::ShowBookmark | KParts::BrowserExtension::ShowReload; 5087 5088 if (linkUrl.isEmpty()) { // click on background 5089 KHTMLPart *khtmlPart = this; 5090 while (khtmlPart->parentPart()) { 5091 khtmlPart = khtmlPart->parentPart(); 5092 } 5093 popupURL = khtmlPart->url(); 5094 referrer = khtmlPart->pageReferrer(); 5095 if (hasSelection()) { 5096 itemflags = KParts::BrowserExtension::ShowTextSelectionItems; 5097 } else { 5098 itemflags |= KParts::BrowserExtension::ShowNavigationItems; 5099 } 5100 } else { // click on link 5101 popupURL = completeURL(linkUrl); 5102 linkKUrl = popupURL; 5103 referrer = this->referrer(); 5104 itemflags |= KParts::BrowserExtension::IsLink; 5105 5106 if (!(d->m_strSelectedURLTarget).isEmpty() && 5107 (d->m_strSelectedURLTarget.toLower() != "_top") && 5108 (d->m_strSelectedURLTarget.toLower() != "_self") && 5109 (d->m_strSelectedURLTarget.toLower() != "_parent")) { 5110 if (d->m_strSelectedURLTarget.toLower() == "_blank") { 5111 browserArgs.setForcesNewWindow(true); 5112 } else { 5113 KHTMLPart *p = this; 5114 while (p->parentPart()) { 5115 p = p->parentPart(); 5116 } 5117 if (!p->frameExists(d->m_strSelectedURLTarget)) { 5118 browserArgs.setForcesNewWindow(true); 5119 } 5120 } 5121 } 5122 } 5123 5124 QMimeDatabase db; 5125 5126 // Danger, Will Robinson. The Popup might stay around for a much 5127 // longer time than KHTMLPart. Deal with it. 5128 KHTMLPopupGUIClient *client = new KHTMLPopupGUIClient(this, linkKUrl); 5129 QPointer<QObject> guard(client); 5130 5131 QString mimetype = QLatin1String("text/html"); 5132 args.metaData()["referrer"] = referrer; 5133 5134 if (!linkUrl.isEmpty()) { // over a link 5135 if (popupURL.isLocalFile()) { // safe to do this 5136 mimetype = db.mimeTypeForUrl(popupURL).name(); 5137 } else { // look at "extension" of link 5138 const QString fname(popupURL.fileName()); 5139 if (!fname.isEmpty() && !popupURL.hasFragment() && popupURL.query().isEmpty()) { 5140 QMimeType pmt = db.mimeTypeForFile(fname, QMimeDatabase::MatchExtension); 5141 5142 // Further check for mime types guessed from the extension which, 5143 // on a web page, are more likely to be a script delivering content 5144 // of undecidable type. If the mime type from the extension is one 5145 // of these, don't use it. Retain the original type 'text/html'. 5146 if (!pmt.isDefault() && 5147 !pmt.inherits("application/x-perl") && 5148 !pmt.inherits("application/x-perl-module") && 5149 !pmt.inherits("application/x-php") && 5150 !pmt.inherits("application/x-python-bytecode") && 5151 !pmt.inherits("application/x-python") && 5152 !pmt.inherits("application/x-shellscript")) { 5153 mimetype = pmt.name(); 5154 } 5155 } 5156 } 5157 } 5158 5159 args.setMimeType(mimetype); 5160 5161 emit d->m_extension->popupMenu(QCursor::pos(), popupURL, S_IFREG /*always a file*/, 5162 args, browserArgs, itemflags, 5163 client->actionGroups()); 5164 5165 if (!guard.isNull()) { 5166 delete client; 5167 emit popupMenu(linkUrl, QCursor::pos()); 5168 d->m_strSelectedURL.clear(); 5169 d->m_strSelectedURLTarget.clear(); 5170 } 5171 } 5172 5173 void KHTMLPart::slotParentCompleted() 5174 { 5175 //qCDebug(KHTML_LOG) << this; 5176 if (!d->m_redirectURL.isEmpty() && !d->m_redirectionTimer.isActive()) { 5177 //qCDebug(KHTML_LOG) << this << ": starting timer for child redirection -> " << d->m_redirectURL; 5178 d->m_redirectionTimer.setSingleShot(true); 5179 d->m_redirectionTimer.start(qMax(0, 1000 * d->m_delayRedirect)); 5180 } 5181 } 5182 5183 void KHTMLPart::slotChildStarted(KIO::Job *job) 5184 { 5185 khtml::ChildFrame *child = frame(sender()); 5186 5187 assert(child); 5188 5189 child->m_bCompleted = false; 5190 5191 if (d->m_bComplete) { 5192 #if 0 5193 // WABA: Looks like this belongs somewhere else 5194 if (!parentPart()) { // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes 5195 emit d->m_extension->openURLNotify(); 5196 } 5197 #endif 5198 d->m_bComplete = false; 5199 emit started(job); 5200 } 5201 } 5202 5203 void KHTMLPart::slotChildCompleted() 5204 { 5205 slotChildCompleted(false); 5206 } 5207 5208 void KHTMLPart::slotChildCompleted(bool pendingAction) 5209 { 5210 khtml::ChildFrame *child = frame(sender()); 5211 5212 if (child) { 5213 // qCDebug(KHTML_LOG) << this << "child=" << child << "m_partContainerElement=" << child->m_partContainerElement; 5214 child->m_bCompleted = true; 5215 child->m_bPendingRedirection = pendingAction; 5216 child->m_args = KParts::OpenUrlArguments(); 5217 child->m_browserArgs = KParts::BrowserArguments(); 5218 // dispatch load event. We don't do that for KHTMLPart's since their internal 5219 // load will be forwarded inside NodeImpl::dispatchWindowEvent 5220 if (!qobject_cast<KHTMLPart *>(child->m_part)) { 5221 QTimer::singleShot(0, child->m_partContainerElement.data(), SLOT(slotEmitLoadEvent())); 5222 } 5223 } 5224 checkCompleted(); 5225 } 5226 5227 void KHTMLPart::slotChildDocCreated() 5228 { 5229 // Set domain to the frameset's domain 5230 // This must only be done when loading the frameset initially (#22039), 5231 // not when following a link in a frame (#44162). 5232 if (KHTMLPart *htmlFrame = qobject_cast<KHTMLPart *>(sender())) { 5233 d->propagateInitialDomainAndBaseTo(htmlFrame); 5234 } 5235 5236 // So it only happens once 5237 disconnect(sender(), SIGNAL(docCreated()), this, SLOT(slotChildDocCreated())); 5238 } 5239 5240 void KHTMLPartPrivate::propagateInitialDomainAndBaseTo(KHTMLPart *kid) 5241 { 5242 // This method is used to propagate our domain and base information for 5243 // child frames, to provide them for about: or JavaScript: URLs 5244 if (m_doc && kid->d->m_doc) { 5245 DocumentImpl *kidDoc = kid->d->m_doc; 5246 if (kidDoc->origin()->isEmpty()) { 5247 kidDoc->setOrigin(m_doc->origin()); 5248 kidDoc->setBaseURL(m_doc->baseURL()); 5249 } 5250 } 5251 } 5252 5253 void KHTMLPart::slotChildURLRequest(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs) 5254 { 5255 khtml::ChildFrame *child = frame(sender()->parent()); 5256 KHTMLPart *callingHtmlPart = const_cast<KHTMLPart *>(dynamic_cast<const KHTMLPart *>(sender()->parent())); 5257 5258 // TODO: handle child target correctly! currently the script are always executed for the parent 5259 QString urlStr = url.toString(); 5260 if (d->isJavaScriptURL(urlStr)) { 5261 executeScript(DOM::Node(), d->codeForJavaScriptURL(urlStr)); 5262 return; 5263 } 5264 5265 QString frameName = browserArgs.frameName.toLower(); 5266 if (!frameName.isEmpty()) { 5267 if (frameName == QLatin1String("_top")) { 5268 emit d->m_extension->openUrlRequest(url, args, browserArgs); 5269 return; 5270 } else if (frameName == QLatin1String("_blank")) { 5271 emit d->m_extension->createNewWindow(url, args, browserArgs); 5272 return; 5273 } else if (frameName == QLatin1String("_parent")) { 5274 KParts::BrowserArguments newBrowserArgs(browserArgs); 5275 newBrowserArgs.frameName.clear(); 5276 emit d->m_extension->openUrlRequest(url, args, newBrowserArgs); 5277 return; 5278 } else if (frameName != QLatin1String("_self")) { 5279 khtml::ChildFrame *_frame = recursiveFrameRequest(callingHtmlPart, url, args, browserArgs); 5280 5281 if (!_frame) { 5282 emit d->m_extension->openUrlRequest(url, args, browserArgs); 5283 return; 5284 } 5285 5286 child = _frame; 5287 } 5288 } 5289 5290 if (child && child->m_type != khtml::ChildFrame::Object) { 5291 // Inform someone that we are about to show something else. 5292 child->m_bNotify = true; 5293 requestObject(child, url, args, browserArgs); 5294 } else if (frameName == "_self") { // this is for embedded objects (via <object>) which want to replace the current document 5295 KParts::BrowserArguments newBrowserArgs(browserArgs); 5296 newBrowserArgs.frameName.clear(); 5297 emit d->m_extension->openUrlRequest(url, args, newBrowserArgs); 5298 } 5299 } 5300 5301 void KHTMLPart::slotRequestFocus(KParts::ReadOnlyPart *) 5302 { 5303 emit d->m_extension->requestFocus(this); 5304 } 5305 5306 khtml::ChildFrame *KHTMLPart::frame(const QObject *obj) 5307 { 5308 assert(obj->inherits("KParts::ReadOnlyPart")); 5309 const KParts::ReadOnlyPart *const part = static_cast<const KParts::ReadOnlyPart *>(obj); 5310 5311 FrameIt it = d->m_frames.begin(); 5312 const FrameIt end = d->m_frames.end(); 5313 for (; it != end; ++it) { 5314 if ((*it)->m_part.data() == part) { 5315 return *it; 5316 } 5317 } 5318 5319 FrameIt oi = d->m_objects.begin(); 5320 const FrameIt oiEnd = d->m_objects.end(); 5321 for (; oi != oiEnd; ++oi) { 5322 if ((*oi)->m_part.data() == part) { 5323 return *oi; 5324 } 5325 } 5326 5327 return nullptr; 5328 } 5329 5330 //#define DEBUG_FINDFRAME 5331 5332 bool KHTMLPart::checkFrameAccess(KHTMLPart *callingHtmlPart) 5333 { 5334 if (callingHtmlPart == this) { 5335 return true; // trivial 5336 } 5337 5338 if (!xmlDocImpl()) { 5339 #ifdef DEBUG_FINDFRAME 5340 qCDebug(KHTML_LOG) << "Empty part" << this << "URL = " << url(); 5341 #endif 5342 return false; // we are empty? 5343 } 5344 5345 // now compare the domains 5346 if (callingHtmlPart && callingHtmlPart->xmlDocImpl() && xmlDocImpl()) { 5347 khtml::SecurityOrigin *actDomain = callingHtmlPart->xmlDocImpl()->origin(); 5348 khtml::SecurityOrigin *destDomain = xmlDocImpl()->origin(); 5349 5350 if (actDomain->canAccess(destDomain)) { 5351 return true; 5352 } 5353 } 5354 #ifdef DEBUG_FINDFRAME 5355 else { 5356 qCDebug(KHTML_LOG) << "Unknown part/domain" << callingHtmlPart << "tries to access part" << this; 5357 } 5358 #endif 5359 return false; 5360 } 5361 5362 KHTMLPart * 5363 KHTMLPart::findFrameParent(KParts::ReadOnlyPart *callingPart, const QString &f, khtml::ChildFrame **childFrame) 5364 { 5365 return d->findFrameParent(callingPart, f, childFrame, false); 5366 } 5367 5368 KHTMLPart *KHTMLPartPrivate::findFrameParent(KParts::ReadOnlyPart *callingPart, 5369 const QString &f, khtml::ChildFrame **childFrame, bool checkForNavigation) 5370 { 5371 #ifdef DEBUG_FINDFRAME 5372 qCDebug(KHTML_LOG) << q << "URL =" << q->url() << "name =" << q->objectName() << "findFrameParent(" << f << ")"; 5373 #endif 5374 // Check access 5375 KHTMLPart *const callingHtmlPart = qobject_cast<KHTMLPart *>(callingPart); 5376 5377 if (!callingHtmlPart) { 5378 return nullptr; 5379 } 5380 5381 if (!checkForNavigation && !q->checkFrameAccess(callingHtmlPart)) { 5382 return nullptr; 5383 } 5384 5385 if (!childFrame && !q->parentPart() && (q->objectName() == f)) { 5386 if (!checkForNavigation || callingHtmlPart->d->canNavigate(q)) { 5387 return q; 5388 } 5389 } 5390 5391 FrameIt it = m_frames.find(f); 5392 const FrameIt end = m_frames.end(); 5393 if (it != end) { 5394 #ifdef DEBUG_FINDFRAME 5395 qCDebug(KHTML_LOG) << "FOUND!"; 5396 #endif 5397 if (!checkForNavigation || callingHtmlPart->d->canNavigate((*it)->m_part.data())) { 5398 if (childFrame) { 5399 *childFrame = *it; 5400 } 5401 return q; 5402 } 5403 } 5404 5405 it = m_frames.begin(); 5406 for (; it != end; ++it) { 5407 if (KHTMLPart *p = qobject_cast<KHTMLPart *>((*it)->m_part.data())) { 5408 KHTMLPart *const frameParent = p->d->findFrameParent(callingPart, f, childFrame, checkForNavigation); 5409 if (frameParent) { 5410 return frameParent; 5411 } 5412 } 5413 } 5414 return nullptr; 5415 } 5416 5417 KHTMLPart *KHTMLPartPrivate::top() 5418 { 5419 KHTMLPart *t = q; 5420 while (t->parentPart()) { 5421 t = t->parentPart(); 5422 } 5423 return t; 5424 } 5425 5426 bool KHTMLPartPrivate::canNavigate(KParts::ReadOnlyPart *bCand) 5427 { 5428 if (!bCand) { // No part here (e.g. invalid url), reuse that frame 5429 return true; 5430 } 5431 5432 KHTMLPart *b = qobject_cast<KHTMLPart *>(bCand); 5433 if (!b) { // Another kind of part? Not sure what to do... 5434 return false; 5435 } 5436 5437 // HTML5 gives conditions for this (a) being able to navigate b 5438 5439 // 1) Same domain 5440 if (q->checkFrameAccess(b)) { 5441 return true; 5442 } 5443 5444 // 2) A is nested, with B its top 5445 if (q->parentPart() && top() == b) { 5446 return true; 5447 } 5448 5449 // 3) B is 'auxilary' -- window.open with opener, 5450 // and A can navigate B's opener 5451 if (b->opener() && canNavigate(b->opener())) { 5452 return true; 5453 } 5454 5455 // 4) B is not top-level, but an ancestor of it has same origin as A 5456 for (KHTMLPart *anc = b->parentPart(); anc; anc = anc->parentPart()) { 5457 if (anc->checkFrameAccess(q)) { 5458 return true; 5459 } 5460 } 5461 5462 return false; 5463 } 5464 5465 KHTMLPart *KHTMLPart::findFrame(const QString &f) 5466 { 5467 khtml::ChildFrame *childFrame; 5468 KHTMLPart *parentFrame = findFrameParent(this, f, &childFrame); 5469 if (parentFrame) { 5470 return qobject_cast<KHTMLPart *>(childFrame->m_part.data()); 5471 } 5472 5473 return nullptr; 5474 } 5475 5476 KParts::ReadOnlyPart *KHTMLPart::findFramePart(const QString &f) 5477 { 5478 khtml::ChildFrame *childFrame; 5479 return findFrameParent(this, f, &childFrame) ? childFrame->m_part.data() : nullptr; 5480 } 5481 5482 KParts::ReadOnlyPart *KHTMLPart::currentFrame() const 5483 { 5484 KParts::ReadOnlyPart *part = (KParts::ReadOnlyPart *)(this); 5485 // Find active part in our frame manager, in case we are a frameset 5486 // and keep doing that (in case of nested framesets). 5487 // Just realized we could also do this recursively, calling part->currentFrame()... 5488 while (part && part->inherits("KHTMLPart") && 5489 static_cast<KHTMLPart *>(part)->d->m_frames.count() > 0) { 5490 KHTMLPart *frameset = static_cast<KHTMLPart *>(part); 5491 part = static_cast<KParts::ReadOnlyPart *>(frameset->partManager()->activePart()); 5492 if (!part) { 5493 return frameset; 5494 } 5495 } 5496 return part; 5497 } 5498 5499 bool KHTMLPart::frameExists(const QString &frameName) 5500 { 5501 FrameIt it = d->m_frames.find(frameName); 5502 if (it == d->m_frames.end()) { 5503 return false; 5504 } 5505 5506 // WABA: We only return true if the child actually has a frame 5507 // set. Otherwise we might find our preloaded-selve. 5508 // This happens when we restore the frameset. 5509 return (!(*it)->m_partContainerElement.isNull()); 5510 } 5511 5512 void KHTMLPartPrivate::renameFrameForContainer(DOM::HTMLPartContainerElementImpl *cont, 5513 const QString &newName) 5514 { 5515 for (int i = 0; i < m_frames.size(); ++i) { 5516 khtml::ChildFrame *f = m_frames[i]; 5517 if (f->m_partContainerElement.data() == cont) { 5518 f->m_name = newName; 5519 } 5520 } 5521 } 5522 5523 KJSProxy *KHTMLPart::framejScript(KParts::ReadOnlyPart *framePart) 5524 { 5525 KHTMLPart *const kp = qobject_cast<KHTMLPart *>(framePart); 5526 if (kp) { 5527 return kp->jScript(); 5528 } 5529 5530 FrameIt it = d->m_frames.begin(); 5531 const FrameIt itEnd = d->m_frames.end(); 5532 5533 for (; it != itEnd; ++it) { 5534 khtml::ChildFrame *frame = *it; 5535 if (framePart == frame->m_part.data()) { 5536 if (!frame->m_jscript) { 5537 frame->m_jscript = new KJSProxy(frame); 5538 } 5539 return frame->m_jscript; 5540 } 5541 } 5542 return nullptr; 5543 } 5544 5545 KHTMLPart *KHTMLPart::parentPart() 5546 { 5547 return qobject_cast<KHTMLPart *>(parent()); 5548 } 5549 5550 khtml::ChildFrame *KHTMLPart::recursiveFrameRequest(KHTMLPart *callingHtmlPart, const QUrl &url, 5551 const KParts::OpenUrlArguments &args, 5552 const KParts::BrowserArguments &browserArgs, bool callParent) 5553 { 5554 #ifdef DEBUG_FINDFRAME 5555 qCDebug(KHTML_LOG) << this << "frame = " << browserArgs.frameName << "url = " << url; 5556 #endif 5557 khtml::ChildFrame *childFrame; 5558 KHTMLPart *childPart = findFrameParent(callingHtmlPart, browserArgs.frameName, &childFrame); 5559 if (childPart) { 5560 if (childPart == this) { 5561 return childFrame; 5562 } 5563 5564 childPart->requestObject(childFrame, url, args, browserArgs); 5565 return nullptr; 5566 } 5567 5568 if (parentPart() && callParent) { 5569 khtml::ChildFrame *res = parentPart()->recursiveFrameRequest(callingHtmlPart, url, args, browserArgs, callParent); 5570 5571 if (res) { 5572 parentPart()->requestObject(res, url, args, browserArgs); 5573 } 5574 } 5575 5576 return nullptr; 5577 } 5578 5579 #ifdef DEBUG_SAVESTATE 5580 static int s_saveStateIndentLevel = 0; 5581 #endif 5582 5583 void KHTMLPart::saveState(QDataStream &stream) 5584 { 5585 #ifdef DEBUG_SAVESTATE 5586 QString indent = QString().leftJustified(s_saveStateIndentLevel * 4, ' '); 5587 const int indentLevel = s_saveStateIndentLevel++; 5588 qCDebug(KHTML_LOG) << indent << "saveState this=" << this << " '" << objectName() << "' saving URL " << url(); 5589 #endif 5590 5591 stream << url() << (qint32)d->m_view->contentsX() << (qint32)d->m_view->contentsY() 5592 << (qint32) d->m_view->contentsWidth() << (qint32) d->m_view->contentsHeight() << (qint32) d->m_view->marginWidth() << (qint32) d->m_view->marginHeight(); 5593 5594 // save link cursor position 5595 int focusNodeNumber; 5596 if (!d->m_focusNodeRestored) { 5597 focusNodeNumber = d->m_focusNodeNumber; 5598 } else if (d->m_doc && d->m_doc->focusNode()) { 5599 focusNodeNumber = d->m_doc->nodeAbsIndex(d->m_doc->focusNode()); 5600 } else { 5601 focusNodeNumber = -1; 5602 } 5603 stream << focusNodeNumber; 5604 5605 // Save the doc's cache id. 5606 stream << d->m_cacheId; 5607 5608 // Save the state of the document (Most notably the state of any forms) 5609 QStringList docState; 5610 if (d->m_doc) { 5611 docState = d->m_doc->docState(); 5612 } 5613 stream << d->m_encoding << d->m_sheetUsed << docState; 5614 5615 stream << d->m_zoomFactor; 5616 stream << d->m_fontScaleFactor; 5617 5618 stream << d->m_httpHeaders; 5619 stream << d->m_pageServices; 5620 stream << d->m_pageReferrer; 5621 5622 // Save ssl data 5623 stream << d->m_ssl_in_use 5624 << d->m_ssl_peer_chain 5625 << d->m_ssl_peer_ip 5626 << d->m_ssl_cipher 5627 << d->m_ssl_protocol_version 5628 << d->m_ssl_cipher_used_bits 5629 << d->m_ssl_cipher_bits 5630 << d->m_ssl_cert_errors 5631 << d->m_ssl_parent_ip 5632 << d->m_ssl_parent_cert; 5633 5634 QStringList frameNameLst, frameServiceTypeLst, frameServiceNameLst; 5635 QList<QUrl> frameURLLst; 5636 QList<QByteArray> frameStateBufferLst; 5637 QList<int> frameTypeLst; 5638 5639 ConstFrameIt it = d->m_frames.constBegin(); 5640 const ConstFrameIt end = d->m_frames.constEnd(); 5641 for (; it != end; ++it) { 5642 if (!(*it)->m_part) { 5643 continue; 5644 } 5645 5646 frameNameLst << (*it)->m_name; 5647 frameServiceTypeLst << (*it)->m_serviceType; 5648 frameServiceNameLst << (*it)->m_serviceName; 5649 frameURLLst << (*it)->m_part.data()->url(); 5650 5651 QByteArray state; 5652 QDataStream frameStream(&state, QIODevice::WriteOnly); 5653 5654 if ((*it)->m_extension) { 5655 (*it)->m_extension.data()->saveState(frameStream); 5656 } 5657 5658 frameStateBufferLst << state; 5659 5660 frameTypeLst << int((*it)->m_type); 5661 } 5662 5663 // Save frame data 5664 stream << (quint32) frameNameLst.count(); 5665 stream << frameNameLst << frameServiceTypeLst << frameServiceNameLst << frameURLLst << frameStateBufferLst << frameTypeLst; 5666 #ifdef DEBUG_SAVESTATE 5667 s_saveStateIndentLevel = indentLevel; 5668 #endif 5669 } 5670 5671 void KHTMLPart::restoreState(QDataStream &stream) 5672 { 5673 QUrl u; 5674 qint32 xOffset, yOffset, wContents, hContents, mWidth, mHeight; 5675 quint32 frameCount; 5676 QStringList frameNames, frameServiceTypes, docState, frameServiceNames; 5677 QList<int> frameTypes; 5678 QList<QUrl> frameURLs; 5679 QList<QByteArray> frameStateBuffers; 5680 QList<int> fSizes; 5681 QString encoding, sheetUsed; 5682 long old_cacheId = d->m_cacheId; 5683 5684 stream >> u >> xOffset >> yOffset >> wContents >> hContents >> mWidth >> mHeight; 5685 5686 d->m_view->setMarginWidth(mWidth); 5687 d->m_view->setMarginHeight(mHeight); 5688 5689 // restore link cursor position 5690 // nth node is active. value is set in checkCompleted() 5691 stream >> d->m_focusNodeNumber; 5692 d->m_focusNodeRestored = false; 5693 5694 stream >> d->m_cacheId; 5695 5696 stream >> encoding >> sheetUsed >> docState; 5697 5698 d->m_encoding = encoding; 5699 d->m_sheetUsed = sheetUsed; 5700 5701 int zoomFactor; 5702 stream >> zoomFactor; 5703 setZoomFactor(zoomFactor); 5704 5705 int fontScaleFactor; 5706 stream >> fontScaleFactor; 5707 setFontScaleFactor(fontScaleFactor); 5708 5709 stream >> d->m_httpHeaders; 5710 stream >> d->m_pageServices; 5711 stream >> d->m_pageReferrer; 5712 5713 // Restore ssl data 5714 stream >> d->m_ssl_in_use 5715 >> d->m_ssl_peer_chain 5716 >> d->m_ssl_peer_ip 5717 >> d->m_ssl_cipher 5718 >> d->m_ssl_protocol_version 5719 >> d->m_ssl_cipher_used_bits 5720 >> d->m_ssl_cipher_bits 5721 >> d->m_ssl_cert_errors 5722 >> d->m_ssl_parent_ip 5723 >> d->m_ssl_parent_cert; 5724 5725 setPageSecurity(d->m_ssl_in_use ? Encrypted : NotCrypted); 5726 5727 stream >> frameCount >> frameNames >> frameServiceTypes >> frameServiceNames 5728 >> frameURLs >> frameStateBuffers >> frameTypes; 5729 5730 d->m_bComplete = false; 5731 d->m_bLoadEventEmitted = false; 5732 5733 // qCDebug(KHTML_LOG) << "docState.count() = " << docState.count(); 5734 // qCDebug(KHTML_LOG) << "m_url " << url() << " <-> " << u; 5735 // qCDebug(KHTML_LOG) << "m_frames.count() " << d->m_frames.count() << " <-> " << frameCount; 5736 5737 if (d->m_cacheId == old_cacheId && signed(frameCount) == d->m_frames.count()) { 5738 // Partial restore 5739 d->m_redirectionTimer.stop(); 5740 5741 FrameIt fIt = d->m_frames.begin(); 5742 const FrameIt fEnd = d->m_frames.end(); 5743 5744 for (; fIt != fEnd; ++fIt) { 5745 (*fIt)->m_bCompleted = false; 5746 } 5747 5748 fIt = d->m_frames.begin(); 5749 5750 QStringList::ConstIterator fNameIt = frameNames.constBegin(); 5751 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin(); 5752 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin(); 5753 QList<QUrl>::ConstIterator fURLIt = frameURLs.constBegin(); 5754 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin(); 5755 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin(); 5756 5757 for (; fIt != fEnd; ++fIt, ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt) { 5758 khtml::ChildFrame *const child = *fIt; 5759 5760 // qCDebug(KHTML_LOG) << *fNameIt << " ---- " << *fServiceTypeIt; 5761 5762 if (child->m_name != *fNameIt || child->m_serviceType != *fServiceTypeIt) { 5763 child->m_bPreloaded = true; 5764 child->m_name = *fNameIt; 5765 child->m_serviceName = *fServiceNameIt; 5766 child->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt); 5767 processObjectRequest(child, *fURLIt, *fServiceTypeIt); 5768 } 5769 if (child->m_part) { 5770 child->m_bCompleted = false; 5771 if (child->m_extension && !(*fBufferIt).isEmpty()) { 5772 QDataStream frameStream(*fBufferIt); 5773 child->m_extension.data()->restoreState(frameStream); 5774 } else { 5775 child->m_part.data()->openUrl(*fURLIt); 5776 } 5777 } 5778 } 5779 5780 KParts::OpenUrlArguments args(arguments()); 5781 args.setXOffset(xOffset); 5782 args.setYOffset(yOffset); 5783 setArguments(args); 5784 5785 KParts::BrowserArguments browserArgs(d->m_extension->browserArguments()); 5786 browserArgs.docState = docState; 5787 d->m_extension->setBrowserArguments(browserArgs); 5788 5789 d->m_view->resizeContents(wContents, hContents); 5790 d->m_view->setContentsPos(xOffset, yOffset); 5791 5792 setUrl(u); 5793 } else { 5794 // Full restore. 5795 closeUrl(); 5796 // We must force a clear because we want to be sure to delete all 5797 // frames. 5798 d->m_bCleared = false; 5799 clear(); 5800 d->m_encoding = encoding; 5801 d->m_sheetUsed = sheetUsed; 5802 5803 QStringList::ConstIterator fNameIt = frameNames.constBegin(); 5804 const QStringList::ConstIterator fNameEnd = frameNames.constEnd(); 5805 5806 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin(); 5807 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin(); 5808 QList<QUrl>::ConstIterator fURLIt = frameURLs.constBegin(); 5809 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin(); 5810 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin(); 5811 5812 for (; fNameIt != fNameEnd; ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt) { 5813 khtml::ChildFrame *const newChild = new khtml::ChildFrame; 5814 newChild->m_bPreloaded = true; 5815 newChild->m_name = *fNameIt; 5816 newChild->m_serviceName = *fServiceNameIt; 5817 newChild->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt); 5818 5819 // qCDebug(KHTML_LOG) << *fNameIt << " ---- " << *fServiceTypeIt; 5820 5821 const FrameIt childFrame = d->m_frames.insert(d->m_frames.end(), newChild); 5822 5823 processObjectRequest(*childFrame, *fURLIt, *fServiceTypeIt); 5824 5825 (*childFrame)->m_bPreloaded = true; 5826 5827 if ((*childFrame)->m_part) { 5828 if ((*childFrame)->m_extension && !(*fBufferIt).isEmpty()) { 5829 QDataStream frameStream(*fBufferIt); 5830 (*childFrame)->m_extension.data()->restoreState(frameStream); 5831 } else { 5832 (*childFrame)->m_part.data()->openUrl(*fURLIt); 5833 } 5834 } 5835 } 5836 5837 KParts::OpenUrlArguments args(arguments()); 5838 args.setXOffset(xOffset); 5839 args.setYOffset(yOffset); 5840 setArguments(args); 5841 5842 KParts::BrowserArguments browserArgs(d->m_extension->browserArguments()); 5843 browserArgs.docState = docState; 5844 d->m_extension->setBrowserArguments(browserArgs); 5845 5846 if (!KHTMLPageCache::self()->isComplete(d->m_cacheId)) { 5847 d->m_restored = true; 5848 openUrl(u); 5849 d->m_restored = false; 5850 } else { 5851 restoreURL(u); 5852 } 5853 } 5854 5855 } 5856 5857 void KHTMLPart::show() 5858 { 5859 if (widget()) { 5860 widget()->show(); 5861 } 5862 } 5863 5864 void KHTMLPart::hide() 5865 { 5866 if (widget()) { 5867 widget()->hide(); 5868 } 5869 } 5870 5871 DOM::Node KHTMLPart::nodeUnderMouse() const 5872 { 5873 return d->m_view->nodeUnderMouse(); 5874 } 5875 5876 DOM::Node KHTMLPart::nonSharedNodeUnderMouse() const 5877 { 5878 return d->m_view->nonSharedNodeUnderMouse(); 5879 } 5880 5881 void KHTMLPart::emitSelectionChanged() 5882 { 5883 // Don't emit signals about our selection if this is a frameset; 5884 // the active frame has the selection (#187403) 5885 if (!d->m_activeFrame) { 5886 emit d->m_extension->enableAction("copy", hasSelection()); 5887 emit d->m_extension->selectionInfo(selectedText()); 5888 emit selectionChanged(); 5889 } 5890 } 5891 5892 int KHTMLPart::zoomFactor() const 5893 { 5894 return d->m_zoomFactor; 5895 } 5896 5897 // ### make the list configurable ? 5898 static const int zoomSizes[] = { 20, 40, 60, 80, 90, 95, 100, 105, 110, 120, 140, 160, 180, 200, 250, 300 }; 5899 static const int zoomSizeCount = (sizeof(zoomSizes) / sizeof(int)); 5900 static const int minZoom = 20; 5901 static const int maxZoom = 300; 5902 5903 // My idea of useful stepping ;-) (LS) 5904 extern const int KHTML_NO_EXPORT fastZoomSizes[] = { 20, 50, 75, 90, 100, 120, 150, 200, 300 }; 5905 extern const int KHTML_NO_EXPORT fastZoomSizeCount = sizeof fastZoomSizes / sizeof fastZoomSizes[0]; 5906 5907 void KHTMLPart::slotIncZoom() 5908 { 5909 zoomIn(zoomSizes, zoomSizeCount); 5910 } 5911 5912 void KHTMLPart::slotDecZoom() 5913 { 5914 zoomOut(zoomSizes, zoomSizeCount); 5915 } 5916 5917 void KHTMLPart::slotIncZoomFast() 5918 { 5919 zoomIn(fastZoomSizes, fastZoomSizeCount); 5920 } 5921 5922 void KHTMLPart::slotDecZoomFast() 5923 { 5924 zoomOut(fastZoomSizes, fastZoomSizeCount); 5925 } 5926 5927 void KHTMLPart::zoomIn(const int stepping[], int count) 5928 { 5929 int zoomFactor = d->m_zoomFactor; 5930 5931 if (zoomFactor < maxZoom) { 5932 // find the entry nearest to the given zoomsizes 5933 for (int i = 0; i < count; ++i) 5934 if (stepping[i] > zoomFactor) { 5935 zoomFactor = stepping[i]; 5936 break; 5937 } 5938 setZoomFactor(zoomFactor); 5939 } 5940 } 5941 5942 void KHTMLPart::zoomOut(const int stepping[], int count) 5943 { 5944 int zoomFactor = d->m_zoomFactor; 5945 if (zoomFactor > minZoom) { 5946 // find the entry nearest to the given zoomsizes 5947 for (int i = count - 1; i >= 0; --i) 5948 if (stepping[i] < zoomFactor) { 5949 zoomFactor = stepping[i]; 5950 break; 5951 } 5952 setZoomFactor(zoomFactor); 5953 } 5954 } 5955 5956 void KHTMLPart::setZoomFactor(int percent) 5957 { 5958 // ### zooming under 100% is majorly botched, 5959 // so disable that for now. 5960 if (percent < 100) { 5961 percent = 100; 5962 } 5963 // ### if (percent < minZoom) percent = minZoom; 5964 5965 if (percent > maxZoom) { 5966 percent = maxZoom; 5967 } 5968 if (d->m_zoomFactor == percent) { 5969 return; 5970 } 5971 d->m_zoomFactor = percent; 5972 5973 updateZoomFactor(); 5974 } 5975 5976 void KHTMLPart::updateZoomFactor() 5977 { 5978 if (d->m_view) { 5979 QApplication::setOverrideCursor(Qt::WaitCursor); 5980 d->m_view->setZoomLevel(d->m_zoomFactor); 5981 QApplication::restoreOverrideCursor(); 5982 } 5983 5984 ConstFrameIt it = d->m_frames.constBegin(); 5985 const ConstFrameIt end = d->m_frames.constEnd(); 5986 for (; it != end; ++it) { 5987 if (KHTMLPart *p = qobject_cast<KHTMLPart *>((*it)->m_part.data())) { 5988 p->setZoomFactor(d->m_zoomFactor); 5989 } 5990 } 5991 5992 if (d->m_guiProfile == BrowserViewGUI) { 5993 d->m_paDecZoomFactor->setEnabled(d->m_zoomFactor > minZoom); 5994 d->m_paIncZoomFactor->setEnabled(d->m_zoomFactor < maxZoom); 5995 } 5996 } 5997 5998 void KHTMLPart::slotIncFontSize() 5999 { 6000 incFontSize(zoomSizes, zoomSizeCount); 6001 } 6002 6003 void KHTMLPart::slotDecFontSize() 6004 { 6005 decFontSize(zoomSizes, zoomSizeCount); 6006 } 6007 6008 void KHTMLPart::slotIncFontSizeFast() 6009 { 6010 incFontSize(fastZoomSizes, fastZoomSizeCount); 6011 } 6012 6013 void KHTMLPart::slotDecFontSizeFast() 6014 { 6015 decFontSize(fastZoomSizes, fastZoomSizeCount); 6016 } 6017 6018 void KHTMLPart::incFontSize(const int stepping[], int count) 6019 { 6020 int zoomFactor = d->m_fontScaleFactor; 6021 6022 if (zoomFactor < maxZoom) { 6023 // find the entry nearest to the given zoomsizes 6024 for (int i = 0; i < count; ++i) 6025 if (stepping[i] > zoomFactor) { 6026 zoomFactor = stepping[i]; 6027 break; 6028 } 6029 setFontScaleFactor(zoomFactor); 6030 } 6031 } 6032 6033 void KHTMLPart::decFontSize(const int stepping[], int count) 6034 { 6035 int zoomFactor = d->m_fontScaleFactor; 6036 if (zoomFactor > minZoom) { 6037 // find the entry nearest to the given zoomsizes 6038 for (int i = count - 1; i >= 0; --i) 6039 if (stepping[i] < zoomFactor) { 6040 zoomFactor = stepping[i]; 6041 break; 6042 } 6043 setFontScaleFactor(zoomFactor); 6044 } 6045 } 6046 6047 void KHTMLPart::setFontScaleFactor(int percent) 6048 { 6049 if (percent < minZoom) { 6050 percent = minZoom; 6051 } 6052 if (percent > maxZoom) { 6053 percent = maxZoom; 6054 } 6055 if (d->m_fontScaleFactor == percent) { 6056 return; 6057 } 6058 d->m_fontScaleFactor = percent; 6059 6060 if (d->m_view && d->m_doc) { 6061 QApplication::setOverrideCursor(Qt::WaitCursor); 6062 if (d->m_doc->styleSelector()) { 6063 d->m_doc->styleSelector()->computeFontSizes(d->m_doc->logicalDpiY(), d->m_fontScaleFactor); 6064 } 6065 d->m_doc->recalcStyle(NodeImpl::Force); 6066 QApplication::restoreOverrideCursor(); 6067 } 6068 6069 ConstFrameIt it = d->m_frames.constBegin(); 6070 const ConstFrameIt end = d->m_frames.constEnd(); 6071 for (; it != end; ++it) { 6072 if (KHTMLPart *p = qobject_cast<KHTMLPart *>((*it)->m_part.data())) { 6073 p->setFontScaleFactor(d->m_fontScaleFactor