// -*- c-basic-offset: 2 -*- /* This file is part of the KDE project * * Copyright (C) 1998, 1999 Torben Weis * 1999 Lars Knoll * 1999 Antti Koivisto * 2000 Simon Hausmann * 2000 Stefan Schimanski <1Stein@gmx.de> * 2001 George Staikos * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "khtml_part.h" #if APPLE_CHANGES #define DIRECT_LINKAGE_TO_ECMA #define QT_NO_CLIPBOARD #define QT_NO_DRAGANDDROP #endif #include "khtml_pagecache.h" #include "css/csshelper.h" #include "css/cssproperties.h" #include "css/cssstyleselector.h" #include "css/css_computedstyle.h" #include "css/css_valueimpl.h" #include "dom/dom_string.h" #include "dom/dom_element.h" #include "dom/html_document.h" #include "editing/markup.h" #include "editing/selection.h" #include "editing/visible_position.h" #include "editing/visible_text.h" #include "editing/visible_units.h" #include "html/html_documentimpl.h" #include "html/html_baseimpl.h" #include "html/html_miscimpl.h" #include "html/html_imageimpl.h" #include "html/html_objectimpl.h" #include "rendering/render_block.h" #include "rendering/render_text.h" #include "rendering/render_frames.h" #include "misc/htmlhashes.h" #include "misc/loader.h" #include "xml/dom2_eventsimpl.h" #include "xml/dom2_rangeimpl.h" #include "xml/xml_tokenizer.h" using namespace DOM; #include "khtmlview.h" #include #include "ecma/kjs_proxy.h" #include "ecma/xmlhttprequest.h" #include "khtml_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(QT_NO_DRAGANDDROP) #include #endif #include #include #include #include #include #include #include #include "khtmlpart_p.h" #if APPLE_CHANGES #include #endif using khtml::ApplyStyleCommand; using khtml::CHARACTER; using khtml::ChildFrame; using khtml::Decoder; using khtml::DocLoader; using khtml::EAffinity; using khtml::EditAction; using khtml::EditCommandPtr; using khtml::ETextGranularity; using khtml::FormData; using khtml::InlineTextBox; using khtml::isEndOfDocument; using khtml::isStartOfDocument; using khtml::PARAGRAPH; using khtml::plainText; using khtml::RenderObject; using khtml::RenderText; using khtml::RenderWidget; using khtml::Selection; using khtml::Tokenizer; using khtml::TypingCommand; using khtml::VisiblePosition; using khtml::WORD; using KParts::BrowserInterface; const int CARET_BLINK_FREQUENCY = 500; namespace khtml { class PartStyleSheetLoader : public CachedObjectClient { public: PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl) { m_part = part; m_cachedSheet = Cache::requestStyleSheet(dl, url ); if (m_cachedSheet) m_cachedSheet->ref( this ); } virtual ~PartStyleSheetLoader() { if ( m_cachedSheet ) m_cachedSheet->deref(this); } virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet) { if ( m_part ) m_part->setUserStyleSheet( sheet.string() ); delete this; } QGuardedPtr m_part; khtml::CachedCSSStyleSheet *m_cachedSheet; }; } FrameList::Iterator FrameList::find( const QString &name ) { Iterator it = begin(); Iterator e = end(); for (; it!=e; ++it ) if ( (*it).m_name==name ) break; return it; } KHTMLPart::KHTMLPart( QWidget *parentWidget, const char *widgetname, QObject *parent, const char *name, GUIProfile prof ) : KParts::ReadOnlyPart( parent, name ) { d = 0; KHTMLFactory::registerPart( this ); setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() ); #if !APPLE_CHANGES init( new KHTMLView( this, parentWidget, widgetname ), prof ); #endif } #if !APPLE_CHANGES KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, const char *name, GUIProfile prof ) : KParts::ReadOnlyPart( parent, name ) { d = 0; KHTMLFactory::registerPart( this ); setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() ); assert( view ); init( view, prof ); } #endif // APPLE_CHANGES void KHTMLPart::init( KHTMLView *view, GUIProfile prof ) { AtomicString::init(); if ( prof == DefaultGUI ) setXMLFile( "khtml.rc" ); else if ( prof == BrowserViewGUI ) setXMLFile( "khtml_browser.rc" ); frameCount = 0; d = new KHTMLPartPrivate(parent()); d->m_view = view; setWidget( d->m_view ); #if !APPLE_CHANGES d->m_guiProfile = prof; #endif d->m_extension = new KHTMLPartBrowserExtension( this ); d->m_hostExtension = new KHTMLPartBrowserHostExtension( this ); d->m_bSecurityInQuestion = false; d->m_bMousePressed = false; #if !APPLE_CHANGES d->m_paLoadImages = 0; d->m_paViewDocument = new KAction( i18n( "View Document Source" ), 0, this, SLOT( slotViewDocumentSource() ), actionCollection(), "viewDocumentSource" ); d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), 0, this, SLOT( slotViewFrameSource() ), actionCollection(), "viewFrameSource" ); d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), 0, this, SLOT( slotSaveBackground() ), actionCollection(), "saveBackground" ); d->m_paSaveDocument = new KAction( i18n( "&Save As..." ), CTRL+Key_S, this, SLOT( slotSaveDocument() ), actionCollection(), "saveDocument" ); if ( parentPart() ) d->m_paSaveDocument->setShortcut( KShortcut() ); // avoid clashes d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), 0, this, SLOT( slotSaveFrame() ), actionCollection(), "saveFrame" ); d->m_paSecurity = new KAction( i18n( "Security..." ), "decrypted", 0, this, SLOT( slotSecurity() ), actionCollection(), "security" ); d->m_paDebugRenderTree = new KAction( "print rendering tree to stdout", 0, this, SLOT( slotDebugRenderTree() ), actionCollection(), "debugRenderTree" ); d->m_paDebugDOMTree = new KAction( "print DOM tree to stdout", 0, this, SLOT( slotDebugDOMTree() ), actionCollection(), "debugDOMTree" ); QString foo1 = i18n("Show Images"); QString foo2 = i18n("Show Animated Images"); QString foo3 = i18n("Stop Animated Images"); d->m_paSetEncoding = new KSelectAction( i18n( "Set &Encoding" ), 0, this, SLOT( slotSetEncoding() ), actionCollection(), "setEncoding" ); QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames(); encodings.prepend( i18n( "Auto" ) ); d->m_paSetEncoding->setItems( encodings ); d->m_paSetEncoding->setCurrentItem(0); d->m_paUseStylesheet = new KSelectAction( i18n( "&Use Stylesheet"), 0, this, SLOT( slotUseStylesheet() ), actionCollection(), "useStylesheet" ); d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, i18n( "Increase Font Sizes" ), "viewmag+", this, SLOT( slotIncZoom() ), actionCollection(), "incFontSizes" ); d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, i18n( "Decrease Font Sizes" ), "viewmag-", this, SLOT( slotDecZoom() ), actionCollection(), "decFontSizes" ); d->m_paFind = KStdAction::find( this, SLOT( slotFind() ), actionCollection(), "find" ); if ( parentPart() ) d->m_paFind->setShortcut( KShortcut() ); // avoid clashes d->m_paPrintFrame = new KAction( i18n( "Print Frame" ), "frameprint", 0, this, SLOT( slotPrintFrame() ), actionCollection(), "printFrame" ); d->m_paSelectAll = KStdAction::selectAll( this, SLOT( slotSelectAll() ), actionCollection(), "selectAll" ); if ( parentPart() ) d->m_paSelectAll->setShortcut( KShortcut() ); // avoid clashes #endif #if !APPLE_CHANGES // set the default java(script) flags according to the current host. d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(); d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled(); d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(); d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(); #else // The java, javascript, and plugin settings will be set after the settings // have been initialized. d->m_bJScriptEnabled = true; d->m_bJScriptDebugEnabled = true; d->m_bJavaEnabled = true; d->m_bPluginsEnabled = true; #endif #if !APPLE_CHANGES connect( this, SIGNAL( completed() ), this, SLOT( updateActions() ) ); connect( this, SIGNAL( completed( bool ) ), this, SLOT( updateActions() ) ); connect( this, SIGNAL( started( KIO::Job * ) ), this, SLOT( updateActions() ) ); d->m_popupMenuXML = KXMLGUIFactory::readConfigFile( locate( "data", "khtml/khtml_popupmenu.rc", KHTMLFactory::instance() ) ); #endif connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ), this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) ); connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ), this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) ); connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ), this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) ); #if !APPLE_CHANGES findTextBegin(); //reset find variables #endif connect( &d->m_redirectionTimer, SIGNAL( timeout() ), this, SLOT( slotRedirect() ) ); connect(&d->m_lifeSupportTimer, SIGNAL(timeout()), this, SLOT(slotEndLifeSupport())); #if !APPLE_CHANGES d->m_dcopobject = new KHTMLPartIface(this); #endif } KHTMLPart::~KHTMLPart() { //kdDebug(6050) << "KHTMLPart::~KHTMLPart " << this << endl; #if !APPLE_CHANGES if ( d->m_findDialog ) disconnect( d->m_findDialog, SIGNAL( destroyed() ), this, SLOT( slotFindDialogDestroyed() ) ); if ( d->m_manager ) { d->m_manager->setActivePart( 0 ); // Shouldn't we delete d->m_manager here ? (David) // No need to, I would say. We specify "this" as parent qobject // in ::partManager() (Simon) } #endif stopAutoScroll(); cancelRedirection(); if (!d->m_bComplete) closeURL(); disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ), this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) ); disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ), this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) ); disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ), this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) ); clear(); if ( d->m_view ) { d->m_view->hide(); d->m_view->viewport()->hide(); d->m_view->m_part = 0; } #if APPLE_CHANGES delete d->m_hostExtension; #endif delete d; d = 0; KHTMLFactory::deregisterPart( this ); } bool KHTMLPart::restoreURL( const KURL &url ) { kdDebug( 6050 ) << "KHTMLPart::restoreURL " << url.url() << endl; cancelRedirection(); /* * That's not a good idea as it will call closeURL() on all * child frames, preventing them from further loading. This * method gets called from restoreState() in case of a full frameset * restoral, and restoreState() calls closeURL() before restoring * anyway. kdDebug( 6050 ) << "closing old URL" << endl; closeURL(); */ d->m_bComplete = false; d->m_bLoadEventEmitted = false; d->m_workingURL = url; // set the java(script) flags according to the current host. #if !APPLE_CHANGES d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host()); d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled(); d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host()); d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host()); #else d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host()); d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled(); d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host()); d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host()); #endif m_url = url; KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &))); emit started( 0L ); return true; } #if APPLE_CHANGES bool KHTMLPart::didOpenURL(const KURL &url) #else bool KHTMLPart::openURL( const KURL &url ) #endif { kdDebug( 6050 ) << "KHTMLPart(" << this << ")::openURL " << url.url() << endl; if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) { // We're about to get a redirect that happened before the document was // created. This can happen when one frame may change the location of a // sibling. return false; } cancelRedirection(); // clear last edit command d->m_lastEditCommand = EditCommandPtr(); #if APPLE_CHANGES KWQ(this)->clearUndoRedoOperations(); #endif #if !APPLE_CHANGES // check to see if this is an "error://" URL. This is caused when an error // occurs before this part was loaded (e.g. KonqRun), and is passed to // khtmlpart so that it can display the error. if ( url.protocol() == "error" && url.hasSubURL() ) { closeURL(); /** * The format of the error url is that two variables are passed in the query: * error = int kio error code, errText = QString error text from kio * and the URL where the error happened is passed as a sub URL. */ KURL::List urls = KURL::split( url ); //kdDebug() << "Handling error URL. URL count:" << urls.count() << endl; if ( urls.count() > 1 ) { KURL mainURL = urls.first(); int error = mainURL.queryItem( "error" ).toInt(); // error=0 isn't a valid error code, so 0 means it's missing from the URL if ( error == 0 ) error = KIO::ERR_UNKNOWN; QString errorText = mainURL.queryItem( "errText" ); urls.pop_front(); d->m_workingURL = KURL::join( urls ); //kdDebug() << "Emitting fixed URL " << d->m_workingURL.prettyURL() << endl; emit d->m_extension->setLocationBarURL( d->m_workingURL.prettyURL() ); htmlError( error, errorText, d->m_workingURL ); return true; } } #endif // APPLE_CHANGES KParts::URLArgs args( d->m_extension->urlArgs() ); #if !APPLE_CHANGES // in case we have a) no frameset (don't test m_frames.count(), iframes get in there) // b) the url is identical with the currently // displayed one (except for the htmlref!) , c) the url request is not a POST // operation and d) the caller did not request to reload the page we try to // be smart and instead of reloading the whole document we just jump to the // request html anchor if (d->m_doc) { bool isFrameSet = false; if ( d->m_doc->isHTMLDocument() ) { HTMLDocumentImpl* htmlDoc = static_cast(d->m_doc); isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET); } if ( !isFrameSet && urlcmp( url.url(), m_url.url(), true, true ) && url.hasRef() && !args.doPost() && !args.reload ) { kdDebug( 6050 ) << "KHTMLPart::openURL, jumping to anchor. m_url = " << url.url() << endl; m_url = url; emit started( 0L ); gotoAnchor(); d->m_bComplete = true; d->m_doc->setParsing(false); kdDebug( 6050 ) << "completed..." << endl; emit completed(); return true; } } #endif // APPLE_CHANGES if (!d->m_restored) { kdDebug( 6050 ) << "closing old URL" << endl; closeURL(); } #if !APPLE_CHANGES args.metaData().insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" ); args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" ); args.metaData().insert("ssl_activate_warnings", "TRUE" ); #endif if (d->m_restored) d->m_cachePolicy = KIO::CC_Cache; else if (args.reload) d->m_cachePolicy = KIO::CC_Refresh; else d->m_cachePolicy = KIO::CC_Verify; if ( args.doPost() && (url.protocol().startsWith("http")) ) { d->m_job = KIO::http_post( url, args.postData, false ); d->m_job->addMetaData("content-type", args.contentType() ); } else { d->m_job = KIO::get( url, false, false ); d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy)); } d->m_job->addMetaData(args.metaData()); connect( d->m_job, SIGNAL( result( KIO::Job * ) ), SLOT( slotFinished( KIO::Job * ) ) ); #if !APPLE_CHANGES connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray &)), SLOT( slotData( KIO::Job*, const QByteArray &))); #endif connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KURL&) ), SLOT( slotRedirection(KIO::Job*,const KURL&) ) ); d->m_bComplete = false; d->m_bLoadingMainResource = true; d->m_bLoadEventEmitted = false; // delete old status bar msg's from kjs (if it _was_ activated on last URL) if( d->m_bJScriptEnabled ) { d->m_kjsStatusBarText = QString::null; d->m_kjsDefaultStatusBarText = QString::null; } // set the javascript flags according to the current url #if !APPLE_CHANGES d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled(); d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host()); d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host()); #else d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled(); d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host()); d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host()); #endif // 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 // data arrives) (Simon) m_url = url; if(m_url.protocol().startsWith( "http" ) && !m_url.host().isEmpty() && m_url.path().isEmpty()) { m_url.setPath("/"); emit d->m_extension->setLocationBarURL( m_url.prettyURL() ); } // copy to m_workingURL after fixing m_url above d->m_workingURL = m_url; kdDebug( 6050 ) << "KHTMLPart::openURL now (before started) m_url = " << m_url.url() << endl; connect( d->m_job, SIGNAL( speed( KIO::Job*, unsigned long ) ), this, SLOT( slotJobSpeed( KIO::Job*, unsigned long ) ) ); connect( d->m_job, SIGNAL( percent( KIO::Job*, unsigned long ) ), this, SLOT( slotJobPercent( KIO::Job*, unsigned long ) ) ); emit started( 0L ); return true; } void KHTMLPart::didExplicitOpen() { d->m_bComplete = false; d->m_bLoadEventEmitted = false; // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results // from a subsequent window.document.open / window.document.write call. // Cancelling redirection here works for all cases because document.open // implicitly precedes document.write. cancelRedirection(); } void KHTMLPart::stopLoading(bool sendUnload) { if (d->m_doc && d->m_doc->tokenizer()) { d->m_doc->tokenizer()->stopParsing(); } if ( d->m_job ) { KHTMLPageCache::self()->cancelEntry(d->m_cacheId); d->m_job->kill(); d->m_job = 0; } if (sendUnload) { if ( d->m_doc && d->m_doc->isHTMLDocument() ) { HTMLDocumentImpl* hdoc = static_cast( d->m_doc ); if ( hdoc->body() && d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted ) { hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false ); if ( d->m_doc ) d->m_doc->updateRendering(); d->m_bUnloadEventEmitted = true; } } if (d->m_doc && !d->m_doc->inPageCache()) d->m_doc->removeAllEventListenersFromAllNodes(); } d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David) d->m_bLoadingMainResource = false; d->m_bLoadEventEmitted = true; // don't want that one either d->m_cachePolicy = KIO::CC_Verify; // Why here? KHTMLPageCache::self()->cancelFetch(this); if ( d->m_doc && d->m_doc->parsing() ) { kdDebug( 6050 ) << " was still parsing... calling end " << endl; slotFinishedParsing(); d->m_doc->setParsing(false); } if ( !d->m_workingURL.isEmpty() ) { // Aborted before starting to render kdDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << m_url.prettyURL() << endl; emit d->m_extension->setLocationBarURL( m_url.prettyURL() ); } d->m_workingURL = KURL(); if (DocumentImpl *doc = d->m_doc) { if (DocLoader *docLoader = doc->docLoader()) khtml::Cache::loader()->cancelRequests(docLoader); KJS::XMLHttpRequest::cancelRequests(doc); } // tell all subframes to stop as well ConstFrameIt it = d->m_frames.begin(); ConstFrameIt end = d->m_frames.end(); for (; it != end; ++it ) { KParts::ReadOnlyPart *part = (*it).m_part; if (part) { KHTMLPart *khtml_part = static_cast(part); if (khtml_part->inherits("KHTMLPart")) khtml_part->stopLoading(sendUnload); else part->closeURL(); } } d->m_bPendingChildRedirection = false; // Stop any started redirections as well!! (DA) cancelRedirection(); // null node activated. emit nodeActivated(Node()); } DOM::HTMLDocument KHTMLPart::htmlDocument() const { if (d->m_doc && d->m_doc->isHTMLDocument()) return static_cast(d->m_doc); else return static_cast(0); } DOM::Document KHTMLPart::document() const { return d->m_doc; } KParts::BrowserExtension *KHTMLPart::browserExtension() const { return d->m_extension; } KHTMLView *KHTMLPart::view() const { return d->m_view; } void KHTMLPart::setJScriptEnabled( bool enable ) { if ( !enable && jScriptEnabled() && d->m_jscript ) { d->m_jscript->clear(); } d->m_bJScriptForce = enable; d->m_bJScriptOverride = true; } bool KHTMLPart::jScriptEnabled() const { if ( d->m_bJScriptOverride ) return d->m_bJScriptForce; return d->m_bJScriptEnabled; } void KHTMLPart::setMetaRefreshEnabled( bool enable ) { d->m_metaRefreshEnabled = enable; } bool KHTMLPart::metaRefreshEnabled() const { return d->m_metaRefreshEnabled; } // Define this to disable dlopening kjs_html, when directly linking to it. // You need to edit khtml/Makefile.am to add ./ecma/libkjs_html.la to LIBADD // and to edit khtml/ecma/Makefile.am to s/kjs_html/libkjs_html/, remove libkhtml from LIBADD, // remove LDFLAGS line, and replace kde_module with either lib (shared) or noinst (static) //#define DIRECT_LINKAGE_TO_ECMA #ifdef DIRECT_LINKAGE_TO_ECMA extern "C" { KJSProxy *kjs_html_init(KHTMLPart *khtmlpart); } #endif bool KHTMLPart::closeURL() { stopLoading(true); return true; } KJSProxy *KHTMLPart::jScript() { if (!jScriptEnabled()){ return 0; } if ( !d->m_jscript ) { #ifndef DIRECT_LINKAGE_TO_ECMA KLibrary *lib = KLibLoader::self()->library("kjs_html"); if ( !lib ) { setJScriptEnabled( false ); return 0; } // look for plain C init function void *sym = lib->symbol("kjs_html_init"); if ( !sym ) { lib->unload(); setJScriptEnabled( false ); return 0; } typedef KJSProxy* (*initFunction)(KHTMLPart *); initFunction initSym = (initFunction) sym; d->m_jscript = (*initSym)(this); d->m_kjs_lib = lib; #else d->m_jscript = kjs_html_init(this); // d->m_kjs_lib remains 0L. #endif if (d->m_bJScriptDebugEnabled) d->m_jscript->setDebugEnabled(true); } return d->m_jscript; } void KHTMLPart::replaceContentsWithScriptResult( const KURL &url ) { QString script = KURL::decode_string(url.url().mid(strlen("javascript:"))); QVariant ret = executeScript(script); if (ret.type() == QVariant::String) { begin(); write(ret.asString()); end(); } } QVariant KHTMLPart::executeScript( const QString &script, bool forceUserGesture ) { return executeScript( DOM::Node(), script, forceUserGesture ); } //Enable this to see all JS scripts being executed //#define KJS_VERBOSE QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script, bool forceUserGesture ) { #ifdef KJS_VERBOSE kdDebug(6070) << "KHTMLPart::executeScript n=" << n.nodeName().string().latin1() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " << script << endl; #endif KJSProxy *proxy = jScript(); if (!proxy || proxy->paused()) return QVariant(); d->m_runningScripts++; // If forceUserGesture is true, then make the script interpreter // treat it as if triggered by a user gesture even if there is no // current DOM event being processed. QVariant ret = proxy->evaluate( forceUserGesture ? QString::null : m_url.url(), 0, script, n ); d->m_runningScripts--; if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm ) submitFormAgain(); DocumentImpl::updateDocumentsRendering(); #ifdef KJS_VERBOSE kdDebug(6070) << "KHTMLPart::executeScript - done" << endl; #endif return ret; } bool KHTMLPart::scheduleScript(const DOM::Node &n, const QString& script) { //kdDebug(6050) << "KHTMLPart::scheduleScript "<< script << endl; d->scheduledScript = script; d->scheduledScriptNode = n; return true; } QVariant KHTMLPart::executeScheduledScript() { if( d->scheduledScript.isEmpty() ) return QVariant(); //kdDebug(6050) << "executing delayed " << d->scheduledScript << endl; QVariant ret = executeScript( d->scheduledScriptNode, d->scheduledScript ); d->scheduledScript = QString(); d->scheduledScriptNode = DOM::Node(); return ret; } void KHTMLPart::setJavaEnabled( bool enable ) { d->m_bJavaForce = enable; d->m_bJavaOverride = true; } bool KHTMLPart::javaEnabled() const { #ifndef Q_WS_QWS if( d->m_bJavaOverride ) return d->m_bJavaForce; return d->m_bJavaEnabled; #else return false; #endif } KJavaAppletContext *KHTMLPart::javaContext() { #ifndef Q_WS_QWS return d->m_javaContext; #else return 0; #endif } KJavaAppletContext *KHTMLPart::createJavaContext() { #ifndef Q_WS_QWS if ( !d->m_javaContext ) { #if APPLE_CHANGES d->m_javaContext = new KJavaAppletContext(d->m_dcopobject, this); #else d->m_javaContext = new KJavaAppletContext(d->m_dcopobject); connect( d->m_javaContext, SIGNAL(showStatus(const QString&)), this, SIGNAL(setStatusBarText(const QString&)) ); connect( d->m_javaContext, SIGNAL(showDocument(const QString&, const QString&)), this, SLOT(slotShowDocument(const QString&, const QString&)) ); #endif } return d->m_javaContext; #else return 0; #endif } void KHTMLPart::setPluginsEnabled( bool enable ) { d->m_bPluginsForce = enable; d->m_bPluginsOverride = true; } bool KHTMLPart::pluginsEnabled() const { if ( d->m_bPluginsOverride ) return d->m_bPluginsForce; return d->m_bPluginsEnabled; } #if !APPLE_CHANGES void KHTMLPart::slotShowDocument( const QString &url, const QString &target ) { // this is mostly copied from KHTMLPart::slotChildURLRequest. The better approach // would be to put those functions into a single one. khtml::ChildFrame *child = 0; KParts::URLArgs args; args.frameName = target; QString frameName = args.frameName.lower(); if ( !frameName.isEmpty() ) { if ( frameName == QString::fromLatin1( "_top" ) ) { emit d->m_extension->openURLRequest( url, args ); return; } else if ( frameName == QString::fromLatin1( "_blank" ) ) { emit d->m_extension->createNewWindow( url, args ); return; } else if ( frameName == QString::fromLatin1( "_parent" ) ) { KParts::URLArgs newArgs( args ); newArgs.frameName = QString::null; emit d->m_extension->openURLRequest( url, newArgs ); return; } else if ( frameName != QString::fromLatin1( "_self" ) ) { khtml::ChildFrame *_frame = recursiveFrameRequest( url, args ); if ( !_frame ) { emit d->m_extension->openURLRequest( url, args ); return; } child = _frame; } } // TODO: handle child target correctly! currently the script are always executed fur the parent if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) { executeScript( KURL::decode_string( url.right( url.length() - 11) ) ); return; } if ( child ) { requestObject( child, KURL(url), args ); } else if ( frameName==QString::fromLatin1("_self") ) // this is for embedded objects (via ) which want to replace the current document { KParts::URLArgs newArgs( args ); newArgs.frameName = QString::null; emit d->m_extension->openURLRequest( KURL(url), newArgs ); } } #endif // APPLE_CHANGES void KHTMLPart::slotDebugDOMTree() { if ( d->m_doc && d->m_doc->firstChild() ) qDebug("%s", createMarkup(d->m_doc->firstChild()).latin1()); } void KHTMLPart::slotDebugRenderTree() { #ifndef NDEBUG if ( d->m_doc ) d->m_doc->renderer()->printTree(); #endif } void KHTMLPart::setAutoloadImages( bool enable ) { if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable ) return; if ( d->m_doc ) d->m_doc->docLoader()->setAutoloadImages( enable ); #if !APPLE_CHANGES unplugActionList( "loadImages" ); if ( enable ) { delete d->m_paLoadImages; d->m_paLoadImages = 0; } else if ( !d->m_paLoadImages ) d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), "images_display", 0, this, SLOT( slotLoadImages() ), actionCollection(), "loadImages" ); if ( d->m_paLoadImages ) { QPtrList lst; lst.append( d->m_paLoadImages ); plugActionList( "loadImages", lst ); } #endif } bool KHTMLPart::autoloadImages() const { if ( d->m_doc ) return d->m_doc->docLoader()->autoloadImages(); return true; } void KHTMLPart::clear() { if ( d->m_bCleared ) return; d->m_bCleared = true; d->m_bClearing = true; #if !APPLE_CHANGES { ConstFrameIt it = d->m_frames.begin(); ConstFrameIt end = d->m_frames.end(); for(; it != end; ++it ) { // Stop HTMLRun jobs for frames if ( (*it).m_run ) (*it).m_run->abort(); } } { QValueList::ConstIterator it = d->m_objects.begin(); QValueList::ConstIterator end = d->m_objects.end(); for(; it != end; ++it ) { // Stop HTMLRun jobs for objects if ( (*it).m_run ) (*it).m_run->abort(); } } findTextBegin(); // resets d->m_findNode and d->m_findPos #endif d->m_mousePressNode = DOM::Node(); if ( d->m_doc ) d->m_doc->detach(); // Moving past doc so that onUnload works. if ( d->m_jscript ) d->m_jscript->clear(); if ( d->m_view ) d->m_view->clear(); // do not dereference the document before the jscript and view are cleared, as some destructors // might still try to access the document. if ( d->m_doc ) d->m_doc->deref(); d->m_doc = 0; if (d->m_decoder) d->m_decoder->deref(); d->m_decoder = 0; { ConstFrameIt it = d->m_frames.begin(); ConstFrameIt end = d->m_frames.end(); for(; it != end; ++it ) { if ( (*it).m_part ) { disconnectChild(&*it); #if !APPLE_CHANGES partManager()->removePart( (*it).m_part ); #endif (*it).m_part->deref(); } } } d->m_frames.clear(); { ConstFrameIt it = d->m_objects.begin(); ConstFrameIt end = d->m_objects.end(); for(; it != end; ++it ) { if ( (*it).m_part ) { #if !APPLE_CHANGES partManager()->removePart( (*it).m_part ); #endif (*it).m_part->deref(); } } } d->m_objects.clear(); #ifndef Q_WS_QWS delete d->m_javaContext; d->m_javaContext = 0; #endif d->m_scheduledRedirection = noRedirectionScheduled; d->m_delayRedirect = 0; d->m_redirectURL = QString::null; d->m_redirectReferrer = QString::null; d->m_redirectLockHistory = true; d->m_redirectUserGesture = false; d->m_bHTTPRefresh = false; d->m_bClearing = false; d->m_frameNameId = 1; d->m_bFirstData = true; d->m_bMousePressed = false; #ifndef QT_NO_CLIPBOARD connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection())); #endif #if !APPLE_CHANGES d->m_totalObjectCount = 0; d->m_loadedObjects = 0; d->m_jobPercent = 0; #endif if ( !d->m_haveEncoding ) d->m_encoding = QString::null; #ifdef SPEED_DEBUG d->m_parsetime.restart(); #endif } bool KHTMLPart::openFile() { return true; } DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const { if ( d ) return d->m_doc; return 0; } void KHTMLPart::replaceDocImpl(DocumentImpl* newDoc) { if (d) { if (d->m_doc) { d->m_doc->detach(); d->m_doc->deref(); } d->m_doc = newDoc; if (newDoc) newDoc->ref(); } } /*bool KHTMLPart::isSSLInUse() const { return d->m_ssl_in_use; }*/ void KHTMLPart::receivedFirstData() { // Leave indented one extra for easier merging. //kdDebug( 6050 ) << "begin!" << endl; begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset ); d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy); d->m_workingURL = KURL(); d->m_cacheId = KHTMLPageCache::self()->createCacheEntry(); // When the first data arrives, the metadata has just been made available #if APPLE_CHANGES QString qData; #else d->m_bSecurityInQuestion = false; d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE"); kdDebug(6050) << "SSL in use? " << d->m_job->queryMetaData("ssl_in_use") << endl; { KHTMLPart *p = parentPart(); if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) { while (p->parentPart()) p = p->parentPart(); p->d->m_paSecurity->setIcon( "halfencrypted" ); p->d->m_bSecurityInQuestion = true; kdDebug(6050) << "parent setIcon half done." << endl; } } d->m_paSecurity->setIcon( d->m_ssl_in_use ? "encrypted" : "decrypted" ); kdDebug(6050) << "setIcon " << ( d->m_ssl_in_use ? "encrypted" : "decrypted" ) << " done." << endl; // Shouldn't all of this be done only if ssl_in_use == true ? (DF) d->m_ssl_peer_certificate = d->m_job->queryMetaData("ssl_peer_certificate"); d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain"); d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip"); d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher"); d->m_ssl_cipher_desc = d->m_job->queryMetaData("ssl_cipher_desc"); d->m_ssl_cipher_version = d->m_job->queryMetaData("ssl_cipher_version"); d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits"); d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits"); d->m_ssl_cert_state = d->m_job->queryMetaData("ssl_cert_state"); // Check for charset meta-data QString qData = d->m_job->queryMetaData("charset"); if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings d->m_encoding = qData; #endif // APPLE_CHANGES // Support for http-refresh qData = d->m_job->queryMetaData("http-refresh"); if( !qData.isEmpty() && d->m_metaRefreshEnabled ) { kdDebug(6050) << "HTTP Refresh Request: " << qData << endl; double delay; int pos = qData.find( ';' ); if ( pos == -1 ) pos = qData.find( ',' ); if( pos == -1 ) { delay = qData.stripWhiteSpace().toDouble(); #if APPLE_CHANGES // We want a new history item if the refresh timeout > 1 second scheduleRedirection( delay, m_url.url(), delay <= 1); #else scheduleRedirection( delay, m_url.url()); #endif } else { int end_pos = qData.length(); delay = qData.left(pos).stripWhiteSpace().toDouble(); while ( qData[++pos] == ' ' ); if ( qData.find( "url", pos, false ) == pos ) { pos += 3; while (qData[pos] == ' ' || qData[pos] == '=' ) pos++; if ( qData[pos] == '"' ) { pos++; int index = end_pos-1; while( index > pos ) { if ( qData[index] == '"' ) break; index--; } if ( index > pos ) end_pos = index; } } #if APPLE_CHANGES // We want a new history item if the refresh timeout > 1 second scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ), delay <= 1); #else scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) )); #endif } d->m_bHTTPRefresh = true; } // Support for http last-modified d->m_lastModified = d->m_job->queryMetaData("modified"); //kdDebug() << "KHTMLPart::slotData metadata modified: " << d->m_lastModified << endl; } #if !APPLE_CHANGES void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data ) { assert ( d->m_job == kio_job ); //kdDebug( 6050 ) << "slotData: " << data.size() << endl; // The first data ? if ( !d->m_workingURL.isEmpty() ) receivedFirstData( ); KHTMLPageCache::self()->addData(d->m_cacheId, data); write( data.data(), data.size() ); } void KHTMLPart::slotRestoreData(const QByteArray &data ) { // The first data ? if ( !d->m_workingURL.isEmpty() ) { long saveCacheId = d->m_cacheId; begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset ); d->m_cacheId = saveCacheId; d->m_workingURL = KURL(); } //kdDebug( 6050 ) << "slotRestoreData: " << data.size() << endl; write( data.data(), data.size() ); if (data.size() == 0) { //kdDebug( 6050 ) << "slotRestoreData: <>" << endl; // End of data. if (d->m_doc && d->m_doc->parsing()) end(); //will emit completed() } } void KHTMLPart::showError( KIO::Job* job ) { kdDebug() << "KHTMLPart::showError d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete << " d->m_bCleared=" << d->m_bCleared << endl; if (job->error() == KIO::ERR_NO_CONTENT) return; if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already job->showErrorDialog( /*d->m_view*/ ); else { htmlError( job->error(), job->errorText(), d->m_workingURL ); } } // This is a protected method, placed here because of it's relevance to showError void KHTMLPart::htmlError( int errorCode, const QString& text, const KURL& reqUrl ) { kdDebug(6050) << "KHTMLPart::htmlError errorCode=" << errorCode << " text=" << text << endl; // make sure we're not executing any embedded JS bool bJSFO = d->m_bJScriptForce; bool bJSOO = d->m_bJScriptOverride; d->m_bJScriptForce = false; d->m_bJScriptOverride = true; begin(); QString errText = QString::fromLatin1( "" ); errText += i18n( "Error while loading %1" ).arg( reqUrl.htmlURL() ); errText += QString::fromLatin1( "

