forked from mirrors/gecko-dev
		
	 1b9ca82439
			
		
	
	
		1b9ca82439
		
	
	
	
	
		
			
			1. Factoring nsIChannel into a protocol specific part, the nsIChannel, and a socket specific, the nsITransport. 2. Derive the nsIChannel from a nsIRequest. 2. Changes the notification system from necko and the URILoader to pass the nsIRequest interface instead of nsIChannel interface. This goal stems from wanting to be able to have active AsyncRead and AsyncWrite operations on nsSocketTransport. This is desired because it would greatly simplify the task of maintaining persistent/reusable socket connections for FTP, HTTP, and Imap (and potentially other protocols). The problem with the existing nsIChannel interface is that it does not allow one to selectively suspend just one of the read or write operations while keeping the other active. The full details of the change on written up in the netlib newsgroup. r=darin@netscape.com sr=rpotts@netscape.com
		
			
				
	
	
		
			1475 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1475 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 | |
|  * vi:tw=2:ts=2:et:sw=2:
 | |
|  *
 | |
|  * The contents of this file are subject to the Netscape Public
 | |
|  * License Version 1.1 (the "License"); you may not use this file
 | |
|  * except in compliance with the License. You may obtain a copy of
 | |
|  * the License at http://www.mozilla.org/NPL/
 | |
|  *
 | |
|  * Software distributed under the License is distributed on an "AS
 | |
|  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 | |
|  * implied. See the License for the specific language governing
 | |
|  * rights and limitations under the License.
 | |
|  *
 | |
|  * The Original Code is Mozilla Communicator client code.
 | |
|  *
 | |
|  * The Initial Developer of the Original Code is Netscape Communications
 | |
|  * Corporation.  Portions created by Netscape are
 | |
|  * Copyright (C) 1998 Netscape Communications Corporation. All
 | |
|  * Rights Reserved.
 | |
|  *
 | |
|  * Contributor(s):
 | |
|  *   Travis Bogard <travis@netscape.com> 
 | |
|  *   Pierre Phaneuf <pp@ludusdesign.com>
 | |
|  */
 | |
| 
 | |
| #ifdef XP_OS2_VACPP
 | |
| // XXX every other file that pulls in _os2.h has no problem with HTMX there;
 | |
| // this one does; the problem may lie with the order of the headers below,
 | |
| // which is why this fix is here instead of in _os2.h
 | |
| typedef unsigned long HMTX;
 | |
| #endif
 | |
| 
 | |
| #include "nsDocShell.h"
 | |
| #include "nsIWebShell.h"
 | |
| #include "nsWebShell.h"
 | |
| #include "nsIWebBrowserChrome.h"
 | |
| #include "nsIInterfaceRequestor.h"
 | |
| #include "nsIWebProgress.h"
 | |
| #include "nsIDocumentLoader.h"
 | |
| #include "nsIDocumentLoaderObserver.h"
 | |
| #include "nsIDocumentLoaderFactory.h"
 | |
| #include "nsIContentViewer.h"
 | |
| #include "nsIDocumentViewer.h"
 | |
| #include "nsIMarkupDocumentViewer.h"
 | |
| #include "nsIClipboardCommands.h"
 | |
| #include "nsILinkHandler.h"
 | |
| #include "nsIStreamListener.h"
 | |
| #include "nsIPrompt.h"
 | |
| #include "nsNetUtil.h"
 | |
| #include "nsIProtocolHandler.h"
 | |
| #include "nsIDNSService.h"
 | |
| #include "nsIRefreshURI.h"
 | |
| #include "nsIScriptGlobalObject.h"
 | |
| #include "nsIScriptGlobalObjectOwner.h"
 | |
| #include "nsIDOMEvent.h"
 | |
| #include "nsIPresContext.h"
 | |
| #include "nsIComponentManager.h"
 | |
| #include "nsIServiceManager.h"
 | |
| #include "nsIEventQueueService.h"
 | |
| #include "nsCRT.h"
 | |
| #include "nsVoidArray.h"
 | |
| #include "nsString.h"
 | |
| #include "nsWidgetsCID.h"
 | |
| #include "nsGfxCIID.h"
 | |
| #include "plevent.h"
 | |
| #include "prprf.h"
 | |
| #include "nsIPluginHost.h"
 | |
| #include "nsplugin.h"
 | |
| //#include "nsPluginsCID.h"
 | |
| #include "nsIPluginManager.h"
 | |
| #include "nsIPref.h"
 | |
| #include "nsITimer.h"
 | |
| #include "nsITimerCallback.h"
 | |
| #include "nsIContent.h"
 | |
| #include "prlog.h"
 | |
| #include "nsCOMPtr.h"
 | |
| #include "nsIPresShell.h"
 | |
| #include "nsIWebShellServices.h"
 | |
| #include "nsIGlobalHistory.h"
 | |
| #include "prmem.h"
 | |
| #include "nsXPIDLString.h"
 | |
| #include "nsDOMError.h"
 | |
| #include "nsIDOMHTMLElement.h"
 | |
| #include "nsIDOMHTMLDocument.h"
 | |
| #include "nsLayoutCID.h"
 | |
| #include "nsIDOMRange.h"
 | |
| #include "nsIURIContentListener.h"
 | |
| #include "nsIDOMDocument.h"
 | |
| #include "nsIBaseWindow.h"
 | |
| #include "nsIDocShell.h"
 | |
| #include "nsIDocShellTreeItem.h"
 | |
| #include "nsIDocShellTreeNode.h"
 | |
| #include "nsIDocShellTreeOwner.h"
 | |
| #include "nsCURILoader.h"
 | |
| #include "nsIDOMWindowInternal.h"
 | |
| #include "nsEscape.h"
 | |
| #include "nsIPlatformCharset.h"
 | |
| #include "nsICharsetConverterManager.h"
 | |
| #include "nsISocketTransportService.h"
 | |
| #include "nsILayoutHistoryState.h"
 | |
| #include "nsTextFormatter.h"
 | |
| #include "nsPIDOMWindow.h"
 | |
| #include "nsIController.h"
 | |
| #include "nsIFocusController.h"
 | |
| 
 | |
| #include "nsIHTTPChannel.h" // add this to the ick include list...we need it to QI for post data interface
 | |
| #include "nsHTTPEnums.h"
 | |
| 
 | |
| 
 | |
| #include "nsILocaleService.h"
 | |
| #include "nsIStringBundle.h"
 | |
| 
 | |
| #include "nsIIOService.h"
 | |
| #include "nsIURL.h"
 | |
| #include "nsIProtocolHandler.h"
 | |
| 
 | |
| //XXX for nsIPostData; this is wrong; we shouldn't see the nsIDocument type
 | |
| #include "nsIDocument.h"
 | |
| 
 | |
| #define SH_IN_FRAMES 1
 | |
| 
 | |
| #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
 | |
| 
 | |
| //static NS_DEFINE_CID(kGlobalHistoryCID, NS_GLOBALHISTORY_CID);
 | |
| //static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
 | |
| static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| 
 | |
| // Class IID's
 | |
| static NS_DEFINE_IID(kEventQueueServiceCID,   NS_EVENTQUEUESERVICE_CID);
 | |
| static NS_DEFINE_CID(kCDOMRangeCID,           NS_RANGE_CID);
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| 
 | |
