mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
3367 lines
101 KiB
C++
3367 lines
101 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* vi:tw=2:ts=2:et:sw=2:
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
* Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Travis Bogard <travis@netscape.com>
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
*/
|
|
|
|
#ifdef XP_OS2_VACPP
|
|
// XXX every other file that pulls in _os2.h has no problem with HTMX there;
|
|
// this one does; the problem may lie with the order of the headers below,
|
|
// which is why this fix is here instead of in _os2.h
|
|
typedef unsigned long HMTX;
|
|
#endif
|
|
#include "nsDocShell.h"
|
|
#include "nsIWebShell.h"
|
|
#include "nsIWebBrowserChrome.h"
|
|
#include "nsIInterfaceRequestor.h"
|
|
#include "nsIDocumentLoader.h"
|
|
#include "nsIDocumentLoaderObserver.h"
|
|
#include "nsIDocumentLoaderFactory.h"
|
|
#include "nsIContentViewer.h"
|
|
#include "nsIDocumentViewer.h"
|
|
#include "nsIMarkupDocumentViewer.h"
|
|
#include "nsIClipboardCommands.h"
|
|
#include "nsILinkHandler.h"
|
|
#include "nsIStreamListener.h"
|
|
#include "nsIPrompt.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsIProtocolHandler.h"
|
|
#include "nsIDNSService.h"
|
|
#include "nsIRefreshURI.h"
|
|
#include "nsIScriptGlobalObject.h"
|
|
#include "nsIScriptGlobalObjectOwner.h"
|
|
#include "nsIProgressEventSink.h"
|
|
#include "nsDOMEvent.h"
|
|
#include "nsIPresContext.h"
|
|
#include "nsIComponentManager.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsIEventQueueService.h"
|
|
#include "nsCRT.h"
|
|
#include "nsVoidArray.h"
|
|
#include "nsString.h"
|
|
#include "nsWidgetsCID.h"
|
|
#include "nsGfxCIID.h"
|
|
#include "plevent.h"
|
|
#include "prprf.h"
|
|
#include "nsIPluginHost.h"
|
|
#include "nsplugin.h"
|
|
//#include "nsPluginsCID.h"
|
|
#include "nsIPluginManager.h"
|
|
#include "nsIPref.h"
|
|
#include "nsITimer.h"
|
|
#include "nsITimerCallback.h"
|
|
#include "nsIContent.h"
|
|
#include "prlog.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsIWebShellServices.h"
|
|
#include "nsIGlobalHistory.h"
|
|
#include "prmem.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsDOMError.h"
|
|
#include "nsIDOMHTMLElement.h"
|
|
#include "nsIDOMHTMLDocument.h"
|
|
#include "nsLayoutCID.h"
|
|
#include "nsIDOMRange.h"
|
|
#include "nsIURIContentListener.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsTimer.h"
|
|
#include "nsIBaseWindow.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsIDocShellTreeItem.h"
|
|
#include "nsIDocShellTreeNode.h"
|
|
#include "nsIDocShellTreeOwner.h"
|
|
#include "nsCURILoader.h"
|
|
#include "nsIDOMWindow.h"
|
|
#include "nsEscape.h"
|
|
#include "nsIPlatformCharset.h"
|
|
#include "nsICharsetConverterManager.h"
|
|
#include "nsISocketTransportService.h"
|
|
|
|
#include "nsIHTTPChannel.h" // add this to the ick include list...we need it to QI for post data interface
|
|
#include "nsHTTPEnums.h"
|
|
|
|
|
|
#include "nsILocaleService.h"
|
|
#include "nsIStringBundle.h"
|
|
static NS_DEFINE_CID(kLocaleServiceCID, NS_LOCALESERVICE_CID);
|
|
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
|
static NS_DEFINE_CID(kCStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
|
|
static NS_DEFINE_CID(kPlatformCharsetCID, NS_PLATFORMCHARSET_CID);
|
|
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
|
|
|
|
|
|
#include "nsIIOService.h"
|
|
#include "nsIURL.h"
|
|
#include "nsIProtocolHandler.h"
|
|
|
|
//XXX for nsIPostData; this is wrong; we shouldn't see the nsIDocument type
|
|
#include "nsIDocument.h"
|
|
|
|
#ifdef DEBUG
|
|
#undef NOISY_LINKS
|
|
#undef NOISY_WEBSHELL_LEAKS
|
|
#else
|
|
#undef NOISY_LINKS
|
|
#undef NOISY_WEBSHELL_LEAKS
|
|
#endif
|
|
|
|
#define NOISY_WEBSHELL_LEAKS
|
|
#ifdef NOISY_WEBSHELL_LEAKS
|
|
#undef DETECT_WEBSHELL_LEAKS
|
|
#define DETECT_WEBSHELL_LEAKS
|
|
#endif
|
|
|
|
#ifdef NS_DEBUG
|
|
/**
|
|
* Note: the log module is created during initialization which
|
|
* means that you cannot perform logging before then.
|
|
*/
|
|
static PRLogModuleInfo* gLogModule = PR_NewLogModule("webshell");
|
|
#endif
|
|
|
|
#define WEB_TRACE_CALLS 0x1
|
|
#define WEB_TRACE_HISTORY 0x2
|
|
|
|
#define WEB_LOG_TEST(_lm,_bit) (PRIntn((_lm)->level) & (_bit))
|
|
|
|
#ifdef NS_DEBUG
|
|
#define WEB_TRACE(_bit,_args) \
|
|
PR_BEGIN_MACRO \
|
|
if (WEB_LOG_TEST(gLogModule,_bit)) { \
|
|
PR_LogPrint _args; \
|
|
} \
|
|
PR_END_MACRO
|
|
#else
|
|
#define WEB_TRACE(_bit,_args)
|
|
#endif
|
|
|
|
|
|
#if OLD_EVENT_QUEUE
|
|
/* The following is not used for the GTK version of the browser.
|
|
* It is still lurking around for Motif
|
|
*/
|
|
PLEventQueue* gWebShell_UnixEventQueue;
|
|
|
|
void nsWebShell_SetUnixEventQueue(PLEventQueue* aEventQueue)
|
|
{
|
|
gWebShell_UnixEventQueue = aEventQueue;
|
|
}
|
|
#endif /* OLD_EVENT_QUEUE */
|
|
|
|
|
|
static NS_DEFINE_CID(kGlobalHistoryCID, NS_GLOBALHISTORY_CID);
|
|
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
typedef enum {
|
|
eCharsetReloadInit,
|
|
eCharsetReloadRequested,
|
|
eCharsetReloadStopOrigional
|
|
} eCharsetReloadState;
|
|
|
|
class nsWebShell : public nsDocShell,
|
|
public nsIWebShell,
|
|
public nsIWebShellContainer,
|
|
public nsIWebShellServices,
|
|
public nsILinkHandler,
|
|
public nsIDocumentLoaderObserver,
|
|
public nsIProgressEventSink, // should go away (nsIDocLoaderObs)
|
|
public nsIRefreshURI,
|
|
public nsIURIContentListener,
|
|
public nsIClipboardCommands
|
|
{
|
|
public:
|
|
nsWebShell();
|
|
virtual ~nsWebShell();
|
|
|
|
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
|
|
|
|
// nsISupports
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
|
|
NS_DECL_NSIURICONTENTLISTENER
|
|
|
|
// nsIInterfaceRequestor
|
|
NS_DECL_NSIINTERFACEREQUESTOR
|
|
|
|
NS_DECL_NSIDOCUMENTLOADEROBSERVER
|
|
|
|
NS_IMETHOD SetupNewViewer(nsIContentViewer* aViewer);
|
|
|
|
// nsIContentViewerContainer
|
|
NS_IMETHOD Embed(nsIContentViewer* aDocViewer,
|
|
const char* aCommand,
|
|
nsISupports* aExtraInfo);
|
|
|
|
// nsIWebShell
|
|
NS_IMETHOD SetContainer(nsIWebShellContainer* aContainer);
|
|
NS_IMETHOD GetContainer(nsIWebShellContainer*& aResult);
|
|
NS_IMETHOD GetTopLevelWindow(nsIWebShellContainer** aWebShellWindow);
|
|
NS_IMETHOD GetRootWebShell(nsIWebShell*& aResult);
|
|
NS_IMETHOD SetParent(nsIWebShell* aParent);
|
|
NS_IMETHOD GetParent(nsIWebShell*& aParent);
|
|
NS_IMETHOD GetReferrer(nsIURI **aReferrer);
|
|
|
|
// Document load api's
|
|
NS_IMETHOD GetDocumentLoader(nsIDocumentLoader*& aResult);
|
|
NS_IMETHOD LoadURL(const PRUnichar *aURLSpec,
|
|
nsIInputStream* aPostDataStream=nsnull,
|
|
PRBool aModifyHistory=PR_TRUE,
|
|
nsLoadFlags aType = nsIChannel::LOAD_NORMAL,
|
|
const PRUint32 localIP = 0,
|
|
nsISupports * aHistoryState = nsnull,
|
|
const PRUnichar* aReferrer=nsnull);
|
|
NS_IMETHOD LoadURL(const PRUnichar *aURLSpec,
|
|
const char* aCommand,
|
|
nsIInputStream* aPostDataStream=nsnull,
|
|
PRBool aModifyHistory=PR_TRUE,
|
|
nsLoadFlags aType = nsIChannel::LOAD_NORMAL,
|
|
const PRUint32 localIP = 0,
|
|
nsISupports * aHistoryState=nsnull,
|
|
const PRUnichar* aReferrer=nsnull,
|
|
const char * aWindowTarget = nsnull);
|
|
|
|
NS_IMETHOD LoadURI(nsIURI * aUri,
|
|
const char * aCommand,
|
|
nsIInputStream* aPostDataStream=nsnull,
|
|
PRBool aModifyHistory=PR_TRUE,
|
|
nsLoadFlags aType = nsIChannel::LOAD_NORMAL,
|
|
const PRUint32 aLocalIP=0,
|
|
nsISupports * aHistoryState=nsnull,
|
|
const PRUnichar* aReferrer=nsnull,
|
|
const char * aWindowTarget = nsnull);
|
|
|
|
NS_IMETHOD GetCanGoBack(PRBool* aCanGoBack);
|
|
NS_IMETHOD GetCanGoForward(PRBool* aCanGoForward);
|
|
NS_IMETHOD GoBack();
|
|
NS_IMETHOD GoForward();
|
|
NS_IMETHOD LoadURI(const PRUnichar* aURI);
|
|
NS_IMETHOD InternalLoad(nsIURI* aURI, nsIURI* aReferrer,
|
|
nsIInputStream* aPostData, loadType aLoadType);
|
|
|
|
NS_IMETHOD Stop(void);
|
|
|
|
void SetReferrer(const PRUnichar* aReferrer);
|
|
|
|
// History api's
|
|
NS_IMETHOD GoTo(PRInt32 aHistoryIndex);
|
|
NS_IMETHOD GetHistoryLength(PRInt32& aResult);
|
|
NS_IMETHOD GetHistoryIndex(PRInt32& aResult);
|
|
NS_IMETHOD GetURL(PRInt32 aHistoryIndex, const PRUnichar** aURLResult);
|
|
|
|
// nsIWebShellContainer
|
|
NS_IMETHOD WillLoadURL(nsIWebShell* aShell, const PRUnichar* aURL, nsLoadType aReason);
|
|
NS_IMETHOD BeginLoadURL(nsIWebShell* aShell, const PRUnichar* aURL);
|
|
NS_IMETHOD ProgressLoadURL(nsIWebShell* aShell, const PRUnichar* aURL, PRInt32 aProgress, PRInt32 aProgressMax);
|
|
NS_IMETHOD EndLoadURL(nsIWebShell* aShell, const PRUnichar* aURL, nsresult aStatus);
|
|
NS_IMETHOD CaptureHistoryState(nsISupports** aLayoutHistoryState);
|
|
NS_IMETHOD GetHistoryState(nsISupports** aLayoutHistoryState);
|
|
NS_IMETHOD SetHistoryState(nsISupports* aLayoutHistoryState);
|
|
NS_IMETHOD FireUnloadEvent(void);
|
|
|
|
// nsIWebShellServices
|
|
NS_IMETHOD LoadDocument(const char* aURL,
|
|
const char* aCharset= nsnull ,
|
|
nsCharsetSource aSource = kCharsetUninitialized);
|
|
NS_IMETHOD ReloadDocument(const char* aCharset= nsnull ,
|
|
nsCharsetSource aSource = kCharsetUninitialized,
|
|
const char* aCmd=nsnull);
|
|
NS_IMETHOD StopDocumentLoad(void);
|
|
NS_IMETHOD SetRendering(PRBool aRender);
|
|
|
|
// nsILinkHandler
|
|
NS_IMETHOD OnLinkClick(nsIContent* aContent,
|
|
nsLinkVerb aVerb,
|
|
const PRUnichar* aURLSpec,
|
|
const PRUnichar* aTargetSpec,
|
|
nsIInputStream* aPostDataStream = 0);
|
|
NS_IMETHOD OnOverLink(nsIContent* aContent,
|
|
const PRUnichar* aURLSpec,
|
|
const PRUnichar* aTargetSpec);
|
|
NS_IMETHOD GetLinkState(const PRUnichar* aURLSpec, nsLinkState& aState);
|
|
|
|
NS_IMETHOD RefreshURL(const char* aURL, PRInt32 millis, PRBool repeat);
|
|
|
|
// nsIRefreshURL interface methods...
|
|
NS_IMETHOD RefreshURI(nsIURI* aURI, PRInt32 aMillis, PRBool aRepeat);
|
|
NS_IMETHOD CancelRefreshURITimers(void);
|
|
|
|
// nsIProgressEventSink
|
|
NS_DECL_NSIPROGRESSEVENTSINK
|
|
|
|
// nsIClipboardCommands
|
|
NS_IMETHOD CanCutSelection (PRBool* aResult);
|
|
NS_IMETHOD CanCopySelection (PRBool* aResult);
|
|
NS_IMETHOD CanPasteSelection(PRBool* aResult);
|
|
|
|
NS_IMETHOD CutSelection (void);
|
|
NS_IMETHOD CopySelection (void);
|
|
NS_IMETHOD PasteSelection(void);
|
|
|
|
NS_IMETHOD SelectAll(void);
|
|
NS_IMETHOD SelectNone(void);
|
|
|
|
NS_IMETHOD FindNext(const PRUnichar * aSearchStr, PRBool aMatchCase, PRBool aSearchDown, PRBool &aIsFound);
|
|
|
|
// nsIBaseWindow
|
|
NS_IMETHOD Create();
|
|
NS_IMETHOD Destroy();
|
|
NS_IMETHOD SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy,
|
|
PRBool fRepaint);
|
|
NS_IMETHOD GetPositionAndSize(PRInt32* x, PRInt32* y, PRInt32* cx,
|
|
PRInt32* cy);
|
|
|
|
// nsIDocShell
|
|
NS_IMETHOD SetDocument(nsIDOMDocument *aDOMDoc, nsIDOMElement *aRootNode);
|
|
|
|
// nsWebShell
|
|
nsIEventQueue* GetEventQueue(void);
|
|
void HandleLinkClickEvent(nsIContent *aContent,
|
|
nsLinkVerb aVerb,
|
|
const PRUnichar* aURLSpec,
|
|
const PRUnichar* aTargetSpec,
|
|
nsIInputStream* aPostDataStream = 0);
|
|
|
|
void ShowHistory();
|
|
|
|
static void RefreshURLCallback(nsITimer* aTimer, void* aClosure);
|
|
|
|
static nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent);
|
|
|
|
nsresult CreatePluginHost(PRBool aAllowPlugins);
|
|
nsresult DestroyPluginHost(void);
|
|
|
|
NS_IMETHOD SetSessionHistory(nsISessionHistory * aSHist);
|
|
NS_IMETHOD GetSessionHistory(nsISessionHistory *& aResult);
|
|
NS_IMETHOD SetIsInSHist(PRBool aIsFrame);
|
|
NS_IMETHOD GetIsInSHist(PRBool& aIsFrame);
|
|
NS_IMETHOD SetURL(const PRUnichar* aURL);
|
|
|
|
protected:
|
|
void GetRootWebShellEvenIfChrome(nsIWebShell** aResult);
|
|
void InitFrameData();
|
|
nsresult CheckForTrailingSlash(nsIURI* aURL);
|
|
nsresult InitDialogVars(void);
|
|
|
|
nsIEventQueue* mThreadEventQueue;
|
|
|
|
nsIWebShellContainer* mContainer;
|
|
nsIDocumentLoader* mDocLoader;
|
|
|
|
nsCOMPtr<nsIPrompt> mPrompter;
|
|
nsCOMPtr<nsIStringBundle> mStringBundle;
|
|
|
|
nsString mDefaultCharacterSet;
|
|
|
|
|
|
nsVoidArray mHistory;
|
|
PRInt32 mHistoryIndex;
|
|
|
|
PRBool mFiredUnloadEvent;
|
|
|
|
nsIGlobalHistory* mHistoryService;
|
|
nsISessionHistory * mSHist;
|
|
|
|
nsRect mBounds;
|
|
nsString mOverURL;
|
|
nsString mOverTarget;
|
|
|
|
PRPackedBool mIsInSHist;
|
|
PRPackedBool mFailedToLoadHistoryService;
|
|
|
|
nsScrollPreference mScrollPref;
|
|
|
|
nsVoidArray mRefreshments;
|
|
|
|
eCharsetReloadState mCharsetReloadState;
|
|
|
|
nsISupports* mHistoryState; // Weak reference. Session history owns this.
|
|
|
|
nsresult FireUnloadForChildren();
|
|
nsresult DoLoadURL(nsIURI * aUri,
|
|
const char* aCommand,
|
|
nsIInputStream* aPostDataStream,
|
|
nsLoadFlags aType,
|
|
const PRUint32 aLocalIP,
|
|
const PRUnichar* aReferrer,
|
|
const char * aWindowTarget,
|
|
PRBool aKickOffLoad = PR_TRUE);
|
|
|
|
nsresult PrepareToLoadURI(nsIURI * aUri,
|
|
nsIInputStream * aPostStream,
|
|
PRBool aModifyHistory,
|
|
nsLoadFlags aType,
|
|
const PRUint32 aLocalIP,
|
|
nsISupports * aHistoryState,
|
|
const PRUnichar * aReferrer);
|
|
|
|
nsresult CreateViewer(nsIChannel* aChannel,
|
|
const char* aContentType,
|
|
const char* aCommand,
|
|
nsIStreamListener** aResult);
|
|
static nsIPluginHost *mPluginHost;
|
|
static nsIPluginManager *mPluginManager;
|
|
static PRUint32 mPluginInitCnt;
|
|
PRBool mProcessedEndDocumentLoad;
|
|
|
|
PRBool mViewSource;
|
|
|
|
MOZ_TIMER_DECLARE(mTotalTime)
|
|
|
|
#ifdef DETECT_WEBSHELL_LEAKS
|
|
private:
|
|
// We're counting the number of |nsWebShells| to help find leaks
|
|
static unsigned long gNumberOfWebShells;
|
|
|
|
public:
|
|
static unsigned long TotalWebShellsInExistence() { return gNumberOfWebShells; }
|
|
#endif
|
|
};
|
|
|
|
#ifdef DETECT_WEBSHELL_LEAKS
|
|
unsigned long nsWebShell::gNumberOfWebShells = 0;
|
|
|
|
extern "C" NS_WEB
|
|
unsigned long
|
|
NS_TotalWebShellsInExistence()
|
|
{
|
|
return nsWebShell::TotalWebShellsInExistence();
|
|
}
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Class IID's
|
|
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
|
static NS_DEFINE_IID(kChildCID, NS_CHILD_CID);
|
|
static NS_DEFINE_IID(kDocLoaderServiceCID, NS_DOCUMENTLOADER_SERVICE_CID);
|
|
static NS_DEFINE_IID(kWebShellCID, NS_WEB_SHELL_CID);
|
|
|
|
// IID's
|
|
static NS_DEFINE_IID(kIContentViewerContainerIID,
|
|
NS_ICONTENT_VIEWER_CONTAINER_IID);
|
|
static NS_DEFINE_IID(kIProgressEventSinkIID, NS_IPROGRESSEVENTSINK_IID);
|
|
static NS_DEFINE_IID(kIDocumentLoaderIID, NS_IDOCUMENTLOADER_IID);
|
|
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
|
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
|
static NS_DEFINE_IID(kRefreshURIIID, NS_IREFRESHURI_IID);
|
|
|
|
static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID);
|
|
static NS_DEFINE_IID(kIPluginManagerIID, NS_IPLUGINMANAGER_IID);
|
|
static NS_DEFINE_IID(kIPluginHostIID, NS_IPLUGINHOST_IID);
|
|
static NS_DEFINE_IID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
|
|
static NS_DEFINE_IID(kIDocumentViewerIID, NS_IDOCUMENT_VIEWER_IID);
|
|
static NS_DEFINE_IID(kITimerCallbackIID, NS_ITIMERCALLBACK_IID);
|
|
static NS_DEFINE_IID(kIWebShellContainerIID, NS_IWEB_SHELL_CONTAINER_IID);
|
|
static NS_DEFINE_IID(kIClipboardCommandsIID, NS_ICLIPBOARDCOMMANDS_IID);
|
|
static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID);
|
|
static NS_DEFINE_IID(kISessionHistoryIID, NS_ISESSIONHISTORY_IID);
|
|
static NS_DEFINE_IID(kIDOMHTMLDocumentIID, NS_IDOMHTMLDOCUMENT_IID);
|
|
static NS_DEFINE_CID(kCDOMRangeCID, NS_RANGE_CID);
|
|
// XXX not sure
|
|
static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID);
|
|
|
|
nsIPluginHost *nsWebShell::mPluginHost = nsnull;
|
|
nsIPluginManager *nsWebShell::mPluginManager = nsnull;
|
|
PRUint32 nsWebShell::mPluginInitCnt = 0;
|
|
|
|
nsresult nsWebShell::CreatePluginHost(PRBool aAllowPlugins)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if ((PR_TRUE == aAllowPlugins) && (0 == mPluginInitCnt))
|
|
{
|
|
if (nsnull == mPluginManager)
|
|
{
|
|
// use the service manager to obtain the plugin manager.
|
|
rv = nsServiceManager::GetService(kCPluginManagerCID, kIPluginManagerIID,
|
|
(nsISupports**)&mPluginManager);
|
|
if (NS_OK == rv)
|
|
{
|
|
if (NS_OK == mPluginManager->QueryInterface(kIPluginHostIID,
|
|
(void **)&mPluginHost))
|
|
{
|
|
mPluginHost->Init();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mPluginInitCnt++;
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult nsWebShell::DestroyPluginHost(void)
|
|
{
|
|
mPluginInitCnt--;
|
|
|
|
NS_ASSERTION(!(mPluginInitCnt < 0), "underflow in plugin host destruction");
|
|
|
|
if (0 == mPluginInitCnt)
|
|
{
|
|
if (nsnull != mPluginHost) {
|
|
mPluginHost->Destroy();
|
|
mPluginHost->Release();
|
|
mPluginHost = NULL;
|
|
}
|
|
|
|
// use the service manager to release the plugin manager.
|
|
if (nsnull != mPluginManager) {
|
|
nsServiceManager::ReleaseService(kCPluginManagerCID, mPluginManager);
|
|
mPluginManager = NULL;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Note: operator new zeros our memory
|
|
nsWebShell::nsWebShell() : nsDocShell()
|
|
{
|
|
#ifdef DETECT_WEBSHELL_LEAKS
|
|
// We're counting the number of |nsWebShells| to help find leaks
|
|
++gNumberOfWebShells;
|
|
#endif
|
|
#ifdef NOISY_WEBSHELL_LEAKS
|
|
printf("WEBSHELL+ = %ld\n", gNumberOfWebShells);
|
|
#endif
|
|
|
|
NS_INIT_REFCNT();
|
|
mHistoryIndex = -1;
|
|
mScrollPref = nsScrollPreference_kAuto;
|
|
mThreadEventQueue = nsnull;
|
|
InitFrameData();
|
|
mItemType = typeContent;
|
|
mSHist = nsnull;
|
|
mIsInSHist = PR_FALSE;
|
|
mFailedToLoadHistoryService = PR_FALSE;
|
|
mDefaultCharacterSet = "";
|
|
mProcessedEndDocumentLoad = PR_FALSE;
|
|
mCharsetReloadState = eCharsetReloadInit;
|
|
mViewSource=PR_FALSE;
|
|
mHistoryService = nsnull;
|
|
mHistoryState = nsnull;
|
|
mFiredUnloadEvent = PR_FALSE;
|
|
mBounds.SetRect(0, 0, 0, 0);
|
|
}
|
|
|
|
nsWebShell::~nsWebShell()
|
|
{
|
|
if (nsnull != mHistoryService) {
|
|
nsServiceManager::ReleaseService(kGlobalHistoryCID, mHistoryService);
|
|
mHistoryService = nsnull;
|
|
}
|
|
|
|
// Stop any pending document loads and destroy the loader...
|
|
if (nsnull != mDocLoader) {
|
|
mDocLoader->Stop();
|
|
mDocLoader->RemoveObserver((nsIDocumentLoaderObserver*)this);
|
|
mDocLoader->SetContainer(nsnull);
|
|
NS_RELEASE(mDocLoader);
|
|
}
|
|
// Cancel any timers that were set for this loader.
|
|
CancelRefreshURITimers();
|
|
|
|
++mRefCnt; // following releases can cause this destructor to be called
|
|
// recursively if the refcount is allowed to remain 0
|
|
|
|
NS_IF_RELEASE(mSHist);
|
|
NS_IF_RELEASE(mThreadEventQueue);
|
|
mContentViewer=nsnull;
|
|
mDeviceContext=nsnull;
|
|
NS_IF_RELEASE(mContainer);
|
|
|
|
if (mScriptGlobal) {
|
|
mScriptGlobal->SetDocShell(nsnull);
|
|
mScriptGlobal = nsnull;
|
|
}
|
|
if (mScriptContext) {
|
|
mScriptContext->SetOwner(nsnull);
|
|
mScriptContext = nsnull;
|
|
}
|
|
|
|
InitFrameData();
|
|
|
|
// Free up history memory
|
|
PRInt32 i, n = mHistory.Count();
|
|
for (i = 0; i < n; i++) {
|
|
nsString* s = (nsString*) mHistory.ElementAt(i);
|
|
delete s;
|
|
}
|
|
|
|
|
|
DestroyPluginHost();
|
|
|
|
#ifdef DETECT_WEBSHELL_LEAKS
|
|
// We're counting the number of |nsWebShells| to help find leaks
|
|
--gNumberOfWebShells;
|
|
#endif
|
|
#ifdef NOISY_WEBSHELL_LEAKS
|
|
printf("WEBSHELL- = %ld\n", gNumberOfWebShells);
|
|
#endif
|
|
}
|
|
|
|
void nsWebShell::InitFrameData()
|
|
{
|
|
SetMarginWidth(-1);
|
|
SetMarginHeight(-1);
|
|
}
|
|
|
|
nsresult
|
|
nsWebShell::FireUnloadForChildren()
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
PRInt32 i, n = mChildren.Count();
|
|
for (i = 0; i < n; i++) {
|
|
nsIDocShell* shell = (nsIDocShell*) mChildren.ElementAt(i);
|
|
nsCOMPtr<nsIWebShell> webShell(do_QueryInterface(shell));
|
|
rv = webShell->FireUnloadEvent();
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::FireUnloadEvent()
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mScriptGlobal) {
|
|
nsIDocumentViewer* docViewer;
|
|
if (mContentViewer && NS_SUCCEEDED(mContentViewer->QueryInterface(kIDocumentViewerIID, (void**)&docViewer))) {
|
|
nsIPresContext *presContext;
|
|
if (NS_SUCCEEDED(docViewer->GetPresContext(presContext))) {
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsMouseEvent event;
|
|
event.eventStructType = NS_EVENT;
|
|
event.message = NS_PAGE_UNLOAD;
|
|
rv = mScriptGlobal->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
|
|
NS_RELEASE(presContext);
|
|
}
|
|
NS_RELEASE(docViewer);
|
|
}
|
|
}
|
|
|
|
//Fire child unloads now while our data is intact.
|
|
rv = FireUnloadForChildren();
|
|
|
|
mFiredUnloadEvent = PR_TRUE;
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsWebShell, nsDocShell)
|
|
NS_IMPL_RELEASE_INHERITED(nsWebShell, nsDocShell)
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsWebShell)
|
|
#if 0 // inherits from nsDocShell:
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebShell)
|
|
#endif
|
|
NS_INTERFACE_MAP_ENTRY(nsIWebShell)
|
|
NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIContentViewerContainer, nsIWebShell)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDocumentLoaderObserver)
|
|
NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
|
|
NS_INTERFACE_MAP_ENTRY(nsIWebShellContainer)
|
|
NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
|
|
NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
|
|
NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
|
|
NS_INTERFACE_MAP_ENTRY(nsIURIContentListener)
|
|
#if 0 // inherits from nsDocShell:
|
|
NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
|
|
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
|
NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDocShell)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode)
|
|
NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
|
|
NS_INTERFACE_MAP_ENTRY(nsIScrollable)
|
|
#endif
|
|
NS_INTERFACE_MAP_END_INHERITING(nsDocShell)
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetInterface(const nsIID &aIID, void** aInstancePtr)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aInstancePtr);
|
|
nsresult rv = NS_OK;
|
|
*aInstancePtr = nsnull;
|
|
|
|
if(aIID.Equals(NS_GET_IID(nsILinkHandler)))
|
|
{
|
|
*aInstancePtr = NS_STATIC_CAST(nsILinkHandler*, this);
|
|
NS_ADDREF((nsISupports*)*aInstancePtr);
|
|
return NS_OK;
|
|
}
|
|
else if(aIID.Equals(NS_GET_IID(nsIScriptGlobalObjectOwner)))
|
|
{
|
|
*aInstancePtr = NS_STATIC_CAST(nsIScriptGlobalObjectOwner*, this);
|
|
NS_ADDREF((nsISupports*)*aInstancePtr);
|
|
return NS_OK;
|
|
}
|
|
else if (aIID.Equals(NS_GET_IID(nsIURIContentListener)))
|
|
{
|
|
*aInstancePtr = NS_STATIC_CAST(nsIURIContentListener*, this);
|
|
NS_ADDREF((nsISupports*)*aInstancePtr);
|
|
return NS_OK;
|
|
}
|
|
else if(aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)))
|
|
{
|
|
NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), NS_ERROR_FAILURE);
|
|
*aInstancePtr = mScriptGlobal;
|
|
NS_ADDREF((nsISupports*)*aInstancePtr);
|
|
return NS_OK;
|
|
}
|
|
else if(aIID.Equals(NS_GET_IID(nsIDOMWindow)))
|
|
{
|
|
NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), NS_ERROR_FAILURE);
|
|
NS_ENSURE_SUCCESS(mScriptGlobal->QueryInterface(NS_GET_IID(nsIDOMWindow),
|
|
aInstancePtr), NS_ERROR_FAILURE);
|
|
return NS_OK;
|
|
}
|
|
else if(mPluginManager) //XXX this seems a little wrong. MMP
|
|
rv = mPluginManager->QueryInterface(aIID, aInstancePtr);
|
|
|
|
if (!*aInstancePtr || NS_FAILED(rv))
|
|
return nsDocShell::GetInterface(aIID,aInstancePtr);
|
|
else
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetupNewViewer(nsIContentViewer* aViewer)
|
|
{
|
|
NS_ENSURE_SUCCESS(nsDocShell::SetupNewViewer(aViewer), NS_ERROR_FAILURE);
|
|
// If the history state has been set by session history,
|
|
// set it on the pres shell now that we have a content
|
|
// viewer.
|
|
if(mContentViewer && mHistoryState)
|
|
{
|
|
nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(mContentViewer));
|
|
if(docv)
|
|
{
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
docv->GetPresShell(*getter_AddRefs(shell));
|
|
if(shell)
|
|
shell->SetHistoryState((nsILayoutHistoryState*)mHistoryState);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::Embed(nsIContentViewer* aContentViewer,
|
|
const char* aCommand,
|
|
nsISupports* aExtraInfo)
|
|
{
|
|
return SetupNewViewer(aContentViewer);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetContainer(nsIWebShellContainer* aContainer)
|
|
{
|
|
NS_IF_RELEASE(mContainer);
|
|
mContainer = aContainer;
|
|
NS_IF_ADDREF(mContainer);
|
|
|
|
// uri dispatching change.....if you set a container for a webshell
|
|
// and that container is a content listener itself....then use
|
|
// it as our parent container.
|
|
nsresult rv = NS_OK;
|
|
nsCOMPtr<nsIURIContentListener> contentListener = do_QueryInterface(mContainer, &rv);
|
|
if (NS_SUCCEEDED(rv) && contentListener)
|
|
SetParentContentListener(contentListener);
|
|
|
|
// if the container is getting set to null, then our parent must be going away
|
|
// so clear out our knowledge of the content listener represented by the container
|
|
if (!aContainer)
|
|
SetParentContentListener(nsnull);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetContainer(nsIWebShellContainer*& aResult)
|
|
{
|
|
aResult = mContainer;
|
|
NS_IF_ADDREF(mContainer);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetTopLevelWindow(nsIWebShellContainer** aTopLevelWindow)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aTopLevelWindow);
|
|
*aTopLevelWindow = nsnull;
|
|
|
|
nsCOMPtr<nsIWebShell> rootWebShell;
|
|
|
|
GetRootWebShellEvenIfChrome(getter_AddRefs(rootWebShell));
|
|
if(!rootWebShell)
|
|
return NS_OK;
|
|
|
|
nsCOMPtr<nsIWebShellContainer> rootContainer;
|
|
rootWebShell->GetContainer(*aTopLevelWindow);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetSessionHistory(nsISessionHistory* aSHist)
|
|
{
|
|
NS_IF_RELEASE(mSHist);
|
|
mSHist = aSHist;
|
|
NS_IF_ADDREF(aSHist);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetSessionHistory(nsISessionHistory *& aResult)
|
|
{
|
|
aResult = mSHist;
|
|
NS_IF_ADDREF(mSHist);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsEventStatus PR_CALLBACK
|
|
nsWebShell::HandleEvent(nsGUIEvent *aEvent)
|
|
{
|
|
return nsEventStatus_eIgnore;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetRootWebShell(nsIWebShell*& aResult)
|
|
{
|
|
nsCOMPtr<nsIDocShellTreeItem> top;
|
|
GetSameTypeRootTreeItem(getter_AddRefs(top));
|
|
nsCOMPtr<nsIWebShell> topAsWebShell(do_QueryInterface(top));
|
|
aResult = topAsWebShell;
|
|
NS_IF_ADDREF(aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsWebShell::GetRootWebShellEvenIfChrome(nsIWebShell** aResult)
|
|
{
|
|
nsCOMPtr<nsIDocShellTreeItem> top;
|
|
GetRootTreeItem(getter_AddRefs(top));
|
|
nsCOMPtr<nsIWebShell> topAsWebShell(do_QueryInterface(top));
|
|
*aResult = topAsWebShell;
|
|
NS_IF_ADDREF(*aResult);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetParent(nsIWebShell* aParent)
|
|
{
|
|
nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem(do_QueryInterface(aParent));
|
|
|
|
mParent = parentAsTreeItem.get();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetParent(nsIWebShell*& aParent)
|
|
{
|
|
nsCOMPtr<nsIDocShellTreeItem> parent;
|
|
NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
|
|
|
|
if(parent)
|
|
parent->QueryInterface(NS_GET_IID(nsIWebShell), (void**)&aParent);
|
|
else
|
|
aParent = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetReferrer(nsIURI **aReferrer)
|
|
{
|
|
*aReferrer = mReferrerURI;
|
|
NS_IF_ADDREF(*aReferrer);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsWebShell::SetReferrer(const PRUnichar* aReferrer)
|
|
{
|
|
NS_NewURI(getter_AddRefs(mReferrerURI), aReferrer, nsnull);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetURL(const PRUnichar* aURL)
|
|
{
|
|
nsCOMPtr<nsIURI> uri;
|
|
NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(uri), aURL, nsnull),
|
|
NS_ERROR_FAILURE);
|
|
SetCurrentURI(uri);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetIsInSHist(PRBool& aResult)
|
|
{
|
|
aResult = mIsInSHist;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetIsInSHist(PRBool aIsInSHist)
|
|
{
|
|
mIsInSHist = aIsInSHist;
|
|
return NS_OK;
|
|
}
|
|
|
|
/**
|
|
* Document Load methods
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetDocumentLoader(nsIDocumentLoader*& aResult)
|
|
{
|
|
aResult = mDocLoader;
|
|
NS_IF_ADDREF(mDocLoader);
|
|
return (nsnull != mDocLoader) ? NS_OK : NS_ERROR_FAILURE;
|
|
}
|
|
|
|
#define FILE_PROTOCOL "file://"
|
|
|
|
static void convertFileToURL(const nsString &aIn, nsString &aOut)
|
|
{
|
|
aOut = aIn;
|
|
#ifdef XP_PC
|
|
// Check for \ in the url-string (PC)
|
|
if(kNotFound != aIn.FindChar(PRUnichar('\\'))) {
|
|
#else
|
|
#if XP_UNIX
|
|
// Check if it starts with / or \ (UNIX)
|
|
const PRUnichar * up = aIn.GetUnicode();
|
|
if((PRUnichar('/') == *up) ||
|
|
(PRUnichar('\\') == *up)) {
|
|
#else
|
|
if (0) {
|
|
// Do nothing (All others for now)
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef XP_PC
|
|
// Translate '\' to '/'
|
|
aOut.ReplaceChar(PRUnichar('\\'), PRUnichar('/'));
|
|
aOut.ReplaceChar(PRUnichar(':'), PRUnichar('|'));
|
|
#endif
|
|
|
|
// Build the file URL
|
|
aOut.Insert(FILE_PROTOCOL,0);
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::LoadURL(const PRUnichar *aURLSpec,
|
|
nsIInputStream* aPostDataStream,
|
|
PRBool aModifyHistory,
|
|
nsLoadFlags aType,
|
|
const PRUint32 aLocalIP,
|
|
nsISupports * aHistoryState,
|
|
const PRUnichar* aReferrer)
|
|
{
|
|
const char *cmd = mViewSource ? "view-source" : "view" ;
|
|
|
|
return LoadURL(aURLSpec, cmd, aPostDataStream,
|
|
aModifyHistory,aType, aLocalIP, aHistoryState,
|
|
aReferrer);
|
|
}
|
|
|
|
|
|
static PRBool EqualBaseURLs(nsIURI* url1, nsIURI* url2)
|
|
{
|
|
nsXPIDLCString spec1;
|
|
nsXPIDLCString spec2;
|
|
char * anchor1 = nsnull, * anchor2=nsnull;
|
|
PRBool rv = PR_FALSE;
|
|
|
|
if (url1 && url2) {
|
|
// XXX We need to make these strcmps case insensitive.
|
|
url1->GetSpec(getter_Copies(spec1));
|
|
url2->GetSpec(getter_Copies(spec2));
|
|
|
|
/* Don't look at the ref-part */
|
|
anchor1 = PL_strrchr(spec1, '#');
|
|
anchor2 = PL_strrchr(spec2, '#');
|
|
|
|
if (anchor1)
|
|
*anchor1 = '\0';
|
|
if (anchor2)
|
|
*anchor2 = '\0';
|
|
|
|
if (0 == PL_strcmp(spec1,spec2)) {
|
|
rv = PR_TRUE;
|
|
}
|
|
} // url1 && url2
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsWebShell::DoLoadURL(nsIURI * aUri,
|
|
const char* aCommand,
|
|
nsIInputStream* aPostDataStream,
|
|
nsLoadFlags aType,
|
|
const PRUint32 aLocalIP,
|
|
const PRUnichar* aReferrer,
|
|
const char * aWindowTarget,
|
|
PRBool aKickOffLoad)
|
|
{
|
|
if (!aUri)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsXPIDLCString urlSpec;
|
|
nsresult rv = NS_OK;
|
|
rv = aUri->GetSpec(getter_Copies(urlSpec));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// If it's a normal reload that uses the cache, look at the destination anchor
|
|
// and see if it's an element within the current document
|
|
// We don't have a reload loadtype yet in necko. So, check for just history
|
|
// loadtype
|
|
if ((aType == nsISessionHistory::LOAD_HISTORY || aType == nsIChannel::LOAD_NORMAL) && (nsnull != mContentViewer) &&
|
|
(nsnull == aPostDataStream))
|
|
{
|
|
nsCOMPtr<nsIDocumentViewer> docViewer;
|
|
if (NS_SUCCEEDED(mContentViewer->QueryInterface(kIDocumentViewerIID,
|
|
getter_AddRefs(docViewer))))
|
|
{
|
|
// Get the document object
|
|
nsCOMPtr<nsIDocument> doc;
|
|
docViewer->GetDocument(*getter_AddRefs(doc));
|
|
|
|
// Get the URL for the document
|
|
nsCOMPtr<nsIURI> docURL = getter_AddRefs(doc->GetDocumentURL());
|
|
|
|
if (aUri && docURL && EqualBaseURLs(docURL, aUri))
|
|
{
|
|
// See if there's a destination anchor
|
|
nsXPIDLCString ref;
|
|
nsCOMPtr<nsIURL> aUrl = do_QueryInterface(aUri);
|
|
if (aUrl)
|
|
rv = aUrl->GetRef(getter_Copies(ref));
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
rv = docViewer->GetPresShell(*getter_AddRefs(presShell));
|
|
|
|
if (NS_SUCCEEDED(rv) && presShell)
|
|
{
|
|
/* Pass OnStartDocument notifications to the docloaderobserver
|
|
* so that urlbar, forward/back buttons will
|
|
* behave properly when going to named anchors
|
|
*/
|
|
nsIInterfaceRequestor * interfaceRequestor = NS_STATIC_CAST(nsIInterfaceRequestor *, this);
|
|
nsCOMPtr<nsIChannel> dummyChannel;
|
|
// creating a channel is expensive...don't create it unless we know we have to
|
|
// so move the creation down into each of the if clauses...
|
|
if (nsnull != (const char *) ref)
|
|
{
|
|
rv = NS_OpenURI(getter_AddRefs(dummyChannel), aUri, nsnull, interfaceRequestor);
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (!mProcessedEndDocumentLoad)
|
|
rv = OnStartDocumentLoad(mDocLoader, aUri, "load");
|
|
// Go to the anchor in the current document
|
|
rv = presShell->GoToAnchor(nsAutoString(ref));
|
|
// Set the URL & referrer if the anchor was successfully visited
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
SetCurrentURI(aUri);
|
|
SetReferrer(aReferrer);
|
|
}
|
|
// Pass on status of scrolling/anchor visit to docloaderobserver
|
|
if (!mProcessedEndDocumentLoad)
|
|
{
|
|
rv = OnEndDocumentLoad(mDocLoader, dummyChannel, rv);
|
|
}
|
|
return rv;
|
|
}
|
|
else if (aType == nsISessionHistory::LOAD_HISTORY)
|
|
{
|
|
rv = NS_OpenURI(getter_AddRefs(dummyChannel), aUri, nsnull, interfaceRequestor);
|
|
if (NS_FAILED(rv)) return rv;
|
|
rv = OnStartDocumentLoad(mDocLoader, aUri, "load");
|
|
// Go to the top of the current document
|
|
nsCOMPtr<nsIViewManager> viewMgr;
|
|
rv = presShell->GetViewManager(getter_AddRefs(viewMgr));
|
|
if (NS_SUCCEEDED(rv) && viewMgr)
|
|
{
|
|
nsIScrollableView* view;
|
|
rv = viewMgr->GetRootScrollableView(&view);
|
|
if (NS_SUCCEEDED(rv) && view)
|
|
rv = view->ScrollTo(0, 0, NS_VMREFRESH_IMMEDIATE);
|
|
if(NS_SUCCEEDED(rv))
|
|
{
|
|
SetCurrentURI(aUri);
|
|
SetReferrer(aReferrer);
|
|
}
|
|
mProcessedEndDocumentLoad = PR_FALSE;
|
|
// Pass on status of scrolling/anchor visit to docloaderobserver
|
|
rv = OnEndDocumentLoad(mDocLoader, dummyChannel, rv);
|
|
return rv;
|
|
}
|
|
}
|
|
#if 0
|
|
mProcessedEndDocumentLoad = PR_FALSE;
|
|
// Pass on status of scrolling/anchor visit to docloaderobserver
|
|
rv = OnEndDocumentLoad(mDocLoader, dummyChannel, rv);
|
|
return rv;
|
|
#endif /* 0 */
|
|
} // NS_SUCCEEDED(rv) && presShell
|
|
} // EqualBaseURLs(docURL, url)
|
|
}
|
|
}
|
|
|
|
// Stop loading the current document (if any...). This call may result in
|
|
// firing an EndLoadURL notification for the old document...
|
|
if (aKickOffLoad)
|
|
StopLoad();
|
|
|
|
|
|
// Tell web-shell-container we are loading a new url
|
|
if (nsnull != mContainer) {
|
|
nsAutoString uniSpec (urlSpec);
|
|
rv = mContainer->BeginLoadURL(this, uniSpec.GetUnicode());
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
mProcessedEndDocumentLoad = PR_FALSE;
|
|
|
|
/* WebShell was primarily passing the buck when it came to streamObserver.
|
|
* So, pass on the observer which is already a streamObserver to DocLoder.
|
|
*/
|
|
if (aKickOffLoad) {
|
|
|
|
#ifdef MOZ_PERF_METRICS
|
|
{
|
|
char* url;
|
|
nsresult rv = NS_OK;
|
|
rv = aUri->GetSpec(&url);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
MOZ_TIMER_LOG(("*** Timing layout processes on url: '%s', webshell: %p\n", url, this));
|
|
delete [] url;
|
|
}
|
|
}
|
|
|
|
MOZ_TIMER_DEBUGLOG(("Reset and start: nsWebShell::DoLoadURL(), this=%p\n", this));
|
|
MOZ_TIMER_RESET(mTotalTime);
|
|
MOZ_TIMER_START(mTotalTime);
|
|
#endif
|
|
|
|
nsCOMPtr<nsIURILoader> pURILoader = do_GetService(NS_URI_LOADER_PROGID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsXPIDLCString aUrlScheme;
|
|
aUri->GetScheme(getter_Copies(aUrlScheme));
|
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
|
pURILoader->GetLoadGroupForContext(NS_STATIC_CAST(nsISupports *, (nsIWebShell *) this), getter_AddRefs(loadGroup));
|
|
|
|
// first, create a channel for the protocol....
|
|
nsCOMPtr<nsIIOService> pNetService = do_GetService(kIOServiceCID, &rv);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
nsCOMPtr<nsIChannel> pChannel;
|
|
nsCOMPtr<nsIInterfaceRequestor> requestor (do_QueryInterface(NS_STATIC_CAST(nsIContentViewerContainer*, (nsIWebShell*)this)));
|
|
|
|
// Create a referrer URI
|
|
nsCOMPtr<nsIURI> referrer;
|
|
if (aReferrer) {
|
|
nsAutoString tempReferrer(aReferrer);
|
|
char* referrerStr = tempReferrer.ToNewCString();
|
|
pNetService->NewURI(referrerStr, nsnull, getter_AddRefs(referrer));
|
|
Recycle(referrerStr);
|
|
}
|
|
|
|
rv = pNetService->NewChannelFromURI(aCommand, aUri, loadGroup, requestor,
|
|
aType, referrer /* referring uri */,
|
|
0, 0,
|
|
getter_AddRefs(pChannel));
|
|
if (NS_FAILED(rv)) {
|
|
if (rv == NS_ERROR_DOM_RETVAL_UNDEFINED) // if causing the channel changed the
|
|
return NS_OK; // dom and there is nothing else to do
|
|
else
|
|
return rv; // uhoh we were unable to get a channel to handle the url!!!
|
|
}
|
|
// Mark the channel as being a document URI...
|
|
nsLoadFlags loadAttribs = 0;
|
|
pChannel->GetLoadAttributes(&loadAttribs);
|
|
loadAttribs |= nsIChannel::LOAD_DOCUMENT_URI;
|
|
|
|
pChannel->SetLoadAttributes(loadAttribs);
|
|
|
|
nsCOMPtr<nsIHTTPChannel> httpChannel(do_QueryInterface(pChannel));
|
|
if (httpChannel)
|
|
{
|
|
// figure out if we need to set the post data stream on the channel...
|
|
// right now, this is only done for http channels.....
|
|
if (aPostDataStream)
|
|
{
|
|
httpChannel->SetRequestMethod(HM_POST);
|
|
httpChannel->SetPostDataStream(aPostDataStream);
|
|
}
|
|
// Set the referrer explicitly
|
|
if (referrer)
|
|
{
|
|
// Referrer is currenly only set for link clicks here.
|
|
httpChannel->SetReferrer(referrer,
|
|
nsIHTTPChannel::REFERRER_LINK_CLICK);
|
|
}
|
|
}
|
|
|
|
// now let's pass the channel into the uri loader
|
|
nsURILoadCommand loadCmd = nsIURILoader::viewNormal;
|
|
if (nsCRT::strcasecmp(aCommand, "view-link-click") == 0)
|
|
loadCmd = nsIURILoader::viewUserClick;
|
|
else if (nsCRT::strcasecmp(aCommand, "view-source") == 0)
|
|
loadCmd = nsIURILoader::viewSource;
|
|
|
|
rv = pURILoader->OpenURI(pChannel, loadCmd, aWindowTarget /* window target */,
|
|
NS_STATIC_CAST(nsIContentViewerContainer*, (nsIWebShell*)this));
|
|
}
|
|
}
|
|
|
|
// Fix for bug 1646. Change the notion of current url and referrer only after
|
|
// the document load succeeds (but only if we're not targeting another window).
|
|
if (NS_SUCCEEDED(rv) && !aWindowTarget) {
|
|
SetCurrentURI(aUri);
|
|
SetReferrer(aReferrer);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::GetCanGoBack(PRBool* aCanGoBack)
|
|
{
|
|
#ifdef DOCSHELL_LOAD
|
|
return nsDocShell::GetCanGoBack(aCanGoBack);
|
|
#else /*!DOCSHELL_LOAD*/
|
|
*aCanGoBack = (mHistoryIndex - 1) > - 1 ? PR_TRUE : PR_FALSE;
|
|
return NS_OK;
|
|
#endif /*!DOCSHELL_LOAD*/
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::GetCanGoForward(PRBool* aCanGoForward)
|
|
{
|
|
#ifdef DOCSHELL_LOAD
|
|
return nsDocShell::GetCanGoForward(aCanGoForward);
|
|
#else /*!DOCSHELL_LOAD*/
|
|
*aCanGoForward = mHistoryIndex < mHistory.Count() - 1 ? PR_TRUE : PR_FALSE;
|
|
return NS_OK;
|
|
#endif /*!DOCSHELL_LOAD*/
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::GoBack()
|
|
{
|
|
#ifdef DOCSHELL_LOAD
|
|
return nsDocShell::GoBack();
|
|
#else /*!DOCSHELL_LOAD*/
|
|
NS_ENSURE_SUCCESS(GoTo(mHistoryIndex - 1), NS_ERROR_FAILURE);
|
|
return NS_OK;
|
|
#endif /*!DOCSHELL_LOAD*/
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::GoForward()
|
|
{
|
|
#ifdef DOCSHELL_LOAD
|
|
return nsDocShell::GoForward();
|
|
#else /*!DOCSHELL_LOAD*/
|
|
NS_ENSURE_SUCCESS(GoTo(mHistoryIndex + 1), NS_ERROR_FAILURE);
|
|
return NS_OK;
|
|
#endif /*!DOCSHELL_LOAD*/
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::LoadURI(const PRUnichar* aURI)
|
|
{
|
|
#ifdef DOCSHELL_LOAD
|
|
return nsDocShell::LoadURI(aURI);
|
|
#else /*!DOCSHELL_LOAD*/
|
|
return LoadURL(aURI);
|
|
#endif /*!DOCSHELL_LOAD*/
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP nsWebShell::InternalLoad(nsIURI* aURI, nsIURI* aReferrer,
|
|
nsIInputStream* aPostData, loadType aLoadType)
|
|
{
|
|
nsXPIDLCString url;
|
|
aURI->GetSpec(getter_Copies(url));
|
|
|
|
nsXPIDLCString referrer;
|
|
if(aReferrer)
|
|
aReferrer->GetSpec(getter_Copies(referrer));
|
|
|
|
|
|
return LoadURL(nsAutoString(url).GetUnicode(), nsnull, PR_FALSE, 0, 0,
|
|
nsnull, nsAutoString(referrer).GetUnicode());
|
|
|
|
}
|
|
|
|
// nsIURIContentListener support
|
|
NS_IMETHODIMP nsWebShell::OnStartURIOpen(nsIURI* aURI, const char* aWindowTarget,
|
|
PRBool* aAbortOpen)
|
|
{
|
|
NS_ENSURE_SUCCESS(EnsureContentListener(), NS_ERROR_FAILURE);
|
|
return mContentListener->OnStartURIOpen(aURI, aWindowTarget, aAbortOpen);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetProtocolHandler(nsIURI *aURI, nsIProtocolHandler **aProtocolHandler)
|
|
{
|
|
// Farm this off to our content listener
|
|
NS_ENSURE_SUCCESS(EnsureContentListener(), NS_ERROR_FAILURE);
|
|
return mContentListener->GetProtocolHandler(aURI, aProtocolHandler);
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::IsPreferred(const char * aContentType,
|
|
nsURILoadCommand aCommand,
|
|
const char * aWindowTarget,
|
|
char ** aDesiredContentType,
|
|
PRBool * aCanHandleContent)
|
|
{
|
|
NS_ENSURE_SUCCESS(EnsureContentListener(), NS_ERROR_FAILURE);
|
|
return mContentListener->IsPreferred(aContentType, aCommand, aWindowTarget, aDesiredContentType,
|
|
aCanHandleContent);
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::CanHandleContent(const char * aContentType,
|
|
nsURILoadCommand aCommand,
|
|
const char * aWindowTarget,
|
|
char ** aDesiredContentType,
|
|
PRBool * aCanHandleContent)
|
|
|
|
{
|
|
NS_ENSURE_SUCCESS(EnsureContentListener(), NS_ERROR_FAILURE);
|
|
return mContentListener->CanHandleContent(aContentType, aCommand, aWindowTarget, aDesiredContentType,
|
|
aCanHandleContent);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::DoContent(const char * aContentType,
|
|
nsURILoadCommand aCommand,
|
|
const char * aWindowTarget,
|
|
nsIChannel * aOpenedChannel,
|
|
nsIStreamListener ** aContentHandler,
|
|
PRBool * aAbortProcess)
|
|
{
|
|
NS_ENSURE_ARG(aOpenedChannel);
|
|
nsresult rv = NS_OK;
|
|
if (aAbortProcess)
|
|
*aAbortProcess = PR_FALSE;
|
|
|
|
nsXPIDLCString strCommand;
|
|
// go to the uri loader and ask it to convert the uri load command into a old
|
|
// world style string
|
|
NS_WITH_SERVICE(nsIURILoader, pURILoader, NS_URI_LOADER_PROGID, &rv);
|
|
if (NS_SUCCEEDED(rv))
|
|
pURILoader->GetStringForCommand(aCommand, getter_Copies(strCommand));
|
|
|
|
|
|
// determine if the channel has just been retargeted to us...
|
|
nsLoadFlags loadAttribs = 0;
|
|
aOpenedChannel->GetLoadAttributes(&loadAttribs);
|
|
// first, run any uri preparation stuff that we would have run normally
|
|
// had we gone through OpenURI
|
|
nsCOMPtr<nsIURI> aUri;
|
|
aOpenedChannel->GetURI(getter_AddRefs(aUri));
|
|
if (loadAttribs & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
|
|
{
|
|
PrepareToLoadURI(aUri, nsnull, PR_TRUE, nsIChannel::LOAD_NORMAL, 0, nsnull, nsnull);
|
|
// mscott: when I called DoLoadURL I found that we ran into problems because
|
|
// we currently don't have channel retargeting yet. Basically, what happens is that
|
|
// DoLoadURL calls StopBeforeRequestingURL and this cancels the current load group
|
|
// however since we can't retarget yet, we were basically canceling our very
|
|
// own load group!!! So the request would get canceled out from under us...
|
|
// after retargeting we may be able to safely call DoLoadURL.
|
|
DoLoadURL(aUri, strCommand, nsnull, nsIChannel::LOAD_NORMAL, 0, nsnull, nsnull, PR_FALSE);
|
|
SetFocus(); // force focus to get set on the retargeted window...
|
|
}
|
|
|
|
OnLoadingSite(aUri);
|
|
|
|
return CreateContentViewer(aContentType, aCommand, aOpenedChannel,
|
|
aContentHandler);
|
|
}
|
|
|
|
nsresult nsWebShell::PrepareToLoadURI(nsIURI * aUri,
|
|
nsIInputStream * aPostStream,
|
|
PRBool aModifyHistory,
|
|
nsLoadFlags aType,
|
|
const PRUint32 aLocalIP,
|
|
nsISupports * aHistoryState,
|
|
const PRUnichar * aReferrer)
|
|
{
|
|
nsresult rv;
|
|
CancelRefreshURITimers();
|
|
nsXPIDLCString scheme, CUriSpec;
|
|
|
|
if (!aUri) return NS_ERROR_NULL_POINTER;
|
|
|
|
rv = aUri->GetScheme(getter_Copies(scheme));
|
|
if (NS_FAILED(rv)) return rv;
|
|
rv = aUri->GetSpec(getter_Copies(CUriSpec));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsAutoString uriSpec(CUriSpec);
|
|
|
|
nsXPIDLCString spec;
|
|
rv = aUri->GetSpec(getter_Copies(spec));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsString* url = new nsString(uriSpec);
|
|
if (aModifyHistory) {
|
|
// Discard part of history that is no longer reachable
|
|
PRInt32 i, n = mHistory.Count();
|
|
i = mHistoryIndex + 1;
|
|
while (--n >= i) {
|
|
nsString* u = (nsString*) mHistory.ElementAt(n);
|
|
delete u;
|
|
mHistory.RemoveElementAt(n);
|
|
}
|
|
|
|
// Tack on new url
|
|
mHistory.AppendElement(url);
|
|
mHistoryIndex++;
|
|
}
|
|
else {
|
|
|
|
// Replace the current history index with this URL
|
|
nsString* u = (nsString*) mHistory.ElementAt(mHistoryIndex);
|
|
if (nsnull != u) {
|
|
delete u;
|
|
}
|
|
mHistory.ReplaceElementAt(url, mHistoryIndex);
|
|
}
|
|
ShowHistory();
|
|
|
|
// Give web-shell-container right of refusal
|
|
if (nsnull != mContainer) {
|
|
nsAutoString str(spec);
|
|
rv = mContainer->WillLoadURL(this, str.GetUnicode(), nsLoadURL);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::LoadURI(nsIURI * aUri,
|
|
const char * aCommand,
|
|
nsIInputStream* aPostDataStream,
|
|
PRBool aModifyHistory,
|
|
nsLoadFlags aType,
|
|
const PRUint32 aLocalIP,
|
|
nsISupports * aHistoryState,
|
|
const PRUnichar* aReferrer,
|
|
const char * aWindowTarget)
|
|
{
|
|
nsresult rv = PrepareToLoadURI(aUri, aPostDataStream,
|
|
aModifyHistory, aType, aLocalIP,
|
|
aHistoryState, aReferrer);
|
|
if (NS_SUCCEEDED(rv))
|
|
rv = DoLoadURL(aUri, aCommand, aPostDataStream, aType, aLocalIP, aReferrer, aWindowTarget);
|
|
return rv;
|
|
}
|
|
|
|
|
|
static nsresult convertURLToFileCharset(nsString& aIn, nsCString& aOut)
|
|
{
|
|
nsresult rv=NS_OK;
|
|
aOut = "";
|
|
// for file url, we need to convert the nsString to the file system
|
|
// charset before we pass to NS_NewURI
|
|
static nsAutoString fsCharset("");
|
|
// find out the file system charset first
|
|
if(0 == fsCharset.Length()) {
|
|
fsCharset = "ISO-8859-1"; // set the fallback first.
|
|
NS_WITH_SERVICE(nsIPlatformCharset, plat, kPlatformCharsetCID, &rv);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "cannot get nsIPlatformCharset");
|
|
if(NS_SUCCEEDED(rv)) {
|
|
rv = plat->GetCharset(kPlatformCharsetSel_FileName, fsCharset);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "nsIPlatformCharset GetCharset failed");
|
|
}
|
|
}
|
|
// We probably should cache ccm here.
|
|
// get a charset converter from the manager
|
|
NS_WITH_SERVICE(nsICharsetConverterManager, ccm, kCharsetConverterManagerCID, &rv);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "cannot get CharsetConverterManager");
|
|
nsCOMPtr<nsIUnicodeEncoder> fsEncoder;
|
|
if(NS_SUCCEEDED(rv)){
|
|
rv = ccm->GetUnicodeEncoder(&fsCharset, getter_AddRefs(fsEncoder));
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "cannot get encoder");
|
|
if(NS_SUCCEEDED(rv)){
|
|
PRInt32 bufLen = 0;
|
|
rv = fsEncoder->GetMaxLength(aIn.GetUnicode(), aIn.Length(), &bufLen);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "GetMaxLength failed");
|
|
aOut.SetCapacity(bufLen+1);
|
|
PRInt32 srclen = aIn.Length();
|
|
rv = fsEncoder->Convert(aIn.GetUnicode(), &srclen,
|
|
(char*)aOut.GetBuffer(), &bufLen);
|
|
if(NS_SUCCEEDED(rv)) {
|
|
((char*)aOut.GetBuffer())[bufLen]='\0';
|
|
aOut.SetLength(bufLen);
|
|
}
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
NS_IMETHODIMP
|
|
nsWebShell::LoadURL(const PRUnichar *aURLSpec,
|
|
const char* aCommand,
|
|
nsIInputStream* aPostDataStream,
|
|
PRBool aModifyHistory,
|
|
nsLoadFlags aType,
|
|
const PRUint32 aLocalIP,
|
|
nsISupports * aHistoryState,
|
|
const PRUnichar* aReferrer,
|
|
const char * aWindowTarget)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
PRBool isMail= PR_FALSE; // XXX mailto: hack
|
|
PRBool keywordsEnabled = PR_FALSE;
|
|
|
|
/*
|
|
TODO This doesnt belong here... The app should be doing all this
|
|
URL play. The webshell should not have a clue about whats "mailto"
|
|
If you insist that this should be here, then put in URL parsing
|
|
optimizations here. -Gagan
|
|
*/
|
|
|
|
mViewSource = (0==PL_strcmp("view-source", aCommand));
|
|
|
|
nsAutoString urlStr(aURLSpec);
|
|
// first things first. try to create a uri out of the string.
|
|
nsCOMPtr<nsIURI> uri;
|
|
nsXPIDLCString spec;
|
|
if(0==urlStr.Find("file:",0)) {
|
|
// if this is file url, we need to convert the URI
|
|
// from Unicode to the FS charset
|
|
nsCAutoString inFSCharset;
|
|
rv = convertURLToFileCharset(urlStr, inFSCharset);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "convertURLToFielCharset failed");
|
|
if (NS_SUCCEEDED(rv))
|
|
rv = NS_NewURI(getter_AddRefs(uri), inFSCharset.GetBuffer(), nsnull);
|
|
} else {
|
|
rv = NS_NewURI(getter_AddRefs(uri), urlStr, nsnull);
|
|
}
|
|
if (NS_FAILED(rv)) {
|
|
// no dice.
|
|
nsAutoString urlSpec;
|
|
urlStr.Trim(" ");
|
|
|
|
// see if we've got a file url.
|
|
convertFileToURL(urlStr, urlSpec);
|
|
nsCAutoString inFSCharset;
|
|
rv = convertURLToFileCharset(urlSpec, inFSCharset);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "convertURLToFielCharset failed");
|
|
if (NS_SUCCEEDED(rv))
|
|
rv = NS_NewURI(getter_AddRefs(uri), inFSCharset.GetBuffer(), nsnull);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
NS_ASSERTION(mPrefs, "the webshell's pref service wasn't initialized");
|
|
|
|
rv = mPrefs->GetBoolPref("keyword.enabled", &keywordsEnabled);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
PRInt32 qMarkLoc = -1, spaceLoc = -1;
|
|
|
|
rv = NS_ERROR_FAILURE;
|
|
if (keywordsEnabled) {
|
|
// These are keyword formatted strings
|
|
// "what is mozilla"
|
|
// "what is mozilla?"
|
|
// "?mozilla"
|
|
// "?What is mozilla"
|
|
|
|
// These are not keyword formatted strings
|
|
// "www.blah.com" - anything with a dot in it
|
|
// "nonQualifiedHost:80" - anything with a colon in it
|
|
// "nonQualifiedHost?"
|
|
// "nonQualifiedHost?args"
|
|
// "nonQualifiedHost?some args"
|
|
|
|
if (urlStr.FindChar('.') == -1 && urlStr.FindChar(':') == -1) {
|
|
qMarkLoc = urlStr.FindChar('?');
|
|
spaceLoc = urlStr.FindChar(' ');
|
|
|
|
PRBool keyword = PR_FALSE;
|
|
if (qMarkLoc == 0) {
|
|
keyword = PR_TRUE;
|
|
} else if ( (spaceLoc > 0) &&
|
|
( (qMarkLoc == -1) || (spaceLoc < qMarkLoc) )) {
|
|
keyword = PR_TRUE;
|
|
}
|
|
|
|
if (keyword) {
|
|
nsCAutoString keywordSpec("keyword:");
|
|
char *utf8Spec = urlStr.ToNewUTF8String();
|
|
if(utf8Spec) {
|
|
char* escapedUTF8Spec = nsEscape(utf8Spec, url_Path);
|
|
if(escapedUTF8Spec) {
|
|
keywordSpec.Append(escapedUTF8Spec);
|
|
rv = NS_NewURI(getter_AddRefs(uri), keywordSpec.GetBuffer(), nsnull);
|
|
nsAllocator::Free(escapedUTF8Spec);
|
|
} // escapedUTF8Spec
|
|
nsAllocator::Free(utf8Spec);
|
|
} // utf8Spec
|
|
} // keyword
|
|
} // FindChar
|
|
} // keywordEnable
|
|
|
|
|
|
PRInt32 colon = -1;
|
|
if (NS_FAILED(rv)) {
|
|
PRInt32 fSlash = urlSpec.FindChar('/');
|
|
PRUnichar port;
|
|
// if no scheme (protocol) is found, assume http.
|
|
if ( ((colon=urlSpec.FindChar(':')) == -1) // no colon at all
|
|
|| ( (fSlash > -1) && (colon > fSlash) ) // the only colon comes after the first slash
|
|
|| ( (colon < urlSpec.Length()-1) // the first char after the first colon is a digit (i.e. a port)
|
|
&& ((port=urlSpec.CharAt(colon+1)) <= '9')
|
|
&& (port > '0') )) {
|
|
// find host name
|
|
PRInt32 hostPos = urlSpec.FindCharInSet("./:");
|
|
if (hostPos == -1) {
|
|
hostPos = urlSpec.Length();
|
|
}
|
|
|
|
// extract host name
|
|
nsAutoString hostSpec;
|
|
urlSpec.Left(hostSpec, hostPos);
|
|
|
|
// insert url spec corresponding to host name
|
|
if (hostSpec.EqualsIgnoreCase("ftp")) {
|
|
urlSpec.Insert("ftp://", 0, 6);
|
|
} else {
|
|
urlSpec.Insert("http://", 0, 7);
|
|
}
|
|
} // end if colon
|
|
|
|
// XXX mailto: hack
|
|
if ((urlSpec.Find("mailto:", PR_TRUE)) >= 0)
|
|
isMail = PR_TRUE;
|
|
|
|
if (!isMail) {
|
|
rv = NS_NewURI(getter_AddRefs(uri), urlSpec, nsnull);
|
|
if (NS_ERROR_UNKNOWN_PROTOCOL == rv) {
|
|
// we weren't able to find a protocol handler
|
|
rv = InitDialogVars();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsXPIDLString messageStr;
|
|
nsAutoString name("protocolNotFound");
|
|
rv = mStringBundle->GetStringFromName(name.GetUnicode(), getter_Copies(messageStr));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
NS_ASSERTION(colon != -1, "we shouldn't have gotten this far if we didn't have a colon");
|
|
|
|
// extract the scheme
|
|
nsAutoString scheme;
|
|
urlSpec.Left(scheme, colon);
|
|
|
|
nsAutoString dnsMsg(scheme);
|
|
dnsMsg.Append(' ');
|
|
dnsMsg.Append(messageStr);
|
|
|
|
(void)mPrompter->Alert(dnsMsg.GetUnicode());
|
|
} // end unknown protocol
|
|
} // end !isMail
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!uri) return rv;
|
|
|
|
rv = uri->GetSpec(getter_Copies(spec));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Get hold of Root webshell
|
|
nsCOMPtr<nsIWebShell> root;
|
|
nsCOMPtr<nsISessionHistory> shist;
|
|
PRBool isLoadingHistory=PR_FALSE; // Is SH currently loading an entry from history?
|
|
rv = GetRootWebShell(*getter_AddRefs(root));
|
|
// Get hold of session History
|
|
if (NS_SUCCEEDED(rv) && root) {
|
|
root->GetSessionHistory(*getter_AddRefs(shist));
|
|
}
|
|
if (shist)
|
|
shist->GetLoadingFlag(&isLoadingHistory);
|
|
|
|
|
|
/*
|
|
* Save the history state for the current index iff this loadurl() request
|
|
* is not from SH. When the request comes from SH, aModifyHistory will
|
|
* be false and nsSessionHistory.cpp takes of this.
|
|
*/
|
|
if (shist) {
|
|
PRInt32 indix;
|
|
shist->GetCurrentIndex(&indix);
|
|
if (indix >= 0 && (aModifyHistory)) {
|
|
nsCOMPtr<nsISupports> historyState;
|
|
rv = CaptureHistoryState(getter_AddRefs(historyState));
|
|
if (NS_SUCCEEDED(rv) && historyState)
|
|
shist->SetHistoryObjectForIndex(indix, historyState);
|
|
}
|
|
}
|
|
/* Set the History state object for the current page in the
|
|
* presentation shell. If it is a new page being visited,
|
|
* aHistoryState is null. If the load is coming from
|
|
* session History, it will be set to the cached history object by
|
|
* session History.
|
|
*/
|
|
SetHistoryState(aHistoryState);
|
|
|
|
/* If the current Uri is the same as the one to be loaded
|
|
* don't add it to session history. This avoids multiple
|
|
* entries for the same url in the go menu
|
|
*/
|
|
nsCOMPtr<nsIURI> currentURI;
|
|
nsresult res = GetCurrentURI(getter_AddRefs(currentURI));
|
|
if (NS_SUCCEEDED(res) && currentURI) {
|
|
nsXPIDLCString currentUriSpec;
|
|
rv = currentURI->GetSpec(getter_Copies(currentUriSpec));
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsAutoString currentURIString(currentUriSpec);
|
|
if (currentURIString == spec) {
|
|
/* The url to be loaded is the same as the
|
|
* url already in the page. Don't add it to session history
|
|
*/
|
|
aModifyHistory = PR_FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/* Add the page to session history */
|
|
if (aModifyHistory && shist && (!isMail)) {
|
|
PRInt32 ret;
|
|
nsCAutoString referrer(aReferrer);
|
|
ret = shist->Add(spec, referrer, this);
|
|
}
|
|
|
|
nsCOMPtr<nsIWebShell> parent;
|
|
res = GetParent(*getter_AddRefs(parent));
|
|
nsCOMPtr<nsIURI> newURI;
|
|
|
|
if ((isLoadingHistory)) {
|
|
/* if LoadURL() got called from SH, AND If we are going "Back/Forward"
|
|
* to a frame page,SH will change the current uri to the right value
|
|
* for smoother redraw.
|
|
*/
|
|
res = GetCurrentURI(getter_AddRefs(newURI));
|
|
}
|
|
else{
|
|
/* If the call is not from SH, use the url passed by the caller
|
|
* so that things like JS will work right. This is for bug # 1646.
|
|
* May regress in other situations.
|
|
* What a hack
|
|
*/
|
|
nsAutoString urlstr = (const char *) spec;
|
|
res = NS_NewURI(getter_AddRefs(newURI), urlstr, nsnull);
|
|
}
|
|
|
|
|
|
if (NS_SUCCEEDED(res)) {
|
|
// now that we have a uri, call the REAL LoadURI method which requires a nsIURI.
|
|
return LoadURI(newURI, aCommand, aPostDataStream, aModifyHistory, aType, aLocalIP, aHistoryState, aReferrer, aWindowTarget);
|
|
}
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP nsWebShell::Stop(void)
|
|
{
|
|
// Cancel any timers that were set for this loader.
|
|
CancelRefreshURITimers();
|
|
|
|
return nsDocShell::Stop();
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
// History methods
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GoTo(PRInt32 aHistoryIndex)
|
|
{
|
|
nsresult rv = NS_ERROR_ILLEGAL_VALUE;
|
|
if ((aHistoryIndex >= 0) &&
|
|
(aHistoryIndex < mHistory.Count())) {
|
|
nsString* s = (nsString*) mHistory.ElementAt(aHistoryIndex);
|
|
|
|
// Give web-shell-container right of refusal
|
|
nsAutoString urlSpec(*s);
|
|
if (nsnull != mContainer) {
|
|
rv = mContainer->WillLoadURL(this, urlSpec.GetUnicode(), nsLoadHistory);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("Goto %d\n", aHistoryIndex);
|
|
#endif
|
|
mHistoryIndex = aHistoryIndex;
|
|
ShowHistory();
|
|
|
|
// convert the uri spec into a url and then pass it to DoLoadURL
|
|
nsCOMPtr<nsIURI> uri;
|
|
rv = NS_NewURI(getter_AddRefs(uri), urlSpec, nsnull);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = DoLoadURL(uri, // URL string
|
|
"view", // Command
|
|
nsnull, // Post Data
|
|
nsISessionHistory::LOAD_HISTORY, // the reload type
|
|
0, // load attributes
|
|
nsnull,nsnull); // referrer
|
|
}
|
|
return rv;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetHistoryLength(PRInt32& aResult)
|
|
{
|
|
aResult = mHistory.Count();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetHistoryIndex(PRInt32& aResult)
|
|
{
|
|
aResult = mHistoryIndex;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetURL(PRInt32 aHistoryIndex, const PRUnichar** aURLResult)
|
|
{
|
|
nsresult rv = NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
// XXX Ownership rules for the string passed back from this
|
|
// method are not XPCOM compliant. If they were correct,
|
|
// the caller would deallocate the string.
|
|
if ((aHistoryIndex >= 0) &&
|
|
(aHistoryIndex <= mHistory.Count() - 1)) {
|
|
nsString* s = (nsString*) mHistory.ElementAt(aHistoryIndex);
|
|
if (nsnull != s) {
|
|
*aURLResult = s->GetUnicode();
|
|
}
|
|
rv = NS_OK;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
nsWebShell::ShowHistory()
|
|
{
|
|
#if defined(NS_DEBUG)
|
|
if (WEB_LOG_TEST(gLogModule, WEB_TRACE_HISTORY)) {
|
|
PRInt32 i, n = mHistory.Count();
|
|
for (i = 0; i < n; i++) {
|
|
if (i == mHistoryIndex) {
|
|
printf("**");
|
|
}
|
|
else {
|
|
printf(" ");
|
|
}
|
|
nsString* u = (nsString*) mHistory.ElementAt(i);
|
|
fputs(*u, stdout);
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
//----------------------------------------
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// WebShell container implementation
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::WillLoadURL(nsIWebShell* aShell, const PRUnichar* aURL, nsLoadType aReason)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
if (nsnull != mContainer) {
|
|
rv = mContainer->WillLoadURL(aShell, aURL, aReason);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::BeginLoadURL(nsIWebShell* aShell, const PRUnichar* aURL)
|
|
{
|
|
if (nsnull != mContainer) {
|
|
// XXX: do not propagate this notification up from any frames...
|
|
return mContainer->BeginLoadURL(aShell, aURL);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::ProgressLoadURL(nsIWebShell* aShell,
|
|
const PRUnichar* aURL,
|
|
PRInt32 aProgress,
|
|
PRInt32 aProgressMax)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
if (nsnull != mContainer) {
|
|
rv = mContainer->ProgressLoadURL(aShell, aURL, aProgress, aProgressMax);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::EndLoadURL(nsIWebShell* aShell, const PRUnichar* aURL, nsresult aStatus)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
if (nsnull != mContainer) {
|
|
// XXX: do not propagate this notification up from any frames...
|
|
return mContainer->EndLoadURL(aShell, aURL, aStatus);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::CaptureHistoryState(nsISupports** aLayoutHistoryState)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
// XXX Need to think about what to do for framesets.
|
|
// For now, return an error if this webshell
|
|
// contains a frame or a frameset document.
|
|
// The main content area will always have a parent. It is
|
|
// enough to check the children count to verify frames.
|
|
if (mChildren.Count() > 0) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
// Ask the pres shell for the history state
|
|
if (mContentViewer) {
|
|
nsCOMPtr<nsIDocumentViewer> docv = do_QueryInterface(mContentViewer);
|
|
if (nsnull != docv) {
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
rv = docv->GetPresShell(*getter_AddRefs(shell));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
rv = shell->CaptureHistoryState((nsILayoutHistoryState**) aLayoutHistoryState);
|
|
}
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetHistoryState(nsISupports** aLayoutHistoryState)
|
|
{
|
|
NS_IF_ADDREF(mHistoryState);
|
|
*aLayoutHistoryState = mHistoryState;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetHistoryState(nsISupports* aLayoutHistoryState)
|
|
{
|
|
mHistoryState = aLayoutHistoryState;
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Web Shell Services API
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::LoadDocument(const char* aURL,
|
|
const char* aCharset,
|
|
nsCharsetSource aSource)
|
|
{
|
|
// XXX hack. kee the aCharset and aSource wait to pick it up
|
|
nsCOMPtr<nsIContentViewer> cv;
|
|
NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
|
|
if (cv)
|
|
{
|
|
nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(cv);
|
|
if (muDV)
|
|
{
|
|
nsCharsetSource hint;
|
|
muDV->GetHintCharacterSetSource((PRInt32 *)(&hint));
|
|
if( aSource > hint )
|
|
{
|
|
nsAutoString inputCharSet(aCharset);
|
|
muDV->SetHintCharacterSet(inputCharSet.GetUnicode());
|
|
muDV->SetHintCharacterSetSource((PRInt32)aSource);
|
|
if(eCharsetReloadRequested != mCharsetReloadState)
|
|
{
|
|
mCharsetReloadState = eCharsetReloadRequested;
|
|
nsAutoString url(aURL);
|
|
LoadURL(url.GetUnicode());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::ReloadDocument(const char* aCharset,
|
|
nsCharsetSource aSource,
|
|
const char* aCmd)
|
|
{
|
|
|
|
// XXX hack. kee the aCharset and aSource wait to pick it up
|
|
nsCOMPtr<nsIContentViewer> cv;
|
|
NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
|
|
if (cv)
|
|
{
|
|
nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(cv);
|
|
if (muDV)
|
|
{
|
|
nsCharsetSource hint;
|
|
muDV->GetHintCharacterSetSource((PRInt32 *)(&hint));
|
|
if( aSource > hint )
|
|
{
|
|
nsAutoString inputCharSet(aCharset);
|
|
muDV->SetHintCharacterSet(inputCharSet.GetUnicode());
|
|
muDV->SetHintCharacterSetSource((PRInt32)aSource);
|
|
if(eCharsetReloadRequested != mCharsetReloadState)
|
|
{
|
|
mCharsetReloadState = eCharsetReloadRequested;
|
|
return Reload(nsIChannel::LOAD_NORMAL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::StopDocumentLoad(void)
|
|
{
|
|
if(eCharsetReloadRequested != mCharsetReloadState)
|
|
{
|
|
Stop();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetRendering(PRBool aRender)
|
|
{
|
|
if(eCharsetReloadRequested != mCharsetReloadState)
|
|
{
|
|
if (mContentViewer) {
|
|
mContentViewer->SetEnableRendering(aRender);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// WebShell link handling
|
|
|
|
struct OnLinkClickEvent : public PLEvent {
|
|
OnLinkClickEvent(nsWebShell* aHandler, nsIContent* aContent,
|
|
nsLinkVerb aVerb, const PRUnichar* aURLSpec,
|
|
const PRUnichar* aTargetSpec, nsIInputStream* aPostDataStream = 0);
|
|
~OnLinkClickEvent();
|
|
|
|
void HandleEvent() {
|
|
mHandler->HandleLinkClickEvent(mContent, mVerb, mURLSpec->GetUnicode(),
|
|
mTargetSpec->GetUnicode(), mPostDataStream);
|
|
}
|
|
|
|
nsWebShell* mHandler;
|
|
nsString* mURLSpec;
|
|
nsString* mTargetSpec;
|
|
nsIInputStream* mPostDataStream;
|
|
nsIContent* mContent;
|
|
nsLinkVerb mVerb;
|
|
};
|
|
|
|
static void PR_CALLBACK HandlePLEvent(OnLinkClickEvent* aEvent)
|
|
{
|
|
aEvent->HandleEvent();
|
|
}
|
|
|
|
static void PR_CALLBACK DestroyPLEvent(OnLinkClickEvent* aEvent)
|
|
{
|
|
delete aEvent;
|
|
}
|
|
|
|
OnLinkClickEvent::OnLinkClickEvent(nsWebShell* aHandler,
|
|
nsIContent *aContent,
|
|
nsLinkVerb aVerb,
|
|
const PRUnichar* aURLSpec,
|
|
const PRUnichar* aTargetSpec,
|
|
nsIInputStream* aPostDataStream)
|
|
{
|
|
nsIEventQueue* eventQueue;
|
|
|
|
mHandler = aHandler;
|
|
NS_ADDREF(aHandler);
|
|
mURLSpec = new nsString(aURLSpec);
|
|
mTargetSpec = new nsString(aTargetSpec);
|
|
mPostDataStream = aPostDataStream;
|
|
NS_IF_ADDREF(mPostDataStream);
|
|
mContent = aContent;
|
|
NS_IF_ADDREF(mContent);
|
|
mVerb = aVerb;
|
|
|
|
PL_InitEvent(this, nsnull,
|
|
(PLHandleEventProc) ::HandlePLEvent,
|
|
(PLDestroyEventProc) ::DestroyPLEvent);
|
|
|
|
eventQueue = aHandler->GetEventQueue();
|
|
eventQueue->PostEvent(this);
|
|
NS_RELEASE(eventQueue);
|
|
}
|
|
|
|
OnLinkClickEvent::~OnLinkClickEvent()
|
|
{
|
|
NS_IF_RELEASE(mContent);
|
|
NS_IF_RELEASE(mHandler);
|
|
NS_IF_RELEASE(mPostDataStream);
|
|
if (nsnull != mURLSpec) delete mURLSpec;
|
|
if (nsnull != mTargetSpec) delete mTargetSpec;
|
|
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnLinkClick(nsIContent* aContent,
|
|
nsLinkVerb aVerb,
|
|
const PRUnichar* aURLSpec,
|
|
const PRUnichar* aTargetSpec,
|
|
nsIInputStream* aPostDataStream)
|
|
{
|
|
OnLinkClickEvent* ev;
|
|
nsresult rv = NS_OK;
|
|
|
|
ev = new OnLinkClickEvent(this, aContent, aVerb, aURLSpec,
|
|
aTargetSpec, aPostDataStream);
|
|
if (nsnull == ev) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
nsIEventQueue* nsWebShell::GetEventQueue(void)
|
|
{
|
|
NS_PRECONDITION(nsnull != mThreadEventQueue, "EventQueue for thread is null");
|
|
NS_ADDREF(mThreadEventQueue);
|
|
return mThreadEventQueue;
|
|
}
|
|
|
|
void
|
|
nsWebShell::HandleLinkClickEvent(nsIContent *aContent,
|
|
nsLinkVerb aVerb,
|
|
const PRUnichar* aURLSpec,
|
|
const PRUnichar* aTargetSpec,
|
|
nsIInputStream* aPostDataStream)
|
|
{
|
|
nsAutoString target(aTargetSpec);
|
|
|
|
|
|
switch(aVerb) {
|
|
case eLinkVerb_New:
|
|
target.Assign("_blank");
|
|
// Fall into replace case
|
|
case eLinkVerb_Replace:
|
|
{
|
|
// for now, just hack the verb to be view-link-clicked
|
|
// and down in the load document code we'll detect this and
|
|
// set the correct uri loader command
|
|
nsXPIDLCString spec;
|
|
mCurrentURI->GetSpec(getter_Copies(spec));
|
|
nsAutoString specString(spec);
|
|
LoadURL(aURLSpec, "view-link-click", aPostDataStream,
|
|
PR_TRUE, nsIChannel::LOAD_NORMAL,
|
|
0, nsnull, specString.GetUnicode(), nsCAutoString(aTargetSpec));
|
|
}
|
|
break;
|
|
case eLinkVerb_Embed:
|
|
default:
|
|
;
|
|
// XXX Need to do this
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnOverLink(nsIContent* aContent,
|
|
const PRUnichar* aURLSpec,
|
|
const PRUnichar* aTargetSpec)
|
|
{
|
|
if (!mOverURL.Equals(aURLSpec) || !mOverTarget.Equals(aTargetSpec)) {
|
|
#ifdef NOISY_LINKS
|
|
fputs("Was '", stdout);
|
|
fputs(mOverURL, stdout);
|
|
fputs("' '", stdout);
|
|
fputs(mOverTarget, stdout);
|
|
fputs("'\n", stdout);
|
|
fputs("Over link '", stdout);
|
|
fputs(aURLSpec, stdout);
|
|
fputs("' '", stdout);
|
|
fputs(aTargetSpec, stdout);
|
|
fputs("'\n", stdout);
|
|
#endif /* NS_DEBUG */
|
|
|
|
mOverURL = aURLSpec;
|
|
mOverTarget = aTargetSpec;
|
|
|
|
|
|
nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
|
|
|
|
if (browserChrome)
|
|
browserChrome->SetOverLink(aURLSpec);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetLinkState(const PRUnichar* aURLSpec, nsLinkState& aState)
|
|
{
|
|
aState = eLinkState_Unvisited;
|
|
|
|
nsresult rv;
|
|
|
|
// XXX: GlobalHistory is going to be moved out of the webshell into a more appropriate place.
|
|
if ((nsnull == mHistoryService) && !mFailedToLoadHistoryService) {
|
|
rv = nsServiceManager::GetService(kGlobalHistoryCID,
|
|
NS_GET_IID(nsIGlobalHistory),
|
|
(nsISupports**) &mHistoryService);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
mFailedToLoadHistoryService = PR_TRUE;
|
|
}
|
|
}
|
|
|
|
if (mHistoryService) {
|
|
// XXX aURLSpec should really be a char*, not a PRUnichar*.
|
|
nsAutoString urlStr(aURLSpec);
|
|
|
|
char buf[256];
|
|
char* url = buf;
|
|
|
|
if (urlStr.Length() >= PRInt32(sizeof buf)) {
|
|
url = new char[urlStr.Length() + 1];
|
|
}
|
|
|
|
PRInt64 lastVisitDate;
|
|
|
|
if (url) {
|
|
urlStr.ToCString(url, urlStr.Length() + 1);
|
|
|
|
rv = mHistoryService->GetLastVisitDate(url, &lastVisitDate);
|
|
|
|
if (url != buf)
|
|
delete[] url;
|
|
}
|
|
else {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
//XXX: Moved to destructor nsServiceManager::ReleaseService(kGlobalHistoryCID, mHistoryService);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// a last-visit-date of zero means we've never seen it before; so
|
|
// if it's not zero, we must've seen it.
|
|
if (! LL_IS_ZERO(lastVisitDate))
|
|
aState = eLinkState_Visited;
|
|
|
|
// XXX how to tell if eLinkState_OutOfDate?
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnStartDocumentLoad(nsIDocumentLoader* loader,
|
|
nsIURI* aURL,
|
|
const char* aCommand)
|
|
{
|
|
nsIDocumentViewer* docViewer;
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
if ((mScriptGlobal) &&
|
|
(loader == mDocLoader)) {
|
|
if (nsnull != mContentViewer &&
|
|
NS_OK == mContentViewer->QueryInterface(kIDocumentViewerIID, (void**)&docViewer)) {
|
|
nsIPresContext *presContext;
|
|
if (NS_OK == docViewer->GetPresContext(presContext)) {
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsMouseEvent event;
|
|
event.eventStructType = NS_EVENT;
|
|
event.message = NS_PAGE_UNLOAD;
|
|
rv = mScriptGlobal->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
|
|
NS_RELEASE(presContext);
|
|
}
|
|
NS_RELEASE(docViewer);
|
|
}
|
|
}
|
|
|
|
if (loader == mDocLoader) {
|
|
nsCOMPtr<nsIDocumentLoaderObserver> dlObserver;
|
|
|
|
if (!mDocLoaderObserver && mParent) {
|
|
/* If this is a frame (in which case it would have a parent && doesn't
|
|
* have a documentloaderObserver, get it from the rootWebShell
|
|
*/
|
|
nsCOMPtr<nsIDocShellTreeItem> rootItem;
|
|
GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
|
|
nsCOMPtr<nsIDocShell> rootDocShell(do_QueryInterface(rootItem));
|
|
|
|
if (rootDocShell)
|
|
rootDocShell->GetDocLoaderObserver(getter_AddRefs(dlObserver));
|
|
}
|
|
else
|
|
{
|
|
dlObserver = do_QueryInterface(mDocLoaderObserver); // we need this to addref
|
|
}
|
|
/*
|
|
* Fire the OnStartDocumentLoad of the webshell observer
|
|
*/
|
|
if ((nsnull != mContainer) && (nsnull != dlObserver))
|
|
{
|
|
dlObserver->OnStartDocumentLoad(mDocLoader, aURL, aCommand);
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnEndDocumentLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
nsresult aStatus)
|
|
{
|
|
#ifdef MOZ_PERF_METRICS
|
|
MOZ_TIMER_DEBUGLOG(("Stop: nsWebShell::OnEndDocumentLoad(), this=%p\n", this));
|
|
MOZ_TIMER_STOP(mTotalTime);
|
|
MOZ_TIMER_LOG(("Total (Layout + Page Load) Time (webshell=%p): ", this));
|
|
MOZ_TIMER_PRINT(mTotalTime);
|
|
#endif
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
if (!channel) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> aURL;
|
|
rv = channel->GetURI(getter_AddRefs(aURL));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// clean up reload state for meta charset
|
|
if(eCharsetReloadRequested == mCharsetReloadState)
|
|
mCharsetReloadState = eCharsetReloadStopOrigional;
|
|
else
|
|
mCharsetReloadState = eCharsetReloadInit;
|
|
|
|
/* one of many safeguards that prevent death and destruction if
|
|
someone is so very very rude as to bring this window down
|
|
during this load handler. */
|
|
nsCOMPtr<nsIWebShell> kungFuDeathGrip(this);
|
|
|
|
//if (!mProcessedEndDocumentLoad) {
|
|
if (loader == mDocLoader) {
|
|
mProcessedEndDocumentLoad = PR_TRUE;
|
|
|
|
if (mScriptGlobal && !mEODForCurrentDocument) {
|
|
nsIDocumentViewer* docViewer;
|
|
if (nsnull != mContentViewer &&
|
|
NS_OK == mContentViewer->QueryInterface(kIDocumentViewerIID, (void**)&docViewer)) {
|
|
nsIPresContext *presContext;
|
|
if (NS_OK == docViewer->GetPresContext(presContext)) {
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsMouseEvent event;
|
|
event.eventStructType = NS_EVENT;
|
|
event.message = NS_PAGE_LOAD;
|
|
rv = mScriptGlobal->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
|
|
NS_RELEASE(presContext);
|
|
}
|
|
NS_RELEASE(docViewer);
|
|
}
|
|
}
|
|
|
|
mEODForCurrentDocument = PR_TRUE;
|
|
|
|
// Fire the EndLoadURL of the web shell container
|
|
if (nsnull != aURL) {
|
|
nsAutoString urlString;
|
|
char* spec;
|
|
rv = aURL->GetSpec(&spec);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
urlString = spec;
|
|
if (nsnull != mContainer) {
|
|
rv = mContainer->EndLoadURL(this, urlString.GetUnicode(), 0);
|
|
}
|
|
nsCRT::free(spec);
|
|
}
|
|
}
|
|
|
|
|
|
nsCOMPtr<nsIDocumentLoaderObserver> dlObserver;
|
|
|
|
if (!mDocLoaderObserver && mParent) {
|
|
/* If this is a frame (in which case it would have a parent && doesn't
|
|
* have a documentloaderObserver, get it from the rootWebShell
|
|
*/
|
|
nsCOMPtr<nsIDocShellTreeItem> rootItem;
|
|
GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
|
|
nsCOMPtr<nsIDocShell> rootDocShell(do_QueryInterface(rootItem));
|
|
|
|
if (rootDocShell)
|
|
rootDocShell->GetDocLoaderObserver(getter_AddRefs(dlObserver));
|
|
}
|
|
else
|
|
{
|
|
/* Take care of the Trailing slash situation */
|
|
if (mSHist)
|
|
CheckForTrailingSlash(aURL);
|
|
dlObserver = do_QueryInterface(mDocLoaderObserver); // we need this to addref
|
|
}
|
|
|
|
/*
|
|
* Fire the OnEndDocumentLoad of the DocLoaderobserver
|
|
*/
|
|
if (dlObserver && (nsnull != aURL)) {
|
|
dlObserver->OnEndDocumentLoad(mDocLoader, channel, aStatus);
|
|
}
|
|
|
|
if (mDocLoader == loader && NS_FAILED(aStatus)) {
|
|
nsAutoString errorMsg;
|
|
nsXPIDLCString host;
|
|
rv = aURL->GetHost(getter_Copies(host));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
CBufDescriptor buf((const char *)host, PR_TRUE, PL_strlen(host) + 1);
|
|
nsCAutoString hostStr(buf);
|
|
PRInt32 dotLoc = hostStr.FindChar('.');
|
|
|
|
|
|
if (aStatus == NS_ERROR_UNKNOWN_HOST
|
|
|| aStatus == NS_ERROR_CONNECTION_REFUSED
|
|
|| aStatus == NS_ERROR_NET_TIMEOUT) {
|
|
// First see if we should throw it to the keyword server.
|
|
NS_ASSERTION(mPrefs, "the webshell's pref service wasn't initialized");
|
|
PRBool keywordsEnabled = PR_FALSE;
|
|
rv = mPrefs->GetBoolPref("keyword.enabled", &keywordsEnabled);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (keywordsEnabled && (-1 == dotLoc)) {
|
|
// only send non-qualified hosts to the keyword server
|
|
nsAutoString keywordSpec("keyword:");
|
|
keywordSpec.Append(host);
|
|
return LoadURL(keywordSpec.GetUnicode(), "view");
|
|
} // end keywordsEnabled
|
|
}
|
|
|
|
// Doc failed to load because the host was not found.
|
|
if (aStatus == NS_ERROR_UNKNOWN_HOST) {
|
|
// Try our www.*.com trick.
|
|
nsCAutoString retryHost;
|
|
nsXPIDLCString scheme;
|
|
rv = aURL->GetScheme(getter_Copies(scheme));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
PRUint32 schemeLen = PL_strlen((const char*)scheme);
|
|
CBufDescriptor schemeBuf((const char*)scheme, PR_TRUE, schemeLen+1, schemeLen);
|
|
nsCAutoString schemeStr(schemeBuf);
|
|
|
|
if (schemeStr.Find("http") == 0) {
|
|
if (-1 == dotLoc) {
|
|
retryHost = "www.";
|
|
retryHost += hostStr;
|
|
retryHost += ".com";
|
|
} else {
|
|
PRInt32 hostLen = hostStr.Length();
|
|
if ( ((hostLen - dotLoc) == 3) || ((hostLen - dotLoc) == 4) ) {
|
|
retryHost = "www.";
|
|
retryHost += hostStr;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!retryHost.IsEmpty()) {
|
|
rv = aURL->SetHost(retryHost.GetBuffer());
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsXPIDLCString aSpec;
|
|
rv = aURL->GetSpec(getter_Copies(aSpec));
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsAutoString newURL(aSpec);
|
|
// reload the url
|
|
return LoadURL(newURL.GetUnicode(), "view");
|
|
} // retry
|
|
|
|
// throw a DNS failure dialog
|
|
rv = InitDialogVars();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsXPIDLString messageStr;
|
|
nsAutoString name("dnsNotFound");
|
|
rv = mStringBundle->GetStringFromName(name.GetUnicode(), getter_Copies(messageStr));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
errorMsg = host;
|
|
errorMsg.Append(' ');
|
|
errorMsg.Append(messageStr);
|
|
|
|
(void)mPrompter->Alert(errorMsg.GetUnicode());
|
|
} else // unknown host
|
|
|
|
// Doc failed to load because we couldn't connect to the server.
|
|
if (aStatus == NS_ERROR_CONNECTION_REFUSED) {
|
|
// throw a connection failure dialog
|
|
PRInt32 port = -1;
|
|
rv = aURL->GetPort(&port);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = InitDialogVars();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsXPIDLString messageStr;
|
|
nsAutoString name("connectionFailure");
|
|
rv = mStringBundle->GetStringFromName(name.GetUnicode(), getter_Copies(messageStr));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
errorMsg = messageStr;
|
|
errorMsg.Append(' ');
|
|
errorMsg.Append(host);
|
|
if (port > 0) {
|
|
errorMsg.Append(':');
|
|
errorMsg.Append(port);
|
|
}
|
|
errorMsg.Append('.');
|
|
|
|
(void)mPrompter->Alert(errorMsg.GetUnicode());
|
|
} else // end NS_ERROR_CONNECTION_REFUSED
|
|
|
|
// Doc failed to load because the socket function timed out.
|
|
if (aStatus == NS_ERROR_NET_TIMEOUT) {
|
|
// throw a timeout dialog
|
|
rv = InitDialogVars();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsXPIDLString messageStr;
|
|
nsAutoString name("netTimeout");
|
|
rv = mStringBundle->GetStringFromName(name.GetUnicode(), getter_Copies(messageStr));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
errorMsg = messageStr;
|
|
errorMsg.Append(' ');
|
|
errorMsg.Append(host);
|
|
errorMsg.Append('.');
|
|
|
|
(void)mPrompter->Alert(errorMsg.GetUnicode());
|
|
} // end NS_ERROR_NET_TIMEOUT
|
|
} // end mDocLoader == loader
|
|
} //!mProcessedEndDocumentLoad
|
|
else {
|
|
rv = NS_OK;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnStartURLLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIURI> aURL;
|
|
rv = channel->GetURI(getter_AddRefs(aURL));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
// Stop loading of the earlier document completely when the document url
|
|
// load starts. Now we know that this url is valid and available.
|
|
PRBool equals = PR_FALSE;
|
|
if (NS_SUCCEEDED(aURL->Equals(mCurrentURI, &equals)) && equals)
|
|
Stop();
|
|
|
|
/*
|
|
*Fire the OnStartDocumentLoad of the webshell observer
|
|
*/
|
|
if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver))
|
|
{
|
|
mDocLoaderObserver->OnStartURLLoad(mDocLoader, channel);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnProgressURLLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
PRUint32 aProgress,
|
|
PRUint32 aProgressMax)
|
|
{
|
|
/*
|
|
*Fire the OnStartDocumentLoad of the webshell observer and container...
|
|
*/
|
|
if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver))
|
|
{
|
|
mDocLoaderObserver->OnProgressURLLoad(mDocLoader, channel, aProgress, aProgressMax);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnStatusURLLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
nsString& aMsg)
|
|
{
|
|
/*
|
|
*Fire the OnStartDocumentLoad of the webshell observer and container...
|
|
*/
|
|
if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver))
|
|
{
|
|
mDocLoaderObserver->OnStatusURLLoad(mDocLoader, channel, aMsg);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnEndURLLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
nsresult aStatus)
|
|
{
|
|
#if 0
|
|
const char* spec;
|
|
aURL->GetSpec(&spec);
|
|
printf("nsWebShell::OnEndURLLoad:%p: loader=%p url=%s status=%d\n", this, loader, spec, aStatus);
|
|
#endif
|
|
/*
|
|
*Fire the OnEndDocumentLoad of the webshell observer
|
|
*/
|
|
if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver))
|
|
{
|
|
mDocLoaderObserver->OnEndURLLoad(mDocLoader, channel, aStatus);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/* For use with redirect/refresh url api */
|
|
class refreshData : public nsITimerCallback
|
|
{
|
|
public:
|
|
refreshData();
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsITimerCallback interface
|
|
NS_IMETHOD_(void) Notify(nsITimer *timer);
|
|
|
|
nsIWebShell* mShell;
|
|
nsString mUrlSpec;
|
|
PRBool mRepeat;
|
|
PRInt32 mDelay;
|
|
|
|
protected:
|
|
virtual ~refreshData();
|
|
};
|
|
|
|
refreshData::refreshData()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
|
|
mShell = nsnull;
|
|
}
|
|
|
|
refreshData::~refreshData()
|
|
{
|
|
NS_IF_RELEASE(mShell);
|
|
}
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(refreshData, kITimerCallbackIID);
|
|
|
|
NS_IMETHODIMP_(void) refreshData::Notify(nsITimer *aTimer)
|
|
{
|
|
NS_PRECONDITION((nsnull != mShell), "Null pointer...");
|
|
if (nsnull != mShell) {
|
|
mShell->LoadURL(mUrlSpec.GetUnicode(), nsnull, PR_TRUE, nsIChannel::LOAD_NORMAL);
|
|
}
|
|
/*
|
|
* LoadURL(...) will cancel all refresh timers... This causes the Timer and
|
|
* its refreshData instance to be released...
|
|
*/
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::RefreshURI(nsIURI* aURI, PRInt32 millis, PRBool repeat)
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
if (nsnull == aURI) {
|
|
NS_PRECONDITION((aURI != nsnull), "Null pointer");
|
|
rv = NS_ERROR_NULL_POINTER;
|
|
goto done;
|
|
}
|
|
|
|
char* spec;
|
|
aURI->GetSpec(&spec);
|
|
rv = RefreshURL(spec, millis, repeat);
|
|
nsCRT::free(spec);
|
|
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::RefreshURL(const char* aURI, PRInt32 millis, PRBool repeat)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
nsITimer *timer=nsnull;
|
|
refreshData *data;
|
|
|
|
if (nsnull == aURI) {
|
|
NS_PRECONDITION((aURI != nsnull), "Null pointer");
|
|
rv = NS_ERROR_NULL_POINTER;
|
|
goto done;
|
|
}
|
|
|
|
NS_NEWXPCOM(data, refreshData);
|
|
if (nsnull == data) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
goto done;
|
|
}
|
|
|
|
// Set the reference count to one...
|
|
NS_ADDREF(data);
|
|
|
|
data->mShell = this;
|
|
NS_ADDREF(data->mShell);
|
|
|
|
data->mUrlSpec = aURI;
|
|
data->mDelay = millis;
|
|
data->mRepeat = repeat;
|
|
|
|
/* Create the timer. */
|
|
if (NS_OK == NS_NewTimer(&timer)) {
|
|
/* Add the timer to our array. */
|
|
NS_LOCK_INSTANCE();
|
|
mRefreshments.AppendElement(timer);
|
|
timer->Init(data, millis);
|
|
NS_UNLOCK_INSTANCE();
|
|
}
|
|
|
|
NS_RELEASE(data);
|
|
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::CancelRefreshURITimers(void)
|
|
{
|
|
PRInt32 i;
|
|
nsITimer* timer;
|
|
|
|
/* Right now all we can do is cancel all the timers for this webshell. */
|
|
NS_LOCK_INSTANCE();
|
|
|
|
/* Walk the list backwards to avoid copying the array as it shrinks.. */
|
|
for (i = mRefreshments.Count()-1; (0 <= i); i--) {
|
|
timer=(nsITimer*)mRefreshments.ElementAt(i);
|
|
/* Remove the entry from the list before releasing the timer.*/
|
|
mRefreshments.RemoveElementAt(i);
|
|
|
|
if (timer) {
|
|
timer->Cancel();
|
|
NS_RELEASE(timer);
|
|
}
|
|
}
|
|
NS_UNLOCK_INSTANCE();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/*
|
|
* There are cases where netlib does things like add a trailing slash
|
|
* to the url being retrieved. We need to watch out for such
|
|
* changes and update the currently loading url's entry in the history
|
|
* list. UpdateHistoryEntry() does this.
|
|
*
|
|
* Assumptions:
|
|
*
|
|
* 1) aURL is the URL that was inserted into the history list in LoadURL()
|
|
* 2) The load of aURL is in progress and this function is being called
|
|
* from one of the functions in nsIStreamListener implemented by nsWebShell.
|
|
*/
|
|
nsresult nsWebShell::CheckForTrailingSlash(nsIURI* aURL)
|
|
{
|
|
|
|
PRInt32 curIndex=0;
|
|
nsresult rv;
|
|
|
|
/* Get current history index and url for it */
|
|
rv = mSHist->GetCurrentIndex(&curIndex);
|
|
|
|
/* Get the url that netlib passed us */
|
|
char* spec;
|
|
aURL->GetSpec(&spec);
|
|
|
|
//Set it in session history
|
|
if (NS_SUCCEEDED(rv) && !mTitle.IsEmpty()) {
|
|
mSHist->SetTitleForIndex(curIndex, mTitle.GetUnicode());
|
|
// Replace the top most history entry with the new url
|
|
mSHist->SetURLForIndex(curIndex, spec);
|
|
}
|
|
nsCRT::free(spec);
|
|
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
NS_IMETHODIMP
|
|
nsWebShell::CanCutSelection(PRBool* aResult)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (nsnull == aResult) {
|
|
rv = NS_ERROR_NULL_POINTER;
|
|
} else {
|
|
*aResult = PR_FALSE;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::CanCopySelection(PRBool* aResult)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (nsnull == aResult) {
|
|
rv = NS_ERROR_NULL_POINTER;
|
|
} else {
|
|
*aResult = PR_FALSE;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::CanPasteSelection(PRBool* aResult)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (nsnull == aResult) {
|
|
rv = NS_ERROR_NULL_POINTER;
|
|
} else {
|
|
*aResult = PR_FALSE;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::CutSelection(void)
|
|
{
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::CopySelection(void)
|
|
{
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::PasteSelection(void)
|
|
{
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SelectAll(void)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIDocumentViewer> docViewer;
|
|
rv = mContentViewer->QueryInterface(kIDocumentViewerIID,
|
|
getter_AddRefs(docViewer));
|
|
if (NS_FAILED(rv) || !docViewer) return rv;
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
rv = docViewer->GetPresShell(*getter_AddRefs(presShell));
|
|
if (NS_FAILED(rv) || !presShell) return rv;
|
|
|
|
nsCOMPtr<nsIDOMSelection> selection;
|
|
rv = presShell->GetSelection(SELECTION_NORMAL, getter_AddRefs(selection));
|
|
if (NS_FAILED(rv) || !selection) return rv;
|
|
|
|
// Get the document object
|
|
nsCOMPtr<nsIDocument> doc;
|
|
rv = docViewer->GetDocument(*getter_AddRefs(doc));
|
|
if (NS_FAILED(rv) || !doc) return rv;
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLDocument> htmldoc;
|
|
rv = doc->QueryInterface(kIDOMHTMLDocumentIID, (void**)&htmldoc);
|
|
if (NS_FAILED(rv) || !htmldoc) return rv;
|
|
|
|
nsCOMPtr<nsIDOMHTMLElement>bodyElement;
|
|
rv = htmldoc->GetBody(getter_AddRefs(bodyElement));
|
|
if (NS_FAILED(rv) || !bodyElement) return rv;
|
|
|
|
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
|
|
if (!bodyNode) return NS_ERROR_NO_INTERFACE;
|
|
|
|
#if 0
|
|
rv = selection->Collapse(bodyNode, 0);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIDOMRange>range;
|
|
rv = selection->GetRangeAt(0, getter_AddRefs(range));
|
|
if (NS_FAILED(rv) || !range) return rv;
|
|
#endif
|
|
|
|
rv = selection->ClearSelection();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
rv = nsComponentManager::CreateInstance(kCDOMRangeCID, nsnull,
|
|
NS_GET_IID(nsIDOMRange),
|
|
getter_AddRefs(range));
|
|
|
|
rv = range->SelectNodeContents(bodyNode);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = selection->AddRange(range);
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SelectNone(void)
|
|
{
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------
|
|
NS_IMETHODIMP
|
|
nsWebShell::FindNext(const PRUnichar * aSearchStr, PRBool aMatchCase, PRBool aSearchDown, PRBool &aIsFound)
|
|
{
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
// Methods from nsIProgressEventSink
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnProgress(nsIChannel* channel, nsISupports* ctxt,
|
|
PRUint32 aProgress,
|
|
PRUint32 aProgressMax)
|
|
{
|
|
if (nsnull != mDocLoaderObserver)
|
|
{
|
|
return mDocLoaderObserver->OnProgressURLLoad(
|
|
mDocLoader,
|
|
channel,
|
|
aProgress,
|
|
aProgressMax);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnStatus(nsIChannel* channel, nsISupports* ctxt,
|
|
const PRUnichar* aMsg)
|
|
{
|
|
if (nsnull != mDocLoaderObserver)
|
|
{
|
|
nsAutoString temp(aMsg);
|
|
nsresult rv = mDocLoaderObserver->OnStatusURLLoad(
|
|
mDocLoader,
|
|
channel,
|
|
temp);
|
|
|
|
return rv;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
#define DIALOG_STRING_URI "chrome://global/locale/appstrings.properties"
|
|
|
|
nsresult nsWebShell::InitDialogVars(void)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
if (!mPrompter) {
|
|
// Get an nsIPrompt so we can throw dialogs.
|
|
nsCOMPtr<nsIWebShellContainer> topLevelWindow;
|
|
GetTopLevelWindow(getter_AddRefs(topLevelWindow));
|
|
if (topLevelWindow)
|
|
mPrompter = do_QueryInterface(topLevelWindow);
|
|
}
|
|
|
|
if (!mStringBundle) {
|
|
// Get a string bundle so we can retrieve dialog strings
|
|
nsCOMPtr<nsILocale> locale;
|
|
NS_WITH_SERVICE(nsILocaleService, localeServ, kLocaleServiceCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = localeServ->GetSystemLocale(getter_AddRefs(locale));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
NS_WITH_SERVICE(nsIStringBundleService, service, kCStringBundleServiceCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = service->CreateBundle(DIALOG_STRING_URI, locale, getter_AddRefs(mStringBundle));
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// nsWebShell::nsIBaseWindow
|
|
//*****************************************************************************
|
|
|
|
NS_IMETHODIMP nsWebShell::Create()
|
|
{
|
|
// Cache the PL_EventQueue of the current UI thread...
|
|
//
|
|
// Since this call must be made on the UI thread, we know the Event Queue
|
|
// will be associated with the current thread...
|
|
//
|
|
nsCOMPtr<nsIEventQueueService> eventService(do_GetService(kEventQueueServiceCID));
|
|
NS_ENSURE_TRUE(eventService, NS_ERROR_FAILURE);
|
|
|
|
NS_ENSURE_SUCCESS(eventService->GetThreadEventQueue(NS_CURRENT_THREAD,
|
|
&mThreadEventQueue), NS_ERROR_FAILURE);
|
|
|
|
//XXX make sure plugins have started up. this really needs to
|
|
//be associated with the nsIContentViewerContainer interfaces,
|
|
//not the nsIWebShell interfaces. this is a hack. MMP
|
|
CreatePluginHost(mAllowPlugins);
|
|
|
|
WEB_TRACE(WEB_TRACE_CALLS,
|
|
("nsWebShell::Init: this=%p", this));
|
|
|
|
// HACK....force the uri loader to give us a load cookie for this webshell...then get it's
|
|
// doc loader and store it...as more of the docshell lands, we'll be able to get rid
|
|
// of this hack...
|
|
nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_PROGID);
|
|
uriLoader->GetDocumentLoaderForContext(NS_STATIC_CAST( nsISupports*, (nsIWebShell *) this), &mDocLoader);
|
|
|
|
// Set the webshell as the default IContentViewerContainer for the loader...
|
|
mDocLoader->SetContainer(NS_STATIC_CAST(nsIContentViewerContainer*, (nsIWebShell*)this));
|
|
|
|
//Register ourselves as an observer for the new doc loader
|
|
mDocLoader->AddObserver((nsIDocumentLoaderObserver*)this);
|
|
|
|
return nsDocShell::Create();
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::Destroy()
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (!mFiredUnloadEvent) {
|
|
//Fire unload event before we blow anything away.
|
|
rv = FireUnloadEvent();
|
|
}
|
|
|
|
// Stop any URLs that are currently being loaded...
|
|
Stop();
|
|
mDocLoader->Destroy();
|
|
|
|
SetContainer(nsnull);
|
|
SetDocLoaderObserver(nsnull);
|
|
|
|
// Remove this docshell from its parent's child list
|
|
nsCOMPtr<nsIDocShellTreeNode> docShellParentAsNode(do_QueryInterface(mParent));
|
|
|
|
if (docShellParentAsNode) {
|
|
docShellParentAsNode->RemoveChild(this);
|
|
}
|
|
|
|
if (nsnull != mDocLoader) {
|
|
mDocLoader->SetContainer(nsnull);
|
|
}
|
|
|
|
mContentViewer = nsnull;
|
|
|
|
// Destroy our child web shells and release references to them
|
|
DestroyChildren();
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx,
|
|
PRInt32 cy, PRBool fRepaint)
|
|
{
|
|
mBounds.SetRect(x, y, cx, cy);
|
|
return nsDocShell::SetPositionAndSize(x, y, cx, cy, fRepaint);
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::GetPositionAndSize(PRInt32* x, PRInt32* y,
|
|
PRInt32* cx, PRInt32* cy)
|
|
{
|
|
if(x)
|
|
*x = mBounds.x;
|
|
if(y)
|
|
*y = mBounds.y;
|
|
if(cx)
|
|
*cx = mBounds.width;
|
|
if(cy)
|
|
*cy = mBounds.height;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
// nsWebShell::nsIDocShell
|
|
//*****************************************************************************
|
|
|
|
NS_IMETHODIMP nsWebShell::SetDocument(nsIDOMDocument *aDOMDoc,
|
|
nsIDOMElement *aRootNode)
|
|
{
|
|
// The tricky part is bypassing the normal load process and just putting a document into
|
|
// the webshell. This is particularly nasty, since webshells don't normally even know
|
|
// about their documents
|
|
|
|
// (1) Create a document viewer
|
|
nsCOMPtr<nsIContentViewer> documentViewer;
|
|
nsCOMPtr<nsIDocumentLoaderFactory> docFactory;
|
|
static NS_DEFINE_CID(kLayoutDocumentLoaderFactoryCID, NS_LAYOUT_DOCUMENT_LOADER_FACTORY_CID);
|
|
NS_ENSURE_SUCCESS(nsComponentManager::CreateInstance(kLayoutDocumentLoaderFactoryCID, nsnull,
|
|
NS_GET_IID(nsIDocumentLoaderFactory),
|
|
(void**)getter_AddRefs(docFactory)),
|
|
NS_ERROR_FAILURE);
|
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDOMDoc);
|
|
if (!doc) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
NS_ENSURE_SUCCESS(docFactory->CreateInstanceForDocument(NS_STATIC_CAST(nsIContentViewerContainer*, (nsIWebShell*)this),
|
|
doc,
|
|
"view",
|
|
getter_AddRefs(documentViewer)),
|
|
NS_ERROR_FAILURE);
|
|
|
|
// (2) Feed the webshell to the content viewer
|
|
NS_ENSURE_SUCCESS(documentViewer->SetContainer((nsIWebShell*)this), NS_ERROR_FAILURE);
|
|
|
|
// (3) Tell the content viewer container to embed the content viewer.
|
|
// (This step causes everything to be set up for an initial flow.)
|
|
NS_ENSURE_SUCCESS(SetupNewViewer(documentViewer), NS_ERROR_FAILURE);
|
|
|
|
// XXX: It would be great to get rid of this dummy channel!
|
|
const nsAutoString uriString = "about:blank";
|
|
nsCOMPtr<nsIURI> uri;
|
|
NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(uri), uriString), NS_ERROR_FAILURE);
|
|
if (!uri) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
|
|
nsCOMPtr<nsIChannel> dummyChannel;
|
|
NS_ENSURE_SUCCESS(NS_OpenURI(getter_AddRefs(dummyChannel), uri, nsnull), NS_ERROR_FAILURE);
|
|
|
|
// (4) fire start document load notification
|
|
nsCOMPtr<nsIStreamListener> outStreamListener; // a valid pointer is required for the returned stream listener
|
|
// XXX: warning: magic cookie! should get string "view delayedContentLoad"
|
|
// from somewhere, maybe nsIHTMLDocument?
|
|
NS_ENSURE_SUCCESS(doc->StartDocumentLoad("view delayedContentLoad", dummyChannel, nsnull, NS_STATIC_CAST(nsIContentViewerContainer*, (nsIWebShell*)this),
|
|
getter_AddRefs(outStreamListener)),
|
|
NS_ERROR_FAILURE);
|
|
NS_ENSURE_SUCCESS(OnStartDocumentLoad(mDocLoader, uri, "load"), NS_ERROR_FAILURE);
|
|
|
|
// (5) hook up the document and its content
|
|
nsCOMPtr<nsIContent> rootContent = do_QueryInterface(aRootNode);
|
|
if (!doc) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
NS_ENSURE_SUCCESS(rootContent->SetDocument(doc, PR_FALSE), NS_ERROR_FAILURE);
|
|
doc->SetRootContent(rootContent);
|
|
rootContent->SetDocument(doc, PR_TRUE);
|
|
|
|
// (6) reflow the document
|
|
PRInt32 i;
|
|
PRInt32 ns = doc->GetNumberOfShells();
|
|
for (i = 0; i < ns; i++)
|
|
{
|
|
nsCOMPtr<nsIPresShell> shell(dont_AddRef(doc->GetShellAt(i)));
|
|
if (shell)
|
|
{
|
|
// Make shell an observer for next time
|
|
NS_ENSURE_SUCCESS(shell->BeginObservingDocument(), NS_ERROR_FAILURE);
|
|
|
|
// Resize-reflow this time
|
|
nsCOMPtr<nsIDocumentViewer> docViewer = do_QueryInterface(documentViewer);
|
|
if (!docViewer) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
nsCOMPtr<nsIPresContext> presContext;
|
|
NS_ENSURE_SUCCESS(docViewer->GetPresContext(*(getter_AddRefs(presContext))), NS_ERROR_FAILURE);
|
|
if (!presContext) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
float p2t;
|
|
presContext->GetScaledPixelsToTwips(&p2t);
|
|
|
|
nsRect r;
|
|
GetPositionAndSize(&r.x, &r.y, &r.width, &r.height);
|
|
NS_ENSURE_SUCCESS(shell->InitialReflow(NSToCoordRound(r.width * p2t), NSToCoordRound(r.height * p2t)), NS_ERROR_FAILURE);
|
|
|
|
// Now trigger a refresh
|
|
nsCOMPtr<nsIViewManager> vm;
|
|
NS_ENSURE_SUCCESS(shell->GetViewManager(getter_AddRefs(vm)), NS_ERROR_FAILURE);
|
|
if (vm)
|
|
{
|
|
PRBool enabled;
|
|
documentViewer->GetEnableRendering(&enabled);
|
|
if (enabled) {
|
|
vm->EnableRefresh(NS_VMREFRESH_IMMEDIATE);
|
|
}
|
|
NS_ENSURE_SUCCESS(vm->SetWindowDimensions(NSToCoordRound(r.width * p2t),
|
|
NSToCoordRound(r.height * p2t)),
|
|
NS_ERROR_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// (7) fire end document load notification
|
|
mProcessedEndDocumentLoad = PR_FALSE;
|
|
nsresult rv = NS_OK;
|
|
NS_ENSURE_SUCCESS(OnEndDocumentLoad(mDocLoader, dummyChannel, rv), NS_ERROR_FAILURE);
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); // test the resulting out-param separately
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::GetParentContentListener(nsIURIContentListener** aParent)
|
|
{
|
|
return GetParentURIContentListener(aParent);
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::SetParentContentListener(nsIURIContentListener* aParent)
|
|
{
|
|
return SetParentURIContentListener(aParent);
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::GetLoadCookie(nsISupports ** aLoadCookie)
|
|
{
|
|
NS_ENSURE_SUCCESS(EnsureContentListener(), NS_ERROR_FAILURE);
|
|
return mContentListener->GetLoadCookie(aLoadCookie);
|
|
}
|
|
|
|
NS_IMETHODIMP nsWebShell::SetLoadCookie(nsISupports * aLoadCookie)
|
|
{
|
|
NS_ENSURE_SUCCESS(EnsureContentListener(), NS_ERROR_FAILURE);
|
|
return mContentListener->SetLoadCookie(aLoadCookie);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Factory code for creating nsWebShell's
|
|
|
|
class nsWebShellFactory : public nsIFactory
|
|
{
|
|
public:
|
|
nsWebShellFactory();
|
|
virtual ~nsWebShellFactory();
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIFactory methods
|
|
NS_IMETHOD CreateInstance(nsISupports *aOuter,
|
|
const nsIID &aIID,
|
|
void **aResult);
|
|
|
|
NS_IMETHOD LockFactory(PRBool aLock);
|
|
};
|
|
|
|
nsWebShellFactory::nsWebShellFactory()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsWebShellFactory::~nsWebShellFactory()
|
|
{
|
|
}
|
|
|
|
NS_IMPL_ADDREF(nsWebShellFactory);
|
|
NS_IMPL_RELEASE(nsWebShellFactory);
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsWebShellFactory)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_ENTRY(nsIFactory)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
nsresult
|
|
nsWebShellFactory::CreateInstance(nsISupports *aOuter,
|
|
const nsIID &aIID,
|
|
void **aResult)
|
|
{
|
|
nsresult rv;
|
|
nsWebShell *inst;
|
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
NS_ENSURE_NO_AGGREGATION(aOuter);
|
|
*aResult = NULL;
|
|
|
|
NS_NEWXPCOM(inst, nsWebShell);
|
|
NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
NS_ADDREF(inst);
|
|
rv = inst->QueryInterface(aIID, aResult);
|
|
NS_RELEASE(inst);
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsWebShellFactory::LockFactory(PRBool aLock)
|
|
{
|
|
// Not implemented in simplest case.
|
|
return NS_OK;
|
|
}
|
|
|
|
extern "C" NS_WEB nsresult
|
|
NS_NewWebShellFactory(nsIFactory** aFactory)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
nsIFactory* inst = new nsWebShellFactory();
|
|
if (nsnull == inst) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
else {
|
|
NS_ADDREF(inst);
|
|
}
|
|
*aFactory = inst;
|
|
return rv;
|
|
}
|