/* -*- 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" #else #include "nsINetSupport.h" #include "nsIRefreshUrl.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 "jsurl.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" #ifdef XP_PC #include #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 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 //---------------------------------------------------------------------- class nsWebShell : public nsIWebShell, public nsIWebShellContainer, public nsIWebShellServices, public nsILinkHandler, public nsIScriptContextOwner, public nsIDocumentLoaderObserver, #ifdef NECKO public nsIPrompt, #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, nsIPostData* aPostData=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, nsIPostData* aPostData=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, PRInt32 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, nsIPostData* aPostData = 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, PRInt32 aStatus, nsIDocumentLoaderObserver * ); NS_IMETHOD OnStartURLLoad(nsIDocumentLoader* loader, nsIChannel* channel, const char* aContentType, 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, PRInt32 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(); // nsIRefreshURL interface methods... NS_IMETHOD RefreshURL(nsIURI* aURL, PRInt32 millis, PRBool repeat); NS_IMETHOD RefreshURL(const char* aURL, PRInt32 millis, PRBool repeat); NS_IMETHOD CancelRefreshURLTimers(void); #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_IMETHOD Alert(const PRUnichar *text); NS_IMETHOD Confirm(const PRUnichar *text, PRBool *_retval); NS_IMETHOD ConfirmCheck(const PRUnichar *text, const PRUnichar *checkMsg, PRBool *checkValue, PRBool *_retval); NS_IMETHOD Prompt(const PRUnichar *text, const PRUnichar *defaultText, PRUnichar **result, PRBool *_retval); NS_IMETHOD PromptUsernameAndPassword(const PRUnichar *text, PRUnichar **user, PRUnichar **pwd, PRBool *_retval); NS_IMETHOD PromptPassword(const PRUnichar *text, PRUnichar **pwd, PRBool *_retval); #else // nsINetSupport interface methods NS_IMETHOD_(void) Alert(const nsString &aText); NS_IMETHOD_(PRBool) Confirm(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, nsIPostData* aPostDat = 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 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); protected: void InitFrameData(PRBool aCompleteInitScrolling); nsresult CheckForTrailingSlash(nsIURI* aURL); nsIEventQueue* mThreadEventQueue; nsIScriptGlobalObject *mScriptGlobal; nsIScriptContext* mScriptContext; nsIStreamObserver * mObserver; nsIWebShellContainer* mContainer; nsIContentViewer* mContentViewer; nsIDeviceContext* mDeviceContext; nsIPref* mPrefs; nsIWidget* mWindow; nsIDocumentLoader* mDocLoader; nsIDocumentLoaderObserver* mDocLoaderObserver; #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; PRBool mIsInSHist; nsScrollPreference mScrollPref; PRInt32 mMarginWidth; PRInt32 mMarginHeight; PRInt32 mScrolling[2]; PRBool mIsFrame; nsVoidArray mRefreshments; nsWebShellType mWebShellType; nsIWebShell* mChromeShell; // Weak reference. void ReleaseChildren(); void DestroyChildren(); nsresult CreateScriptEnvironment(); nsresult DoLoadURL(const nsString& aUrlSpec, const char* aCommand, nsIPostData* aPostData, #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; }; //---------------------------------------------------------------------- // 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); #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; // XXX we should get such mDefaultCharacterSet from pref laster... mDefaultCharacterSet = "ISO-8859-1"; 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. CancelRefreshURLTimers(); ++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; } #ifndef NECKO if (aIID.Equals(kRefreshURLIID)) { *aInstancePtr = (void*)(nsIRefreshUrl*)this; NS_ADDREF_THIS(); return NS_OK; } #endif #ifdef NECKO if (aIID.Equals(nsIPrompt::GetIID())) { *aInstancePtr = (void*) ((nsIPrompt*)this); NS_ADDREF_THIS(); return NS_OK; } #else if (aIID.Equals(kINetSupportIID)) { *aInstancePtr = (void*) ((nsINetSupport*)this); NS_ADDREF_THIS(); return NS_OK; } #endif 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); 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(); } // 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); nsWidgetInitData widgetInit; CreatePluginHost(aAllowPlugins); //mScrollPref = aScrolling; WEB_TRACE(WEB_TRACE_CALLS, ("nsWebShell::Init: this=%p", this)); // 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); // 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.mBorderStyle = aIsSunkenBorder ? eBorderStyle_3DChildWindow : eBorderStyle_none; mWindow->Create(aNativeParent, aBounds, nsWebShell::HandleEvent, mDeviceContext, nsnull, nsnull, &widgetInit); done: return rv; } 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; NS_PRECONDITION(nsnull != mWindow, "null window"); aResult.SetRect(0, 0, 0, 0); if (nsnull != mWindow) { mWindow->GetClientBounds(aResult); } 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) { 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); } // 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() { 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() { 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() { NS_PRECONDITION(nsnull != mWindow, "null window"); if (nsnull != mWindow) { mWindow->SetFocus(); } return NS_OK; } NS_IMETHODIMP nsWebShell::RemoveFocus() { 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) { 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) { 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::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); aChild->SetDefaultCharacterSet(mDefaultCharacterSet.GetUnicode()); 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, nsIPostData* aPostData, 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",aPostData,aModifyHistory,aType, aLocalIP); } nsresult nsWebShell::DoLoadURL(const nsString& aUrlSpec, const char* aCommand, nsIPostData* aPostData, #ifdef NECKO nsLoadFlags aType, #else nsURLReloadType aType, #endif const PRUint32 aLocalIP) { // 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 if ((aType == nsIChannel::LOAD_NORMAL) && (nsnull != mContentViewer)) #else if ((aType == nsURLReload) && (nsnull != mContentViewer)) #endif { nsCOMPtr docViewer; if (NS_SUCCEEDED(mContentViewer->QueryInterface(kIDocumentViewerIID, getter_AddRefs(docViewer)))) { // Get the document object nsCOMPtr doc; docViewer->GetDocument(*getter_AddRefs(doc)); // Get the URL for the document nsCOMPtr docURL = nsDontAddRef(doc->GetDocumentURL()); // See if they're the same nsCOMPtr url; #ifndef NECKO NS_NewURL(getter_AddRefs(url), aUrlSpec); #else nsresult rv; NS_WITH_SERVICE(nsIIOService, service, kIOServiceCID, &rv); if (NS_FAILED(rv)) return rv; nsIURI *uri = nsnull; char *uriSpec = aUrlSpec.ToNewCString(); rv = service->NewURI(uriSpec, nsnull, &uri); nsCRT::free(uriSpec); if (NS_FAILED(rv)) return rv; rv = uri->QueryInterface(nsIURI::GetIID(), (void**)&url); NS_RELEASE(uri); if (NS_FAILED(rv)) return rv; #endif // NECKO #ifdef NECKO PRBool eq; rv = docURL->Equals(url, &eq); if (NS_SUCCEEDED(rv) && eq) #else if ((PRBool)docURL->Equals(url)) #endif { // See if there's a destination anchor #ifdef NECKO char* ref = nsnull; nsCOMPtr url2 = do_QueryInterface(url); if (url2) { rv = url2->GetRef(&ref); } #else const char* ref; url->GetRef(&ref); #endif if (nsnull != ref) { // Get the pres shell object nsCOMPtr presShell; docViewer->GetPresShell(*getter_AddRefs(presShell)); presShell->GoToAnchor(nsAutoString(ref)); return NS_OK; } } } } // Stop loading the current document (if any...). This call may result in // firing an EndLoadURL notification for the old document... Stop(); // 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 aPostData, // Post Data nsnull, // Extra Info... mObserver, // Observer aType, // reload type aLocalIP); // load attributes. } NS_IMETHODIMP nsWebShell::LoadURL(const PRUnichar *aURLSpec, const char* aCommand, nsIPostData* aPostData, PRBool aModifyHistory, #ifdef NECKO nsLoadFlags aType, #else nsURLReloadType aType, #endif const PRUint32 aLocalIP) { nsresult rv; PRInt32 colon, fSlash; PRUnichar port; nsAutoString urlSpec; convertFileToURL(nsString(aURLSpec), urlSpec); fSlash=urlSpec.Find('/'); // if no scheme (protocol) is found, assume http. if ( ((colon=urlSpec.Find(':')) == -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 int 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("www")) { nsString ftpDef("http://"); urlSpec.Insert(ftpDef, 0, 7); } else if (hostSpec.EqualsIgnoreCase("ftp")) { nsString ftpDef("ftp://"); urlSpec.Insert(ftpDef, 0, 6); } else { nsString httpDef("http://"); urlSpec.Insert(httpDef, 0, 7); } } mURL = urlSpec.GetUnicode(); /* If this is one of the frames, get it from the top level shell */ if (aModifyHistory) { nsCOMPtr webShell; nsresult res = GetRootWebShell(*getter_AddRefs(webShell)); if (NS_SUCCEEDED(res) && webShell) { nsCOMPtr 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(urlSpec); 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; } } const PRUnichar * urlString=nsnull; GetURL(&urlString); nsAutoString newURL(urlString); return DoLoadURL(newURL, aCommand, aPostData, aType, aLocalIP); } NS_IMETHODIMP nsWebShell::Stop(void) { if (nsnull != mContentViewer) { mContentViewer->Stop(); } // Cancel any timers that were set for this loader. CancelRefreshURLTimers(); 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; } #ifdef NECKO NS_IMETHODIMP nsWebShell::Reload(nsLoadFlags aType) #else NS_IMETHODIMP nsWebShell::Reload(nsURLReloadType aType) #endif { 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; } //---------------------------------------- // History methods NS_IMETHODIMP nsWebShell::Back(void) { return GoTo(mHistoryIndex - 1); } NS_IMETHODIMP nsWebShell::CanBack(void) { return (mHistoryIndex > 0 ? NS_OK : NS_COMFALSE); } NS_IMETHODIMP nsWebShell::Forward(void) { return GoTo(mHistoryIndex + 1); } NS_IMETHODIMP nsWebShell::CanForward(void) { return (mHistoryIndex < mHistory.Count() - 1 ? NS_OK : NS_COMFALSE); } NS_IMETHODIMP nsWebShell::GoTo(PRInt32 aHistoryIndex) { nsresult rv = NS_ERROR_ILLEGAL_VALUE; if ((aHistoryIndex >= 0) && (aHistoryIndex < mHistory.Count())) { nsString* s = (nsString*) mHistory.ElementAt(aHistoryIndex); // Give web-shell-container right of refusal nsAutoString urlSpec(*s); if (nsnull != mContainer) { rv = mContainer->WillLoadURL(this, urlSpec.GetUnicode(), nsLoadHistory); if (NS_FAILED(rv)) { return rv; } } 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; } NS_IMETHODIMP nsWebShell::GetHistoryLength(PRInt32& aResult) { aResult = mHistory.Count(); return NS_OK; } NS_IMETHODIMP nsWebShell::GetHistoryIndex(PRInt32& aResult) { aResult = mHistoryIndex; return NS_OK; } NS_IMETHODIMP nsWebShell::GetURL(PRInt32 aHistoryIndex, const PRUnichar** aURLResult) { nsresult rv = NS_ERROR_ILLEGAL_VALUE; if ((aHistoryIndex >= 0) && (aHistoryIndex <= mHistory.Count() - 1)) { nsString* s = (nsString*) mHistory.ElementAt(aHistoryIndex); if (nsnull != s) { *aURLResult = s->GetUnicode(); } rv = NS_OK; } return rv; } void nsWebShell::ShowHistory() { #ifdef 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); } } 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, PRInt32 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; nsString* s = (nsString*) mHistory.ElementAt(mHistoryIndex); nsresult rv = NS_OK; if(s) { char* url = s->ToNewCString(); if(url) { mHistoryIndex--; rv = this->RefreshURL((const char*)url,0,PR_FALSE); delete [] url; } } return rv; } 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, nsIPostData* aPostData = 0); ~OnLinkClickEvent(); void HandleEvent() { mHandler->HandleLinkClickEvent(mContent, mVerb, mURLSpec->GetUnicode(), mTargetSpec->GetUnicode(), mPostData); } nsWebShell* mHandler; nsString* mURLSpec; nsString* mTargetSpec; nsIPostData* mPostData; 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, nsIPostData* aPostData) { nsIEventQueue* eventQueue; mHandler = aHandler; NS_ADDREF(aHandler); mURLSpec = new nsString(aURLSpec); mTargetSpec = new nsString(aTargetSpec); mPostData = aPostData; NS_IF_ADDREF(mPostData); 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(mPostData); if (nsnull != mURLSpec) delete mURLSpec; if (nsnull != mTargetSpec) delete mTargetSpec; } //---------------------------------------- NS_IMETHODIMP nsWebShell::OnLinkClick(nsIContent* aContent, nsLinkVerb aVerb, const PRUnichar* aURLSpec, const PRUnichar* aTargetSpec, nsIPostData* aPostData) { OnLinkClickEvent* ev; nsresult rv = NS_OK; ev = new OnLinkClickEvent(this, aContent, aVerb, aURLSpec, aTargetSpec, aPostData); 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")) { if (nsnull == mParent) { target = this; } else { target = mParent; } 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(PRUint32(~0), 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, nsIPostData* aPostData) { 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) { shell->LoadURL(aURLSpec, aPostData); 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) { nsString URLSpec(aURLSpec); aState = eLinkState_Unvisited; nsresult rv; // XXX: GlobalHistory is going to be moved out of the webshell into a more appropriate place. if (nsnull == mHistoryService) { rv = nsServiceManager::GetService(kGlobalHistoryCID, nsIGlobalHistory::GetIID(), (nsISupports**) &mHistoryService); if (NS_FAILED(rv)) return NS_OK; // XXX Okay, we couldn't color the link. Big deal. } // XXX aURLSpec should really be a char*, not a PRUnichar*. nsAutoString urlStr(aURLSpec); char buf[256]; char* url = buf; if (urlStr.Length() >= 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_CreateContext(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) { #if DEBUG_nisheeth const char* spec; aURL->GetSpec(&spec); printf("nsWebShell::OnStartDocumentLoad:%p: loader=%p url=%s command=%s\n", this, loader, spec, aCommand); #endif 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 PRInt32 aStatus, nsIDocumentLoaderObserver * aWebShell) { nsresult rv = NS_ERROR_FAILURE; #ifdef NECKO nsCOMPtr aURL; rv = channel->GetURI(getter_AddRefs(aURL)); if (NS_FAILED(rv)) return rv; #endif #if DEBUG_nisheeth const char* spec; aURL->GetSpec(&spec); printf("nsWebShell::OnEndDocumentLoad:%p: loader=%p url=%s status=%d\n", this, loader, spec, aStatus); #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 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 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 } } //!mProcessedEndDocumentLoad else { rv = NS_OK; } return rv; } NS_IMETHODIMP nsWebShell::OnStartURLLoad(nsIDocumentLoader* loader, #ifdef NECKO nsIChannel* channel, #else nsIURI* aURL, #endif const char* aContentType, nsIContentViewer* aViewer) { nsresult rv; #ifdef NECKO nsCOMPtr aURL; rv = channel->GetURI(getter_AddRefs(aURL)); if (NS_FAILED(rv)) return rv; #endif // 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, aContentType, 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, #else nsIURI* aURL, #endif PRInt32 aStatus) { #if 0 const char* spec; aURL->GetSpec(&spec); printf("nsWebShell::OnEndURLLoad:%p: loader=%p url=%s status=%d\n", this, loader, spec, aStatus); #endif /* *Fire the 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 nsWebShell::RefreshURL(nsIURI* aURL, PRInt32 millis, PRBool repeat) { nsresult rv = NS_OK; if (nsnull == aURL) { NS_PRECONDITION((aURL != nsnull), "Null pointer"); rv = NS_ERROR_NULL_POINTER; goto done; } #ifdef NECKO char* spec; #else const char* spec; #endif aURL->GetSpec(&spec); rv = RefreshURL(spec, millis, repeat); #ifdef NECKO nsCRT::free(spec); #endif done: return rv; } NS_IMETHODIMP nsWebShell::RefreshURL(const char* aURL, PRInt32 millis, PRBool repeat) { nsresult rv = NS_OK; nsITimer *timer=nsnull; refreshData *data; if (nsnull == aURL) { NS_PRECONDITION((aURL != 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 = aURL; data->mDelay = millis; data->mRepeat = repeat; /* Create the timer. */ if (NS_OK == NS_NewTimer(&timer)) { /* Add the timer to our array. */ NS_LOCK_INSTANCE(); mRefreshments.AppendElement(timer); timer->Init(data, millis); NS_UNLOCK_INSTANCE(); } NS_RELEASE(data); done: return rv; } NS_IMETHODIMP nsWebShell::CancelRefreshURLTimers(void) { PRInt32 i; nsITimer* timer; /* Right now all we can do is cancel all the timers for this webshell. */ NS_LOCK_INSTANCE(); /* Walk the list backwards to avoid copying the array as it shrinks.. */ for (i = mRefreshments.Count()-1; (0 <= i); i--) { timer=(nsITimer*)mRefreshments.ElementAt(i); /* Remove the entry from the list before releasing the timer.*/ mRefreshments.RemoveElementAt(i); if (timer) { timer->Cancel(); NS_RELEASE(timer); } } NS_UNLOCK_INSTANCE(); return NS_OK; } //---------------------------------------------------------------------- /* * There are cases where netlib does things like add a trailing slash * to the url being retrieved. We need to watch out for such * changes and update the currently loading url's entry in the history * list. UpdateHistoryEntry() does this. * * Assumptions: * * 1) aURL is the URL that was inserted into the history list in LoadURL() * 2) The load of aURL is in progress and this function is being called * from one of the functions in nsIStreamListener implemented by nsWebShell. */ nsresult nsWebShell::CheckForTrailingSlash(nsIURI* aURL) { #if OLD_HISTORY nsString* historyURL = (nsString*) mHistory.ElementAt(mHistoryIndex); const char* spec; aURL->GetSpec(&spec); nsString* newURL = (nsString*) new nsString(spec); if (newURL && newURL->Last() == '/' && !historyURL->Equals(*newURL)) { // Replace the top most history entry with the new url if (nsnull != historyURL) { delete historyURL; } mHistory.ReplaceElementAt(newURL, mHistoryIndex); } else delete newURL; #endif /* OLD_HISTORY */ 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::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::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; } NS_IMETHODIMP nsWebShell::GetDefaultCharacterSet (const PRUnichar** aDefaultCharacterSet) { *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() { // XXX TEMPORARY Till we have real pluggable protocol handlers NET_InitJavaScriptProtocol(); 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; }