| // Note: operator new zeros our memory
 | |
| nsWebShell::nsWebShell() : nsDocShell()
 | |
| {
 | |
| #ifdef DEBUG
 | |
|   // We're counting the number of |nsWebShells| to help find leaks
 | |
|   ++gNumberOfWebShells;
 | |
| #endif
 | |
| #ifdef DEBUG
 | |
|     printf("WEBSHELL+ = %ld\n", gNumberOfWebShells);
 | |
| #endif
 | |
| 
 | |
|   NS_INIT_REFCNT();
 | |
|   mThreadEventQueue = nsnull;
 | |
|   InitFrameData();
 | |
|   mItemType = typeContent;
 | |
|   mCharsetReloadState = eCharsetReloadInit;
 | |
|   mHistoryState = nsnull;
 | |
|   mFiredUnloadEvent = PR_FALSE;
 | |
|   mBounds.SetRect(0, 0, 0, 0);
 | |
| }
 | |
| 
 | |
| nsWebShell::~nsWebShell()
 | |
| {
 | |
|    Destroy();
 | |
| 
 | |
|   // Stop any pending document loads and destroy the loader...
 | |
|   if (nsnull != mDocLoader) {
 | |
|     mDocLoader->Stop();
 | |
|     mDocLoader->SetContainer(nsnull);
 | |
|     mDocLoader->Destroy();
 | |
|     NS_RELEASE(mDocLoader);
 | |
|   }
 | |
|   // Cancel any timers that were set for this loader.
 | |
|   CancelRefreshURITimers();
 | |
| 
 | |
|   ++mRefCnt; // following releases can cause this destructor to be called
 | |
|              // recursively if the refcount is allowed to remain 0
 | |
| 
 | |
|   NS_IF_RELEASE(mThreadEventQueue);
 | |
|   mContentViewer=nsnull;
 | |
|   mDeviceContext=nsnull;
 | |
|   NS_IF_RELEASE(mContainer);
 | |
| 
 | |
|   if (mScriptGlobal) {
 | |
|     mScriptGlobal->SetDocShell(nsnull);
 | |
|     mScriptGlobal = nsnull;
 | |
|   }
 | |
|   if (mScriptContext) {
 | |
|     mScriptContext->SetOwner(nsnull);
 | |
|     mScriptContext = nsnull;
 | |
|   }
 | |
| 
 | |
|   InitFrameData();
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   // We're counting the number of |nsWebShells| to help find leaks
 | |
|   --gNumberOfWebShells;
 | |
| #endif
 | |
| #ifdef DEBUG
 | |
|   printf("WEBSHELL- = %ld\n", gNumberOfWebShells);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void nsWebShell::InitFrameData()
 | |
| {
 | |
|   SetMarginWidth(-1);    
 | |
|   SetMarginHeight(-1);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsWebShell::FireUnloadForChildren()
 | |
| {
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   PRInt32 i, n = mChildren.Count();
 | |
|   for (i = 0; i < n; i++) {
 | |
|     nsIDocShell* shell = (nsIDocShell*) mChildren.ElementAt(i);
 | |
|     nsCOMPtr<nsIWebShell> webShell(do_QueryInterface(shell));
 | |
|     rv = webShell->FireUnloadEvent();
 | |
|   }
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::FireUnloadEvent()
 | |
| {
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   if (!mFiredUnloadEvent) {
 | |
|     mFiredUnloadEvent = PR_TRUE;
 | |
| 
 | |
|     if (mScriptGlobal) {
 | |
|       nsIDocumentViewer* docViewer;
 | |
|       if (mContentViewer && NS_SUCCEEDED(mContentViewer->QueryInterface(NS_GET_IID(nsIDocumentViewer), (void**)&docViewer))) {
 | |
|         nsIPresContext *presContext;
 | |
|         if (NS_SUCCEEDED(docViewer->GetPresContext(presContext))) {
 | |
|           nsEventStatus status = nsEventStatus_eIgnore;
 | |
|           nsMouseEvent event;
 | |
|           event.eventStructType = NS_EVENT;
 | |
|           event.message = NS_PAGE_UNLOAD;
 | |
|           rv = mScriptGlobal->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
 | |
| 
 | |
|           NS_RELEASE(presContext);
 | |
|         }
 | |
|         NS_RELEASE(docViewer);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   //Fire child unloads now while our data is intact.
 | |
|   rv = FireUnloadForChildren();
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| NS_IMPL_ADDREF_INHERITED(nsWebShell, nsDocShell)
 | |
| NS_IMPL_RELEASE_INHERITED(nsWebShell, nsDocShell)
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN(nsWebShell)
 | |
| #if 0 // inherits from nsDocShell:
 | |
|    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebShell)
 | |
| #endif
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIWebShell)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
 | |
|    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIContentViewerContainer, nsIWebShell)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIWebShellContainer)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
 | |
| #if 0 // inherits from nsDocShell:
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIDocShell)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
 | |
|    NS_INTERFACE_MAP_ENTRY(nsIScrollable)
 | |
| #endif
 | |
| NS_INTERFACE_MAP_END_INHERITING(nsDocShell)
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetInterface(const nsIID &aIID, void** aInstancePtr)
 | |
| {
 | |
|    NS_ENSURE_ARG_POINTER(aInstancePtr);
 | |
|    nsresult rv = NS_OK;
 | |
|    *aInstancePtr = nsnull;
 | |
| 
 | |
|    if(aIID.Equals(NS_GET_IID(nsILinkHandler)))
 | |
|       {
 | |
|       *aInstancePtr = NS_STATIC_CAST(nsILinkHandler*, this);
 | |
|       NS_ADDREF((nsISupports*)*aInstancePtr);
 | |
|       return NS_OK;
 | |
|       }
 | |
|    else if(aIID.Equals(NS_GET_IID(nsIScriptGlobalObjectOwner)))
 | |
|       {
 | |
|       *aInstancePtr = NS_STATIC_CAST(nsIScriptGlobalObjectOwner*, this);
 | |
|       NS_ADDREF((nsISupports*)*aInstancePtr);
 | |
|       return NS_OK;
 | |
|       }
 | |
|    else if(aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)))
 | |
|       {
 | |
|       NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), NS_ERROR_FAILURE);
 | |
|       *aInstancePtr = mScriptGlobal;
 | |
|       NS_ADDREF((nsISupports*)*aInstancePtr);
 | |
|       return NS_OK;
 | |
|       }
 | |
|    else if(aIID.Equals(NS_GET_IID(nsIDOMWindowInternal)))
 | |
|       {
 | |
|       NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), NS_ERROR_FAILURE);
 | |
|       NS_ENSURE_SUCCESS(mScriptGlobal->QueryInterface(NS_GET_IID(nsIDOMWindowInternal),
 | |
|          aInstancePtr), NS_ERROR_FAILURE);
 | |
|       return NS_OK;
 | |
|       }
 | |
|    else if(aIID.Equals(NS_GET_IID(nsIDOMWindow)))
 | |
|       {
 | |
|       NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), NS_ERROR_FAILURE);
 | |
|       NS_ENSURE_SUCCESS(mScriptGlobal->QueryInterface(NS_GET_IID(nsIDOMWindow),
 | |
|          aInstancePtr), NS_ERROR_FAILURE);
 | |
