gecko-dev/docshell/base/nsWebShell.cpp
troy%netscape.com 161acbaff9 Changed GetLinkState() to remember that it failed to load the global
history service and that way it won't repeatedly try and fail. That was
causing performance problems for viewer
1999-08-24 18:20:30 +00:00

4244 lines
108 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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.
*/
#include "nsIWebShell.h"
#include "nsIDocumentLoader.h"
#include "nsIContentViewer.h"
#include "nsIDocumentViewer.h"
#include "nsIClipboardCommands.h"
#include "nsIDeviceContext.h"
#include "nsILinkHandler.h"
#include "nsIStreamListener.h"
#ifdef NECKO
#include "nsIPrompt.h"
#include "nsNeckoUtil.h"
#include "nsIProtocolHandler.h"
#include "nsIDNSService.h"
#include "nsIRefreshURI.h"
#else
#include "nsINetSupport.h"
#include "nsIRefreshUrl.h"
#include "jsurl.h"
#endif
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContextOwner.h"
#include "nsIDocumentLoaderObserver.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 "nsIBrowserWindow.h"
#include "nsIContent.h"
#include "prlog.h"
#include "nsCOMPtr.h"
#include "nsIPresShell.h"
#include "nsIStreamObserver.h"
#include "nsIWebShellServices.h"
#include "nsIGlobalHistory.h"
#include "prmem.h"
#include "nsXPIDLString.h"
#ifdef XP_PC
#include <windows.h>
#endif
//XXX used for nsIStreamObserver implementation. This sould be replaced by DocLoader
// notifications...
#include "nsIURL.h"
#ifdef NECKO
#include "nsIIOService.h"
#include "nsIURL.h"
#endif // NECKO
//XXX for nsIPostData; this is wrong; we shouldn't see the nsIDocument type
#include "nsIDocument.h"
#ifdef DEBUG
#undef NOISY_LINKS
#else
#undef NOISY_LINKS
#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 OLD_HISTORY 1
#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);
#ifdef NECKO
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
#endif // NECKO
static nsAutoString LinkCommand("linkclick");
//----------------------------------------------------------------------
class nsWebShell : public nsIWebShell,
public nsIWebShellContainer,
public nsIWebShellServices,
public nsILinkHandler,
public nsIScriptContextOwner,
public nsIDocumentLoaderObserver,
#ifdef NECKO
public nsIPrompt,
public nsIRefreshURI,
#else
public nsIRefreshUrl,
public nsINetSupport,
#endif
// public nsIStreamObserver,
public nsIClipboardCommands
{
public:
nsWebShell();
virtual ~nsWebShell();
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
// nsISupports
NS_DECL_ISUPPORTS
// nsIContentViewerContainer
NS_IMETHOD QueryCapability(const nsIID &aIID, void** aResult);
NS_IMETHOD Embed(nsIContentViewer* aDocViewer,
const char* aCommand,
nsISupports* aExtraInfo);
NS_IMETHOD GetContentViewer(nsIContentViewer** aResult);
// nsIWebShell
NS_IMETHOD Init(nsNativeWidget aNativeParent,
PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h,
nsScrollPreference aScrolling = nsScrollPreference_kAuto,
PRBool aAllowPlugins = PR_TRUE,
PRBool aIsSunkenBorder = PR_FALSE);
NS_IMETHOD Destroy(void);
NS_IMETHOD GetBounds(PRInt32 &x, PRInt32 &y, PRInt32 &w, PRInt32 &h);
NS_IMETHOD SetBounds(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h);
NS_IMETHOD MoveTo(PRInt32 aX, PRInt32 aY);
NS_IMETHOD Show();
NS_IMETHOD Hide();
NS_IMETHOD SetFocus();
NS_IMETHOD RemoveFocus();
NS_IMETHOD Repaint(PRBool aForce);
NS_IMETHOD SetContentViewer(nsIContentViewer* aViewer);
NS_IMETHOD SetContainer(nsIWebShellContainer* aContainer);
NS_IMETHOD GetContainer(nsIWebShellContainer*& aResult);
NS_IMETHOD SetObserver(nsIStreamObserver* anObserver);
NS_IMETHOD GetObserver(nsIStreamObserver*& aResult);
NS_IMETHOD SetDocLoaderObserver(nsIDocumentLoaderObserver* anObserver);
NS_IMETHOD GetDocLoaderObserver(nsIDocumentLoaderObserver*& aResult);
NS_IMETHOD SetPrefs(nsIPref* aPrefs);
NS_IMETHOD GetPrefs(nsIPref*& aPrefs);
NS_IMETHOD GetRootWebShell(nsIWebShell*& aResult);
NS_IMETHOD GetRootWebShellEvenIfChrome(nsIWebShell*& aResult);
NS_IMETHOD SetParent(nsIWebShell* aParent);
NS_IMETHOD GetParent(nsIWebShell*& aParent);
NS_IMETHOD GetParentEvenIfChrome(nsIWebShell*& aParent);
NS_IMETHOD GetChildCount(PRInt32& aResult);
NS_IMETHOD AddChild(nsIWebShell* aChild);
NS_IMETHOD RemoveChild(nsIWebShell* aChild);
NS_IMETHOD ChildAt(PRInt32 aIndex, nsIWebShell*& aResult);
NS_IMETHOD GetName(const PRUnichar** aName);
NS_IMETHOD SetName(const PRUnichar* aName);
NS_IMETHOD FindChildWithName(const PRUnichar* aName,
nsIWebShell*& aResult);
NS_IMETHOD SetWebShellType(nsWebShellType aWebShellType);
NS_IMETHOD GetWebShellType(nsWebShellType& aWebShellType);
NS_IMETHOD GetContainingChromeShell(nsIWebShell** aResult);
NS_IMETHOD SetContainingChromeShell(nsIWebShell* aChromeShell);
NS_IMETHOD GetMarginWidth (PRInt32& aWidth);
NS_IMETHOD SetMarginWidth (PRInt32 aWidth);
NS_IMETHOD GetMarginHeight(PRInt32& aWidth);
NS_IMETHOD SetMarginHeight(PRInt32 aHeight);
NS_IMETHOD GetScrolling(PRInt32& aScrolling);
NS_IMETHOD SetScrolling(PRInt32 aScrolling, PRBool aSetCurrentAndInitial = PR_TRUE);
NS_IMETHOD GetIsFrame(PRBool& aIsFrame);
NS_IMETHOD SetIsFrame(PRBool aIsFrame);
NS_IMETHOD SetZoom(float aZoom);
NS_IMETHOD GetZoom(float *aZoom);
// Document load api's
NS_IMETHOD GetDocumentLoader(nsIDocumentLoader*& aResult);
NS_IMETHOD LoadURL(const PRUnichar *aURLSpec,
nsIInputStream* aPostDataStream=nsnull,
PRBool aModifyHistory=PR_TRUE,
#ifdef NECKO
nsLoadFlags aType = nsIChannel::LOAD_NORMAL,
#else
nsURLReloadType aType = nsURLReload,
#endif
const PRUint32 localIP = 0);
NS_IMETHOD LoadURL(const PRUnichar *aURLSpec,
const char* aCommand,
nsIInputStream* aPostDataStream=nsnull,
PRBool aModifyHistory=PR_TRUE,
#ifdef NECKO
nsLoadFlags aType = nsIChannel::LOAD_NORMAL,
#else
nsURLReloadType aType = nsURLReload,
#endif
const PRUint32 localIP = 0);
NS_IMETHOD Stop(void);
#ifdef NECKO
NS_IMETHOD Reload(nsLoadFlags aType);
#else
NS_IMETHOD Reload(nsURLReloadType aType);
#endif
// History api's
NS_IMETHOD Back(void);
NS_IMETHOD CanBack(void);
NS_IMETHOD Forward(void);
NS_IMETHOD CanForward(void);
NS_IMETHOD GoTo(PRInt32 aHistoryIndex);
NS_IMETHOD GetHistoryLength(PRInt32& aResult);
NS_IMETHOD GetHistoryIndex(PRInt32& aResult);
NS_IMETHOD GetURL(PRInt32 aHistoryIndex, const PRUnichar** aURLResult);
// Chrome api's
NS_IMETHOD SetTitle(const PRUnichar* aTitle);
NS_IMETHOD GetTitle(const PRUnichar** aResult);
// 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 NewWebShell(PRUint32 aChromeMask,
PRBool aVisible,
nsIWebShell *&aNewWebShell);
NS_IMETHOD ContentShellAdded(nsIWebShell* aChildShell, nsIContent* frameNode);
NS_IMETHOD CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent,
PRInt32 aXPos, PRInt32 aYPos,
const nsString& aPopupType, const nsString& anAnchorAlignment,
const nsString& aPopupAlignment,
nsIDOMWindow* aWindow, nsIDOMWindow** outPopup);
NS_IMETHOD FindWebShellWithName(const PRUnichar* aName, nsIWebShell*& aResult);
NS_IMETHOD FocusAvailable(nsIWebShell* aFocusedWebShell, PRBool& aFocusTaken);
// nsIWebShellServices
NS_IMETHOD LoadDocument(const char* aURL,
const char* aCharset= nsnull ,
nsCharsetSource aSource = kCharsetUninitialized);
NS_IMETHOD ReloadDocument(const char* aCharset= nsnull ,
nsCharsetSource aSource = kCharsetUninitialized);
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);
// nsIScriptContextOwner
NS_IMETHOD GetScriptContext(nsIScriptContext **aContext);
NS_IMETHOD GetScriptGlobalObject(nsIScriptGlobalObject **aGlobal);
NS_IMETHOD ReleaseScriptContext(nsIScriptContext *aContext);
#ifdef NECKO
// nsIDocumentLoaderObserver
NS_IMETHOD OnStartDocumentLoad(nsIDocumentLoader* loader,
nsIURI* aURL,
const char* aCommand);
NS_IMETHOD OnEndDocumentLoad(nsIDocumentLoader* loader,
nsIChannel* channel,
nsresult aStatus,
nsIDocumentLoaderObserver * );
NS_IMETHOD OnStartURLLoad(nsIDocumentLoader* loader,
nsIChannel* channel,
nsIContentViewer* aViewer);
NS_IMETHOD OnProgressURLLoad(nsIDocumentLoader* loader,
nsIChannel* channel, PRUint32 aProgress,
PRUint32 aProgressMax);
NS_IMETHOD OnStatusURLLoad(nsIDocumentLoader* loader,
nsIChannel* channel, nsString& aMsg);
NS_IMETHOD OnEndURLLoad(nsIDocumentLoader* loader,
nsIChannel* channel, nsresult aStatus);
NS_IMETHOD HandleUnknownContentType(nsIDocumentLoader* loader,
nsIChannel* channel,
const char *aContentType,
const char *aCommand );
#else
// nsIDocumentLoaderObserver
NS_IMETHOD OnStartDocumentLoad(nsIDocumentLoader* loader,
nsIURI* aURL,
const char* aCommand);
NS_IMETHOD OnEndDocumentLoad(nsIDocumentLoader* loader,
nsIURI* aURL,
PRInt32 aStatus,
nsIDocumentLoaderObserver * );
NS_IMETHOD OnStartURLLoad(nsIDocumentLoader* loader,
nsIURI* aURL, const char* aContentType,
nsIContentViewer* aViewer);
NS_IMETHOD OnProgressURLLoad(nsIDocumentLoader* loader,
nsIURI* aURL, PRUint32 aProgress,
PRUint32 aProgressMax);
NS_IMETHOD OnStatusURLLoad(nsIDocumentLoader* loader,
nsIURI* aURL, nsString& aMsg);
NS_IMETHOD OnEndURLLoad(nsIDocumentLoader* loader,
nsIURI* aURL, PRInt32 aStatus);
NS_IMETHOD HandleUnknownContentType(nsIDocumentLoader* loader,
nsIURI* aURL,
const char *aContentType,
const char *aCommand );
#endif
// NS_IMETHOD OnConnectionsComplete();
NS_IMETHOD RefreshURL(const char* aURL, PRInt32 millis, PRBool repeat);
// nsIRefreshURL interface methods...
#ifndef NECKO
NS_IMETHOD RefreshURL(nsIURI* aURL, PRInt32 aMillis, PRBool aRepeat);
NS_IMETHOD CancelRefreshURLTimers(void);
#else
NS_IMETHOD RefreshURI(nsIURI* aURI, PRInt32 aMillis, PRBool aRepeat);
NS_IMETHOD CancelRefreshURITimers(void);
#endif // NECKO
#if 0
// nsIStreamObserver
NS_IMETHOD OnStartRequest(nsIURI* aURL, const char *aContentType);
NS_IMETHOD OnProgress(nsIURI* aURL, PRUint32 aProgress, PRUint32 aProgressMax);
NS_IMETHOD OnStatus(nsIURI* aURL, const PRUnichar* aMsg);
NS_IMETHOD OnStopRequest(nsIURI* aURL, nsresult aStatus, const PRUnichar* aMsg);
#endif /* 0 */
#ifdef NECKO
// nsIPrompt
NS_DECL_NSIPROMPT
#else
// nsINetSupport interface methods
NS_IMETHOD_(void) Alert(const nsString &aText);
NS_IMETHOD_(PRBool) Confirm(const nsString &aText);
NS_IMETHOD_(PRBool) ConfirmYN(const nsString &aText);
NS_IMETHOD_(PRBool) Prompt(const nsString &aText,
const nsString &aDefault,
nsString &aResult);
NS_IMETHOD_(PRBool) PromptUserAndPassword(const nsString &aText,
nsString &aUser,
nsString &aPassword);
NS_IMETHOD_(PRBool) PromptPassword(const nsString &aText,
nsString &aPassword);
#endif
// 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);
// nsWebShell
nsIEventQueue* GetEventQueue(void);
void HandleLinkClickEvent(nsIContent *aContent,
nsLinkVerb aVerb,
const PRUnichar* aURLSpec,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream = 0);
void ShowHistory();
nsIWebShell* GetTarget(const PRUnichar* aName);
nsIBrowserWindow* GetBrowserWindow(void);
static void RefreshURLCallback(nsITimer* aTimer, void* aClosure);
static nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent);
nsresult CreatePluginHost(PRBool aAllowPlugins);
nsresult DestroyPluginHost(void);
NS_IMETHOD IsBusy(PRBool& aResult);
NS_IMETHOD GetDefaultCharacterSet (const PRUnichar** aDefaultCharacterSet);
NS_IMETHOD SetDefaultCharacterSet (const PRUnichar* aDefaultCharacterSet);
NS_IMETHOD GetForceCharacterSet (const PRUnichar** aForceCharacterSet);
NS_IMETHOD SetForceCharacterSet (const PRUnichar* aForceCharacterSet);
NS_IMETHOD GetCharacterSetHint (const PRUnichar** oHintCharset, nsCharsetSource* oSource);
NS_IMETHOD SetSessionHistory(nsISessionHistory * aSHist);
NS_IMETHOD GetSessionHistory(nsISessionHistory *& aResult);
NS_IMETHOD SetIsInSHist(PRBool aIsFrame);
NS_IMETHOD GetIsInSHist(PRBool& aIsFrame);
NS_IMETHOD GetURL(const PRUnichar** aURL);
NS_IMETHOD SetURL(const PRUnichar* aURL);
NS_IMETHOD SetUrlDispatcher(nsIUrlDispatcher * anObserver);
NS_IMETHOD GetUrlDispatcher(nsIUrlDispatcher *& aResult);
protected:
void InitFrameData(PRBool aCompleteInitScrolling);
nsresult CheckForTrailingSlash(nsIURI* aURL);
nsresult StopBeforeRequestingURL(void);
nsresult StopAfterURLAvailable(void);
nsIEventQueue* mThreadEventQueue;
nsIScriptGlobalObject *mScriptGlobal;
nsIScriptContext* mScriptContext;
nsIStreamObserver * mObserver;
nsIWebShellContainer* mContainer;
nsIContentViewer* mContentViewer;
nsIDeviceContext* mDeviceContext;
nsIPref* mPrefs;
nsIWidget* mWindow;
nsIDocumentLoader* mDocLoader;
nsIDocumentLoaderObserver* mDocLoaderObserver;
nsIUrlDispatcher * mUrlDispatcher;
#ifdef NECKO
nsIPrompt* mPrompter;
#else
nsINetSupport* mNetSupport;
#endif
nsIWebShell* mParent;
nsVoidArray mChildren;
nsString mName;
nsString mDefaultCharacterSet;
nsVoidArray mHistory;
PRInt32 mHistoryIndex;
nsIGlobalHistory* mHistoryService;
nsISessionHistory * mSHist;
nsString mTitle;
nsString mURL;
nsString mOverURL;
nsString mOverTarget;
PRPackedBool mIsInSHist;
PRPackedBool mIsFrame;
PRPackedBool mFailedToLoadHistoryService;
nsScrollPreference mScrollPref;
PRInt32 mMarginWidth;
PRInt32 mMarginHeight;
PRInt32 mScrolling[2];
nsVoidArray mRefreshments;
nsWebShellType mWebShellType;
nsIWebShell* mChromeShell; // Weak reference.
void ReleaseChildren();
void DestroyChildren();
nsresult CreateScriptEnvironment();
nsresult DoLoadURL(const nsString& aUrlSpec,
const char* aCommand,
nsIInputStream* aPostDataStream,
#ifdef NECKO
nsLoadFlags aType,
#else
nsURLReloadType aType,
#endif
const PRUint32 aLocalIP);
float mZoom;
static nsIPluginHost *mPluginHost;
static nsIPluginManager *mPluginManager;
static PRUint32 mPluginInitCnt;
PRBool mProcessedEndDocumentLoad;
// XXX store mHintCharset and mHintCharsetSource here untill we find out a good cood path
nsString mHintCharset;
nsCharsetSource mHintCharsetSource;
nsString mForceCharacterSet;
// if there is no mWindow, this will keep track of the bounds --dwc0001
nsRect mBounds;
};
//----------------------------------------------------------------------
// Class IID's
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_IID(kChildCID, NS_CHILD_CID);
static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_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(kIDocumentLoaderObserverIID,
NS_IDOCUMENT_LOADER_OBSERVER_IID);
static NS_DEFINE_IID(kIDeviceContextIID, NS_IDEVICE_CONTEXT_IID);
static NS_DEFINE_IID(kIDocumentLoaderIID, NS_IDOCUMENTLOADER_IID);
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
static NS_DEFINE_IID(kIScriptContextOwnerIID, NS_ISCRIPTCONTEXTOWNER_IID);
static NS_DEFINE_IID(kIStreamObserverIID, NS_ISTREAMOBSERVER_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
#ifndef NECKO
static NS_DEFINE_IID(kINetSupportIID, NS_INETSUPPORT_IID);
static NS_DEFINE_IID(kRefreshURLIID, NS_IREFRESHURL_IID);
#else
static NS_DEFINE_IID(kRefreshURIIID, NS_IREFRESHURI_IID);
#endif
static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID);
static NS_DEFINE_IID(kIWebShellServicesIID, NS_IWEB_SHELL_SERVICES_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(kCPluginHostCID, NS_PLUGIN_HOST_CID);
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(kIBrowserWindowIID, NS_IBROWSER_WINDOW_IID);
static NS_DEFINE_IID(kIClipboardCommandsIID, NS_ICLIPBOARDCOMMANDS_IID);
static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID);
static NS_DEFINE_IID(kISessionHistoryIID, NS_ISESSION_HISTORY_IID);
// 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()
{
NS_INIT_REFCNT();
mHistoryIndex = -1;
mScrollPref = nsScrollPreference_kAuto;
mScriptGlobal = nsnull;
mScriptContext = nsnull;
mThreadEventQueue = nsnull;
InitFrameData(PR_TRUE);
mIsFrame = PR_FALSE;
mWebShellType = nsWebShellContent;
mChromeShell = nsnull;
mSHist = nsnull;
mIsInSHist = PR_FALSE;
mFailedToLoadHistoryService = PR_FALSE;
mDefaultCharacterSet = "";
mProcessedEndDocumentLoad = PR_FALSE;
mHintCharset = "";
mHintCharsetSource = kCharsetUninitialized;
mForceCharacterSet = "";
mHistoryService = nsnull;
#ifdef NECKO
mPrompter = nsnull;
#else
mNetSupport = nsnull;
#endif
}
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.
#ifndef NECKO
CancelRefreshURLTimers();
#else
CancelRefreshURITimers();
#endif // NECKO
++mRefCnt; // following releases can cause this destructor to be called
// recursively if the refcount is allowed to remain 0
NS_IF_RELEASE(mWindow);
NS_IF_RELEASE(mThreadEventQueue);
NS_IF_RELEASE(mContentViewer);
NS_IF_RELEASE(mDeviceContext);
NS_IF_RELEASE(mPrefs);
NS_IF_RELEASE(mContainer);
NS_IF_RELEASE(mObserver);
#ifdef NECKO
NS_IF_RELEASE(mPrompter);
#else
NS_IF_RELEASE(mNetSupport);
#endif
if (nsnull != mScriptGlobal) {
mScriptGlobal->SetWebShell(nsnull);
NS_RELEASE(mScriptGlobal);
}
NS_IF_RELEASE(mScriptContext);
InitFrameData(PR_TRUE);
mIsFrame = PR_FALSE;
// XXX Because we hold references to the children and they hold references
// to us we never get destroyed. See Destroy() instead...
#if 0
// Release references on our children
ReleaseChildren();
#endif
// Free up history memory
PRInt32 i, n = mHistory.Count();
for (i = 0; i < n; i++) {
nsString* s = (nsString*) mHistory.ElementAt(i);
delete s;
}
DestroyPluginHost();
}
void nsWebShell::InitFrameData(PRBool aCompleteInitScrolling)
{
if (aCompleteInitScrolling) {
mScrolling[0] = -1;
mScrolling[1] = -1;
mMarginWidth = -1;
mMarginHeight = -1;
}
else {
mScrolling[1] = mScrolling[0];
}
}
void
nsWebShell::ReleaseChildren()
{
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
nsIWebShell* shell = (nsIWebShell*) mChildren.ElementAt(i);
shell->SetParent(nsnull);
//Break circular reference of webshell to contentviewer
shell->SetContentViewer(nsnull);
NS_RELEASE(shell);
}
mChildren.Clear();
}
void
nsWebShell::DestroyChildren()
{
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
nsIWebShell* shell = (nsIWebShell*) mChildren.ElementAt(i);
shell->SetParent(nsnull);
shell->Destroy();
NS_RELEASE(shell);
}
mChildren.Clear();
}
NS_IMETHODIMP_(nsrefcnt) nsWebShell::AddRef(void)
{
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
++mRefCnt;
return mRefCnt;
}
NS_IMETHODIMP_(nsrefcnt) nsWebShell::Release(void)
{
NS_PRECONDITION(0 != mRefCnt, "dup release");
--mRefCnt;
if (mRefCnt == 0) {
NS_DELETEXPCOM(this);
return 0;
}
return mRefCnt;
}
nsresult
nsWebShell::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
nsresult rv = NS_NOINTERFACE;
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIWebShellServicesIID)) {
*aInstancePtr = (void*)(nsIWebShellServices*)this;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIWebShellIID)) {
*aInstancePtr = (void*)(nsIWebShell*)this;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIContentViewerContainerIID)) {
*aInstancePtr = (void*)(nsIContentViewerContainer*)this;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIScriptContextOwnerIID)) {
*aInstancePtr = (void*)(nsIScriptContextOwner*)this;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIDocumentLoaderObserverIID)) {
*aInstancePtr = (void*)(nsIDocumentLoaderObserver*)this;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIWebShellContainerIID)) {
*aInstancePtr = (void*)(nsIWebShellContainer*)this;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kILinkHandlerIID)) {
//I added this for plugin support of jumping
//through links. maybe there is a better way... MMP
*aInstancePtr = (void*)(nsILinkHandler*)this;
NS_ADDREF_THIS();
return NS_OK;
}
#ifdef NECKO
if (aIID.Equals(nsIPrompt::GetIID())) {
*aInstancePtr = (void*) ((nsIPrompt*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kRefreshURIIID)) {
*aInstancePtr = (void*) ((nsIRefreshURI*)this);
NS_ADDREF_THIS();
return NS_OK;
}
#else
if (aIID.Equals(kINetSupportIID)) {
*aInstancePtr = (void*) ((nsINetSupport*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kRefreshURLIID)) {
*aInstancePtr = (void*)((nsIRefreshUrl*)this);
NS_ADDREF_THIS();
return NS_OK;
}
#endif // NECKO
if (aIID.Equals(kIClipboardCommandsIID)) {
*aInstancePtr = (void*) ((nsIClipboardCommands*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
*aInstancePtr = (void*)(nsISupports*)(nsIWebShell*)this;
NS_ADDREF_THIS();
return NS_OK;
}
#if defined(NS_DEBUG)
/*
* Check for the debug-only interface indicating thread-safety
*/
static NS_DEFINE_IID(kIsThreadsafeIID, NS_ISTHREADSAFE_IID);
if (aIID.Equals(kIsThreadsafeIID)) {
return NS_OK;
}
#endif /* NS_DEBUG */
return rv;
}
NS_IMETHODIMP
nsWebShell::QueryCapability(const nsIID &aIID, void** aInstancePtr)
{
if (nsnull == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kILinkHandlerIID)) {
*aInstancePtr = (void*) ((nsILinkHandler*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIScriptContextOwnerIID)) {
*aInstancePtr = (void*) ((nsIScriptContextOwner*)this);
NS_ADDREF_THIS();
return NS_OK;
}
//XXX this seems a little wrong. MMP
if (nsnull != mPluginManager)
return mPluginManager->QueryInterface(aIID, aInstancePtr);
return NS_NOINTERFACE;
}
NS_IMETHODIMP
nsWebShell::Embed(nsIContentViewer* aContentViewer,
const char* aCommand,
nsISupports* aExtraInfo)
{
nsresult rv;
nsRect bounds;
WEB_TRACE(WEB_TRACE_CALLS,
("nsWebShell::Embed: this=%p aDocViewer=%p aCommand=%s aExtraInfo=%p",
this, aContentViewer, aCommand ? aCommand : "", aExtraInfo));
NS_IF_RELEASE(mContentViewer);
if (nsnull != mScriptContext) {
mScriptContext->GC();
}
mContentViewer = aContentViewer;
NS_ADDREF(aContentViewer);
// check to see if we have a window to embed into --dwc0001
if(mWindow) {
mWindow->GetClientBounds(bounds);
bounds.x = bounds.y = 0;
rv = mContentViewer->Init(mWindow->GetNativeData(NS_NATIVE_WIDGET),
mDeviceContext,
mPrefs,
bounds,
mScrollPref);
if (NS_SUCCEEDED(rv)) {
mContentViewer->Show();
}
} else {
mContentViewer = nsnull;
}
// Now that we have switched documents, forget all of our children
DestroyChildren();
return rv;
}
NS_IMETHODIMP
nsWebShell::GetContentViewer(nsIContentViewer** aResult)
{
nsresult rv = NS_OK;
if (nsnull == aResult) {
rv = NS_ERROR_NULL_POINTER;
} else {
*aResult = mContentViewer;
NS_IF_ADDREF(mContentViewer);
}
return rv;
}
NS_IMETHODIMP
nsWebShell::HandleUnknownContentType(nsIDocumentLoader* loader,
#ifdef NECKO
nsIChannel* channel,
#else
nsIURI* aURL,
#endif
const char *aContentType,
const char *aCommand ) {
// If we have a doc loader observer, let it respond to this.
#ifdef NECKO
return mDocLoaderObserver ? mDocLoaderObserver->HandleUnknownContentType( mDocLoader, channel, aContentType, aCommand )
#else
return mDocLoaderObserver ? mDocLoaderObserver->HandleUnknownContentType( mDocLoader, aURL, aContentType, aCommand )
#endif
: NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsWebShell::Init(nsNativeWidget aNativeParent,
PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h,
nsScrollPreference aScrolling,
PRBool aAllowPlugins,
PRBool aIsSunkenBorder)
{
nsresult rv = NS_OK;
// 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...
//
nsIEventQueueService* eventService;
rv = nsServiceManager::GetService(kEventQueueServiceCID,
kIEventQueueServiceIID,
(nsISupports **)&eventService);
if (NS_SUCCEEDED(rv)) {
// XXX: What if this fails?
rv = eventService->GetThreadEventQueue(PR_GetCurrentThread(),
&mThreadEventQueue);
nsServiceManager::ReleaseService(kEventQueueServiceCID, eventService);
}
//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
nsRect aBounds(x,y,w,h);
mBounds.SetRect(x,y,w,h); // initialize the webshells bounds --dwc0001
nsWidgetInitData widgetInit;
CreatePluginHost(aAllowPlugins);
//mScrollPref = aScrolling;
WEB_TRACE(WEB_TRACE_CALLS,
("nsWebShell::Init: this=%p", this));
/* it is ok to have a webshell without an aNativeParent (used later to create the mWindow --dwc0001
// Initial error checking...
NS_PRECONDITION(nsnull != aNativeParent, "null Parent Window");
if (nsnull == aNativeParent) {
rv = NS_ERROR_NULL_POINTER;
goto done;
}
*/
// Create a document loader...
if (nsnull != mParent) {
nsIDocumentLoader* parentLoader;
// Create a child document loader...
rv = mParent->GetDocumentLoader(parentLoader);
if (NS_SUCCEEDED(rv)) {
rv = parentLoader->CreateDocumentLoader(&mDocLoader);
NS_RELEASE(parentLoader);
}
} else {
nsIDocumentLoader* docLoaderService;
// Get the global document loader service...
rv = nsServiceManager::GetService(kDocLoaderServiceCID,
kIDocumentLoaderIID,
(nsISupports **)&docLoaderService);
if (NS_SUCCEEDED(rv)) {
rv = docLoaderService->CreateDocumentLoader(&mDocLoader);
nsServiceManager::ReleaseService(kDocLoaderServiceCID, docLoaderService);
}
}
if (NS_FAILED(rv)) {
goto done;
}
// Set the webshell as the default IContentViewerContainer for the loader...
mDocLoader->SetContainer(this);
//Register ourselves as an observer for the new doc loader
mDocLoader->AddObserver((nsIDocumentLoaderObserver*)this);
/* this is the old code, commented out for the new code below while I figure this out -- dwc0001
// Create device context
rv = nsComponentManager::CreateInstance(kDeviceContextCID, nsnull,
kIDeviceContextIID,
(void **)&mDeviceContext);
if (NS_FAILED(rv)) {
goto done;
}
mDeviceContext->Init(aNativeParent);
float dev2twip;
mDeviceContext->GetDevUnitsToTwips(dev2twip);
mDeviceContext->SetDevUnitsToAppUnits(dev2twip);
float twip2dev;
mDeviceContext->GetTwipsToDevUnits(twip2dev);
mDeviceContext->SetAppUnitsToDevUnits(twip2dev);
// mDeviceContext->SetGamma(1.7f);
mDeviceContext->SetGamma(1.0f);
// Create a Native window for the shell container...
rv = nsComponentManager::CreateInstance(kChildCID, nsnull, kIWidgetIID, (void**)&mWindow);
if (NS_FAILED(rv)) {
goto done;
}
widgetInit.clipChildren = PR_FALSE;
widgetInit.mWindowType = eWindowType_child;
//widgetInit.mBorderStyle = aIsSunkenBorder ? eBorderStyle_3DChildWindow : eBorderStyle_none;
mWindow->Create(aNativeParent, aBounds, nsWebShell::HandleEvent,
mDeviceContext, nsnull, nsnull, &widgetInit);
*/
// Create device context
if (nsnull != aNativeParent) {
rv = nsComponentManager::CreateInstance(kDeviceContextCID, nsnull,
kIDeviceContextIID,
(void **)&mDeviceContext);
if (NS_FAILED(rv)) {
goto done;
}
mDeviceContext->Init(aNativeParent);
float dev2twip;
mDeviceContext->GetDevUnitsToTwips(dev2twip);
mDeviceContext->SetDevUnitsToAppUnits(dev2twip);
float twip2dev;
mDeviceContext->GetTwipsToDevUnits(twip2dev);
mDeviceContext->SetAppUnitsToDevUnits(twip2dev);
// mDeviceContext->SetGamma(1.7f);
mDeviceContext->SetGamma(1.0f);
// Create a Native window for the shell container...
rv = nsComponentManager::CreateInstance(kChildCID, nsnull, kIWidgetIID, (void**)&mWindow);
if (NS_FAILED(rv)) {
goto done;
}
widgetInit.clipChildren = PR_FALSE;
widgetInit.mWindowType = eWindowType_child;
//widgetInit.mBorderStyle = aIsSunkenBorder ? eBorderStyle_3DChildWindow : eBorderStyle_none;
mWindow->Create(aNativeParent, aBounds, nsWebShell::HandleEvent,
mDeviceContext, nsnull, nsnull, &widgetInit);
} else {
// we need a deviceContext
rv = nsComponentManager::CreateInstance(kDeviceContextCID, nsnull,kIDeviceContextIID,(void **)&mDeviceContext);
if (NS_FAILED(rv)) {
goto done;
}
mDeviceContext->Init(aNativeParent);
float dev2twip;
mDeviceContext->GetDevUnitsToTwips(dev2twip);
mDeviceContext->SetDevUnitsToAppUnits(dev2twip);
float twip2dev;
mDeviceContext->GetTwipsToDevUnits(twip2dev);
mDeviceContext->SetAppUnitsToDevUnits(twip2dev);
mDeviceContext->SetGamma(1.0f);
widgetInit.clipChildren = PR_FALSE;
widgetInit.mWindowType = eWindowType_child;
}
done:
return rv;
}
NS_IMETHODIMP
nsWebShell::IsBusy(PRBool& aResult)
{
if (mDocLoader!=nsnull) {
mDocLoader->IsBusy(aResult);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::Destroy()
{
nsresult rv = NS_OK;
//Fire unload event before we blow anything away.
if (nsnull != mScriptGlobal) {
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_UNLOAD;
rv = mScriptGlobal->HandleDOMEvent(*presContext, &event, nsnull, NS_EVENT_FLAG_INIT, status);
NS_RELEASE(presContext);
}
NS_RELEASE(docViewer);
}
}
// Stop any URLs that are currently being loaded...
Stop();
SetContainer(nsnull);
SetObserver(nsnull);
SetDocLoaderObserver(nsnull);
// Remove this webshell from its parent's child list
if (nsnull != mParent) {
mParent->RemoveChild(this);
}
if (nsnull != mDocLoader) {
mDocLoader->SetContainer(nsnull);
}
NS_IF_RELEASE(mContentViewer);
// Destroy our child web shells and release references to them
DestroyChildren();
return rv;
}
NS_IMETHODIMP
nsWebShell::GetBounds(PRInt32 &x, PRInt32 &y, PRInt32 &w, PRInt32 &h)
{
nsRect aResult;
/* old code path --dwc001
NS_PRECONDITION(nsnull != mWindow, "null window");
aResult.SetRect(0, 0, 0, 0);
if (nsnull != mWindow) {
mWindow->GetClientBounds(aResult);
}
*/
if (nsnull != mWindow) {
mWindow->GetClientBounds(aResult);
} else {
aResult = mBounds;
}
x = aResult.x;
y = aResult.y;
w = aResult.width;
h = aResult.height;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetBounds(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h)
{
/*
--dwc0001
NS_PRECONDITION(nsnull != mWindow, "null window");
*/
PRInt32 borderWidth = 0;
PRInt32 borderHeight = 0;
if (nsnull != mWindow) {
mWindow->GetBorderSize(borderWidth, borderHeight);
// Don't have the widget repaint. Layout will generate repaint requests
// during reflow
mWindow->Resize(x, y, w, h, PR_FALSE);
}
mBounds.SetRect(x,y,w,h); // set the webshells bounds --dwc0001
// Set the size of the content area, which is the size of the window
// minus the borders
if (nsnull != mContentViewer) {
nsRect rr(0, 0, w-(borderWidth*2), h-(borderHeight*2));
mContentViewer->SetBounds(rr);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::MoveTo(PRInt32 aX, PRInt32 aY)
{
NS_PRECONDITION(nsnull != mWindow, "null window");
if (nsnull != mWindow) {
mWindow->Move(aX, aY);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::Show()
{
/*
--dwc001
NS_PRECONDITION(nsnull != mWindow, "null window");
*/
if (nsnull != mWindow) {
mWindow->Show(PR_TRUE);
}
if (nsnull != mContentViewer) {
mContentViewer->Show();
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::Hide()
{
/*
--dwc0001
NS_PRECONDITION(nsnull != mWindow, "null window");
*/
if (nsnull != mWindow) {
mWindow->Show(PR_FALSE);
}
if (nsnull != mContentViewer) {
mContentViewer->Hide();
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetFocus()
{
/*
--dwc0001
NS_PRECONDITION(nsnull != mWindow, "null window");
*/
if (nsnull != mWindow) {
mWindow->SetFocus();
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::RemoveFocus()
{
/*
--dwc0001
NS_PRECONDITION(nsnull != mWindow, "null window");
*/
if (nsnull != mWindow) {
nsIWidget *parentWidget = mWindow->GetParent();
if (nsnull != parentWidget) {
parentWidget->SetFocus();
NS_RELEASE(parentWidget);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::Repaint(PRBool aForce)
{
/*
--dwc0001
NS_PRECONDITION(nsnull != mWindow, "null window");
*/
if (nsnull != mWindow) {
mWindow->Invalidate(aForce);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetContentViewer(nsIContentViewer* aViewer)
{
NS_IF_RELEASE(mContentViewer);
mContentViewer = aViewer;
NS_IF_ADDREF(aViewer);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetContainer(nsIWebShellContainer* aContainer)
{
NS_IF_RELEASE(mContainer);
mContainer = aContainer;
NS_IF_ADDREF(aContainer);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetContainer(nsIWebShellContainer*& aResult)
{
aResult = mContainer;
NS_IF_ADDREF(mContainer);
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::SetObserver(nsIStreamObserver* anObserver)
{
NS_IF_RELEASE(mObserver);
#ifdef NECKO
NS_IF_RELEASE(mPrompter);
#else
NS_IF_RELEASE(mNetSupport);
#endif
mObserver = anObserver;
if (nsnull != mObserver) {
#ifdef NECKO
mObserver->QueryInterface(nsIPrompt::GetIID(), (void**)&mPrompter);
#else
mObserver->QueryInterface(kINetSupportIID, (void **) &mNetSupport);
#endif
NS_ADDREF(mObserver);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetObserver(nsIStreamObserver*& aResult)
{
aResult = mObserver;
NS_IF_ADDREF(mObserver);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetDocLoaderObserver(nsIDocumentLoaderObserver* anObserver)
{
// if (anObserver != nsnull) {
NS_IF_RELEASE(mDocLoaderObserver);
mDocLoaderObserver = anObserver;
NS_IF_ADDREF(mDocLoaderObserver);
// }
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetDocLoaderObserver(nsIDocumentLoaderObserver*& aResult)
{
aResult = mDocLoaderObserver;
NS_IF_ADDREF(mDocLoaderObserver);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetUrlDispatcher(nsIUrlDispatcher* aDispatcher)
{
NS_IF_RELEASE(mUrlDispatcher);
mUrlDispatcher = aDispatcher;
NS_IF_ADDREF(mUrlDispatcher);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetUrlDispatcher(nsIUrlDispatcher*& aResult)
{
aResult = mUrlDispatcher;
NS_IF_ADDREF(mUrlDispatcher);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetPrefs(nsIPref* aPrefs)
{
NS_IF_RELEASE(mPrefs);
mPrefs = aPrefs;
NS_IF_ADDREF(mPrefs);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetPrefs(nsIPref*& aPrefs)
{
aPrefs = mPrefs;
NS_IF_ADDREF(aPrefs);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetRootWebShell(nsIWebShell*& aResult)
{
nsIWebShell* top = this;
NS_ADDREF(this);
for (;;) {
nsIWebShell* parent;
top->GetParent(parent);
if (nsnull == parent) {
break;
}
NS_RELEASE(top);
top = parent;
}
aResult = top;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetRootWebShellEvenIfChrome(nsIWebShell*& aResult)
{
nsIWebShell* top = this;
NS_ADDREF(this);
for (;;) {
nsIWebShell* parent;
top->GetParentEvenIfChrome(parent);
if (nsnull == parent) {
break;
}
NS_RELEASE(top);
top = parent;
}
aResult = top;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetParent(nsIWebShell* aParent)
{
NS_IF_RELEASE(mParent);
mParent = aParent;
NS_IF_ADDREF(aParent);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetParent(nsIWebShell*& aParent)
{
if (mWebShellType == nsWebShellContent)
{
// We cannot return our parent if it is a chrome webshell.
nsWebShellType parentType;
if (mParent)
{
mParent->GetWebShellType(parentType);
if (parentType == nsWebShellChrome)
{
aParent = nsnull; // Just return null.
return NS_OK;
}
}
}
aParent = mParent;
NS_IF_ADDREF(mParent);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetParentEvenIfChrome(nsIWebShell*& aParent)
{
aParent = mParent;
NS_IF_ADDREF(mParent);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetChildCount(PRInt32& aResult)
{
aResult = mChildren.Count();
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::AddChild(nsIWebShell* aChild)
{
NS_PRECONDITION(nsnull != aChild, "null ptr");
if (nsnull == aChild) {
return NS_ERROR_NULL_POINTER;
}
mChildren.AppendElement(aChild);
aChild->SetParent(this);
const PRUnichar *defaultCharset=nsnull;
if(NS_SUCCEEDED(this->GetDefaultCharacterSet (&defaultCharset)))
aChild->SetDefaultCharacterSet(defaultCharset);
aChild->SetForceCharacterSet(mForceCharacterSet.GetUnicode());
NS_ADDREF(aChild);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::RemoveChild(nsIWebShell* aChild)
{
NS_PRECONDITION(nsnull != aChild, "nsWebShell::RemoveChild(): null ptr");
if (nsnull == aChild) {
return NS_ERROR_NULL_POINTER;
}
mChildren.RemoveElement(aChild);
aChild->SetParent(nsnull);
NS_RELEASE(aChild);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::ChildAt(PRInt32 aIndex, nsIWebShell*& aResult)
{
if (PRUint32(aIndex) >= PRUint32(mChildren.Count())) {
aResult = nsnull;
}
else {
aResult = (nsIWebShell*) mChildren.ElementAt(aIndex);
NS_IF_ADDREF(aResult);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetName(const PRUnichar** aName)
{
*aName = mName.GetUnicode();
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetName(const PRUnichar* aName)
{
mName = aName;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetURL(const PRUnichar** aURL)
{
*aURL = mURL.GetUnicode();
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetURL(const PRUnichar* aURL)
{
mURL = aURL;
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;
}
NS_IMETHODIMP
nsWebShell::FindChildWithName(const PRUnichar* aName1,
nsIWebShell*& aResult)
{
aResult = nsnull;
nsString aName(aName1);
const PRUnichar *childName;
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
nsIWebShell* child = (nsIWebShell*) mChildren.ElementAt(i);
if (nsnull != child) {
child->GetName(&childName);
if (aName.Equals(childName)) {
aResult = child;
NS_ADDREF(child);
break;
}
// See if child contains the shell with the given name
nsresult rv = child->FindChildWithName(aName.GetUnicode(), aResult);
if (NS_FAILED(rv)) {
return rv;
}
if (nsnull != aResult) {
break;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetWebShellType(nsWebShellType& aWebShellType)
{
aWebShellType = mWebShellType;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetWebShellType(nsWebShellType aWebShellType)
{
if (aWebShellType != nsWebShellChrome &&
aWebShellType != nsWebShellContent)
{
NS_ERROR("Attempt to set bogus webshell type: values should be content or chrome.");
return NS_ERROR_FAILURE;
}
mWebShellType = aWebShellType;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetContainingChromeShell(nsIWebShell** aResult)
{
NS_IF_ADDREF(mChromeShell);
*aResult = mChromeShell;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetContainingChromeShell(nsIWebShell* aChromeShell)
{
// Weak reference. Don't addref.
mChromeShell = aChromeShell;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetMarginWidth(PRInt32& aWidth)
{
aWidth = mMarginWidth;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetMarginWidth(PRInt32 aWidth)
{
mMarginWidth = aWidth;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetMarginHeight(PRInt32& aHeight)
{
aHeight = mMarginHeight;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetMarginHeight(PRInt32 aHeight)
{
mMarginHeight = aHeight;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetScrolling(PRInt32& aScrolling)
{
aScrolling = mScrolling[1];
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetScrolling(PRInt32 aScrolling, PRBool aSetCurrentAndInitial)
{
mScrolling[1] = aScrolling;
if (aSetCurrentAndInitial) {
mScrolling[0] = aScrolling;
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetIsFrame(PRBool& aIsFrame)
{
aIsFrame = mIsFrame;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetIsFrame(PRBool aIsFrame)
{
mIsFrame = aIsFrame;
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetZoom(float aZoom)
{
mZoom = aZoom;
if (mDeviceContext)
mDeviceContext->SetZoom(mZoom);
if (mContentViewer) {
nsIDocumentViewer* docv = nsnull;
mContentViewer->QueryInterface(kIDocumentViewerIID, (void**) &docv);
if (nsnull != docv) {
nsIPresContext* cx = nsnull;
docv->GetPresContext(cx);
if (nsnull != cx) {
nsIPresShell *shell = nsnull;
cx->GetShell(&shell);
if (nsnull != shell) {
nsIViewManager *vm = nsnull;
shell->GetViewManager(&vm);
if (nsnull != vm) {
nsIView *rootview = nsnull;
nsIScrollableView *sv = nsnull;
vm->GetRootScrollableView(&sv);
if (nsnull != sv)
sv->ComputeScrollOffsets();
vm->GetRootView(rootview);
if (nsnull != rootview)
vm->UpdateView(rootview, nsnull, 0);
NS_RELEASE(vm);
}
NS_RELEASE(shell);
}
NS_RELEASE(cx);
}
NS_RELEASE(docv);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetZoom(float *aZoom)
{
*aZoom = mZoom;
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)
{
#ifdef XP_PC
char szFile[1000];
aIn.ToCString(szFile, sizeof(szFile));
if (PL_strchr(szFile, '\\')) {
PRInt32 len = strlen(szFile);
PRInt32 sum = len + sizeof(FILE_PROTOCOL);
char* lpszFileURL = (char *)PR_Malloc(sum + 1);
// Translate '\' to '/'
for (PRInt32 i = 0; i < len; i++) {
if (szFile[i] == '\\') {
szFile[i] = '/';
}
if (szFile[i] == ':') {
szFile[i] = '|';
}
}
// Build the file URL
PR_snprintf(lpszFileURL, sum, "%s%s", FILE_PROTOCOL, szFile);
aOut = lpszFileURL;
PR_Free((void *)lpszFileURL);
}
else
#endif
{
aOut = aIn;
}
}
NS_IMETHODIMP
nsWebShell::LoadURL(const PRUnichar *aURLSpec,
nsIInputStream* aPostDataStream,
PRBool aModifyHistory,
#ifdef NECKO
nsLoadFlags aType,
#else
nsURLReloadType aType,
#endif
const PRUint32 aLocalIP)
{
// Initialize margnwidth, marginheight. Put scrolling back the way it was
// before the last document was loaded.
InitFrameData(PR_FALSE);
return LoadURL(aURLSpec, "view", aPostDataStream,
aModifyHistory,aType, aLocalIP);
}
// Nisheeth: returns true if the host and the file parts of
// the two nsIURI's match.
static PRBool EqualBaseURLs(nsIURI* url1, nsIURI* url2)
{
nsXPIDLCString host1;
nsXPIDLCString host2;
nsXPIDLCString file1;
nsXPIDLCString file2;
char * anchor1 = nsnull, * anchor2=nsnull;
PRBool rv = PR_FALSE;
if (url1 && url2) {
// XXX We need to make these strcmps case insensitive.
#ifdef NECKO
url1->GetHost(getter_Copies(host1));
url2->GetHost(getter_Copies(host2));
#else
url1->GetHost(getter_Shares(host1));
url2->GetHost(getter_Shares(host2));
#endif
if (0 == PL_strcmp(host1, host2)) {
#ifdef NECKO
url1->GetPath(getter_Copies(file1));
url2->GetPath(getter_Copies(file2));
#else
url1->GetFile(getter_Shares(file1));
url2->GetFile(getter_Shares(file2));
#endif
anchor1 = PL_strrchr(file1, '#');
if (anchor1) {
char * tmp = PL_strstr(file1, file2);
if (tmp && (const char *)tmp == file1) {
return PR_TRUE;
}
}
anchor2 = PL_strrchr(file2, '#');
if (anchor2) {
char * tmp = PL_strstr(file2, file1);
if (tmp && (const char *)tmp == file2) {
return PR_TRUE;
}
}
if (0 == PL_strcmp(file1, file2)) {
rv = PR_TRUE;
}
} // strcmp(host1, host2)
} // url1 && url2
return rv;
}
nsresult
nsWebShell::DoLoadURL(const nsString& aUrlSpec,
const char* aCommand,
nsIInputStream* aPostDataStream,
#ifdef NECKO
nsLoadFlags aType,
#else
nsURLReloadType aType,
#endif
const PRUint32 aLocalIP)
{
// Ugh. It sucks that we have to hack webshell like this. Forgive me, Father.
do {
nsresult rv;
NS_WITH_SERVICE(nsIGlobalHistory, history, "component://netscape/browser/global-history", &rv);
if (NS_FAILED(rv)) break;
rv = history->AddPage(nsCAutoString(aUrlSpec), nsnull /* referrer */, PR_Now());
if (NS_FAILED(rv)) break;
} while (0);
// 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
#ifdef NECKO
// We don't have a reload loadtype yet in necko. So, check for just history
// loadtype
if ((aType == LOAD_HISTORY || aType == nsIChannel::LOAD_NORMAL) && (nsnull != mContentViewer) &&
(nsnull == aPostDataStream))
#else
if ((aType == nsURLReload || aType == nsURLReloadFromHistory) &&
(nsnull != mContentViewer) && (nsnull == aPostDataStream))
#endif
{
nsCOMPtr<nsIDocumentViewer> docViewer;
nsresult rv;
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 = nsDontAddRef<nsIURI>(doc->GetDocumentURL());
// See if they're the same
nsCOMPtr<nsIURI> url;
#ifndef NECKO
rv = NS_NewURL(getter_AddRefs(url), aUrlSpec);
#else
rv = NS_NewURI(getter_AddRefs(url), aUrlSpec);
#ifdef DEBUG
char* urlStr = aUrlSpec.ToNewCString();
if (rv == NS_ERROR_UNKNOWN_PROTOCOL)
printf("Error: Unknown protocol: %s\n", urlStr);
else if (rv == NS_ERROR_UNKNOWN_HOST)
printf("Error: Unknown host: %s\n", urlStr);
else if (rv == NS_ERROR_MALFORMED_URI)
printf("Error: Malformed URI: %s\n", urlStr);
else if (NS_FAILED(rv))
printf("Error: Can't load: %s (%x)\n", urlStr, rv);
nsCRT::free(urlStr);
#endif
#endif // NECKO
if (NS_FAILED(rv)) return rv;
if (url && docURL && EqualBaseURLs(docURL, url)) {
// See if there's a destination anchor
#ifdef NECKO
char* ref = nsnull;
nsCOMPtr<nsIURL> url2 = do_QueryInterface(url);
if (url2) {
rv = url2->GetRef(&ref);
}
#else
const char* ref;
url->GetRef(&ref);
#endif
nsCOMPtr<nsIPresShell> presShell;
rv = docViewer->GetPresShell(*getter_AddRefs(presShell));
if (NS_SUCCEEDED(rv) && presShell) {
if (nsnull != ref) {
// Go to the anchor in the current document
rv = presShell->GoToAnchor(nsAutoString(ref));
// Pass notifications to BrowserAppCore just to be consistent with
// regular page loads thro' necko
nsCOMPtr<nsIChannel> dummyChannel;
rv = NS_OpenURI(getter_AddRefs(dummyChannel), url);
if (NS_FAILED(rv)) return rv;
mProcessedEndDocumentLoad = PR_FALSE;
rv = OnEndDocumentLoad(mDocLoader, dummyChannel, 0, this);
return rv;
}
#ifdef NECKO
else if (aType == LOAD_HISTORY)
#else
else if (aType == nsURLReloadFromHistory)
#endif
{
// 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);
// Pass notifications to BrowserAppCore just to be consistent with
// regular necko loads.
nsCOMPtr<nsIChannel> dummyChannel;
rv = NS_OpenURI(getter_AddRefs(dummyChannel), url);
if (NS_FAILED(rv)) return rv;
mProcessedEndDocumentLoad = PR_FALSE;
rv = OnEndDocumentLoad(mDocLoader, dummyChannel, 0, this);
}
return rv;
}
}
} // EqualBaseURLs(docURL, url)
}
}
// Stop loading the current document (if any...). This call may result in
// firing an EndLoadURL notification for the old document...
StopBeforeRequestingURL();
// Tell web-shell-container we are loading a new url
if (nsnull != mContainer) {
nsresult rv = mContainer->BeginLoadURL(this, aUrlSpec.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.
* - Radha
*/
return mDocLoader->LoadDocument(aUrlSpec, // URL string
aCommand, // Command
this, // Container
aPostDataStream, // Post Data
nsnull, // Extra Info...
mObserver, // Observer
aType, // reload type
aLocalIP); // load attributes.
}
NS_IMETHODIMP
nsWebShell::LoadURL(const PRUnichar *aURLSpec,
const char* aCommand,
nsIInputStream* aPostDataStream,
PRBool aModifyHistory,
#ifdef NECKO
nsLoadFlags aType,
#else
nsURLReloadType aType,
#endif
const PRUint32 aLocalIP)
{
nsresult rv;
nsString2 urlStr = aURLSpec;
#ifdef NECKO
CancelRefreshURITimers();
#endif // NECKO
// first things first. try to create a uri out of the string.
nsIURI *uri = nsnull;
rv = NS_NewURI(&uri, urlStr, nsnull);
if (NS_FAILED(rv)) {
// no dice.
nsAutoString urlSpec;
urlStr.Trim(" ", PR_TRUE, PR_TRUE);
// see if we've got a file url.
convertFileToURL(urlStr, urlSpec);
rv = NS_NewURI(&uri, urlSpec, nsnull);
if (NS_FAILED(rv)) {
// no dice, try more tricks
PRInt32 colon, 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
rv = NS_NewURI(&uri, urlSpec, nsnull);
if (NS_FAILED(rv)) {
// no dice, even more tricks?
return rv;
}
}
}
char *scheme = nsnull, *CUriSpec = nsnull;
rv = uri->GetScheme(&scheme);
if (NS_FAILED(rv)) return rv;
rv = uri->GetSpec(&CUriSpec);
NS_RELEASE(uri);
if (NS_FAILED(rv)) return rv;
nsAutoString uriSpec(CUriSpec);
nsAllocator::Free(CUriSpec);
mURL = uriSpec;
//Take care of mailto: url
PRBool isMail= PR_FALSE, isBrowser = PR_FALSE;
nsAutoString mailTo("mailto");
if (mailTo.Equals(scheme, PR_TRUE)) {
isMail = PR_TRUE;
}
nsAllocator::Free(scheme);
nsIWebShell * root= nsnull;
rv = GetRootWebShell(root);
if (NS_SUCCEEDED(rv) && root) {
nsIDocumentLoaderObserver * dlObserver = nsnull;
rv = root->GetDocLoaderObserver(dlObserver);
if (NS_SUCCEEDED(rv) && dlObserver) {
isBrowser = PR_TRUE;
NS_RELEASE(dlObserver);
}
}
/* Ask the URL dispatcher to take car of this URL only if it is a
* mailto: link clicked inside a browser or any link clicked
* inside a *non-browser* window. Note this mechanism s'd go away once
* we have the protocol registry and window manager available
*/
if (isMail) {
//Ask the container to load the appropriate component for the URL.
if (root) {
nsCOMPtr<nsIUrlDispatcher> urlDispatcher = nsnull;
rv = GetUrlDispatcher(*getter_AddRefs(urlDispatcher));
if (NS_SUCCEEDED(rv) && urlDispatcher) {
printf("calling HandleUrl\n");
urlDispatcher->HandleUrl(LinkCommand.GetUnicode(),
mURL.GetUnicode(), aPostDataStream);
return NS_OK;
}
NS_RELEASE(root);
}
}
/* If this is one of the frames, get it from the top level shell */
if (aModifyHistory) {
nsCOMPtr<nsIWebShell> webShell;
rv = GetRootWebShell(*getter_AddRefs(webShell));
if (NS_SUCCEEDED(rv) && webShell)
{
nsCOMPtr<nsISessionHistory> shist;
webShell->GetSessionHistory(*getter_AddRefs(shist));
/* Add yourself to the Session History */
if (shist) {
PRInt32 ret=0;
ret = shist->add(this);
}
}
}
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();
/* The session History may have changed the URL. So pass on the
* right one for loading
*/
// Give web-shell-container right of refusal
if (nsnull != mContainer) {
rv = mContainer->WillLoadURL(this, mURL.GetUnicode(), nsLoadURL);
if (NS_FAILED(rv)) {
return rv;
}
}
return DoLoadURL(uriSpec, aCommand, aPostDataStream, aType, aLocalIP);
//#endif
}
NS_IMETHODIMP nsWebShell::Stop(void)
{
if (nsnull != mContentViewer) {
mContentViewer->Stop();
}
// Cancel any timers that were set for this loader.
#ifndef NECKO
CancelRefreshURLTimers();
#else
CancelRefreshURITimers();
#endif // NECKO
if (mDocLoader) {
// Stop any documents that are currently being loaded...
mDocLoader->Stop();
}
// Stop the documents being loaded by children too...
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
nsIWebShell* shell = (nsIWebShell*) mChildren.ElementAt(i);
shell->Stop();
}
return NS_OK;
}
// This "stops" the current document load enough so that the document loader
// can be used to load a new URL.
nsresult
nsWebShell::StopBeforeRequestingURL()
{
if (mDocLoader) {
// Stop any documents that are currently being loaded...
mDocLoader->Stop();
}
// Recurse down the webshell hierarchy.
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
nsWebShell* shell = (nsWebShell*) mChildren.ElementAt(i);
shell->StopBeforeRequestingURL();
}
return NS_OK;
}
// This "stops" the current document load completely and is called once
// it has been determined that the new URL is valid and ready to be thrown
// at us from netlib.
nsresult
nsWebShell::StopAfterURLAvailable()
{
if (nsnull != mContentViewer) {
mContentViewer->Stop();
}
// Cancel any timers that were set for this loader.
#ifndef NECKO
CancelRefreshURLTimers();
#else
CancelRefreshURITimers();
#endif // NECKO
// Recurse down the webshell hierarchy.
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
nsWebShell* shell = (nsWebShell*) mChildren.ElementAt(i);
shell->StopAfterURLAvailable();
}
return NS_OK;
}
/* The generic session History code here is now obsolete.
* Use nsISessionHistory instead
*/
#ifdef NECKO
NS_IMETHODIMP nsWebShell::Reload(nsLoadFlags aType)
#else
NS_IMETHODIMP nsWebShell::Reload(nsURLReloadType aType)
#endif
{
#ifdef OLD_HISTORY
nsString* s = (nsString*) mHistory.ElementAt(mHistoryIndex);
if (nsnull != s) {
// XXX What about the post data?
return LoadURL(s->GetUnicode(), nsnull, PR_FALSE, aType);
}
return NS_ERROR_FAILURE;
#else
if (mSHist)
return mSHist->Reload(this, aType);
return NS_OK;
#endif
}
//----------------------------------------
// History methods
NS_IMETHODIMP
nsWebShell::Back(void)
{
#ifdef OLD_HISTORY
return GoTo(mHistoryIndex - 1);
#else
if (mSHist)
return mSHist->GoBack(this);
return NS_OK;
#endif
}
NS_IMETHODIMP
nsWebShell::CanBack(void)
{
#ifdef OLD_HISTORY
return (mHistoryIndex > mHistory.Count() - 1 ? NS_OK : NS_COMFALSE);
#else
if (mSHist) {
PRBool result=PR_TRUE;
mSHist->canBack(result);
return (result ? NS_OK : NS_COMFALSE);
}
return NS_OK;
#endif
}
NS_IMETHODIMP
nsWebShell::Forward(void)
{
#ifdef OLD_HISTORY
return GoTo(mHistoryIndex + 1);
#else
if (mSHist)
return mSHist->GoForward(this);
return NS_OK;
#endif
}
NS_IMETHODIMP
nsWebShell::CanForward(void)
{
#ifdef OLD_HISTORY
return (mHistoryIndex < mHistory.Count() - 1 ? NS_OK : NS_COMFALSE);
#else
if (mSHist) {
PRBool result=PR_TRUE;
mSHist->canForward(result);
return (result ? NS_OK : NS_COMFALSE);
}
return NS_OK;
#endif
}
NS_IMETHODIMP
nsWebShell::GoTo(PRInt32 aHistoryIndex)
{
#ifdef OLD_HISTORY
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;
}
}
printf("Goto %d\n", aHistoryIndex);
mHistoryIndex = aHistoryIndex;
ShowHistory();
rv = DoLoadURL(urlSpec, // URL string
"view", // Command
nsnull, // Post Data
#ifdef NECKO
nsIChannel::LOAD_NORMAL, // the reload type
#else
nsURLReload, // the reload type
#endif
0); // load attributes
}
return rv;
#else
if (mSHist)
return mSHist->Goto(aHistoryIndex, this, PR_FALSE);
return NS_OK;
#endif
}
NS_IMETHODIMP
nsWebShell::GetHistoryLength(PRInt32& aResult)
{
#ifdef OLD_HISTORY
aResult = mHistory.Count();
#else
if (mSHist)
return mSHist->getHistoryLength(aResult);
#endif
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetHistoryIndex(PRInt32& aResult)
{
#ifdef OLD_HISTORY
aResult = mHistoryIndex;
#else
if (mSHist)
return mSHist->getCurrentIndex(aResult);
#endif
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetURL(PRInt32 aHistoryIndex, const PRUnichar** aURLResult)
{
nsresult rv = NS_ERROR_ILLEGAL_VALUE;
#ifdef OLD_HISTORY
if ((aHistoryIndex >= 0) &&
(aHistoryIndex <= mHistory.Count() - 1)) {
nsString* s = (nsString*) mHistory.ElementAt(aHistoryIndex);
if (nsnull != s) {
*aURLResult = s->GetUnicode();
}
rv = NS_OK;
}
#else
if (mSHist)
return mSHist->GetURLForIndex(aHistoryIndex, aURLResult);
#endif
return rv;
}
void
nsWebShell::ShowHistory()
{
#if defined(OLD_HISTORY) && 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
}
//----------------------------------------
// Chrome API's
NS_IMETHODIMP
nsWebShell::SetTitle(const PRUnichar* aTitle)
{
// Record local title
mTitle = aTitle;
// Title's set on the top level web-shell are passed ont to the container
nsIWebShell* parent;
GetParent(parent);
if (nsnull == parent) {
nsIBrowserWindow *browserWindow = GetBrowserWindow();
if (nsnull != browserWindow) {
browserWindow->SetTitle(aTitle);
NS_RELEASE(browserWindow);
// Oh this hack sucks. But there isn't any other way that I can
// reliably get the title text. Sorry.
do {
nsresult rv;
NS_WITH_SERVICE(nsIGlobalHistory, history, "component://netscape/browser/global-history", &rv);
if (NS_FAILED(rv)) break;
rv = history->SetPageTitle(nsCAutoString(mURL), aTitle);
if (NS_FAILED(rv)) break;
} while (0);
}
} else {
NS_RELEASE(parent);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetTitle(const PRUnichar** aResult)
{
*aResult = mTitle.GetUnicode();
return NS_OK;
}
//----------------------------------------------------------------------
// 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::NewWebShell(PRUint32 aChromeMask,
PRBool aVisible,
nsIWebShell *&aNewWebShell)
{
if (nsnull != mContainer) {
return mContainer->NewWebShell(aChromeMask, aVisible, aNewWebShell);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::ContentShellAdded(nsIWebShell* aChildShell, nsIContent* frameNode)
{
if (nsnull != mContainer) {
return mContainer->ContentShellAdded(aChildShell, frameNode);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent,
PRInt32 aXPos, PRInt32 aYPos,
const nsString& aPopupType, const nsString& anAnchorAlignment,
const nsString& aPopupAlignment,
nsIDOMWindow* aWindow, nsIDOMWindow** outPopup)
{
if (nsnull != mContainer) {
return mContainer->CreatePopup(aElement, aPopupContent, aXPos, aYPos, aPopupType,
anAnchorAlignment, aPopupAlignment,
aWindow, outPopup);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::FindWebShellWithName(const PRUnichar* aName, nsIWebShell*& aResult)
{
if (nsnull != mContainer) {
return mContainer->FindWebShellWithName(aName, aResult);
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::FocusAvailable(nsIWebShell* aFocusedWebShell, PRBool& aFocusTaken)
{
//If the WebShell with focus is us, pass this up to container
if (this == aFocusedWebShell && nsnull != mContainer) {
mContainer->FocusAvailable(this, aFocusTaken);
}
nsIWebShell* shell = nsnull;
//Other wise, check children and move focus to next one
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
shell = (nsIWebShell*)mChildren.ElementAt(i);
if (shell == aFocusedWebShell) {
if (++i < n) {
shell = (nsIWebShell*)mChildren.ElementAt(i);
shell->SetFocus();
break;
}
else if (nsnull != mContainer) {
mContainer->FocusAvailable(this, aFocusTaken);
break;
}
}
}
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
mHintCharset = aCharset;
mHintCharsetSource = aSource;
nsAutoString url(aURL);
LoadURL(url.GetUnicode());
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::ReloadDocument(const char* aCharset,
nsCharsetSource aSource)
{
// XXX hack. kee the aCharset and aSource wait to pick it up
mHintCharset = aCharset;
mHintCharsetSource= aSource;
return Reload( nsIChannel::LOAD_NORMAL);
}
NS_IMETHODIMP
nsWebShell::StopDocumentLoad(void)
{
Stop();
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetRendering(PRBool aRender)
{
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;
}
// Find the web shell in the entire tree that we can reach that the
// link click should go to.
// XXX This doesn't yet know how to target other windows with their
// own tree
nsIWebShell*
nsWebShell::GetTarget(const PRUnichar* aName)
{
nsAutoString name(aName);
nsIWebShell* target = nsnull;
if (0 == name.Length()) {
NS_ADDREF_THIS();
return this;
}
if (name.EqualsIgnoreCase("_blank")) {
nsIWebShell *shell;
if (NS_OK == NewWebShell(PRUint32(~0), PR_TRUE, shell))
target = shell;
else
{
//don't know what to do here? MMP
NS_ASSERTION(PR_FALSE, "unable to get new webshell");
}
}
else if (name.EqualsIgnoreCase("_self")) {
target = this;
NS_ADDREF(target);
}
else if (name.EqualsIgnoreCase("_parent")) {
GetParent(target);
if (target == nsnull) {
target = this;
NS_ADDREF(target);
}
}
else if (name.EqualsIgnoreCase("_top")) {
GetRootWebShell(target); // this addrefs, which is OK
}
else if (name.EqualsIgnoreCase("_content")) {
// a kind of special case: only the window can answer this question
NS_ASSERTION(mContainer, "null container in WebShell::GetTarget");
if (nsnull != mContainer)
mContainer->FindWebShellWithName(aName, target);
// (and don't SetName())
// else target remains nsnull, which would be bad
}
else {
// Look from the top of the tree downward
NS_ASSERTION(mContainer, "null container in WebShell::GetTarget");
if (nsnull != mContainer) {
mContainer->FindWebShellWithName(aName, target);
if (nsnull == target) {
mContainer->NewWebShell(NS_CHROME_ALL_CHROME, PR_TRUE, target);
}
if (nsnull != target) {
target->SetName(aName);
}
else {
target = this;
NS_ADDREF(target);
}
}
}
return target;
}
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.SetString("_blank");
// Fall into replace case
case eLinkVerb_Replace:
{
nsIWebShell* shell = GetTarget(target.GetUnicode());
if (nsnull != shell) {
(void)shell->LoadURL(aURLSpec, aPostDataStream);
NS_RELEASE(shell);
}
}
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;
// Get the browser window and setStatus
nsIBrowserWindow *browserWindow;
browserWindow = GetBrowserWindow();
if (nsnull != browserWindow) {
browserWindow->SetStatus(aURLSpec);
NS_RELEASE(browserWindow);
}
}
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,
nsIGlobalHistory::GetIID(),
(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;
}
//----------------------------------------------------------------------
nsIBrowserWindow* nsWebShell::GetBrowserWindow()
{
nsIBrowserWindow *browserWindow = nsnull;
nsIWebShell *rootWebShell;
GetRootWebShellEvenIfChrome(rootWebShell);
if (nsnull != rootWebShell) {
nsIWebShellContainer *rootContainer;
rootWebShell->GetContainer(rootContainer);
if (nsnull != rootContainer) {
rootContainer->QueryInterface(kIBrowserWindowIID, (void**)&browserWindow);
NS_RELEASE(rootContainer);
}
NS_RELEASE(rootWebShell);
}
return browserWindow;
}
nsresult
nsWebShell::CreateScriptEnvironment()
{
nsresult res = NS_OK;
if (nsnull == mScriptGlobal) {
res = NS_NewScriptGlobalObject(&mScriptGlobal);
if (NS_FAILED(res)) {
return res;
}
mScriptGlobal->SetWebShell(this);
}
if (nsnull == mScriptContext) {
res = NS_CreateScriptContext(mScriptGlobal, &mScriptContext);
}
return res;
}
nsresult
nsWebShell::GetScriptContext(nsIScriptContext** aContext)
{
NS_PRECONDITION(nsnull != aContext, "null arg");
nsresult res = NS_OK;
res = CreateScriptEnvironment();
if (NS_SUCCEEDED(res)) {
*aContext = mScriptContext;
NS_ADDREF(mScriptContext);
}
return res;
}
nsresult
nsWebShell::GetScriptGlobalObject(nsIScriptGlobalObject** aGlobal)
{
NS_PRECONDITION(nsnull != aGlobal, "null arg");
nsresult res = NS_OK;
res = CreateScriptEnvironment();
if (NS_SUCCEEDED(res)) {
*aGlobal = mScriptGlobal;
NS_IF_ADDREF(mScriptGlobal);
}
return res;
}
nsresult
nsWebShell::ReleaseScriptContext(nsIScriptContext *aContext)
{
// XXX Is this right? Why are we passing in a context?
NS_IF_RELEASE(aContext);
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::OnStartDocumentLoad(nsIDocumentLoader* loader,
nsIURI* aURL,
const char* aCommand)
{
nsIDocumentViewer* docViewer;
nsresult rv = NS_ERROR_FAILURE;
if ((nsnull != 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);
}
}
/*
*Fire the OnStartDocumentLoad of the webshell observer
*/
if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver))
{
mDocLoaderObserver->OnStartDocumentLoad(mDocLoader, aURL, aCommand);
}
return rv;
}
NS_IMETHODIMP
nsWebShell::OnEndDocumentLoad(nsIDocumentLoader* loader,
#ifdef NECKO
nsIChannel* channel,
#else
nsIURI* aURL,
#endif
#ifdef NECKO
nsresult aStatus,
#else
PRInt32 aStatus,
#endif
nsIDocumentLoaderObserver * aWebShell)
{
nsresult rv = NS_ERROR_FAILURE;
#ifdef NECKO
nsCOMPtr<nsIURI> aURL;
rv = channel->GetURI(getter_AddRefs(aURL));
if (NS_FAILED(rv)) return rv;
#endif
if (!mProcessedEndDocumentLoad) {
mProcessedEndDocumentLoad = PR_TRUE;
if (nsnull != mScriptGlobal) {
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);
}
}
// Fire the EndLoadURL of the web shell container
if (nsnull != aURL) {
nsAutoString urlString;
#ifdef NECKO
char* spec;
#else
const char* spec;
#endif
rv = aURL->GetSpec(&spec);
if (NS_SUCCEEDED(rv)) {
urlString = spec;
if (nsnull != mContainer) {
rv = mContainer->EndLoadURL(this, urlString.GetUnicode(), 0);
}
#ifdef NECKO
nsCRT::free(spec);
#endif
}
}
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<nsIWebShell> root;
nsresult res = GetRootWebShell(*getter_AddRefs(root));
if (NS_SUCCEEDED(res) && root)
root->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)) {
#ifdef NECKO
dlObserver->OnEndDocumentLoad(mDocLoader, channel, aStatus, aWebShell);
#else
dlObserver->OnEndDocumentLoad(mDocLoader, aURL, aStatus, aWebShell);
#endif
}
#ifdef NECKO
if ( (mDocLoader == loader) && (aStatus == NS_ERROR_UNKNOWN_HOST) ) {
// We need to check for a dns failure in aStatus, but dns failure codes
// aren't proliferated yet. This checks for failure for a host lacking
// "www." and/or ".com" and munges the url acordingly, then fires off
// a new request.
//
// XXX This code may or may not have mem leaks depending on the version
// XXX stdurl that is in the tree at a given point in time. This needs to
// XXX be fixed once we have a solid version of std url in.
char *host = nsnull;
nsString2 hostStr;
rv = aURL->GetHost(&host);
if (NS_FAILED(rv)) return rv;
hostStr.SetString(host);
nsAllocator::Free(host);
PRInt32 dotLoc = -1;
dotLoc = hostStr.Find('.');
PRBool retry = PR_FALSE;
if (-1 == dotLoc) {
hostStr.Insert("www.", 0, 4);
hostStr.Append(".com");
retry = PR_TRUE;
} else if ( (hostStr.Length() - dotLoc) == 3) {
hostStr.Insert("www.", 0, 4);
retry = PR_TRUE;
}
if (retry) {
char *modHost = hostStr.ToNewCString();
if (!modHost)
return NS_ERROR_OUT_OF_MEMORY;
rv = aURL->SetHost(modHost);
nsAllocator::Free(modHost);
modHost = nsnull;
if (NS_FAILED(rv)) return rv;
char *aSpec = nsnull;
rv = aURL->GetSpec(&aSpec);
if (NS_FAILED(rv)) return rv;
nsString2 newURL(aSpec);
// reload the url
const PRUnichar *spec = newURL.GetUnicode();
if (spec) {
rv = LoadURL(spec, "view");
}
} // retry
} // unknown host
#endif //NECKO
} //!mProcessedEndDocumentLoad
else {
rv = NS_OK;
}
return rv;
}
NS_IMETHODIMP
nsWebShell::OnStartURLLoad(nsIDocumentLoader* loader,
#ifdef NECKO
nsIChannel* channel,
#else
nsIURI* aURL,
const char* aContentType,
#endif
nsIContentViewer* aViewer)
{
nsresult rv;
#ifdef NECKO
nsCOMPtr<nsIURI> aURL;
rv = channel->GetURI(getter_AddRefs(aURL));
if (NS_FAILED(rv)) return rv;
#endif
// Stop loading of the earlier document completely when the document url
// load starts. Now we know that this url is valid and available.
nsXPIDLCString url;
#ifdef NECKO
aURL->GetSpec(getter_Copies(url));
#else
aURL->GetSpec(getter_Shares(url));
#endif
if (0 == PL_strcmp(url, mURL.GetBuffer()))
StopAfterURLAvailable();
// XXX This is a temporary hack for meeting the M4 milestone
// for seamonkey. I think Netlib should send a message to all stream listeners
// when it changes the URL like this. That would mean adding a new method
// to nsIStreamListener. Need to talk to Rick, Kipp, Gagan about this.
/* Overriding comments: History mechanism has changed. So is Necko changing.
* Need to check in the new world if this is still valid. If so, new methods
* need to be added to nsISessionHistory. Until then. We don't need this.
* This is being done so that old History code can be removed.
*/
// CheckForTrailingSlash(aURL);
/*
*Fire the OnStartDocumentLoad of the webshell observer
*/
if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver))
{
#ifdef NECKO
mDocLoaderObserver->OnStartURLLoad(mDocLoader, channel, aViewer);
#else
mDocLoaderObserver->OnStartURLLoad(mDocLoader, aURL, aContentType, aViewer);
#endif
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::OnProgressURLLoad(nsIDocumentLoader* loader,
#ifdef NECKO
nsIChannel* channel,
#else
nsIURI* aURL,
#endif
PRUint32 aProgress,
PRUint32 aProgressMax)
{
/*
*Fire the OnStartDocumentLoad of the webshell observer and container...
*/
if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver))
{
#ifdef NECKO
mDocLoaderObserver->OnProgressURLLoad(mDocLoader, channel, aProgress, aProgressMax);
#else
mDocLoaderObserver->OnProgressURLLoad(mDocLoader, aURL, aProgress, aProgressMax);
#endif
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::OnStatusURLLoad(nsIDocumentLoader* loader,
#ifdef NECKO
nsIChannel* channel,
#else
nsIURI* aURL,
#endif
nsString& aMsg)
{
/*
*Fire the OnStartDocumentLoad of the webshell observer and container...
*/
if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver))
{
#ifdef NECKO
mDocLoaderObserver->OnStatusURLLoad(mDocLoader, channel, aMsg);
#else
mDocLoaderObserver->OnStatusURLLoad(mDocLoader, aURL, aMsg);
#endif
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::OnEndURLLoad(nsIDocumentLoader* loader,
#ifdef NECKO
nsIChannel* channel,
nsresult aStatus)
#else
nsIURI* aURL,
PRInt32 aStatus)
#endif // NECKO
{
#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 OnStartDocumentLoad of the webshell observer
*/
if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver))
{
#ifdef NECKO
mDocLoaderObserver->OnEndURLLoad(mDocLoader, channel, aStatus);
#else
mDocLoaderObserver->OnEndURLLoad(mDocLoader, aURL, aStatus);
#endif
}
return NS_OK;
}
/* For use with redirect/refresh url api */
class refreshData : public nsITimerCallback
{
public:
refreshData();
NS_DECL_ISUPPORTS
// nsITimerCallback interface
virtual 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);
void refreshData::Notify(nsITimer *aTimer)
{
NS_PRECONDITION((nsnull != mShell), "Null pointer...");
if (nsnull != mShell) {
#ifdef NECKO
mShell->LoadURL(mUrlSpec.GetUnicode(), nsnull, PR_TRUE, nsIChannel::LOAD_NORMAL);
#else
mShell->LoadURL(mUrlSpec.GetUnicode(), nsnull, PR_TRUE, nsURLReload);
#endif
}
/*
* LoadURL(...) will cancel all refresh timers... This causes the Timer and
* its refreshData instance to be released...
*/
}
NS_IMETHODIMP
#ifndef NECKO
nsWebShell::RefreshURL(nsIURI* aURI, PRInt32 millis, PRBool repeat)
#else
nsWebShell::RefreshURI(nsIURI* aURI, PRInt32 millis, PRBool repeat)
#endif // NECKO
{
nsresult rv = NS_OK;
if (nsnull == aURI) {
NS_PRECONDITION((aURI != nsnull), "Null pointer");
rv = NS_ERROR_NULL_POINTER;
goto done;
}
#ifdef NECKO
char* spec;
#else
const char* spec;
#endif
aURI->GetSpec(&spec);
rv = RefreshURL(spec, millis, repeat);
#ifdef NECKO
nsCRT::free(spec);
#endif
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
#ifdef NECKO
nsWebShell::CancelRefreshURITimers(void)
#else
nsWebShell::CancelRefreshURLTimers(void)
#endif // NECKO
{
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)
{
const PRUnichar * url=nsnull;
PRInt32 curIndex=0;
/* Get current history index and url for it */
mSHist->getCurrentIndex(curIndex);
mSHist->GetURLForIndex(curIndex, &url);
nsString * historyURL = (nsString *) new nsString(url);
/* Get the url that netlib passed us */
#ifdef NECKO
char* spec;
#else
const char* spec;
#endif
aURL->GetSpec(&spec);
nsString* newURL = (nsString*) new nsString(spec);
#ifdef NECKO
nsCRT::free(spec);
#endif
if (newURL && newURL->Last() == '/' && !historyURL->Equals(*newURL)) {
// Replace the top most history entry with the new url
printf("Changing URL from %s to %s for history entry %d\n", historyURL->ToNewCString(), newURL->ToNewCString(), curIndex);
mSHist->SetURLForIndex(curIndex, newURL->GetUnicode());
}
else {
delete newURL;
delete historyURL;
}
return NS_OK;
}
#if 0
NS_IMETHODIMP
nsWebShell::OnStartRequest(nsIURI* aURL, const char *aContentType)
{
nsresult rv = NS_OK;
if (nsnull != mObserver) {
rv = mObserver->OnStartRequest(aURL, aContentType);
}
return rv;
}
NS_IMETHODIMP
nsWebShell::OnProgress(nsIURI* aURL, PRUint32 aProgress, PRUint32 aProgressMax)
{
nsresult rv = NS_OK;
if (nsnull != mObserver) {
rv = mObserver->OnProgress(aURL, aProgress, aProgressMax);
}
// Pass status messages out to the nsIBrowserWindow...
nsIBrowserWindow *browserWindow;
browserWindow = GetBrowserWindow();
if (nsnull != browserWindow) {
browserWindow->SetProgress(aProgress, aProgressMax);
NS_RELEASE(browserWindow);
}
return rv;
}
NS_IMETHODIMP
nsWebShell::OnStatus(nsIURI* aURL, const PRUnichar* aMsg)
{
nsresult rv = NS_OK;
if (nsnull != mObserver) {
rv = mObserver->OnStatus(aURL, aMsg);
}
// Pass status messages out to the nsIBrowserWindow...
nsIBrowserWindow *browserWindow;
browserWindow = GetBrowserWindow();
if (nsnull != browserWindow) {
browserWindow->SetStatus(aMsg);
NS_RELEASE(browserWindow);
}
return rv;
}
NS_IMETHODIMP
nsWebShell::OnStopRequest(nsIURI* aURL, nsresult aStatus, const PRUnichar* aMsg)
{
nsresult rv = NS_OK;
if (nsnull != mObserver) {
rv = mObserver->OnStopRequest(aURL, aStatus, aMsg);
}
return rv;
}
#endif /* 0 */
//----------------------------------------------------------------------
#ifdef NECKO
NS_IMETHODIMP
nsWebShell::Alert(const PRUnichar *text)
#else
NS_IMETHODIMP_(void)
nsWebShell::Alert(const nsString &aText)
#endif
{
#ifdef NECKO
if (mPrompter == nsnull)
return NS_OK;
return mPrompter->Alert(text);
#else
if (nsnull != mNetSupport) {
mNetSupport->Alert(aText);
}
#endif
}
#ifdef NECKO
NS_IMETHODIMP
nsWebShell::Confirm(const PRUnichar *text,
PRBool *result)
#else
NS_IMETHODIMP_(PRBool)
nsWebShell::Confirm(const nsString &aText)
#endif
{
#ifdef NECKO
if (mPrompter == nsnull)
return NS_OK;
return mPrompter->Confirm(text, result);
#else
PRBool bResult = PR_FALSE;
if (nsnull != mNetSupport) {
bResult = mNetSupport->Confirm(aText);
}
return bResult;
#endif
}
#ifdef NECKO
NS_IMETHODIMP
nsWebShell::ConfirmYN(const PRUnichar *text,
PRBool *result)
#else
NS_IMETHODIMP_(PRBool)
nsWebShell::ConfirmYN(const nsString &aText)
#endif
{
#ifdef NECKO
if (mPrompter == nsnull)
return NS_OK;
return mPrompter->ConfirmYN(text, result);
#else
PRBool bResult = PR_FALSE;
if (nsnull != mNetSupport) {
bResult = mNetSupport->ConfirmYN(aText);
}
return bResult;
#endif
}
#ifdef NECKO
NS_IMETHODIMP
nsWebShell::ConfirmCheck(const PRUnichar *text,
const PRUnichar *checkMsg,
PRBool *checkValue,
PRBool *result)
{
if (mPrompter == nsnull)
return NS_OK;
return mPrompter->ConfirmCheck(text, checkMsg, checkValue, result);
}
#endif
#ifdef NECKO
NS_IMETHODIMP
nsWebShell::ConfirmCheckYN(const PRUnichar *text,
const PRUnichar *checkMsg,
PRBool *checkValue,
PRBool *result)
{
if (mPrompter == nsnull)
return NS_OK;
return mPrompter->ConfirmCheckYN(text, checkMsg, checkValue, result);
}
#endif
#ifdef NECKO
NS_IMETHODIMP
nsWebShell::Prompt(const PRUnichar *text,
const PRUnichar *defaultText,
PRUnichar **result,
PRBool *_retval)
#else
NS_IMETHODIMP_(PRBool)
nsWebShell::Prompt(const nsString &aText,
const nsString &aDefault,
nsString &aResult)
#endif
{
#ifdef NECKO
if (mPrompter == nsnull)
return NS_OK;
return mPrompter->Prompt(text, defaultText, result, _retval);
#else
PRBool bResult = PR_FALSE;
if (nsnull != mNetSupport) {
bResult = mNetSupport->Prompt(aText, aDefault, aResult);
}
return bResult;
#endif
}
#ifdef NECKO
NS_IMETHODIMP
nsWebShell::PromptUsernameAndPassword(const PRUnichar *text,
PRUnichar **user,
PRUnichar **pwd,
PRBool *_retval)
#else
NS_IMETHODIMP_(PRBool)
nsWebShell::PromptUserAndPassword(const nsString &aText,
nsString &aUser,
nsString &aPassword)
#endif
{
#ifdef NECKO
if (mPrompter == nsnull)
return NS_OK;
return mPrompter->PromptUsernameAndPassword(text, user, pwd, _retval);
#else
PRBool bResult = PR_FALSE;
if (nsnull != mNetSupport) {
bResult = mNetSupport->PromptUserAndPassword(aText, aUser, aPassword);
}
return bResult;
#endif
}
#ifdef NECKO
NS_IMETHODIMP
nsWebShell::PromptPassword(const PRUnichar *text,
PRUnichar **pwd,
PRBool *_retval)
#else
NS_IMETHODIMP_(PRBool)
nsWebShell::PromptPassword(const nsString &aText,
nsString &aPassword)
#endif
{
#ifdef NECKO
if (mPrompter == nsnull)
return NS_OK;
return mPrompter->PromptPassword(text, pwd, _retval);
#else
PRBool bResult = PR_FALSE;
if (nsnull != mNetSupport) {
bResult = mNetSupport->PromptPassword(aText, aPassword);
}
return bResult;
#endif
}
//----------------------------------------------------
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)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsWebShell::SelectNone(void)
{
return NS_ERROR_FAILURE;
}
static char *gDefCharset = nsnull;
NS_IMETHODIMP
nsWebShell::GetDefaultCharacterSet (const PRUnichar** aDefaultCharacterSet)
{
if(0 == mDefaultCharacterSet.Length())
{
if((nsnull == gDefCharset) || (nsnull == *gDefCharset))
{
if(mPrefs)
mPrefs->CopyCharPref("intl.charset.default", &gDefCharset);
}
if((nsnull == gDefCharset) || (nsnull == *gDefCharset))
mDefaultCharacterSet = "ISO-8859-1";
else
mDefaultCharacterSet = gDefCharset;
}
*aDefaultCharacterSet = mDefaultCharacterSet.GetUnicode();
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetDefaultCharacterSet (const PRUnichar* aDefaultCharacterSet)
{
mDefaultCharacterSet = aDefaultCharacterSet;
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
nsIWebShell* child = (nsIWebShell*) mChildren.ElementAt(i);
if (nsnull != child) {
child->SetDefaultCharacterSet(aDefaultCharacterSet);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::GetForceCharacterSet (const PRUnichar** aForceCharacterSet)
{
nsString emptyStr = "";
if (mForceCharacterSet.Equals(emptyStr)) {
*aForceCharacterSet = nsnull;
}
else {
*aForceCharacterSet = mForceCharacterSet.GetUnicode();
}
return NS_OK;
}
NS_IMETHODIMP
nsWebShell::SetForceCharacterSet (const PRUnichar* aForceCharacterSet)
{
mForceCharacterSet = aForceCharacterSet;
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
nsIWebShell* child = (nsIWebShell*) mChildren.ElementAt(i);
if (nsnull != child) {
child->SetForceCharacterSet(aForceCharacterSet);
}
}
return NS_OK;
}
NS_IMETHODIMP nsWebShell::GetCharacterSetHint (const PRUnichar** oHintCharset, nsCharsetSource* oSource)
{
*oSource = mHintCharsetSource;
if(kCharsetUninitialized == mHintCharsetSource) {
*oHintCharset = nsnull;
} else {
*oHintCharset = mHintCharset.GetUnicode();
// clean up after we access it.
mHintCharsetSource = kCharsetUninitialized;
}
return NS_OK;
}
//----------------------------------------------------
NS_IMETHODIMP
nsWebShell::FindNext(const PRUnichar * aSearchStr, PRBool aMatchCase, PRBool aSearchDown, PRBool &aIsFound)
{
return NS_ERROR_FAILURE;
}
//----------------------------------------------------------------------
// Factory code for creating nsWebShell's
class nsWebShellFactory : public nsIFactory
{
public:
nsWebShellFactory();
virtual ~nsWebShellFactory();
// nsISupports methods
NS_IMETHOD QueryInterface(const nsIID &aIID, void **aResult);
NS_IMETHOD_(nsrefcnt) AddRef(void);
NS_IMETHOD_(nsrefcnt) Release(void);
// nsIFactory methods
NS_IMETHOD CreateInstance(nsISupports *aOuter,
const nsIID &aIID,
void **aResult);
NS_IMETHOD LockFactory(PRBool aLock);
private:
// XXX TEMPORARY placeholder for starting up some
// services in lieu of a service manager.
static void StartServices();
static PRBool mStartedServices;
nsrefcnt mRefCnt;
};
PRBool nsWebShellFactory::mStartedServices = PR_FALSE;
void
nsWebShellFactory::StartServices()
{
#ifndef NECKO
// XXX TEMPORARY Till we have real pluggable protocol handlers
NET_InitJavaScriptProtocol();
#endif // NECKO
mStartedServices = PR_TRUE;
}
nsWebShellFactory::nsWebShellFactory()
{
if (!mStartedServices) {
StartServices();
}
mRefCnt = 0;
}
nsWebShellFactory::~nsWebShellFactory()
{
NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction");
}
nsresult
nsWebShellFactory::QueryInterface(const nsIID &aIID, void **aResult)
{
if (aResult == NULL) {
return NS_ERROR_NULL_POINTER;
}
// Always NULL result, in case of failure
*aResult = NULL;
if (aIID.Equals(kISupportsIID)) {
*aResult = (void *)(nsISupports*)this;
} else if (aIID.Equals(kIFactoryIID)) {
*aResult = (void *)(nsIFactory*)this;
}
if (*aResult == NULL) {
return NS_NOINTERFACE;
}
NS_ADDREF_THIS(); // Increase reference count for caller
return NS_OK;
}
nsrefcnt
nsWebShellFactory::AddRef()
{
return ++mRefCnt;
}
nsrefcnt
nsWebShellFactory::Release()
{
if (--mRefCnt == 0) {
delete this;
return 0; // Don't access mRefCnt after deleting!
}
return mRefCnt;
}
nsresult
nsWebShellFactory::CreateInstance(nsISupports *aOuter,
const nsIID &aIID,
void **aResult)
{
nsresult rv;
nsWebShell *inst;
if (aResult == NULL) {
return NS_ERROR_NULL_POINTER;
}
*aResult = NULL;
if (nsnull != aOuter) {
rv = NS_ERROR_NO_AGGREGATION;
goto done;
}
NS_NEWXPCOM(inst, nsWebShell);
if (inst == NULL) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto done;
}
NS_ADDREF(inst);
rv = inst->QueryInterface(aIID, aResult);
NS_RELEASE(inst);
done:
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;
}