" ); errText += i18n( "An error occured while loading %1:" ).arg( reqUrl.htmlURL() ); errText += QString::fromLatin1( "

" ); QString kioErrString = KIO::buildErrorString( errorCode, text ); kioErrString.replace(QRegExp("&"), QString("&")); kioErrString.replace(QRegExp("<"), QString("<")); kioErrString.replace(QRegExp(">"), QString(">")); // In case the error string has '\n' in it, replace with
kioErrString.replace( QRegExp("\n"), "
" ); errText += kioErrString; errText += QString::fromLatin1( "

" ); write(errText); end(); d->m_bJScriptForce = bJSFO; d->m_bJScriptOverride = bJSOO; // make the working url the current url, so that reload works and // emit the progress signals to advance one step in the history // (so that 'back' works) m_url = reqUrl; // same as d->m_workingURL d->m_workingURL = KURL(); emit started( 0 ); emit completed(); return; // following disabled until 3.1 QString errorName, techName, description; QStringList causes, solutions; QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl ); QDataStream stream(raw, IO_ReadOnly); stream >> errorName >> techName >> description >> causes >> solutions; QString url, protocol, datetime; url = reqUrl.prettyURL(); protocol = reqUrl.protocol(); datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(), false ); QString doc = QString::fromLatin1( "" ); doc += i18n( "Error: " ); doc += errorName; doc += QString::fromLatin1( " - %1

" ).arg( url ); doc += i18n( "The requested operation could not be completed" ); doc += QString::fromLatin1( "

" ); doc += errorName; doc += QString::fromLatin1( "

" ); if ( techName != QString::null ) { doc += QString::fromLatin1( "

" ); doc += i18n( "Technical Reason: " ); doc += techName; doc += QString::fromLatin1( "

" ); } doc += QString::fromLatin1( "

" ); doc += i18n( "Details of the Request:" ); doc += QString::fromLatin1( "

  • " ); doc += i18n( "URL: %1" ).arg( url ); doc += QString::fromLatin1( "
  • " ); if ( protocol != QString::null ) { // uncomment for 3.1... i18n change // doc += i18n( "Protocol: %1" ).arg( protocol ).arg( protocol ); doc += QString::fromLatin1( "
  • " ); } doc += i18n( "Date and Time: %1" ).arg( datetime ); doc += QString::fromLatin1( "
  • " ); doc += i18n( "Additional Information: %1" ).arg( text ); doc += QString::fromLatin1( "

" ); doc += i18n( "Description:" ); doc += QString::fromLatin1( "

" ); doc += description; doc += QString::fromLatin1( "

" ); if ( causes.count() ) { doc += QString::fromLatin1( "

" ); doc += i18n( "Possible Causes:" ); doc += QString::fromLatin1( "

  • " ); doc += causes.join( "
  • " ); doc += QString::fromLatin1( "
" ); } if ( solutions.count() ) { doc += QString::fromLatin1( "

" ); doc += i18n( "Possible Solutions:" ); doc += QString::fromLatin1( "

  • " ); doc += solutions.join( "
  • " ); doc += QString::fromLatin1( "
" ); } doc += QString::fromLatin1( "" ); write( doc ); end(); } #endif void KHTMLPart::slotFinished( KIO::Job * job ) { if (job->error()) { KHTMLPageCache::self()->cancelEntry(d->m_cacheId); d->m_job = 0L; #if !APPLE_CHANGES emit canceled( job->errorString() ); #endif // TODO: what else ? checkCompleted(); #if !APPLE_CHANGES showError( job ); #endif return; } //kdDebug( 6050 ) << "slotFinished" << endl; KHTMLPageCache::self()->endData(d->m_cacheId); if ( d->m_doc && d->m_doc->docLoader()->expireDate() && m_url.protocol().lower().startsWith("http")) KIO::http_update_cache(m_url, false, d->m_doc->docLoader()->expireDate()); d->m_workingURL = KURL(); d->m_job = 0L; if (d->m_doc->parsing()) end(); //will emit completed() } #if APPLE_CHANGES void KHTMLPart::childBegin() { // We need to do this when the child is created so as to avoid the bogus state of the parent's // child->m_bCompleted being false but the child's m_bComplete being true. If the child gets // an error early on, we had trouble where checkingComplete on the child was a NOP because // it thought it was already complete, and thus the parent was never signaled, and never set // its child->m_bComplete. d->m_bComplete = false; } #endif void KHTMLPart::begin( const KURL &url, int xOffset, int yOffset ) { #if APPLE_CHANGES // If we aren't loading an actual URL, then we need to make sure // that we have at least an empty document. createEmptyDocument will // do that if we don't have a document already. if (d->m_workingURL.isEmpty()) { KWQ(this)->createEmptyDocument(); } #endif clear(); #if APPLE_CHANGES KWQ(this)->partClearedInBegin(); #endif // Only do this after clearing the part, so that JavaScript can // clean up properly if it was on for the last load. #if !APPLE_CHANGES d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host()); #else d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host()); #endif d->m_bCleared = false; d->m_cacheId = 0; d->m_bComplete = false; d->m_bLoadEventEmitted = false; d->m_bLoadingMainResource = true; if(url.isValid()) { #if APPLE_CHANGES KHTMLFactory::vLinks()->insert( KWQ(this)->requestedURLString() ); #else QString urlString = url.url(); KHTMLFactory::vLinks()->insert( urlString ); QString urlString2 = url.prettyURL(); if ( urlString != urlString2 ) { KHTMLFactory::vLinks()->insert( urlString2 ); } #endif } // ### //stopParser(); KParts::URLArgs args( d->m_extension->urlArgs() ); args.xOffset = xOffset; args.yOffset = yOffset; d->m_extension->setURLArgs( args ); KURL ref(url); ref.setUser(QSTRING_NULL); ref.setPass(QSTRING_NULL); ref.setRef(QSTRING_NULL); d->m_referrer = ref.url(); m_url = url; KURL baseurl; #if APPLE_CHANGES // We don't need KDE chained URI handling or window caption setting if ( !m_url.isEmpty() ) { baseurl = m_url; } #else if ( !m_url.isEmpty() ) { KURL::List lst = KURL::split( m_url ); if ( !lst.isEmpty() ) baseurl = *lst.begin(); KURL title( baseurl ); title.setRef( QString::null ); title.setQuery( QString::null ); emit setWindowCaption( title.url() ); } else emit setWindowCaption( i18n( "no title", "* Unknown *" ) ); #endif if (args.serviceType == "text/xml" || args.serviceType == "application/xml" || args.serviceType == "application/xhtml+xml" || args.serviceType == "text/xsl" || args.serviceType == "application/rss+xml" || args.serviceType == "application/atom+xml") d->m_doc = DOMImplementationImpl::instance()->createDocument( d->m_view ); else d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view ); d->m_doc->ref(); if (!d->m_doc->attached()) d->m_doc->attach( ); d->m_doc->setURL( m_url.url() ); // We prefer m_baseURL over m_url because m_url changes when we are // about to load a new page. d->m_doc->setBaseURL( baseurl.url() ); #if APPLE_CHANGES if (d->m_decoder) d->m_doc->setDecoder(d->m_decoder); #endif #if !APPLE_CHANGES d->m_doc->docLoader()->setShowAnimations( KHTMLFactory::defaultHTMLSettings()->showAnimations() ); #else d->m_doc->docLoader()->setShowAnimations( d->m_settings->showAnimations() ); #endif #if APPLE_CHANGES KWQ(this)->updatePolicyBaseURL(); #endif #if !APPLE_CHANGES d->m_paUseStylesheet->setItems(QStringList()); d->m_paUseStylesheet->setEnabled( false ); #endif #if !APPLE_CHANGES setAutoloadImages( KHTMLFactory::defaultHTMLSettings()->autoLoadImages() ); QString userStyleSheet = KHTMLFactory::defaultHTMLSettings()->userStyleSheet(); #else setAutoloadImages( d->m_settings->autoLoadImages() ); QString userStyleSheet = d->m_settings->userStyleSheet(); #endif if ( !userStyleSheet.isEmpty() ) setUserStyleSheet( KURL( userStyleSheet ) ); #if APPLE_CHANGES KWQ(this)->restoreDocumentState(); #else d->m_doc->setRestoreState(args.docState); #endif d->m_doc->implicitOpen(); // clear widget if (d->m_view) d->m_view->resizeContents( 0, 0 ); connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing())); #if !APPLE_CHANGES emit d->m_extension->enableAction( "print", true ); #endif } void KHTMLPart::write( const char *str, int len ) { if ( !d->m_decoder ) { d->m_decoder = new Decoder; if (!d->m_encoding.isNull()) d->m_decoder->setEncoding(d->m_encoding.latin1(), d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader); else { // Inherit the default encoding from the parent frame if there is one. const char *defaultEncoding = (parentPart() && parentPart()->d->m_decoder) ? parentPart()->d->m_decoder->encoding() : settings()->encoding().latin1(); d->m_decoder->setEncoding(defaultEncoding, Decoder::DefaultEncoding); } #if APPLE_CHANGES if (d->m_doc) d->m_doc->setDecoder(d->m_decoder); #endif } if ( len == 0 ) return; if ( len == -1 ) len = strlen( str ); QString decoded = d->m_decoder->decode( str, len ); if(decoded.isEmpty()) return; if(d->m_bFirstData) { // determine the parse mode d->m_doc->determineParseMode( decoded ); d->m_bFirstData = false; //kdDebug(6050) << "KHTMLPart::write haveEnc = " << d->m_haveEncoding << endl; // ### this is still quite hacky, but should work a lot better than the old solution if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered(); d->m_doc->recalcStyle( NodeImpl::Force ); } if (jScript()) jScript()->appendSourceFile(m_url.url(),decoded); Tokenizer* t = d->m_doc->tokenizer(); if(t) t->write( decoded, true ); } void KHTMLPart::write( const QString &str ) { if ( str.isNull() ) return; if(d->m_bFirstData) { // determine the parse mode d->m_doc->setParseMode( DocumentImpl::Strict ); d->m_bFirstData = false; } if (jScript()) jScript()->appendSourceFile(m_url.url(),str); Tokenizer* t = d->m_doc->tokenizer(); if(t) t->write( str, true ); } void KHTMLPart::end() { d->m_bLoadingMainResource = false; endIfNotLoading(); } void KHTMLPart::endIfNotLoading() { if (d->m_bLoadingMainResource) return; // make sure nothing's left in there... if (d->m_decoder) write(d->m_decoder->flush()); if (d->m_doc) d->m_doc->finishParsing(); else // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to // become true. An example is when a subframe is a pure text doc, and that subframe is the // last one to complete. checkCompleted(); } void KHTMLPart::stop() { // make sure nothing's left in there... Tokenizer* t = d->m_doc ? d->m_doc->tokenizer() : 0; if (t) t->stopped(); if (d->m_doc) d->m_doc->finishParsing(); else // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to // become true. An example is when a subframe is a pure text doc, and that subframe is the // last one to complete. checkCompleted(); } #if !APPLE_CHANGES void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more) { if (!d->m_view) return; d->m_view->paint(p, rc, yOff, more); } #endif void KHTMLPart::stopAnimations() { if ( d->m_doc ) d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled ); ConstFrameIt it = d->m_frames.begin(); ConstFrameIt end = d->m_frames.end(); for (; it != end; ++it ) if ( !( *it ).m_part.isNull() && ( *it ).m_part->inherits( "KHTMLPart" ) ) { KParts::ReadOnlyPart* p = ( *it ).m_part; static_cast( p )->stopAnimations(); } } void KHTMLPart::gotoAnchor() { if (m_url.hasRef()) { QString ref = m_url.encodedHtmlRef(); if (!gotoAnchor(ref)) { // Can't use htmlRef() here because it doesn't know which encoding to use to decode. // Decoding here has to match encoding in completeURL, which means it has to use the // page's encoding rather than UTF-8. if (d->m_decoder) #if !APPLE_CHANGES gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()->mibEnum())); #else gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec())); #endif } } } void KHTMLPart::slotFinishedParsing() { d->m_doc->setParsing(false); if (!d->m_view) return; // We are probably being destructed. checkCompleted(); if (!d->m_view) return; // We are being destroyed by something checkCompleted called. // check if the scrollbars are really needed for the content // if not, remove them, relayout, and repaint d->m_view->restoreScrollBar(); gotoAnchor(); } void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj ) { #if !APPLE_CHANGES if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) { KHTMLPart* p = this; while ( p ) { KHTMLPart* op = p; p->d->m_totalObjectCount++; p = p->parentPart(); if ( !p && d->m_loadedObjects <= d->m_totalObjectCount ) QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) ); } } #endif } void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj ) { #if !APPLE_CHANGES if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) { KHTMLPart* p = this; while ( p ) { KHTMLPart* op = p; p->d->m_loadedObjects++; p = p->parentPart(); if ( !p && d->m_loadedObjects <= d->m_totalObjectCount && d->m_jobPercent >= 100 ) QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) ); } } #endif // We really only need to call checkCompleted when our own resources are done loading. // So we should check that d->m_doc->docLoader() == dl here. // That might help with performance by skipping some unnecessary work, but it's too // risky to make that change right now (2005-02-07), because we might be accidentally // depending on the extra checkCompleted calls. if (d->m_doc) { checkCompleted(); } } #if !APPLE_CHANGES void KHTMLPart::slotProgressUpdate() { int percent; if ( d->m_loadedObjects < d->m_totalObjectCount ) percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount ); else percent = d->m_jobPercent; if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 ) emit d->m_extension->infoMessage( i18n( "%1 of 1 Image loaded", "%1 of %n Images loaded", d->m_totalObjectCount ).arg( d->m_loadedObjects ) ); emit d->m_extension->loadingProgress( percent ); } void KHTMLPart::slotJobSpeed( KIO::Job* /*job*/, unsigned long speed ) { emit d->m_extension->speedProgress( speed ); } void KHTMLPart::slotJobPercent( KIO::Job* /*job*/, unsigned long percent ) { d->m_jobPercent = percent; if ( !parentPart() ) QTimer::singleShot( 0, this, SLOT( slotProgressUpdate() ) ); } #endif void KHTMLPart::checkCompleted() { // kdDebug( 6050 ) << "KHTMLPart::checkCompleted() parsing: " << d->m_doc->parsing() << endl; // kdDebug( 6050 ) << " complete: " << d->m_bComplete << endl; #if !APPLE_CHANGES // restore the cursor position if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored) { if (d->m_focusNodeNumber >= 0) d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber)); else d->m_doc->setFocusNode(0); d->m_focusNodeRestored = true; } #endif // Any frame that hasn't completed yet ? ConstFrameIt it = d->m_frames.begin(); ConstFrameIt end = d->m_frames.end(); for (; it != end; ++it ) if ( !(*it).m_bCompleted ) return; // Have we completed before? if ( d->m_bComplete ) return; // Are we still parsing? if ( d->m_doc && d->m_doc->parsing() ) return; // Still waiting for images/scripts from the loader ? int requests = 0; if ( d->m_doc && d->m_doc->docLoader() ) requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() ); if ( requests > 0 ) return; // OK, completed. // Now do what should be done when we are really completed. d->m_bComplete = true; checkEmitLoadEvent(); // if we didn't do it before #if !APPLE_CHANGES // check that the view has not been moved by the user if ( !m_url.hasRef() && d->m_view->contentsY() == 0 ) d->m_view->setContentsPos( d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset ); #endif if ( d->m_scheduledRedirection != noRedirectionScheduled ) { // Do not start redirection for frames here! That action is // deferred until the parent emits a completed signal. if ( parentPart() == 0 ) d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true ); emit completed( true ); } else { if ( d->m_bPendingChildRedirection ) emit completed ( true ); else emit completed(); } #if !APPLE_CHANGES // find the alternate stylesheets QStringList sheets; if (d->m_doc) sheets = d->m_doc->availableStyleSheets(); d->m_paUseStylesheet->setItems( sheets ); d->m_paUseStylesheet->setEnabled( !sheets.isEmpty() ); if (!sheets.isEmpty()) { d->m_paUseStylesheet->setCurrentItem(kMax(sheets.findIndex(d->m_sheetUsed), 0)); slotUseStylesheet(); } if (!parentPart()) emit setStatusBarText(i18n("Done.")); #endif #ifdef SPEED_DEBUG kdDebug(6050) << "DONE: " <m_parsetime.elapsed() << endl; #endif } void KHTMLPart::checkEmitLoadEvent() { if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return; ConstFrameIt it = d->m_frames.begin(); ConstFrameIt end = d->m_frames.end(); for (; it != end; ++it ) if ( !(*it).m_bCompleted ) // still got a frame running -> too early return; // All frames completed -> set their domain to the frameset's domain // This must only be done when loading the frameset initially (#22039), // not when following a link in a frame (#44162). if ( d->m_doc ) { DOMString domain = d->m_doc->domain(); ConstFrameIt it = d->m_frames.begin(); ConstFrameIt end = d->m_frames.end(); for (; it != end; ++it ) { KParts::ReadOnlyPart *p = (*it).m_part; if ( p && p->inherits( "KHTMLPart" )) { KHTMLPart* htmlFrame = static_cast(p); if (htmlFrame->d->m_doc) { kdDebug() << "KHTMLPart::checkCompleted setting frame domain to " << domain.string() << endl; htmlFrame->d->m_doc->setDomain( domain ); } } } } d->m_bLoadEventEmitted = true; d->m_bUnloadEventEmitted = false; if (d->m_doc) d->m_doc->implicitClose(); } const KHTMLSettings *KHTMLPart::settings() const { return d->m_settings; } #ifndef KDE_NO_COMPAT KURL KHTMLPart::baseURL() const { if ( !d->m_doc ) return KURL(); return d->m_doc->baseURL(); } QString KHTMLPart::baseTarget() const { if ( !d->m_doc ) return QString::null; return d->m_doc->baseTarget(); } #endif KURL KHTMLPart::completeURL( const QString &url ) { if ( !d->m_doc ) return url; #if !APPLE_CHANGES if (d->m_decoder) return KURL(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum()); #endif return KURL( d->m_doc->completeURL( url ) ); } void KHTMLPart::scheduleRedirection( double delay, const QString &url, bool doLockHistory) { kdDebug(6050) << "KHTMLPart::scheduleRedirection delay=" << delay << " url=" << url << endl; if (delay < 0 || delay > INT_MAX / 1000) return; if ( d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect ) { d->m_scheduledRedirection = redirectionScheduled; d->m_delayRedirect = delay; d->m_redirectURL = url; d->m_redirectReferrer = QString::null; d->m_redirectLockHistory = doLockHistory; d->m_redirectUserGesture = false; d->m_redirectionTimer.stop(); if ( d->m_bComplete ) d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true ); } } void KHTMLPart::scheduleLocationChange(const QString &url, const QString &referrer, bool lockHistory, bool userGesture) { // Handle a location change of a page with no document as a special case. // This may happen when a frame changes the location of another frame. d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad; // If a redirect was scheduled during a load, then stop the current load. // Otherwise when the current load transitions from a provisional to a // committed state, pending redirects may be cancelled. if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) { stopLoading(true); } d->m_delayRedirect = 0; d->m_redirectURL = url; d->m_redirectReferrer = referrer; d->m_redirectLockHistory = lockHistory; d->m_redirectUserGesture = userGesture; d->m_redirectionTimer.stop(); if (d->m_bComplete) d->m_redirectionTimer.start(0, true); } bool KHTMLPart::isScheduledLocationChangePending() const { switch (d->m_scheduledRedirection) { case noRedirectionScheduled: case redirectionScheduled: return false; case historyNavigationScheduled: case locationChangeScheduled: case locationChangeScheduledDuringLoad: return true; } return false; } void KHTMLPart::scheduleHistoryNavigation( int steps ) { #if APPLE_CHANGES // navigation will always be allowed in the 0 steps case, which is OK because // that's supposed to force a reload. if (!KWQ(this)->canGoBackOrForward(steps)) { cancelRedirection(); return; } #endif d->m_scheduledRedirection = historyNavigationScheduled; d->m_delayRedirect = 0; d->m_redirectURL = QString::null; d->m_redirectReferrer = QString::null; d->m_scheduledHistoryNavigationSteps = steps; d->m_redirectionTimer.stop(); if (d->m_bComplete) d->m_redirectionTimer.start(0, true); } void KHTMLPart::cancelRedirection(bool cancelWithLoadInProgress) { if (d) { d->m_cancelWithLoadInProgress = cancelWithLoadInProgress; d->m_scheduledRedirection = noRedirectionScheduled; d->m_redirectionTimer.stop(); } } void KHTMLPart::changeLocation(const QString &URL, const QString &referrer, bool lockHistory, bool userGesture) { if (URL.find("javascript:", 0, false) == 0) { QString script = KURL::decode_string(URL.mid(11)); QVariant result = executeScript(script, userGesture); if (result.type() == QVariant::String) { begin(url()); write(result.asString()); end(); } return; } KParts::URLArgs args; args.setLockHistory(lockHistory); if (!referrer.isEmpty()) args.metaData()["referrer"] = referrer; urlSelected(URL, 0, 0, "_self", args); } void KHTMLPart::slotRedirect() { if (d->m_scheduledRedirection == historyNavigationScheduled) { d->m_scheduledRedirection = noRedirectionScheduled; // Special case for go(0) from a frame -> reload only the frame // go(i!=0) from a frame navigates into the history of the frame only, // in both IE and NS (but not in Mozilla).... we can't easily do that // in Konqueror... if (d->m_scheduledHistoryNavigationSteps == 0) // add && parentPart() to get only frames, but doesn't matter openURL( url() ); /// ## need args.reload=true? else { if (d->m_extension) { BrowserInterface *interface = d->m_extension->browserInterface(); if (interface) interface->callMethod( "goHistory(int)", d->m_scheduledHistoryNavigationSteps ); } } return; } QString URL = d->m_redirectURL; QString referrer = d->m_redirectReferrer; bool lockHistory = d->m_redirectLockHistory; bool userGesture = d->m_redirectUserGesture; d->m_scheduledRedirection = noRedirectionScheduled; d->m_delayRedirect = 0; d->m_redirectURL = QString::null; d->m_redirectReferrer = QString::null; changeLocation(URL, referrer, lockHistory, userGesture); } void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url) { // the slave told us that we got redirected // kdDebug( 6050 ) << "redirection by KIO to " << url.url() << endl; emit d->m_extension->setLocationBarURL( url.prettyURL() ); d->m_workingURL = url; } #if !APPLE_CHANGES bool KHTMLPart::setEncoding( const QString &name, bool override ) { d->m_encoding = name; d->m_haveEncoding = override; if( !m_url.isEmpty() ) { // reload document closeURL(); KURL url = m_url; m_url = 0; d->m_restored = true; openURL(url); d->m_restored = false; } return true; } #endif QString KHTMLPart::encoding() const { if(d->m_haveEncoding && !d->m_encoding.isEmpty()) return d->m_encoding; if(d->m_decoder && d->m_decoder->encoding()) return QString(d->m_decoder->encoding()); return(settings()->encoding()); } void KHTMLPart::setUserStyleSheet(const KURL &url) { if ( d->m_doc && d->m_doc->docLoader() ) (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader()); } void KHTMLPart::setUserStyleSheet(const QString &styleSheet) { if ( d->m_doc ) d->m_doc->setUserStyleSheet( styleSheet ); } bool KHTMLPart::gotoAnchor( const QString &name ) { if (!d->m_doc) return false; NodeImpl *n = d->m_doc->getElementById(name); if (!n) { HTMLCollectionImpl *anchors = new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS); anchors->ref(); n = anchors->namedItem(name, !d->m_doc->inCompatMode()); anchors->deref(); } d->m_doc->setCSSTarget(n); // Setting to null will clear the current target. // Implement the rule that "" and "top" both mean top of page as in other browsers. if (!n && !(name.isEmpty() || name.lower() == "top")) { kdDebug(6050) << "KHTMLPart::gotoAnchor node '" << name << "' not found" << endl; return false; } // We need to update the layout before scrolling, otherwise we could // really mess things up if an anchor scroll comes at a bad moment. if ( d->m_doc ) { d->m_doc->updateRendering(); // Only do a layout if changes have occurred that make it necessary. if ( d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() ) { d->m_view->layout(); } } int x = 0, y = 0; if (n) { static_cast(n)->getUpperLeftCorner(x, y); } // Scroll to actual top left of element with no slop, since some pages expect anchors to be exactly scrolled to. #if APPLE_CHANGES // Call recursive version so this will expose correctly from within nested frames. d->m_view->setContentsPosRecursive(x, y); #else d->m_view->setContentsPos(x, y); #endif return true; } void KHTMLPart::setStandardFont( const QString &name ) { d->m_settings->setStdFontName(name); } void KHTMLPart::setFixedFont( const QString &name ) { d->m_settings->setFixedFontName(name); } #if !APPLE_CHANGES void KHTMLPart::setURLCursor( const QCursor &c ) { d->m_linkCursor = c; } #endif QCursor KHTMLPart::urlCursor() const { #if APPLE_CHANGES // Don't load the link cursor until it's actually used. // Also, we don't need setURLCursor. // This speeds up startup time. return KCursor::handCursor(); #else return d->m_linkCursor; #endif } bool KHTMLPart::onlyLocalReferences() const { return d->m_onlyLocalReferences; } void KHTMLPart::setOnlyLocalReferences(bool enable) { d->m_onlyLocalReferences = enable; } #if !APPLE_CHANGES void KHTMLPart::findTextBegin(NodeImpl *startNode, int startPos) { d->m_findPos = startPos; d->m_findNode = startNode; } bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensitive, bool isRegExp ) { if ( !d->m_doc ) return false; if(!d->m_findNode) { if (d->m_doc->isHTMLDocument()) d->m_findNode = static_cast(d->m_doc)->body(); else d->m_findNode = d->m_doc; } if ( !d->m_findNode ) { kdDebug() << "KHTMLPart::findTextNext no findNode -> return false" << endl; return false; } if ( d->m_findNode->id() == ID_FRAMESET ) { kdDebug() << "KHTMLPart::findTextNext FRAMESET -> return false" << endl; return false; } while(1) { if( (d->m_findNode->nodeType() == Node::TEXT_NODE || d->m_findNode->nodeType() == Node::CDATA_SECTION_NODE) && d->m_findNode->renderer() ) { DOMString nodeText = d->m_findNode->nodeValue(); DOMStringImpl *t = nodeText.implementation(); QConstString s(t->s, t->l); int matchLen = 0; if ( isRegExp ) { QRegExp matcher( str ); matcher.setCaseSensitive( caseSensitive ); d->m_findPos = matcher.search(s.string(), d->m_findPos+1); if ( d->m_findPos != -1 ) matchLen = matcher.matchedLength(); } else { d->m_findPos = s.string().find(str, d->m_findPos+1, caseSensitive); matchLen = str.length(); } if(d->m_findPos != -1) { int x = 0, y = 0; static_cast(d->m_findNode->renderer()) ->posOfChar(d->m_findPos, x, y); d->m_view->setContentsPos(x-50, y-50); Position p1(d->m_findNode, d->m_findPos); Position p2(d->m_findNode, d->m_findPos + matchLen); setSelection(Selection(p1, khtml::DOWNSTREAM, p2, khtml::SEL_PREFER_UPSTREAM_AFFINITY)); return true; } } d->m_findPos = -1; NodeImpl *next; if ( forward ) { next = d->m_findNode->firstChild(); if(!next) next = d->m_findNode->nextSibling(); while(d->m_findNode && !next) { d->m_findNode = d->m_findNode->parentNode(); if( d->m_findNode ) { next = d->m_findNode->nextSibling(); } } } else { next = d->m_findNode->lastChild(); if (!next ) next = d->m_findNode->previousSibling(); while ( d->m_findNode && !next ) { d->m_findNode = d->m_findNode->parentNode(); if( d->m_findNode ) { next = d->m_findNode->previousSibling(); } } } d->m_findNode = next; if(!d->m_findNode) return false; } } #endif // APPLE_CHANGES QString KHTMLPart::text(const DOM::Range &r) const { return plainText(r); } QString KHTMLPart::selectedText() const { return text(selection().toRange()); } bool KHTMLPart::hasSelection() const { return d->m_selection.isCaretOrRange(); } const Selection &KHTMLPart::selection() const { return d->m_selection; } ETextGranularity KHTMLPart::selectionGranularity() const { return d->m_selectionGranularity; } void KHTMLPart::setSelectionGranularity(ETextGranularity granularity) const { d->m_selectionGranularity = granularity; } const Selection &KHTMLPart::dragCaret() const { return d->m_dragCaret; } const Selection &KHTMLPart::mark() const { return d->m_mark; } void KHTMLPart::setMark(const Selection &s) { d->m_mark = s; } void KHTMLPart::setSelection(const Selection &s, bool closeTyping, bool keepTypingStyle) { if (d->m_selection == s) { return; } clearCaretRectIfNeeded(); #if APPLE_CHANGES Selection oldSelection = d->m_selection; #endif d->m_selection = s; if (!s.isNone()) setFocusNodeIfNeeded(); selectionLayoutChanged(); // Always clear the x position used for vertical arrow navigation. // It will be restored by the vertical arrow navigation code if necessary. d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation; if (closeTyping) TypingCommand::closeTyping(lastEditCommand()); if (!keepTypingStyle) clearTypingStyle(); #if APPLE_CHANGES KWQ(this)->respondToChangedSelection(oldSelection, closeTyping); #endif emitSelectionChanged(); } void KHTMLPart::setDragCaret(const Selection &dragCaret) { if (d->m_dragCaret != dragCaret) { d->m_dragCaret.needsCaretRepaint(); d->m_dragCaret = dragCaret; d->m_dragCaret.needsCaretRepaint(); } } void KHTMLPart::clearSelection() { setSelection(Selection()); } void KHTMLPart::invalidateSelection() { clearCaretRectIfNeeded(); d->m_selection.setNeedsLayout(); selectionLayoutChanged(); } void KHTMLPart::setCaretVisible(bool flag) { if (d->m_caretVisible == flag) return; clearCaretRectIfNeeded(); if (flag) setFocusNodeIfNeeded(); d->m_caretVisible = flag; selectionLayoutChanged(); } #if !APPLE_CHANGES void KHTMLPart::slotClearSelection() { clearSelection(); } #endif void KHTMLPart::clearCaretRectIfNeeded() { if (d->m_caretPaint) { d->m_caretPaint = false; d->m_selection.needsCaretRepaint(); } } // Helper function that tells whether a particular node is an element that has an entire // KHTMLPart and KHTMLView, a ,