|       return NS_OK;
 | |
|       }
 | |
| 
 | |
|    if (!*aInstancePtr || NS_FAILED(rv))
 | |
|      return nsDocShell::GetInterface(aIID,aInstancePtr);
 | |
|    else
 | |
|      return rv;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::SetupNewViewer(nsIContentViewer* aViewer)
 | |
| {
 | |
|    NS_ENSURE_SUCCESS(FireUnloadEvent(), NS_ERROR_FAILURE);
 | |
|    NS_ENSURE_SUCCESS(nsDocShell::SetupNewViewer(aViewer), NS_ERROR_FAILURE);
 | |
| 
 | |
|    // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
 | |
|    // *new* document will fire.
 | |
|    mFiredUnloadEvent = PR_FALSE;
 | |
| 
 | |
|     // If the history state has been set by session history,
 | |
|     // set it on the pres shell now that we have a content
 | |
|     // viewer.
 | |
|    if(mContentViewer && mHistoryState)
 | |
|       {
 | |
|       nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(mContentViewer));
 | |
|       if(docv)
 | |
|          {
 | |
|          nsCOMPtr<nsIPresShell> shell;
 | |
|          docv->GetPresShell(*getter_AddRefs(shell));
 | |
|          if(shell)
 | |
|             shell->SetHistoryState((nsILayoutHistoryState*)mHistoryState);
 | |
|          }
 | |
|       }
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::Embed(nsIContentViewer* aContentViewer,
 | |
|                   const char* aCommand,
 | |
|                   nsISupports* aExtraInfo)
 | |
| {
 | |
| #ifdef SH_IN_FRAMES
 | |
| 	return nsDocShell::Embed(aContentViewer, aCommand, aExtraInfo);
 | |
| #else
 | |
|    return SetupNewViewer(aContentViewer);
 | |
| #endif /* SH_IN_FRAMES */
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::SetContainer(nsIWebShellContainer* aContainer)
 | |
| {
 | |
|   NS_IF_RELEASE(mContainer);
 | |
|   mContainer = aContainer;
 | |
|   NS_IF_ADDREF(mContainer);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetContainer(nsIWebShellContainer*& aResult)
 | |
| {
 | |
|   aResult = mContainer;
 | |
|   NS_IF_ADDREF(mContainer);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetTopLevelWindow(nsIWebShellContainer** aTopLevelWindow)
 | |
| {
 | |
|    NS_ENSURE_ARG_POINTER(aTopLevelWindow);
 | |
|    *aTopLevelWindow = nsnull;
 | |
| 
 | |
|    nsCOMPtr<nsIWebShell> rootWebShell;
 | |
| 
 | |
|    GetRootWebShellEvenIfChrome(getter_AddRefs(rootWebShell));
 | |
|    if(!rootWebShell)
 | |
|       return NS_OK;
 | |
|    
 | |
|    nsCOMPtr<nsIWebShellContainer> rootContainer;
 | |
|    rootWebShell->GetContainer(*aTopLevelWindow);
 | |
| 
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| nsEventStatus PR_CALLBACK
 | |
| nsWebShell::HandleEvent(nsGUIEvent *aEvent)
 | |
| {
 | |
|   return nsEventStatus_eIgnore;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetRootWebShell(nsIWebShell*& aResult)
 | |
| {
 | |
|    nsCOMPtr<nsIDocShellTreeItem> top;
 | |
|    GetSameTypeRootTreeItem(getter_AddRefs(top));
 | |
|    nsCOMPtr<nsIWebShell> topAsWebShell(do_QueryInterface(top));
 | |
|    aResult = topAsWebShell;
 | |
|    NS_IF_ADDREF(aResult);
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| void
 | |
| nsWebShell::GetRootWebShellEvenIfChrome(nsIWebShell** aResult)
 | |
| {
 | |
|    nsCOMPtr<nsIDocShellTreeItem> top;
 | |
|    GetRootTreeItem(getter_AddRefs(top));
 | |
|    nsCOMPtr<nsIWebShell> topAsWebShell(do_QueryInterface(top));
 | |
|    *aResult = topAsWebShell;
 | |
|    NS_IF_ADDREF(*aResult);
 | |
| }
 | |
| 
 | |
| /*
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::SetParent(nsIWebShell* aParent)
 | |
| {
 | |
|    nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem(do_QueryInterface(aParent));
 | |
| 
 | |
|    mParent = parentAsTreeItem.get();
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetParent(nsIWebShell*& aParent)
 | |
| {
 | |
|    nsCOMPtr<nsIDocShellTreeItem> parent;
 | |
|    NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
 | |
| 
 | |
|    if(parent)
 | |
|       parent->QueryInterface(NS_GET_IID(nsIWebShell), (void**)&aParent);
 | |
|    else
 | |
|       aParent = nsnull;
 | |
|    return NS_OK;
 | |
| }
 | |
| */
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetReferrer(nsIURI **aReferrer)
 | |
| {
 | |
|    *aReferrer = mReferrerURI;
 | |
|    NS_IF_ADDREF(*aReferrer);
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| void
 | |
| nsWebShell::SetReferrer(const PRUnichar* aReferrer)
 | |
| {
 | |
|    NS_NewURI(getter_AddRefs(mReferrerURI), nsLiteralString(aReferrer), nsnull);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::SetURL(const PRUnichar* aURL)
 | |
| {
 | |
|   nsCOMPtr<nsIURI> uri;
 | |
|   NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(uri), nsLiteralString(aURL),
 | |
|                               nsnull),
 | |
|                     NS_ERROR_FAILURE);
 | |
|   SetCurrentURI(uri);
 | |
|   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;
 | |
| }
 | |
| 
 | |
| //----------------------------------------
 | |
| 
 | |
| // History methods
 | |
| 
 | |
| NS_IMETHODIMP nsWebShell::GoTo(PRInt32 aIndex)
 | |
| {
 | |
|    NS_ENSURE_STATE(mSessionHistory);
 | |
|    NS_ENSURE_TRUE(!IsFrame(), NS_ERROR_FAILURE);
 | |
| 
 | |
|    nsCOMPtr<nsISHEntry> entry;
 | |
| 
 | |
|    NS_ENSURE_SUCCESS(mSessionHistory->GetEntryAtIndex(aIndex, PR_TRUE, 
 | |
|       getter_AddRefs(entry)), NS_ERROR_FAILURE);
 | |
|    NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
 | |
| 
 | |
|    UpdateCurrentSessionHistory();  
 | |
| #ifdef SH_IN_FRAMES
 | |
|    NS_ENSURE_SUCCESS(LoadHistoryEntry(entry, LOAD_HISTORY), NS_ERROR_FAILURE);
 | |
| #else
 | |
|    NS_ENSURE_SUCCESS(LoadHistoryEntry(entry), NS_ERROR_FAILURE);
 | |
| #endif
 | |
| 
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetHistoryLength(PRInt32& aResult)
 | |
| {
 | |
|    NS_ENSURE_STATE(mSessionHistory);
 | |
|    NS_ENSURE_TRUE(!IsFrame(), NS_ERROR_FAILURE);
 | |
|    
 | |
|    NS_ENSURE_SUCCESS(mSessionHistory->GetCount(&aResult), NS_ERROR_FAILURE);
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetHistoryIndex(PRInt32& aResult)
 | |
| {
 | |
|    NS_ENSURE_STATE(mSessionHistory);
 | |
|    NS_ENSURE_TRUE(!IsFrame(), NS_ERROR_FAILURE);
 | |
|    
 | |
|    NS_ENSURE_SUCCESS(mSessionHistory->GetIndex(&aResult), NS_ERROR_FAILURE);
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetURL(PRInt32 aIndex, const PRUnichar** aURLResult)
 | |
| {
 | |
|    NS_ENSURE_STATE(mSessionHistory);
 | |
|    NS_ENSURE_TRUE(!IsFrame(), NS_ERROR_FAILURE);
 | |
| 
 | |
|    nsCOMPtr<nsISHEntry> entry;
 | |
| 
 | |
|    NS_ENSURE_SUCCESS(mSessionHistory->GetEntryAtIndex(aIndex, PR_TRUE, 
 | |
|       getter_AddRefs(entry)), NS_ERROR_FAILURE);
 | |
|    NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
 | |
| 
 | |
|    nsCOMPtr<nsIURI> uri;
 | |
| 
 | |
|    entry->GetURI(getter_AddRefs(uri));
 | |
| 
 | |
|    NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 | |
| 
 | |
|    nsXPIDLCString spec;
 | |
|    uri->GetSpec(getter_Copies(spec));
 | |
| 
 | |
|    *aURLResult = NS_ConvertASCIItoUCS2(spec).ToNewUnicode();
 | |
| 
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| //----------------------------------------
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| 
 | |
| // WebShell container implementation
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::SetHistoryState(nsISupports* aLayoutHistoryState)
 | |
| {
 | |
|   mHistoryState = aLayoutHistoryState;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // Web Shell Services API
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::LoadDocument(const char* aURL,
 | |
|                          const char* aCharset,
 | |
|                          nsCharsetSource aSource)
 | |
| {
 | |
|   // XXX hack. kee the aCharset and aSource wait to pick it up
 | |
|   nsCOMPtr<nsIContentViewer> cv;
 | |
|   NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
 | |
|   if (cv)
 | |
|   {
 | |
|     nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(cv);  
 | |
|     if (muDV)
 | |
|     {
 | |
|       nsCharsetSource hint;
 | |
|       muDV->GetHintCharacterSetSource((PRInt32 *)(&hint));
 | |
|       if( aSource > hint ) 
 | |
|       {
 | |
|         muDV->SetHintCharacterSet(NS_ConvertASCIItoUCS2(aCharset).GetUnicode());
 | |
|         muDV->SetHintCharacterSetSource((PRInt32)aSource);
 | |
|         if(eCharsetReloadRequested != mCharsetReloadState) 
 | |
|         {
 | |
|           mCharsetReloadState = eCharsetReloadRequested;
 | |
|           LoadURI(NS_ConvertASCIItoUCS2(aURL).GetUnicode(), LOAD_FLAGS_NONE);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::ReloadDocument(const char* aCharset,
 | |
|                            nsCharsetSource aSource)
 | |
| {
 | |
| 
 | |
|   // XXX hack. kee the aCharset and aSource wait to pick it up
 | |
|   nsCOMPtr<nsIContentViewer> cv;
 | |
|   NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
 | |
|   if (cv)
 | |
|   {
 | |
|     nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(cv);  
 | |
|     if (muDV)
 | |
|     {
 | |
|       nsCharsetSource hint;
 | |
|       muDV->GetHintCharacterSetSource((PRInt32 *)(&hint));
 | |
|       if( aSource > hint ) 
 | |
|       {
 | |
|          muDV->SetHintCharacterSet(NS_ConvertASCIItoUCS2(aCharset).GetUnicode());
 | |
|          muDV->SetHintCharacterSetSource((PRInt32)aSource);
 | |
|          if(eCharsetReloadRequested != mCharsetReloadState) 
 | |
|          {
 | |
|             mCharsetReloadState = eCharsetReloadRequested;
 | |
|             return Reload(LOAD_FLAGS_NONE);
 | |
|          }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::StopDocumentLoad(void)
 | |
| {
 | |
|   if(eCharsetReloadRequested != mCharsetReloadState) 
 | |
|   {
 | |
|      Stop();
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::SetRendering(PRBool aRender)
 | |
| {
 | |
|   if(eCharsetReloadRequested != mCharsetReloadState) 
 | |
|   {
 | |
|     if (mContentViewer) {
 | |
|        mContentViewer->SetEnableRendering(aRender);
 | |
|     }
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| 
 | |
| // WebShell link handling
 | |
| 
 | |
| struct OnLinkClickEvent : public PLEvent {
 | |
|   OnLinkClickEvent(nsWebShell* aHandler, nsIContent* aContent,
 | |
|                    nsLinkVerb aVerb, const PRUnichar* aURLSpec,
 | |
|                    const PRUnichar* aTargetSpec, nsIInputStream* aPostDataStream = 0, 
 | |
|                    nsIInputStream* aHeadersDataStream = 0);
 | |
|   ~OnLinkClickEvent();
 | |
| 
 | |
|   void HandleEvent() {
 | |
|     mHandler->HandleLinkClickEvent(mContent, mVerb, mURLSpec->GetUnicode(),
 | |
|                                    mTargetSpec->GetUnicode(), mPostDataStream,
 | |
|                                    mHeadersDataStream);
 | |
|   }
 | |
| 
 | |
|   nsWebShell*  mHandler;
 | |
|   nsString*    mURLSpec;
 | |
|   nsString*    mTargetSpec;
 | |
|   nsIInputStream* mPostDataStream;
 | |
|   nsIInputStream* mHeadersDataStream;
 | |
|   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,
 | |
|                                    nsIInputStream* aHeadersDataStream)
 | |
| {
 | |
|   nsIEventQueue* eventQueue;
 | |
| 
 | |
|   mHandler = aHandler;
 | |
|   NS_ADDREF(aHandler);
 | |
|   mURLSpec = new nsString(aURLSpec);
 | |
|   mTargetSpec = new nsString(aTargetSpec);
 | |
|   mPostDataStream = aPostDataStream;
 | |
|   NS_IF_ADDREF(mPostDataStream);
 | |
|   mHeadersDataStream = aHeadersDataStream;
 | |
|   NS_IF_ADDREF(mHeadersDataStream);
 | |
|   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);
 | |
|   NS_IF_RELEASE(mHeadersDataStream);
 | |
|   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,
 | |
|                         nsIInputStream* aHeadersDataStream)
 | |
| {
 | |
|   OnLinkClickEvent* ev;
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   ev = new OnLinkClickEvent(this, aContent, aVerb, aURLSpec,
 | |
|                             aTargetSpec, aPostDataStream, aHeadersDataStream);
 | |
|   if (nsnull == ev) {
 | |
|     rv = NS_ERROR_OUT_OF_MEMORY;
 | |
|   }
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| nsIEventQueue* nsWebShell::GetEventQueue(void)
 | |
| {
 | |
|   NS_PRECONDITION(nsnull != mThreadEventQueue, "EventQueue for thread is null");
 | |
|   NS_ADDREF(mThreadEventQueue);
 | |
|   return mThreadEventQueue;
 | |
| }
 | |
| 
 | |
| void
 | |
| nsWebShell::HandleLinkClickEvent(nsIContent *aContent,
 | |
|                                  nsLinkVerb aVerb,
 | |
|                                  const PRUnichar* aURLSpec,
 | |
|                                  const PRUnichar* aTargetSpec,
 | |
|                                  nsIInputStream* aPostDataStream,
 | |
|                                  nsIInputStream* aHeadersDataStream)
 | |
| {
 | |
|   nsCAutoString target; target.AssignWithConversion(aTargetSpec);
 | |
| 
 | |
|   switch(aVerb) {
 | |
|     case eLinkVerb_New:
 | |
|       target = "_blank";
 | |
|       // Fall into replace case
 | |
|     case eLinkVerb_Undefined:
 | |
|       // Fall through, this seems like the most reasonable action
 | |
|     case eLinkVerb_Replace:
 | |
|       {
 | |
|         // for now, just hack the verb to be view-link-clicked
 | |
|         // and down in the load document code we'll detect this and
 | |
|         // set the correct uri loader command
 | |
|         nsCOMPtr<nsIURI> uri;
 | |
|         NS_NewURI(getter_AddRefs(uri), nsLiteralString(aURLSpec), nsnull);
 | |
| 
 | |
|         // No URI object? This may indicate the URLspec is for an
 | |
|         // unrecognized protocol. Embedders might still be interested
 | |
|         // in handling the click, so we fire a notification before
 | |
|         // throwing the click away.
 | |
|         if (!uri && NS_SUCCEEDED(EnsureContentListener()))
 | |
|         {
 | |
|             nsCOMPtr<nsIURIContentListener> listener = do_QueryInterface(mContentListener);
 | |
|             nsCAutoString spec; spec.AssignWithConversion(aURLSpec);
 | |
|             PRBool abort = PR_FALSE;
 | |
|             nsresult rv;
 | |
|             uri = do_CreateInstance(kSimpleURICID, &rv);
 | |
|             NS_ASSERTION(NS_SUCCEEDED(rv), "can't create simple uri");
 | |
|             if (NS_SUCCEEDED(rv))
 | |
|             {
 | |
|                 rv = uri->SetSpec(spec);
 | |
|                 NS_ASSERTION(NS_SUCCEEDED(rv), "spec is invalid");
 | |
|                 if (NS_SUCCEEDED(rv))
 | |
|                 {
 | |
|                     listener->OnStartURIOpen(uri, target, &abort);
 | |
|                 }
 | |
|             }
 | |
|             return;
 | |
|         }
 | |
| 
 | |
| #ifdef SH_IN_FRAMES
 | |
| 		InternalLoad(uri, mCurrentURI, nsnull, PR_TRUE, PR_FALSE, target, aPostDataStream, 
 | |
|                  aHeadersDataStream, LOAD_LINK, nsnull); 
 | |
| #else
 | |
|         InternalLoad(uri, mCurrentURI, nsnull, PR_TRUE, target, 
 | |
|                      aPostDataStream, aHeadersDataStream, LOAD_LINK); 
 | |
| #endif  /* SH_IN_FRAMES */
 | |
|       }
 | |
|       break;
 | |
|     case eLinkVerb_Embed:
 | |
|       // XXX TODO Should be similar to the HTML IMG ALT attribute handling
 | |
|       //          in NS 4.x
 | |
|     default:
 | |
|       NS_ABORT_IF_FALSE(0,"unexpected link verb");
 | |
|   }
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::OnOverLink(nsIContent* aContent,
 | |
|                        const PRUnichar* aURLSpec,
 | |
|                        const PRUnichar* aTargetSpec)
 | |
| {
 | |
|     nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
 | |
| 
 | |
|    if(browserChrome)
 | |
|       browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, aURLSpec);
 | |
| 
 | |
|    return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::GetLinkState(const char* aLinkURI, nsLinkState& aState)
 | |
| {
 | |
|   aState = eLinkState_Unvisited;
 | |
| 
 | |
|    if(mGlobalHistory)
 | |
|       {
 | |
|       PRInt64 lastVisitDate;
 | |
|       NS_ENSURE_SUCCESS(mGlobalHistory->GetLastVisitDate(aLinkURI,
 | |
|          &lastVisitDate), NS_ERROR_FAILURE);
 | |
| 
 | |
|       // 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;
 | |
| }
 | |
| 
 | |
| //
 | |
| // XXX: This is a temporary method to emulate the mDocLoaderObserver
 | |
| //      notifications that are fired as a result of calling
 | |
| //      SetDocLoaderObserver(...)
 | |
| //
 | |
| //      This method will go away once all of the callers of SetDocLoaderObserver(...)
 | |
| //      are cleaned up.
 | |
| //
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::OnStateChange(nsIWebProgress *aProgress, nsIRequest *request,
 | |
|                           PRInt32 aStateFlags, nsresult aStatus)
 | |
| {
 | |
|   if (!request) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   if (aStateFlags & STATE_IS_DOCUMENT) {
 | |
|     nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(mLoadCookie));
 | |
| 
 | |
|     if (aProgress == webProgress.get()) {
 | |
|       nsCOMPtr<nsIURI> url;
 | |
|       
 | |
|       nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
 | |
|       nsCOMPtr<nsIDocumentLoaderObserver> dlObserver;
 | |
| 
 | |
|       (void) channel->GetURI(getter_AddRefs(url));
 | |
| 
 | |
|       if(!mDocLoaderObserver && mParent) {
 | |
|         /* If this is a frame (in which case it would have a parent && doesn't
 | |
|          * have a documentloaderObserver, get it from the rootWebShell
 | |
|          */
 | |
|         nsCOMPtr<nsIDocShellTreeItem> rootItem;
 | |
|         GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
 | |
|         nsCOMPtr<nsIDocShell> rootDocShell(do_QueryInterface(rootItem));
 | |
|         if(rootDocShell) {
 | |
|           rootDocShell->GetDocLoaderObserver(getter_AddRefs(dlObserver));
 | |
|         }
 | |
|       }
 | |
|       else {
 | |
|         dlObserver = do_QueryInterface(mDocLoaderObserver);  // we need this to addref
 | |
|       }
 | |
| 
 | |
|       if (aStateFlags & STATE_START) {
 | |
|         /*
 | |
|          * Fire the OnStartDocumentLoad of the webshell observer
 | |
|          */
 | |
|         if(mContainer && dlObserver) {
 | |
|           dlObserver->OnStartDocumentLoad(mDocLoader, url, "command is bogus");
 | |
|         }
 | |
|       }
 | |
|       else if (aStateFlags & STATE_STOP) {
 | |
|         /*
 | |
|          * Fire the OnEndDocumentLoad of the DocLoaderobserver
 | |
|          */
 | |
|         if(dlObserver && url) {
 | |
|           dlObserver->OnEndDocumentLoad(mDocLoader, request, aStatus);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (aStateFlags & STATE_IS_REQUEST) {
 | |
|     nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
 | |
|       
 | |
|     if (aStateFlags & STATE_START) {
 | |
|       /*
 | |
|        *Fire the OnStartDocumentLoad of the webshell observer
 | |
|        */
 | |
|       if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver)) {
 | |
|         mDocLoaderObserver->OnStartURLLoad(mDocLoader, request);
 | |
|       }
 | |
|     }
 | |
|     else if (aStateFlags & STATE_STOP) {
 | |
|       /*
 | |
|        *Fire the OnEndDocumentLoad of the webshell observer
 | |
|        */
 | |
|       if ((nsnull != mContainer) && (nsnull != mDocLoaderObserver)) {
 | |
|         mDocLoaderObserver->OnEndURLLoad(mDocLoader, request, aStatus);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return nsDocShell::OnStateChange(aProgress, request, aStateFlags, aStatus);
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress,
 | |
|                                  nsIChannel* channel,
 | |
|                                  nsresult aStatus)
 | |
| {
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   if(!channel)
 | |
|     return NS_ERROR_NULL_POINTER;
 | |
|     
 | |
|   nsCOMPtr<nsIURI> url;
 | |
|   rv = channel->GetURI(getter_AddRefs(url));
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
|   
 | |
|   // clean up reload state for meta charset
 | |
|   if(eCharsetReloadRequested == mCharsetReloadState)
 | |
|     mCharsetReloadState = eCharsetReloadStopOrigional;
 | |
|   else 
 | |
|     mCharsetReloadState = eCharsetReloadInit;
 | |
| 
 | |
|   //
 | |
|   // one of many safeguards that prevent death and destruction if
 | |
|   // someone is so very very rude as to bring this window down
 | |
|   // during this load handler.
 | |
|   //
 | |
|   nsCOMPtr<nsIWebShell> kungFuDeathGrip(this);
 | |
|   nsDocShell::EndPageLoad(aProgress, channel, aStatus);
 | |
| 
 | |
|   //
 | |
|   // If the page load failed, then deal with the error condition...
 | |
|   // Errors are handled as follows:
 | |
|   //   1. Send the URI to a keyword server (if enabled)
 | |
|   //   2. If the error was DNS failure, then add www and .com to the URI
 | |
|   //      (if appropriate).
 | |
|   //   3. Throw an error dialog box...
 | |
|   //
 | |
|   if(url && NS_FAILED(aStatus)) {
 | |
|     nsXPIDLCString host;
 | |
| 
 | |
|     rv = url->GetHost(getter_Copies(host));
 | |
|     if (!host) {
 | |
|       return rv;
 | |
|     }
 | |
| 
 | |
|     CBufDescriptor buf((const char *)host, PR_TRUE, PL_strlen(host) + 1);
 | |
|     nsCAutoString hostStr(buf);
 | |
|     PRInt32 dotLoc = hostStr.FindChar('.');
 | |
| 
 | |
|     nsXPIDLCString scheme;
 | |
|     url->GetScheme(getter_Copies(scheme));
 | |
| 
 | |
|     PRUint32 schemeLen = PL_strlen((const char*)scheme);
 | |
|     CBufDescriptor schemeBuf((const char*)scheme, PR_TRUE, schemeLen+1, schemeLen);
 | |
|     nsCAutoString schemeStr(schemeBuf);
 | |
| 
 | |
|     //
 | |
|     // First try sending the request to a keyword server (if enabled)...
 | |
|     //
 | |
|     if(aStatus == NS_ERROR_UNKNOWN_HOST ||
 | |
|        aStatus == NS_ERROR_CONNECTION_REFUSED ||
 | |
|        aStatus == NS_ERROR_NET_TIMEOUT)
 | |
|     {
 | |
|       PRBool keywordsEnabled = PR_FALSE;
 | |
| 
 | |
|       if(mPrefs) {
 | |
|         rv = mPrefs->GetBoolPref("keyword.enabled", &keywordsEnabled);
 | |
|         if (NS_FAILED(rv)) return rv;
 | |
|       }
 | |
| 
 | |
|       // we should only perform a keyword search under the following conditions:
 | |
|       // (0) Pref keyword.enabled is true
 | |
|       // (1) the url scheme is http (or https)
 | |
|       // (2) the url does not have a protocol scheme
 | |
|       // If we don't enforce such a policy, then we end up doing keyword searchs on urls
 | |
|       // we don't intend like imap, file, mailbox, etc. This could lead to a security
 | |
|       // problem where we send data to the keyword server that we shouldn't be. 
 | |
|       // Someone needs to clean up keywords in general so we can determine on a per url basis
 | |
|       // if we want keywords enabled...this is just a bandaid...
 | |
|       if (keywordsEnabled && !schemeStr.IsEmpty() &&
 | |
|          (schemeStr.Find("http") != 0)) {
 | |
|           keywordsEnabled = PR_FALSE;
 | |
|       }
 | |
| 
 | |
|       if(keywordsEnabled && (-1 == dotLoc)) {
 | |
|         // only send non-qualified hosts to the keyword server
 | |
|         nsAutoString keywordSpec; keywordSpec.AssignWithConversion("keyword:");
 | |
|         keywordSpec.Append(NS_ConvertUTF8toUCS2(host));
 | |
| 
 | |
|         return LoadURI(keywordSpec.GetUnicode(), LOAD_FLAGS_NONE);
 | |
|       } // end keywordsEnabled
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Next, try rewriting the URI using our www.*.com trick
 | |
|     //
 | |
|     if(aStatus == NS_ERROR_UNKNOWN_HOST) {
 | |
|       // Try our www.*.com trick.
 | |
|       nsCAutoString retryHost;
 | |
| 
 | |
| 
 | |
|       if(schemeStr.Find("http") == 0) {
 | |
|         if(-1 == dotLoc) {
 | |
|           retryHost = "www.";
 | |
|           retryHost += hostStr;
 | |
|           retryHost += ".com";
 | |
|         } else {
 | |
|           PRInt32 hostLen = hostStr.Length();
 | |
|           if(((hostLen - dotLoc) == 3) || ((hostLen - dotLoc) == 4)) {
 | |
|             retryHost = "www.";
 | |
|             retryHost += hostStr;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if(!retryHost.IsEmpty()) {
 | |
|         // This seems evil, since it is modifying the original URL
 | |
|         rv = url->SetHost(retryHost.GetBuffer());
 | |
|         if (NS_FAILED(rv)) return rv;
 | |
|         
 | |
|         rv = url->GetSpec(getter_Copies(host));
 | |
|         if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|         // reload the url
 | |
|         return LoadURI(NS_ConvertASCIItoUCS2(host).GetUnicode(), LOAD_FLAGS_NONE);
 | |
|       } // retry
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Well, none of the URI rewriting tricks worked :-(
 | |
|     // It is time to throw an error dialog box, and be done with it...
 | |
|     //
 | |
| 
 | |
|     // Doc failed to load because the host was not found.
 | |
|     if(aStatus == NS_ERROR_UNKNOWN_HOST) {
 | |
|       // throw a DNS failure dialog
 | |
|       nsCOMPtr<nsIPrompt> prompter;
 | |
|       nsCOMPtr<nsIStringBundle> stringBundle;
 | |
|       
 | |
|       rv = GetPromptAndStringBundle(getter_AddRefs(prompter),
 | |
|                                     getter_AddRefs(stringBundle));
 | |
|       if (!stringBundle) {
 | |
|         return rv;
 | |
|       }
 | |
| 
 | |
|       nsXPIDLString messageStr;
 | |
|       rv = stringBundle->GetStringFromName(NS_ConvertASCIItoUCS2("dnsNotFound").GetUnicode(),
 | |
|                                            getter_Copies(messageStr));
 | |
|       if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|       if (host) {
 | |
|         PRUnichar *msg = nsTextFormatter::smprintf(messageStr, (const char*)host);
 | |
|         if (!msg) return NS_ERROR_OUT_OF_MEMORY;
 | |
| 
 | |
|         prompter->Alert(nsnull, msg);
 | |
|         nsTextFormatter::smprintf_free(msg);
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Doc failed to load because we couldn't connect to the server.
 | |
|     // throw a connection failure dialog
 | |
|     //
 | |
|     else if(aStatus == NS_ERROR_CONNECTION_REFUSED) {
 | |
|       PRInt32 port = -1;
 | |
| 
 | |
|       rv = url->GetPort(&port);
 | |
|       if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|       nsCOMPtr<nsIPrompt> prompter;
 | |
|       nsCOMPtr<nsIStringBundle> stringBundle;
 | |
| 
 | |
|       rv = GetPromptAndStringBundle(getter_AddRefs(prompter), 
 | |
|                                     getter_AddRefs(stringBundle));
 | |
|       if (!stringBundle) {
 | |
|         return rv;
 | |
|       }
 | |
| 
 | |
|       nsXPIDLString messageStr;
 | |
|       rv = stringBundle->GetStringFromName(NS_ConvertASCIItoUCS2("connectionFailure").GetUnicode(),
 | |
|                                            getter_Copies(messageStr));
 | |
|       if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|       // build up the host:port string.
 | |
|       nsCAutoString combo(host);
 | |
|       if (port > 0) {
 | |
|         combo.Append(':');
 | |
|         combo.AppendInt(port);
 | |
|       }
 | |
|       
 | |
|       PRUnichar *msg = nsTextFormatter::smprintf(messageStr, combo.GetBuffer());
 | |
|       if (!msg) return NS_ERROR_OUT_OF_MEMORY;
 | |
| 
 | |
|       prompter->Alert(nsnull, msg);
 | |
|       nsTextFormatter::smprintf_free(msg);
 | |
|     }
 | |
|     //
 | |
|     // Doc failed to load because the socket function timed out.
 | |
|     // throw a timeout dialog
 | |
|     //
 | |
|     else if(aStatus == NS_ERROR_NET_TIMEOUT) {
 | |
|       nsCOMPtr<nsIPrompt> prompter;
 | |
|       nsCOMPtr<nsIStringBundle> stringBundle;
 | |
| 
 | |
|       rv = GetPromptAndStringBundle(getter_AddRefs(prompter),
 | |
|                                     getter_AddRefs(stringBundle));
 | |
|       if (!stringBundle) {
 | |
|         return rv;
 | |
|       }
 | |
| 
 | |
|       nsXPIDLString messageStr;
 | |
|       rv = stringBundle->GetStringFromName(NS_ConvertASCIItoUCS2("netTimeout").GetUnicode(),
 | |
|                                            getter_Copies(messageStr));
 | |
|       if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|       PRUnichar *msg = nsTextFormatter::smprintf(messageStr, (const char*)host);
 | |
|       if (!msg) return NS_ERROR_OUT_OF_MEMORY;
 | |
| 
 | |
|       prompter->Alert(nsnull, msg);
 | |
|       nsTextFormatter::smprintf_free(msg);
 | |
|     } // end NS_ERROR_NET_TIMEOUT
 | |
|   } // if we have a host
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| //
 | |
| // Routines for selection and clipboard
 | |
| //
 | |
| 
 | |
| #ifdef XP_MAC
 | |
| #pragma mark -
 | |
| #endif
 | |
| 
 | |
| nsresult
 | |
| nsWebShell :: GetControllerForCommand ( const nsAReadableString & inCommand, nsIController** outController )
 | |
| {
 | |
|   nsresult rv = NS_ERROR_FAILURE;
 | |
|   
 | |
|   nsCOMPtr<nsPIDOMWindow> window ( do_QueryInterface(mScriptGlobal) );
 | |
|   if ( window ) {
 | |
|     nsCOMPtr<nsIFocusController> focusController;
 | |
|     rv = window->GetRootFocusController ( getter_AddRefs(focusController) );
 | |
|     if ( focusController )
 | |
|       rv = focusController->GetControllerForCommand ( inCommand, getter_AddRefs(outController) ) ;
 | |
|   } // if window
 | |
| 
 | |
|   return rv;
 | |
|   
 | |
| } // GetControllerForCommand
 | |
| 
 | |
| 
 | |
| nsresult
 | |
| nsWebShell :: IsCommandEnabled ( const nsAReadableString & inCommand, PRBool* outEnabled )
 | |
| {
 | |
|   nsresult rv = NS_ERROR_FAILURE;
 | |
|   
 | |
|   nsCOMPtr<nsIController> controller;
 | |
|   rv = GetControllerForCommand ( inCommand, getter_AddRefs(controller) );
 | |
|   if ( controller )
 | |
|     rv = controller->IsCommandEnabled(nsPromiseFlatString(inCommand), outEnabled);
 | |
|   
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| 
 | |
| nsresult
 | |
| nsWebShell :: DoCommand ( const nsAReadableString & inCommand )
 | |
| {
 | |
|   nsresult rv = NS_ERROR_FAILURE;
 | |
|   
 | |
|   nsCOMPtr<nsIController> controller;
 | |
|   rv = GetControllerForCommand ( inCommand, getter_AddRefs(controller) );
 | |
|   if ( controller )
 | |
|     rv = controller->DoCommand(nsPromiseFlatString(inCommand));
 | |
|   
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::CanCutSelection(PRBool* aResult)
 | |
| {
 | |
|   nsresult rv = NS_ERROR_NULL_POINTER;
 | |
| 
 | |
|   if ( aResult )
 | |
|     rv = IsCommandEnabled ( NS_LITERAL_STRING("cmd_cut"), aResult );
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::CanCopySelection(PRBool* aResult)
 | |
| {
 | |
|   nsresult rv = NS_ERROR_NULL_POINTER;
 | |
| 
 | |
|   if ( aResult )
 | |
|     rv = IsCommandEnabled ( NS_LITERAL_STRING("cmd_copy"), aResult );
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::CanPaste(PRBool* aResult)
 | |
| {
 | |
|   nsresult rv = NS_ERROR_NULL_POINTER;
 | |
| 
 | |
|   if ( aResult )
 | |
|     rv = IsCommandEnabled ( NS_LITERAL_STRING("cmd_paste"), aResult );
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::CutSelection(void)
 | |
| {
 | |
|   return DoCommand ( NS_LITERAL_STRING("cmd_cut") );
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::CopySelection(void)
 | |
| {
 | |
|   return DoCommand ( NS_LITERAL_STRING("cmd_copy") );
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::CopyLinkLocation(void)
 | |
| {
 | |
|   return DoCommand ( NS_LITERAL_STRING("cmd_copy_link") );
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::Paste(void)
 | |
| {
 | |
|   return DoCommand ( NS_LITERAL_STRING("cmd_paste") );
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::SelectAll(void)
 | |
| {
 | |
|   nsresult rv;
 | |
| 
 | |
|   nsCOMPtr<nsIDocumentViewer> docViewer ( do_QueryInterface(mContentViewer, &rv) );
 | |
|   if (NS_FAILED(rv) || !docViewer) return rv;
 | |
| 
 | |
|   nsCOMPtr<nsIPresShell> presShell;
 | |
|   rv = docViewer->GetPresShell(*getter_AddRefs(presShell));
 | |
|   if (NS_FAILED(rv) || !presShell) return rv;
 | |
|   
 | |
|   nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(presShell, &rv);
 | |
|   if (NS_FAILED(rv) || !selCon) return rv;
 | |
| 
 | |
|   nsCOMPtr<nsISelection> selection;
 | |
|   rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
 | |
|   if (NS_FAILED(rv) || !selection) return rv;
 | |
| 
 | |
|   // Get the document object
 | |
|   nsCOMPtr<nsIDocument> doc;
 | |
|   rv = docViewer->GetDocument(*getter_AddRefs(doc));
 | |
|   if (NS_FAILED(rv) || !doc) return rv;
 | |
| 
 | |
| 
 | |
|   nsCOMPtr<nsIDOMHTMLDocument> htmldoc( do_QueryInterface(doc) );
 | |
|   if (NS_FAILED(rv) || !htmldoc) return rv;
 | |
| 
 | |
|   nsCOMPtr<nsIDOMHTMLElement>bodyElement;
 | |
|   rv = htmldoc->GetBody(getter_AddRefs(bodyElement));
 | |
|   if (NS_FAILED(rv) || !bodyElement) return rv;
 | |
| 
 | |
|   nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
 | |
|   if (!bodyNode) return NS_ERROR_NO_INTERFACE;
 | |
| 
 | |
| #if 0
 | |
|   rv = selection->Collapse(bodyNode, 0);
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|   nsCOMPtr<nsIDOMRange>range;
 | |
|   rv = selection->GetRangeAt(0, getter_AddRefs(range));
 | |
|   if (NS_FAILED(rv) || !range) return rv;
 | |
| #endif
 | |
| 
 | |
|   rv = selection->RemoveAllRanges();
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|   nsCOMPtr<nsIDOMRange> range;
 | |
|   rv = nsComponentManager::CreateInstance(kCDOMRangeCID, nsnull,
 | |
|                                           NS_GET_IID(nsIDOMRange),
 | |
|                                           getter_AddRefs(range));
 | |
| 
 | |
|   rv = range->SelectNodeContents(bodyNode);
 | |
|   if (NS_FAILED(rv)) return rv;
 | |
| 
 | |
|   rv = selection->AddRange(range);
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| 
 | |
| //
 | |
| // SelectNone
 | |
| //
 | |
| // Collapses the current selection, insertion point ends up at beginning
 | |
| // of previous selection.
 | |
| //
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::SelectNone(void)
 | |
| {
 | |
|   nsresult rv = NS_OK;
 | |
|   
 | |
|   nsCOMPtr<nsIDocumentViewer> docViewer ( do_QueryInterface(mContentViewer, &rv) );
 | |
|   if (NS_FAILED(rv) || !docViewer) return rv;
 | |
| 
 | |
|   nsCOMPtr<nsIPresShell> presShell;
 | |
|   rv = docViewer->GetPresShell(*getter_AddRefs(presShell));
 | |
|   if (NS_FAILED(rv) || !presShell) return rv;
 | |
|   
 | |
|   nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(presShell, &rv);
 | |
|   if (NS_FAILED(rv) || !selCon) return rv;
 | |
| 
 | |
|   nsCOMPtr<nsISelection> selection;
 | |
|   rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
 | |
|   if (NS_FAILED(rv) || !selection) return rv;
 | |
|   
 | |
|   return selection->CollapseToStart();
 | |
| }
 | |
| 
 | |
| 
 | |
| //----------------------------------------------------
 | |
| NS_IMETHODIMP
 | |
| nsWebShell::FindNext(const PRUnichar * aSearchStr, PRBool aMatchCase, PRBool aSearchDown, PRBool &aIsFound)
 | |
| {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| #ifdef XP_MAC
 | |
| #pragma mark -
 | |
| #endif
 | |
| 
 | |
| //*****************************************************************************
 | |
| // nsWebShell::nsIBaseWindow
 | |
| //*****************************************************************************   
 | |
| 
 | |
| NS_IMETHODIMP nsWebShell::Create()
 | |
| {
 | |
|      // Cache the PL_EventQueue of the current UI thread...
 | |
|   //
 | |
|   // Since this call must be made on the UI thread, we know the Event Queue
 | |
|   // will be associated with the current thread...
 | |
|   //
 | |
|   nsCOMPtr<nsIEventQueueService> eventService(do_GetService(kEventQueueServiceCID));
 | |
|   NS_ENSURE_TRUE(eventService, NS_ERROR_FAILURE);
 | |
| 
 | |
|   NS_ENSURE_SUCCESS(eventService->GetThreadEventQueue(NS_CURRENT_THREAD,
 | |
|    &mThreadEventQueue), NS_ERROR_FAILURE);
 | |
| 
 | |
|   WEB_TRACE(WEB_TRACE_CALLS,
 | |
|             ("nsWebShell::Init: this=%p", this));
 | |
| 
 | |
|   // HACK....force the uri loader to give us a load cookie for this webshell...then get it's
 | |
|   // doc loader and store it...as more of the docshell lands, we'll be able to get rid
 | |
|   // of this hack...
 | |
|   nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID);
 | |
|   uriLoader->GetDocumentLoaderForContext(NS_STATIC_CAST( nsISupports*, (nsIWebShell *) this), &mDocLoader);
 | |
| 
 | |
|   // Set the webshell as the default IContentViewerContainer for the loader...
 | |
|   mDocLoader->SetContainer(NS_STATIC_CAST(nsIContentViewerContainer*, (nsIWebShell*)this));
 | |
| 
 | |
|    return nsDocShell::Create();
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP nsWebShell::Destroy()
 | |
| {
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   //Fire unload event before we blow anything away.
 | |
|   rv = FireUnloadEvent();
 | |
| 
 | |
|   nsDocShell::Destroy();
 | |
| 
 | |
|   SetContainer(nsnull);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP nsWebShell::SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx,
 | |
|    PRInt32 cy, PRBool fRepaint)
 | |
| {
 | |
|    mBounds.SetRect(x, y, cx, cy);
 | |
|    return nsDocShell::SetPositionAndSize(x, y, cx, cy, fRepaint);   
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP nsWebShell::GetPositionAndSize(PRInt32* x, PRInt32* y, 
 | |
|    PRInt32* cx, PRInt32* cy)
 | |
| {
 | |
|    if(x)
 | |
|       *x = mBounds.x;
 | |
|    if(y)
 | |
|       *y = mBounds.y;
 | |
|    if(cx)
 | |
|       *cx = mBounds.width;
 | |
|    if(cy)
 | |
|       *cy = mBounds.height;
 | |
|       
 | |
|    return NS_OK; 
 | |
| }
 | |
| 
 | |
| #ifdef DEBUG
 | |
| unsigned long nsWebShell::gNumberOfWebShells = 0;
 | |
| #endif
 |