gecko-dev/docshell/base/nsDocShell.cpp
mscott%netscape.com 8e00b3b8cf Fix for Bug #41707 --> JS and data urls were not getting an owner set on them when they were entered from the urlbar. this
prevented them from getting executed properly. For now, we'll inherit the owner of the current document in these
two cases.
r=mstoltz
2000-07-12 05:06:28 +00:00

3904 lines
110 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla 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/MPL/
*
* 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 the Mozilla browser.
*
* The Initial Developer of the Original Code is Netscape
* Communications, Inc. Portions created by Netscape are
* Copyright (C) 1999, Mozilla. All Rights Reserved.
*
* Contributor(s):
* Travis Bogard <travis@netscape.com>
* Pierre Phaneuf <pp@ludusdesign.com>
*/
#include "nsIComponentManager.h"
#include "nsIContent.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
#include "nsIDocumentViewer.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsCURILoader.h"
#include "nsLayoutCID.h"
#include "nsNetUtil.h"
#include "nsRect.h"
#include "prprf.h"
#include "nsIMarkupDocumentViewer.h"
#include "nsXPIDLString.h"
#include "nsIChromeEventHandler.h"
#include "nsIDOMWindow.h"
#include "nsIWebBrowserChrome.h"
#include "nsPoint.h"
#include "nsGfxCIID.h"
#include "nsIPrompt.h"
#include "nsTextFormatter.h"
// Local Includes
#include "nsDocShell.h"
#include "nsDocShellLoadInfo.h"
// Helper Classes
#include "nsDOMError.h"
#include "nsEscape.h"
#include "nsHTTPEnums.h"
// Interfaces Needed
#include "nsICharsetConverterManager.h"
#include "nsIHTTPChannel.h"
#include "nsIDataChannel.h"
#include "nsIProgressEventSink.h"
#include "nsIWebProgress.h"
#include "nsILayoutHistoryState.h"
#include "nsILocaleService.h"
#include "nsIPlatformCharset.h"
#include "nsITimer.h"
#include "nsIFileStream.h"
#include "nsIPrincipal.h"
// For reporting errors with the console service.
// These can go away if error reporting is propagated up past nsDocShell.
#include "nsIConsoleService.h"
#include "nsIScriptError.h"
// used to dispatch urls to default protocol handlers
#include "nsCExternalHandlerService.h"
#include "nsIExternalProtocolService.h"
static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID);
static NS_DEFINE_CID(kPlatformCharsetCID, NS_PLATFORMCHARSET_CID);
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
//*****************************************************************************
//*** nsDocShell: Object Management
//*****************************************************************************
nsDocShell::nsDocShell() :
mContentListener(nsnull),
mInitInfo(nsnull),
mMarginWidth(0),
mMarginHeight(0),
mItemType(typeContent),
mCurrentScrollbarPref(-1,-1),
mDefaultScrollbarPref(-1,-1),
mInitialPageLoad(PR_TRUE),
mAllowPlugins(PR_TRUE),
mViewMode(viewNormal),
mEODForCurrentDocument (PR_FALSE),
mUseExternalProtocolHandler (PR_FALSE),
mParent(nsnull),
mTreeOwner(nsnull),
mChromeEventHandler(nsnull)
{
NS_INIT_REFCNT();
}
nsDocShell::~nsDocShell()
{
Destroy();
}
NS_IMETHODIMP nsDocShell::DestroyChildren()
{
PRInt32 i, n = mChildren.Count();
nsCOMPtr<nsIDocShellTreeItem> shell;
for (i = 0; i < n; i++)
{
shell = dont_AddRef((nsIDocShellTreeItem*)mChildren.ElementAt(i));
if(!NS_WARN_IF_FALSE(shell, "docshell has null child"))
shell->SetParent(nsnull);
nsCOMPtr<nsIBaseWindow> shellWin(do_QueryInterface(shell));
if(shellWin)
shellWin->Destroy();
}
mChildren.Clear();
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsISupports
//*****************************************************************************
NS_IMPL_THREADSAFE_ADDREF(nsDocShell)
NS_IMPL_THREADSAFE_RELEASE(nsDocShell)
NS_INTERFACE_MAP_BEGIN(nsDocShell)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShell)
NS_INTERFACE_MAP_ENTRY(nsIDocShell)
NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode)
NS_INTERFACE_MAP_ENTRY(nsIDocShellHistory)
NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
NS_INTERFACE_MAP_ENTRY(nsIScrollable)
NS_INTERFACE_MAP_ENTRY(nsITextScroll)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END_THREADSAFE
///*****************************************************************************
// nsDocShell::nsIInterfaceRequestor
//*****************************************************************************
NS_IMETHODIMP nsDocShell::GetInterface(const nsIID& aIID, void** aSink)
{
NS_ENSURE_ARG_POINTER(aSink);
if(aIID.Equals(NS_GET_IID(nsIURIContentListener)) &&
NS_SUCCEEDED(EnsureContentListener()))
*aSink = mContentListener;
else if(aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) &&
NS_SUCCEEDED(EnsureScriptEnvironment()))
*aSink = mScriptGlobal;
else if(aIID.Equals(NS_GET_IID(nsIDOMWindow)) &&
NS_SUCCEEDED(EnsureScriptEnvironment()))
{
NS_ENSURE_SUCCESS(mScriptGlobal->QueryInterface(NS_GET_IID(nsIDOMWindow),
aSink), NS_ERROR_FAILURE);
return NS_OK;
}
else if(aIID.Equals(NS_GET_IID(nsIPrompt)))
{
nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mTreeOwner));
if (prompter)
{
*aSink = prompter;
NS_ADDREF((nsISupports*)*aSink);
return NS_OK;
}
else
return NS_NOINTERFACE;
}
else if (aIID.Equals(NS_GET_IID(nsIProgressEventSink)) ||
aIID.Equals(NS_GET_IID(nsIWebProgress)))
{
nsCOMPtr<nsIURILoader> uriLoader(do_GetService(NS_URI_LOADER_PROGID));
NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocumentLoader> docLoader;
NS_ENSURE_SUCCESS(uriLoader->GetDocumentLoaderForContext(NS_STATIC_CAST(nsIDocShell*, this),
getter_AddRefs(docLoader)), NS_ERROR_FAILURE);
if (docLoader) {
nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryInterface(docLoader));
return requestor->GetInterface(aIID, aSink);
}
else
return NS_ERROR_FAILURE;
}
else
return QueryInterface(aIID, aSink);
NS_IF_ADDREF(((nsISupports*)*aSink));
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsIDocShell
//*****************************************************************************
NS_IMETHODIMP
nsDocShell::LoadURI(nsIURI* aURI, nsIDocShellLoadInfo* aLoadInfo)
{
nsresult rv;
nsCOMPtr<nsIURI> referrer;
nsCOMPtr<nsISupports> owner;
nsCOMPtr<nsISHEntry> shEntry;
nsDocShellInfoLoadType loadType = nsIDocShellLoadInfo::loadNormal;
NS_ENSURE_ARG(aURI);
// Extract the info from the DocShellLoadInfo struct...
if(aLoadInfo) {
aLoadInfo->GetReferrer(getter_AddRefs(referrer));
aLoadInfo->GetLoadType(&loadType);
aLoadInfo->GetOwner(getter_AddRefs(owner));
aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
}
if (!shEntry) {
/* Check if we are in the middle of loading a subframe whose parent
* was originally loaded thro' Session History. ie., you were in a frameset
* page, went somewhere else and clicked 'back'. The loading of the root page
* is done and we are currently loading one of its children or sub-children.
*/
nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
GetSameTypeParent(getter_AddRefs(parentAsItem));
// Try to get your SHEntry from your parent
if (parentAsItem) {
nsCOMPtr<nsIDocShellHistory> parent(do_QueryInterface(parentAsItem));
// XXX: Should we care if this QI fails?
if (parent) {
parent->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
if (shEntry) {
loadType = nsIDocShellLoadInfo::loadHistory;
}
}
}
}
if (shEntry) {
rv = LoadHistoryEntry(shEntry, loadType);
} else {
rv = InternalLoad(aURI, referrer, owner, nsnull, nsnull, loadType, nsnull);
}
return rv;
}
NS_IMETHODIMP nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI *aURI,
const char *aContentType, PRInt32 aContentLen,
nsIDocShellLoadInfo* aLoadInfo)
{
NS_ENSURE_ARG(aStream);
NS_ENSURE_ARG(aContentType);
NS_ENSURE_ARG(aContentLen);
// if the caller doesn't pass in a URI we need to create a dummy URI. necko
// currently requires a URI in various places during the load. Some consumers
// do as well.
nsCOMPtr<nsIURI> uri = aURI;
if (!uri) {
// HACK ALERT
nsresult rv = NS_OK;
uri = do_CreateInstance(kSimpleURICID, &rv);
if (NS_FAILED(rv)) return rv;
rv = uri->SetSpec("stream");
if (NS_FAILED(rv)) return rv;
}
nsDocShellInfoLoadType loadType = nsIDocShellLoadInfo::loadNormal;
if(aLoadInfo)
(void)aLoadInfo->GetLoadType(&loadType);
NS_ENSURE_SUCCESS(StopLoad(), NS_ERROR_FAILURE);
// Cancel any timers that were set for this loader.
(void)CancelRefreshURITimers();
mLoadType = loadType;
// build up a channel for this stream.
nsCOMPtr<nsIChannel> channel;
NS_ENSURE_SUCCESS(NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, aStream,
aContentType, aContentLen), NS_ERROR_FAILURE);
nsCOMPtr<nsIURILoader> uriLoader(do_GetService(NS_URI_LOADER_PROGID));
NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(DoChannelLoad(channel, nsIURILoader::viewNormal, nsnull, uriLoader), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo** aLoadInfo)
{
nsDocShellLoadInfo* loadInfo = new nsDocShellLoadInfo();
NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
*aLoadInfo = localRef;
NS_ADDREF(*aLoadInfo);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::StopLoad()
{
if(mLoadCookie)
{
nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_PROGID);
if(uriLoader)
uriLoader->Stop(mLoadCookie);
}
PRInt32 n;
PRInt32 count = mChildren.Count();
for(n = 0; n < count; n++)
{
nsIDocShellTreeItem* shellItem = (nsIDocShellTreeItem*)mChildren.ElementAt(n);
nsCOMPtr<nsIDocShell> shell(do_QueryInterface(shellItem));
if(shell)
shell->StopLoad();
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetDocument(nsIDOMDocument *aDOMDoc, nsIDOMElement *aRootNode)
{
/* XXX: This method is obsolete and will be removed. */
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsDocShell::GetCurrentURI(nsIURI** aURI)
{
NS_ENSURE_ARG_POINTER(aURI);
*aURI = mCurrentURI;
NS_IF_ADDREF(*aURI);
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetDocLoaderObserver(nsIDocumentLoaderObserver * *aDocLoaderObserver)
{
NS_ENSURE_ARG_POINTER(aDocLoaderObserver);
*aDocLoaderObserver = mDocLoaderObserver;
NS_IF_ADDREF(*aDocLoaderObserver);
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetDocLoaderObserver(nsIDocumentLoaderObserver * aDocLoaderObserver)
{
// it's legal for aDocLoaderObserver to be null.
mDocLoaderObserver = aDocLoaderObserver;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetPresContext(nsIPresContext** aPresContext)
{
nsresult rv = NS_OK;
NS_ENSURE_ARG_POINTER(aPresContext);
*aPresContext = nsnull;
if (mContentViewer) {
nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(mContentViewer));
if (docv) {
rv = docv->GetPresContext(*aPresContext);
}
}
// Fail silently, if no PresContext is available...
return rv;
}
NS_IMETHODIMP nsDocShell::GetPresShell(nsIPresShell** aPresShell)
{
nsresult rv = NS_OK;
NS_ENSURE_ARG_POINTER(aPresShell);
*aPresShell = nsnull;
nsCOMPtr<nsIPresContext> presContext;
(void) GetPresContext(getter_AddRefs(presContext));
if(presContext) {
rv = presContext->GetShell(aPresShell);
}
return rv;
}
NS_IMETHODIMP nsDocShell::GetContentViewer(nsIContentViewer** aContentViewer)
{
NS_ENSURE_ARG_POINTER(aContentViewer);
*aContentViewer = mContentViewer;
NS_IF_ADDREF(*aContentViewer);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetChromeEventHandler(nsIChromeEventHandler* aChromeEventHandler)
{
// Weak reference. Don't addref.
mChromeEventHandler = aChromeEventHandler;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetChromeEventHandler(nsIChromeEventHandler** aChromeEventHandler)
{
NS_ENSURE_ARG_POINTER(aChromeEventHandler);
*aChromeEventHandler = mChromeEventHandler;
NS_IF_ADDREF(*aChromeEventHandler);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetParentURIContentListener(nsIURIContentListener**
aParent)
{
NS_ENSURE_ARG_POINTER(aParent);
NS_ENSURE_SUCCESS(EnsureContentListener(), NS_ERROR_FAILURE);
return mContentListener->GetParentContentListener(aParent);
}
NS_IMETHODIMP nsDocShell::SetParentURIContentListener(nsIURIContentListener*
aParent)
{
NS_ENSURE_SUCCESS(EnsureContentListener(), NS_ERROR_FAILURE);
return mContentListener->SetParentContentListener(aParent);
}
NS_IMETHODIMP nsDocShell::GetDocumentCharsetInfo(nsIDocumentCharsetInfo**
aDocumentCharsetInfo)
{
NS_ENSURE_ARG_POINTER(aDocumentCharsetInfo);
*aDocumentCharsetInfo = mDocumentCharsetInfo;
NS_IF_ADDREF(*aDocumentCharsetInfo);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetDocumentCharsetInfo(nsIDocumentCharsetInfo*
aDocumentCharsetInfo)
{
mDocumentCharsetInfo = aDocumentCharsetInfo;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetAllowPlugins(PRBool* aAllowPlugins)
{
NS_ENSURE_ARG_POINTER(aAllowPlugins);
*aAllowPlugins = mAllowPlugins;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetAllowPlugins(PRBool aAllowPlugins)
{
mAllowPlugins = aAllowPlugins;
//XXX should enable or disable a plugin host
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetViewMode(PRInt32* aViewMode)
{
NS_ENSURE_ARG_POINTER(aViewMode);
*aViewMode = mViewMode;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetViewMode(PRInt32 aViewMode)
{
NS_ENSURE_ARG((viewNormal == aViewMode) || (viewSource == aViewMode));
PRBool reload = PR_FALSE;
if((mViewMode != aViewMode) && mCurrentURI)
reload = PR_TRUE;
mViewMode = aViewMode;
if(reload)
Reload(nsIDocShellLoadInfo::loadReloadNormal);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetZoom(float* zoom)
{
NS_ENSURE_ARG_POINTER(zoom);
NS_ENSURE_SUCCESS(EnsureDeviceContext(), NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(mDeviceContext->GetZoom(*zoom), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetZoom(float zoom)
{
NS_ENSURE_SUCCESS(EnsureDeviceContext(), NS_ERROR_FAILURE);
mDeviceContext->SetZoom(zoom);
// get the pres shell
nsCOMPtr<nsIPresShell> presShell;
NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
// get the view manager
nsCOMPtr<nsIViewManager> vm;
NS_ENSURE_SUCCESS(presShell->GetViewManager(getter_AddRefs(vm)), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
// get the root scrollable view
nsIScrollableView* scrollableView = nsnull;
vm->GetRootScrollableView(&scrollableView);
if(scrollableView)
scrollableView->ComputeScrollOffsets();
// get the root view
nsIView *rootView=nsnull; // views are not ref counted
vm->GetRootView(rootView);
if(rootView)
vm->UpdateView(rootView, 0);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetMarginWidth(PRInt32* aWidth)
{
NS_ENSURE_ARG_POINTER(aWidth);
*aWidth = mMarginWidth;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetMarginWidth(PRInt32 aWidth)
{
mMarginWidth = aWidth;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetMarginHeight(PRInt32* aHeight)
{
NS_ENSURE_ARG_POINTER(aHeight);
*aHeight = mMarginHeight;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetMarginHeight(PRInt32 aHeight)
{
mMarginHeight = aHeight;
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsIDocShellTreeItem
//*****************************************************************************
NS_IMETHODIMP nsDocShell::GetName(PRUnichar** aName)
{
NS_ENSURE_ARG_POINTER(aName);
*aName = mName.ToNewUnicode();
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetName(const PRUnichar* aName)
{
mName = aName; // this does a copy of aName
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetItemType(PRInt32* aItemType)
{
NS_ENSURE_ARG_POINTER(aItemType);
*aItemType = mItemType;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetItemType(PRInt32 aItemType)
{
NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
NS_ENSURE_STATE(!mParent);
mItemType = aItemType;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetParent(nsIDocShellTreeItem** aParent)
{
NS_ENSURE_ARG_POINTER(aParent);
*aParent = mParent;
NS_IF_ADDREF(*aParent);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetParent(nsIDocShellTreeItem* aParent)
{
// null aParent is ok
/*
Note this doesn't do an addref on purpose. This is because the parent
is an implied lifetime. We don't want to create a cycle by refcounting
the parent.
*/
mParent = aParent;
nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(aParent));
if(parentURIListener)
SetParentURIContentListener(parentURIListener);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetSameTypeParent(nsIDocShellTreeItem** aParent)
{
NS_ENSURE_ARG_POINTER(aParent);
*aParent = nsnull;
if(!mParent)
return NS_OK;
PRInt32 parentType;
NS_ENSURE_SUCCESS(mParent->GetItemType(&parentType), NS_ERROR_FAILURE);
if(parentType == mItemType)
{
*aParent = mParent;
NS_ADDREF(*aParent);
}
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetRootTreeItem(nsIDocShellTreeItem** aRootTreeItem)
{
NS_ENSURE_ARG_POINTER(aRootTreeItem);
*aRootTreeItem = NS_STATIC_CAST(nsIDocShellTreeItem*, this);
nsCOMPtr<nsIDocShellTreeItem> parent;
NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
while(parent)
{
*aRootTreeItem = parent;
NS_ENSURE_SUCCESS((*aRootTreeItem)->GetParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
}
NS_ADDREF(*aRootTreeItem);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem** aRootTreeItem)
{
NS_ENSURE_ARG_POINTER(aRootTreeItem);
*aRootTreeItem = NS_STATIC_CAST(nsIDocShellTreeItem*, this);
nsCOMPtr<nsIDocShellTreeItem> parent;
NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
while(parent)
{
*aRootTreeItem = parent;
NS_ENSURE_SUCCESS((*aRootTreeItem)->GetSameTypeParent(getter_AddRefs(parent)),
NS_ERROR_FAILURE);
}
NS_ADDREF(*aRootTreeItem);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::FindItemWithName(const PRUnichar *aName,
nsISupports* aRequestor, nsIDocShellTreeItem **_retval)
{
NS_ENSURE_ARG(aName);
NS_ENSURE_ARG_POINTER(_retval);
*_retval = nsnull; // if we don't find one, we return NS_OK and a null result
// This QI may fail, but the places where we want to compare, comparing
// against nsnull serves the same purpose.
nsCOMPtr<nsIDocShellTreeItem> reqAsTreeItem(do_QueryInterface(aRequestor));
// First we check our name.
if(mName.EqualsWithConversion(aName))
{
*_retval = NS_STATIC_CAST(nsIDocShellTreeItem*, this);
NS_ADDREF(*_retval);
return NS_OK;
}
// Second we check our children making sure not to ask a child if it
// is the aRequestor.
NS_ENSURE_SUCCESS(FindChildWithName(aName, PR_TRUE, PR_TRUE, reqAsTreeItem,
_retval),
NS_ERROR_FAILURE);
if(*_retval)
return NS_OK;
// Third if we have a parent and it isn't the requestor then we should ask
// it to do the search. If it is the requestor we should just stop here
// and let the parent do the rest.
// If we don't have a parent, then we should ask the docShellTreeOwner to do
// the search.
if(mParent)
{
if(mParent == reqAsTreeItem.get())
return NS_OK;
PRInt32 parentType;
mParent->GetItemType(&parentType);
if(parentType == mItemType)
{
NS_ENSURE_SUCCESS(mParent->FindItemWithName(aName,
NS_STATIC_CAST(nsIDocShellTreeItem*, this), _retval),
NS_ERROR_FAILURE);
return NS_OK;
}
// If the parent isn't of the same type fall through and ask tree owner.
}
// This QI may fail, but comparing against null serves the same purpose
nsCOMPtr<nsIDocShellTreeOwner> reqAsTreeOwner(do_QueryInterface(aRequestor));
if(mTreeOwner && (mTreeOwner != reqAsTreeOwner.get()))
{
NS_ENSURE_SUCCESS(mTreeOwner->FindItemWithName(aName,
NS_STATIC_CAST(nsIDocShellTreeItem*, this), _retval),
NS_ERROR_FAILURE);
}
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner)
{
NS_ENSURE_ARG_POINTER(aTreeOwner);
*aTreeOwner = mTreeOwner;
NS_IF_ADDREF(*aTreeOwner);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
{
// Don't automatically set the progress based on the tree owner for frames
if (!IsFrame()) {
nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(mLoadCookie));
if (webProgress) {
nsCOMPtr<nsIWebProgressListener> oldListener(do_QueryInterface(mTreeOwner));
nsCOMPtr<nsIWebProgressListener> newListener(do_QueryInterface(aTreeOwner));
if (oldListener) {
webProgress->RemoveProgressListener(oldListener);
}
if (newListener) {
webProgress->AddProgressListener(newListener);
}
}
}
mTreeOwner = aTreeOwner; // Weak reference per API
PRInt32 i, n = mChildren.Count();
for(i = 0; i < n; i++)
{
nsIDocShellTreeItem* child = (nsIDocShellTreeItem*) mChildren.ElementAt(i); // doesn't addref the result
NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
PRInt32 childType = ~mItemType; // Set it to not us in case the get fails
child->GetItemType(&childType); // We don't care if this fails, if it does we won't set the owner
if(childType == mItemType)
child->SetTreeOwner(aTreeOwner);
}
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetChildOffset(PRInt32 aChildOffset)
{
mChildOffset = aChildOffset;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetChildOffset(PRInt32 *aChildOffset)
{
NS_ENSURE_ARG_POINTER(aChildOffset);
*aChildOffset = mChildOffset;
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsIDocShellTreeNode
//*****************************************************************************
NS_IMETHODIMP nsDocShell::GetChildCount(PRInt32 *aChildCount)
{
NS_ENSURE_ARG_POINTER(aChildCount);
*aChildCount = mChildren.Count();
return NS_OK;
}
NS_IMETHODIMP nsDocShell::AddChild(nsIDocShellTreeItem *aChild)
{
NS_ENSURE_ARG_POINTER(aChild);
NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
mChildren.AppendElement(aChild);
NS_ADDREF(aChild);
// Set the child's index in the parent's children list
// XXX What if the parent had different types of children?
// XXX in that case docshell hierarchyand SH hierarchy won't match.
PRInt32 childCount = mChildren.Count();
aChild->SetChildOffset(childCount-1);
PRInt32 childType = ~mItemType; // Set it to not us in case the get fails
aChild->GetItemType(&childType);
if(childType != mItemType)
return NS_OK;
// Everything below here is only done when the child is the same type.
aChild->SetTreeOwner(mTreeOwner);
nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
if(!childAsDocShell)
return NS_OK;
// Do some docShell Specific stuff.
nsXPIDLString defaultCharset;
nsXPIDLString forceCharset;
NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(mContentViewer);
if(muDV)
{
NS_ENSURE_SUCCESS(muDV->GetDefaultCharacterSet(getter_Copies(defaultCharset)),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(muDV->GetForceCharacterSet(getter_Copies(forceCharset)),
NS_ERROR_FAILURE);
}
nsCOMPtr<nsIContentViewer> childCV;
NS_ENSURE_SUCCESS(childAsDocShell->GetContentViewer(getter_AddRefs(childCV)),
NS_ERROR_FAILURE);
if(childCV)
{
nsCOMPtr<nsIMarkupDocumentViewer> childmuDV = do_QueryInterface(childCV);
if(childmuDV)
{
NS_ENSURE_SUCCESS(childmuDV->SetDefaultCharacterSet(defaultCharset),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(childmuDV->SetForceCharacterSet(forceCharset),
NS_ERROR_FAILURE);
}
}
return NS_OK;
}
NS_IMETHODIMP nsDocShell::RemoveChild(nsIDocShellTreeItem *aChild)
{
NS_ENSURE_ARG_POINTER(aChild);
if(mChildren.RemoveElement(aChild))
{
aChild->SetParent(nsnull);
aChild->SetTreeOwner(nsnull);
NS_RELEASE(aChild);
}
else
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetChildAt(PRInt32 aIndex, nsIDocShellTreeItem** aChild)
{
NS_ENSURE_ARG_POINTER(aChild);
NS_ENSURE_ARG_RANGE(aIndex, 0, mChildren.Count() - 1);
*aChild = (nsIDocShellTreeItem*) mChildren.ElementAt(aIndex);
NS_IF_ADDREF(*aChild);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::FindChildWithName(const PRUnichar *aName,
PRBool aRecurse, PRBool aSameType, nsIDocShellTreeItem* aRequestor,
nsIDocShellTreeItem **_retval)
{
NS_ENSURE_ARG(aName);
NS_ENSURE_ARG_POINTER(_retval);
*_retval = nsnull; // if we don't find one, we return NS_OK and a null result
nsAutoString name(aName);
nsXPIDLString childName;
PRInt32 i, n = mChildren.Count();
for(i = 0; i < n; i++)
{
nsIDocShellTreeItem* child = (nsIDocShellTreeItem*) mChildren.ElementAt(i); // doesn't addref the result
NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
PRInt32 childType;
child->GetItemType(&childType);
if(aSameType && (childType != mItemType))
continue;
child->GetName(getter_Copies(childName));
if(name.EqualsWithConversion(childName))
{
*_retval = child;
NS_ADDREF(*_retval);
break;
}
if(childType != mItemType) //Only ask it to check children if it is same type
continue;
if(aRecurse && (aRequestor != child)) // Only ask the child if it isn't the requestor
{
// See if child contains the shell with the given name
nsCOMPtr<nsIDocShellTreeNode> childAsNode(do_QueryInterface(child));
if(child)
{
NS_ENSURE_SUCCESS(childAsNode->FindChildWithName(aName, PR_TRUE,
aSameType, NS_STATIC_CAST(nsIDocShellTreeItem*, this), _retval),
NS_ERROR_FAILURE);
}
}
if(*_retval) // found it
return NS_OK;
}
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsIDocShellHistory
//*****************************************************************************
NS_IMETHODIMP
nsDocShell::GetChildSHEntry(PRInt32 aChildOffset, nsISHEntry ** aResult)
{
nsresult rv = NS_OK;
NS_ENSURE_ARG_POINTER(aResult);
*aResult = nsnull;
//
// A nsISHEntry for a child is *only* available when the parent is in
// the progress of loading a document too...
//
if (LSHE) {
nsCOMPtr<nsISHContainer> container(do_QueryInterface(LSHE));
if (container) {
rv = container->GetChildAt(aChildOffset, aResult);
}
}
return rv;
}
NS_IMETHODIMP
nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
PRInt32 aChildOffset)
{
nsresult rv;
if (LSHE) {
/* You get here if you are currently building a
* hierarchy ie.,you just visited a frameset page
*/
nsCOMPtr<nsISHContainer> container(do_QueryInterface(LSHE, &rv));
if(container)
rv = container->AddChild(aNewEntry, aChildOffset);
}
else if (mSessionHistory) {
/* You are currently in the rootDocShell.
* You will get here when a subframe has a new url
* to load and you have walked up the tree all the
* way to the top
*/
PRInt32 index=-1;
nsCOMPtr<nsISHEntry> currentEntry;
mSessionHistory->GetIndex(&index);
if (index < 0)
return NS_ERROR_FAILURE;
rv = mSessionHistory->GetEntryAtIndex(index, PR_FALSE,
getter_AddRefs(currentEntry));
if (currentEntry) {
nsCOMPtr<nsISHEntry> nextEntry; //(do_CreateInstance(NS_SHENTRY_PROGID));
// NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
rv = CloneAndReplace(currentEntry, aCloneRef, aNewEntry,
getter_AddRefs(nextEntry));
if (NS_SUCCEEDED(rv)) {
rv = mSessionHistory->AddEntry(nextEntry, PR_TRUE);
}
}
}
else {
/* You will get here when you are in a subframe and
* a new url has been loaded on you.
* The OSHE in this subframe will be the previous url's
* OSHE. This OSHE will be used as the identification
* for this subframe in the CloneAndReplace function.
*/
nsCOMPtr<nsIDocShellHistory> parent(do_QueryInterface(mParent, &rv));
if (parent) {
if (!aCloneRef) {
aCloneRef = OSHE;
}
rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset);
}
}
return rv;
}
//*****************************************************************************
// nsDocShell::nsIWebNavigation
//*****************************************************************************
NS_IMETHODIMP nsDocShell::GetCanGoBack(PRBool* aCanGoBack)
{
#ifndef SH_IN_FRAMES
NS_ENSURE_ARG_POINTER(aCanGoBack);
*aCanGoBack = PR_FALSE;
if (mSessionHistory == nsnull) {
return NS_OK;
}
NS_ENSURE_STATE(mSessionHistory);
PRInt32 index = -1;
NS_ENSURE_SUCCESS(mSessionHistory->GetIndex(&index), NS_ERROR_FAILURE);
if(index > 0)
*aCanGoBack = PR_TRUE;
#else
if (mSessionHistory) {
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mSessionHistory));
if (webNav) {
return webNav->GetCanGoBack(aCanGoBack);
}
}
#endif
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetCanGoForward(PRBool* aCanGoForward)
{
#ifndef SH_IN_FRAMES
NS_ENSURE_ARG_POINTER(aCanGoForward);
*aCanGoForward = PR_FALSE;
if (mSessionHistory == nsnull) {
return NS_OK;
}
NS_ENSURE_STATE(mSessionHistory);
PRInt32 index = -1;
PRInt32 count = -1;
NS_ENSURE_SUCCESS(mSessionHistory->GetIndex(&index), NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(mSessionHistory->GetCount(&count), NS_ERROR_FAILURE);
if((index >= 0) && (index < (count - 1)))
*aCanGoForward = PR_TRUE;
#else
if (mSessionHistory) {
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mSessionHistory));
if (webNav) {
return webNav->GetCanGoForward(aCanGoForward);
}
}
#endif
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GoBack()
{
#ifndef SH_IN_FRAMES
if (mSessionHistory == nsnull) {
return NS_OK;
}
nsCOMPtr<nsIDocShellTreeItem> root;
GetSameTypeRootTreeItem(getter_AddRefs(root));
if(root.get() != NS_STATIC_CAST(nsIDocShellTreeItem*, this))
{
nsCOMPtr<nsIWebNavigation> rootAsNav(do_QueryInterface(root));
return rootAsNav->GoBack();
}
NS_ENSURE_STATE(mSessionHistory);
UpdateCurrentSessionHistory();
nsCOMPtr<nsISHEntry> previousEntry;
NS_ENSURE_SUCCESS(mSessionHistory->GetPreviousEntry(PR_TRUE,
getter_AddRefs(previousEntry)), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(previousEntry, NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(LoadHistoryEntry(previousEntry), NS_ERROR_FAILURE);
#else
if (mSessionHistory) {
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mSessionHistory));
if (webNav) {
return webNav->GoBack();
}
}
#endif
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GoForward()
{
#ifndef SH_IN_FRAMES
if (mSessionHistory == nsnull) {
return NS_OK;
}
nsCOMPtr<nsIDocShellTreeItem> root;
GetSameTypeRootTreeItem(getter_AddRefs(root));
if(root.get() != NS_STATIC_CAST(nsIDocShellTreeItem*, this))
{
nsCOMPtr<nsIWebNavigation> rootAsNav(do_QueryInterface(root));
return rootAsNav->GoForward();
}
NS_ENSURE_STATE(mSessionHistory);
UpdateCurrentSessionHistory();
nsCOMPtr<nsISHEntry> nextEntry;
NS_ENSURE_SUCCESS(mSessionHistory->GetNextEntry(PR_TRUE,
getter_AddRefs(nextEntry)), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(nextEntry, NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(LoadHistoryEntry(nextEntry), NS_ERROR_FAILURE);
#else
if (mSessionHistory) {
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mSessionHistory));
if (webNav) {
return webNav->GoForward();
}
}
#endif
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GotoIndex(PRInt32 aIndex)
{
return NS_OK;
}
NS_IMETHODIMP nsDocShell::LoadURI(const PRUnichar* aURI)
{
nsCOMPtr<nsIURI> uri;
nsresult rv = CreateFixupURI(aURI, getter_AddRefs(uri));
if(NS_ERROR_UNKNOWN_PROTOCOL == rv)
{
// we weren't able to find a protocol handler
nsCOMPtr<nsIPrompt> prompter;
nsCOMPtr<nsIStringBundle> stringBundle;
GetPromptAndStringBundle(getter_AddRefs(prompter),
getter_AddRefs(stringBundle));
NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
nsXPIDLString messageStr;
NS_ENSURE_SUCCESS(stringBundle->GetStringFromName(NS_ConvertASCIItoUCS2("protocolNotFound").GetUnicode(),
getter_Copies(messageStr)), NS_ERROR_FAILURE);
nsAutoString uriString(aURI);
PRInt32 colon = uriString.FindChar(':');
// extract the scheme
nsAutoString scheme;
uriString.Left(scheme, colon);
nsCAutoString cScheme;
cScheme.AssignWithConversion(scheme);
PRUnichar *msg = nsTextFormatter::smprintf(messageStr, cScheme.GetBuffer());
if (!msg) return NS_ERROR_OUT_OF_MEMORY;
prompter->Alert(nsnull, msg);
nsTextFormatter::smprintf_free(msg);
} // end unknown protocol
if(!uri)
return NS_ERROR_FAILURE;
NS_ENSURE_SUCCESS(LoadURI(uri, nsnull), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::Reload(PRInt32 aReloadType)
{
#ifdef SH_IN_FRAMES
// XXX Honor the reload type
NS_ENSURE_STATE(mCurrentURI);
// XXXTAB Convert reload type to our type
nsDocShellInfoLoadType type = nsIDocShellLoadInfo::loadReloadNormal;
if ( aReloadType == nsIWebNavigation::loadReloadBypassProxyAndCache )
type = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
// XXX: Why does reload fail if session history is not available?
// Won't this break reloading framesets?
if (mSessionHistory == nsnull) {
return NS_OK;
}
nsCOMPtr<nsIDocShellTreeItem> root;
GetSameTypeRootTreeItem(getter_AddRefs(root));
if(root.get() != NS_STATIC_CAST(nsIDocShellTreeItem*, this))
{
nsCOMPtr<nsIWebNavigation> rootAsNav(do_QueryInterface(root));
return rootAsNav->Reload(aReloadType);
}
NS_ENSURE_STATE(mSessionHistory);
UpdateCurrentSessionHistory();
nsCOMPtr<nsISHEntry> entry;
PRInt32 index = -1;
NS_ENSURE_SUCCESS(mSessionHistory->GetIndex(&index), NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(mSessionHistory->GetEntryAtIndex(index, PR_FALSE,
getter_AddRefs(entry)), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIInputStream> postdata;
entry->GetURI(getter_AddRefs(uri));
entry->GetPostData(getter_AddRefs(postdata));
NS_ENSURE_SUCCESS(InternalLoad(uri, mReferrerURI, nsnull, nsnull,
postdata, type, entry), NS_ERROR_FAILURE);
#else
// XXX Honor the reload type
NS_ENSURE_STATE(mCurrentURI);
// XXXTAB Convert reload type to our type
nsDocShellInfoLoadType type = nsIDocShellLoadInfo::loadReloadNormal;
if ( aReloadType == nsIWebNavigation::loadReloadBypassProxyAndCache )
type = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
UpdateCurrentSessionHistory();
NS_ENSURE_SUCCESS(InternalLoad(mCurrentURI, mReferrerURI, nsnull, nsnull,
nsnull, type), NS_ERROR_FAILURE);
#endif /* SH_IN_FRAMES */
return NS_OK;
}
NS_IMETHODIMP nsDocShell::Stop()
{
// Cancel any timers that were set for this loader.
CancelRefreshURITimers();
if(mContentViewer)
mContentViewer->Stop();
if(mLoadCookie)
{
nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_PROGID);
if(uriLoader)
uriLoader->Stop(mLoadCookie);
}
PRInt32 n;
PRInt32 count = mChildren.Count();
for(n = 0; n < count; n++)
{
nsIDocShellTreeItem* shell = (nsIDocShellTreeItem*)mChildren.ElementAt(n);
nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryInterface(shell));
if(shellAsNav)
shellAsNav->Stop();
}
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetDocument(nsIDOMDocument* aDocument,
const PRUnichar* aContentType)
{
//XXX First Checkin
NS_ERROR("Not Yet Implemented");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsDocShell::GetDocument(nsIDOMDocument** aDocument)
{
NS_ENSURE_ARG_POINTER(aDocument);
NS_ENSURE_STATE(mContentViewer);
return mContentViewer->GetDOMDocument(aDocument);
}
NS_IMETHODIMP nsDocShell::GetCurrentURI(PRUnichar** aCurrentURI)
{
NS_ENSURE_ARG_POINTER(aCurrentURI);
if(!mCurrentURI)
{
*aCurrentURI = nsnull;
return NS_OK;
}
char* spec;
NS_ENSURE_SUCCESS(mCurrentURI->GetSpec(&spec), NS_ERROR_FAILURE);
*aCurrentURI = NS_ConvertASCIItoUCS2(spec).ToNewUnicode();
if(spec)
nsCRT::free(spec);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetSessionHistory(nsISHistory* aSessionHistory)
{
mSessionHistory = aSessionHistory;
#if defined(SH_IN_FRAMES)
if (mSessionHistory) {
mSessionHistory->SetRootDocShell(this);
}
#endif /* SH_IN_FRAMES */
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetSessionHistory(nsISHistory** aSessionHistory)
{
NS_ENSURE_ARG_POINTER(aSessionHistory);
*aSessionHistory = mSessionHistory;
NS_IF_ADDREF(*aSessionHistory);
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsIBaseWindow
//*****************************************************************************
NS_IMETHODIMP nsDocShell::InitWindow(nativeWindow parentNativeWindow,
nsIWidget* parentWidget, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
{
NS_ENSURE_ARG(parentWidget); // DocShells must get a widget for a parent
SetParentWidget(parentWidget);
SetPositionAndSize(x, y, cx, cy, PR_FALSE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::Create()
{
NS_ENSURE_STATE(!mContentViewer);
mPrefs = do_GetService(NS_PREF_PROGID);
mGlobalHistory = do_GetService(NS_GLOBALHISTORY_PROGID);
// i don't want to read this pref in every time we load a url
// so read it in once here and be done with it...
mPrefs->GetBoolPref("network.protocols.useSystemDefaults", &mUseExternalProtocolHandler);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::Destroy()
{
// Stop any URLs that are currently being loaded...
Stop();
if(mDocLoader)
{
mDocLoader->Destroy();
mDocLoader->SetContainer(nsnull);
}
SetDocLoaderObserver(nsnull);
// Save the state of the current document, before destroying the window.
// This is needed to capture the state of a frameset when the new document
// causes the frameset to be destroyed...
PersistLayoutHistoryState();
// Remove this docshell from its parent's child list
nsCOMPtr<nsIDocShellTreeNode> docShellParentAsNode(do_QueryInterface(mParent));
if(docShellParentAsNode)
docShellParentAsNode->RemoveChild(this);
mContentViewer = nsnull;
DestroyChildren();
mDocLoader = nsnull;
mDocLoaderObserver = nsnull;
mParentWidget = nsnull;
mPrefs = nsnull;
mCurrentURI = nsnull;
if(mScriptGlobal)
{
mScriptGlobal->SetDocShell(nsnull);
mScriptGlobal = nsnull;
}
if(mScriptContext)
{
mScriptContext->SetOwner(nsnull);
mScriptContext = nsnull;
}
mScriptGlobal = nsnull;
mScriptContext = nsnull;
mSessionHistory = nsnull;
SetTreeOwner(nsnull);
SetLoadCookie(nsnull);
if(mInitInfo)
{
delete mInitInfo;
mInitInfo = nsnull;
}
if(mContentListener)
{
mContentListener->DocShell(nsnull);
NS_RELEASE(mContentListener);
}
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetPosition(PRInt32 x, PRInt32 y)
{
if(mContentViewer)
NS_ENSURE_SUCCESS(mContentViewer->Move(x, y), NS_ERROR_FAILURE);
else if(InitInfo())
{
mInitInfo->x = x;
mInitInfo->y = y;
}
else
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetPosition(PRInt32* aX, PRInt32* aY)
{
PRInt32 dummyHolder;
return GetPositionAndSize(aX, aY, &dummyHolder, &dummyHolder);
}
NS_IMETHODIMP nsDocShell::SetSize(PRInt32 aCX, PRInt32 aCY, PRBool aRepaint)
{
PRInt32 x = 0, y = 0;
GetPosition(&x, &y);
return SetPositionAndSize(x, y, aCX, aCY, aRepaint);
}
NS_IMETHODIMP nsDocShell::GetSize(PRInt32* aCX, PRInt32* aCY)
{
PRInt32 dummyHolder;
return GetPositionAndSize(&dummyHolder, &dummyHolder, aCX, aCY);
}
NS_IMETHODIMP nsDocShell::SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx,
PRInt32 cy, PRBool fRepaint)
{
if(mContentViewer)
{
//XXX Border figured in here or is that handled elsewhere?
nsRect bounds(x, y, cx, cy);
NS_ENSURE_SUCCESS(mContentViewer->SetBounds(bounds), NS_ERROR_FAILURE);
}
else if(InitInfo())
{
mInitInfo->x = x;
mInitInfo->y = y;
mInitInfo->cx = cx;
mInitInfo->cy = cy;
}
else
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetPositionAndSize(PRInt32* x, PRInt32* y, PRInt32* cx,
PRInt32* cy)
{
if(mContentViewer)
{
nsRect bounds;
NS_ENSURE_SUCCESS(mContentViewer->GetBounds(bounds), NS_ERROR_FAILURE);
if(x)
*x = bounds.x;
if(y)
*y = bounds.y;
if(cx)
*cx = bounds.width;
if(cy)
*cy = bounds.height;
}
else if(InitInfo())
{
if(x)
*x = mInitInfo->x;
if(y)
*y = mInitInfo->y;
if(cx)
*cx = mInitInfo->cx;
if(cy)
*cy = mInitInfo->cy;
}
else
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::Repaint(PRBool aForce)
{
nsCOMPtr<nsIDocumentViewer> docViewer(do_QueryInterface(mContentViewer));
NS_ENSURE_TRUE(docViewer, NS_ERROR_FAILURE);
nsCOMPtr<nsIPresContext> context;
docViewer->GetPresContext(*getter_AddRefs(context));
NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
nsCOMPtr<nsIPresShell> shell;
context->GetShell(getter_AddRefs(shell));
NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
nsCOMPtr<nsIViewManager> viewManager;
shell->GetViewManager(getter_AddRefs(viewManager));
NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
// what about aForce ?
NS_ENSURE_SUCCESS(viewManager->UpdateAllViews(0), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetParentWidget(nsIWidget** parentWidget)
{
NS_ENSURE_ARG_POINTER(parentWidget);
*parentWidget = mParentWidget;
NS_IF_ADDREF(*parentWidget);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetParentWidget(nsIWidget* aParentWidget)
{
NS_ENSURE_STATE(!mContentViewer);
mParentWidget = aParentWidget;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetParentNativeWindow(nativeWindow* parentNativeWindow)
{
NS_ENSURE_ARG_POINTER(parentNativeWindow);
if(mParentWidget)
*parentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
else
*parentNativeWindow = nsnull;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsDocShell::GetVisibility(PRBool* aVisibility)
{
NS_ENSURE_ARG_POINTER(aVisibility);
if(!mContentViewer)
{
*aVisibility = PR_FALSE;
return NS_OK;
}
// get the pres shell
nsCOMPtr<nsIPresShell> presShell;
NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
// get the view manager
nsCOMPtr<nsIViewManager> vm;
NS_ENSURE_SUCCESS(presShell->GetViewManager(getter_AddRefs(vm)), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
// get the root view
nsIView *rootView=nsnull; // views are not ref counted
NS_ENSURE_SUCCESS(vm->GetRootView(rootView), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
// convert the view's visibility attribute to a bool
nsViewVisibility vis;
NS_ENSURE_TRUE(rootView->GetVisibility(vis), NS_ERROR_FAILURE);
*aVisibility = nsViewVisibility_kHide==vis ? PR_FALSE : PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetVisibility(PRBool aVisibility)
{
if(!mContentViewer)
return NS_OK;
if(aVisibility)
{
NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
mContentViewer->Show();
}
else if(mContentViewer)
mContentViewer->Hide();
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetMainWidget(nsIWidget** aMainWidget)
{
// We don't create our own widget, so simply return the parent one.
return GetParentWidget(aMainWidget);
}
NS_IMETHODIMP nsDocShell::SetFocus()
{
nsCOMPtr<nsIWidget> mainWidget;
GetMainWidget(getter_AddRefs(mainWidget));
if(mainWidget)
mainWidget->SetFocus();
return NS_OK;
}
NS_IMETHODIMP nsDocShell::FocusAvailable(nsIBaseWindow* aCurrentFocus,
PRBool* aTookFocus)
{
NS_ENSURE_ARG_POINTER(aTookFocus);
// Next person we should call is first the parent otherwise the
// docshell tree owner.
nsCOMPtr<nsIBaseWindow> nextCallWin(do_QueryInterface(mParent));
if(!nextCallWin)
{
nextCallWin = do_QueryInterface(mTreeOwner);
}
//If the current focus is us, offer it to the next owner.
if(aCurrentFocus == NS_STATIC_CAST(nsIBaseWindow*, this))
{
if(nextCallWin)
return nextCallWin->FocusAvailable(aCurrentFocus, aTookFocus);
return NS_OK;
}
//Otherwise, check the chilren and offer it to the next sibling.
PRInt32 i;
PRInt32 n = mChildren.Count();
for(i = 0; i < n; i++)
{
nsCOMPtr<nsIBaseWindow>
child(do_QueryInterface((nsISupports*)mChildren.ElementAt(i)));
if(child.get() == aCurrentFocus)
{
while(++i < n)
{
child = do_QueryInterface((nsISupports*)mChildren.ElementAt(i));
if(NS_SUCCEEDED(child->SetFocus()))
{
*aTookFocus = PR_TRUE;
return NS_OK;
}
}
}
}
if(nextCallWin)
return nextCallWin->FocusAvailable(aCurrentFocus, aTookFocus);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetTitle(PRUnichar** aTitle)
{
NS_ENSURE_ARG_POINTER(aTitle);
*aTitle = mTitle.ToNewUnicode();
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetTitle(const PRUnichar* aTitle)
{
// Store local title
mTitle = aTitle;
nsCOMPtr<nsIDocShellTreeItem> parent;
GetSameTypeParent(getter_AddRefs(parent));
// When title is set on the top object it should then be passed to the
// tree owner.
if(!parent)
{
nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
if (treeOwnerAsWin)
treeOwnerAsWin->SetTitle(aTitle);
}
if(mGlobalHistory && mCurrentURI)
{
nsXPIDLCString url;
mCurrentURI->GetSpec(getter_Copies(url));
mGlobalHistory->SetPageTitle(url, aTitle);
}
// Update SessionHistory too with Title. Otherwise entry for current page
// has previous page's title.
if(mSessionHistory)
{
PRInt32 index = -1;
mSessionHistory->GetIndex(&index);
nsCOMPtr<nsISHEntry> shEntry;
mSessionHistory->GetEntryAtIndex(index, PR_FALSE, getter_AddRefs(shEntry));
if(shEntry)
shEntry->SetTitle(mTitle.GetUnicode());
}
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsIScrollable
//*****************************************************************************
NS_IMETHODIMP nsDocShell::GetCurScrollPos(PRInt32 scrollOrientation,
PRInt32* curPos)
{
NS_ENSURE_ARG_POINTER(curPos);
nsCOMPtr<nsIScrollableView> scrollView;
NS_ENSURE_SUCCESS(GetRootScrollableView(getter_AddRefs(scrollView)),
NS_ERROR_FAILURE);
if (!scrollView)
{
return NS_ERROR_FAILURE;
}
nscoord x, y;
NS_ENSURE_SUCCESS(scrollView->GetScrollPosition(x, y), NS_ERROR_FAILURE);
switch(scrollOrientation)
{
case ScrollOrientation_X:
*curPos = x;
return NS_OK;
case ScrollOrientation_Y:
*curPos = y;
return NS_OK;
default:
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsDocShell::SetCurScrollPos(PRInt32 scrollOrientation,
PRInt32 curPos)
{
nsCOMPtr<nsIScrollableView> scrollView;
NS_ENSURE_SUCCESS(GetRootScrollableView(getter_AddRefs(scrollView)),
NS_ERROR_FAILURE);
if (!scrollView)
{
return NS_ERROR_FAILURE;
}
PRInt32 other;
PRInt32 x;
PRInt32 y;
GetCurScrollPos(scrollOrientation, &other);
switch(scrollOrientation)
{
case ScrollOrientation_X:
x = curPos;
y = other;
break;
case ScrollOrientation_Y:
x = other;
y = curPos;
break;
default:
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
}
NS_ENSURE_SUCCESS(scrollView->ScrollTo(x, y, NS_VMREFRESH_IMMEDIATE),
NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetCurScrollPosEx(PRInt32 curHorizontalPos,
PRInt32 curVerticalPos)
{
nsCOMPtr<nsIScrollableView> scrollView;
NS_ENSURE_SUCCESS(GetRootScrollableView(getter_AddRefs(scrollView)),
NS_ERROR_FAILURE);
if (!scrollView)
{
return NS_ERROR_FAILURE;
}
NS_ENSURE_SUCCESS(scrollView->ScrollTo(curHorizontalPos, curVerticalPos,
NS_VMREFRESH_IMMEDIATE), NS_ERROR_FAILURE);
return NS_OK;
}
// XXX This is wrong
NS_IMETHODIMP nsDocShell::GetScrollRange(PRInt32 scrollOrientation,
PRInt32* minPos, PRInt32* maxPos)
{
NS_ENSURE_ARG_POINTER(minPos && maxPos);
nsCOMPtr<nsIScrollableView> scrollView;
NS_ENSURE_SUCCESS(GetRootScrollableView(getter_AddRefs(scrollView)),
NS_ERROR_FAILURE);
if (!scrollView)
{
return NS_ERROR_FAILURE;
}
PRInt32 cx;
PRInt32 cy;
NS_ENSURE_SUCCESS(scrollView->GetContainerSize(&cx, &cy), NS_ERROR_FAILURE);
*minPos = 0;
switch(scrollOrientation)
{
case ScrollOrientation_X:
*maxPos = cx;
return NS_OK;
case ScrollOrientation_Y:
*maxPos = cy;
return NS_OK;
default:
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsDocShell::SetScrollRange(PRInt32 scrollOrientation,
PRInt32 minPos, PRInt32 maxPos)
{
//XXX First Check
/*
Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
something less than the current thumb position, curPos is set = to maxPos.
@return NS_OK - Setting or Getting completed successfully.
NS_ERROR_INVALID_ARG - returned when curPos is not within the
minPos and maxPos.
*/
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsDocShell::SetScrollRangeEx(PRInt32 minHorizontalPos,
PRInt32 maxHorizontalPos, PRInt32 minVerticalPos, PRInt32 maxVerticalPos)
{
//XXX First Check
/*
Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
something less than the current thumb position, curPos is set = to maxPos.
@return NS_OK - Setting or Getting completed successfully.
NS_ERROR_INVALID_ARG - returned when curPos is not within the
minPos and maxPos.
*/
return NS_ERROR_FAILURE;
}
// Get scroll setting for this document only
//
// One important client is nsCSSFrameConstructor::ConstructRootFrame()
NS_IMETHODIMP nsDocShell::GetCurrentScrollbarPreferences(PRInt32 scrollOrientation,
PRInt32* scrollbarPref)
{
NS_ENSURE_ARG_POINTER(scrollbarPref);
switch(scrollOrientation) {
case ScrollOrientation_X:
*scrollbarPref = mCurrentScrollbarPref.x;
return NS_OK;
case ScrollOrientation_Y:
*scrollbarPref = mCurrentScrollbarPref.y;
return NS_OK;
default:
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
}
return NS_ERROR_FAILURE;
}
// This returns setting for all documents in this webshell
NS_IMETHODIMP nsDocShell::GetDefaultScrollbarPreferences(PRInt32 scrollOrientation,
PRInt32* scrollbarPref)
{
NS_ENSURE_ARG_POINTER(scrollbarPref);
switch(scrollOrientation) {
case ScrollOrientation_X:
*scrollbarPref = mDefaultScrollbarPref.x;
return NS_OK;
case ScrollOrientation_Y:
*scrollbarPref = mDefaultScrollbarPref.y;
return NS_OK;
default:
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
}
return NS_ERROR_FAILURE;
}
// Set scrolling preference for this document only.
//
// There are three possible values stored in the shell:
// 1) NS_STYLE_OVERFLOW_HIDDEN = no scrollbars
// 2) NS_STYLE_OVERFLOW_AUTO = scrollbars appear if needed
// 3) NS_STYLE_OVERFLOW_SCROLL = scrollbars always
//
// XXX Currently OVERFLOW_SCROLL isn't honored,
// as it is not implemented by Gfx scrollbars
// XXX setting has no effect after the root frame is created
// as it is not implemented by Gfx scrollbars
//
// One important client is HTMLContentSink::StartLayout()
NS_IMETHODIMP nsDocShell::SetCurrentScrollbarPreferences(PRInt32 scrollOrientation,
PRInt32 scrollbarPref)
{
switch(scrollOrientation) {
case ScrollOrientation_X:
mCurrentScrollbarPref.x = scrollbarPref;
return NS_OK;
case ScrollOrientation_Y:
mCurrentScrollbarPref.y = scrollbarPref;
return NS_OK;
default:
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
}
return NS_ERROR_FAILURE;
}
// Set scrolling preference for all documents in this shell
// One important client is nsHTMLFrameInnerFrame::CreateWebShell()
NS_IMETHODIMP nsDocShell::SetDefaultScrollbarPreferences(PRInt32 scrollOrientation,
PRInt32 scrollbarPref)
{
switch(scrollOrientation) {
case ScrollOrientation_X:
mDefaultScrollbarPref.x = scrollbarPref;
return NS_OK;
case ScrollOrientation_Y:
mDefaultScrollbarPref.y = scrollbarPref;
return NS_OK;
default:
NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
}
return NS_ERROR_FAILURE;
}
// Reset 'current' scrollbar settings to 'default'.
// This must be called before every document load or else
// frameset scrollbar settings (e.g. <IFRAME SCROLLING="no">
// will not be preserved.
//
// One important client is HTMLContentSink::StartLayout()
NS_IMETHODIMP nsDocShell::ResetScrollbarPreferences()
{
mCurrentScrollbarPref = mDefaultScrollbarPref;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetScrollbarVisibility(PRBool* verticalVisible,
PRBool* horizontalVisible)
{
nsCOMPtr<nsIScrollableView> scrollView;
NS_ENSURE_SUCCESS(GetRootScrollableView(getter_AddRefs(scrollView)),
NS_ERROR_FAILURE);
if (!scrollView)
{
return NS_ERROR_FAILURE;
}
PRBool vertVisible;
PRBool horizVisible;
NS_ENSURE_SUCCESS(scrollView->GetScrollbarVisibility(&vertVisible,
&horizVisible), NS_ERROR_FAILURE);
if(verticalVisible)
*verticalVisible = vertVisible;
if(horizontalVisible)
*horizontalVisible = horizVisible;
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsITextScroll
//*****************************************************************************
NS_IMETHODIMP nsDocShell::ScrollByLines(PRInt32 numLines)
{
nsCOMPtr<nsIScrollableView> scrollView;
NS_ENSURE_SUCCESS(GetRootScrollableView(getter_AddRefs(scrollView)),
NS_ERROR_FAILURE);
if (!scrollView)
{
return NS_ERROR_FAILURE;
}
NS_ENSURE_SUCCESS(scrollView->ScrollByLines(0, numLines), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::ScrollByPages(PRInt32 numPages)
{
nsCOMPtr<nsIScrollableView> scrollView;
NS_ENSURE_SUCCESS(GetRootScrollableView(getter_AddRefs(scrollView)),
NS_ERROR_FAILURE);
if (!scrollView)
{
return NS_ERROR_FAILURE;
}
NS_ENSURE_SUCCESS(scrollView->ScrollByPages(numPages), NS_ERROR_FAILURE);
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsIScriptGlobalObjectOwner
//*****************************************************************************
NS_IMETHODIMP nsDocShell::GetScriptGlobalObject(nsIScriptGlobalObject** aGlobal)
{
NS_ENSURE_ARG_POINTER(aGlobal);
NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), NS_ERROR_FAILURE);
*aGlobal = mScriptGlobal;
NS_IF_ADDREF(*aGlobal);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::ReportScriptError(nsIScriptError *errorObject)
{
nsresult rv;
if (errorObject == nsnull)
return NS_ERROR_NULL_POINTER;
// Get the console service, where we're going to register the error.
nsCOMPtr<nsIConsoleService> consoleService
(do_GetService("mozilla.consoleservice.1"));
if (consoleService != nsnull)
{
rv = consoleService->LogMessage(errorObject);
if (NS_SUCCEEDED(rv))
{
return NS_OK;
}
else
{
return rv;
}
}
else
{
return NS_ERROR_NOT_AVAILABLE;
}
}
//*****************************************************************************
// nsDocShell::nsIRefreshURI
//*****************************************************************************
NS_IMETHODIMP nsDocShell::RefreshURI(nsIURI *aURI, PRInt32 aDelay, PRBool aRepeat)
{
NS_ENSURE_ARG(aURI);
nsRefreshTimer* refreshTimer = new nsRefreshTimer();
NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsISupports> dataRef = refreshTimer; // Get the ref count to 1
refreshTimer->mDocShell = this;
refreshTimer->mURI = aURI;
refreshTimer->mDelay = aDelay;
refreshTimer->mRepeat = aRepeat;
if (!mRefreshURIList)
{
NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList)),
NS_ERROR_FAILURE);
}
nsCOMPtr<nsITimer> timer = do_CreateInstance("component://netscape/timer");
NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
mRefreshURIList->AppendElement(timer); // owning timer ref
timer->Init(refreshTimer, aDelay);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::CancelRefreshURITimers()
{
if (!mRefreshURIList) return NS_OK;
PRUint32 n;
mRefreshURIList->Count(&n);
while (n)
{
nsCOMPtr<nsISupports> element;
mRefreshURIList->GetElementAt(0, getter_AddRefs(element));
nsCOMPtr<nsITimer> timer(do_QueryInterface(element));
mRefreshURIList->RemoveElementAt(0); // bye bye owning timer ref
if (timer)
timer->Cancel();
n--;
}
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsIContentViewerContainer
//*****************************************************************************
NS_IMETHODIMP nsDocShell::Embed(nsIContentViewer* aContentViewer,
const char * aCommand,
nsISupports * aExtraInfo)
{
#ifdef SH_IN_FRAMES
// Save the LayoutHistoryState of the previous document, before
// setting up new document
PersistLayoutHistoryState();
nsresult rv = SetupNewViewer(aContentViewer);
// XXX What if SetupNewViewer fails?
OSHE = LSHE;
/*
PRBool updateHistory = PR_TRUE;
// Determine if this type of load should update history
switch(mLoadType)
{
case nsIDocShellLoadInfo::loadHistory:
case nsIDocShellLoadInfo::loadReloadNormal:
case nsIDocShellLoadInfo::loadReloadBypassCache:
case nsIDocShellLoadInfo::loadReloadBypassProxy:
case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
updateHistory = PR_FALSE;
break;
default:
break;
}
*/
if (OSHE) {
nsCOMPtr<nsILayoutHistoryState> layoutState;
rv = OSHE->GetLayoutHistoryState(getter_AddRefs(layoutState));
if (layoutState) {
// This is a SH load. That's why there is a LayoutHistoryState in OSHE
nsCOMPtr<nsIPresShell> presShell;
rv = GetPresShell(getter_AddRefs(presShell));
if (NS_SUCCEEDED(rv) && presShell) {
rv = presShell->SetHistoryState(layoutState);
}
}
}
return NS_OK;
#else
return SetupNewViewer(aContentViewer);
#endif /* SH_IN_FRAMES */
}
//*****************************************************************************
// nsDocShell::nsIWebProgressListener
//*****************************************************************************
NS_IMETHODIMP
nsDocShell::OnProgressChange(nsIWebProgress *aProgress, nsIRequest *aRequest,
PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
{
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::OnStateChange(nsIWebProgress *aProgress, nsIRequest *aRequest,
PRInt32 aStateFlags, nsresult aStatus)
{
// Clear the LSHE reference to indicate document loading has finished
// one way or another.
if ((aStateFlags & flag_stop) && (aStateFlags & flag_is_network)) {
LSHE = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::OnLocationChange(nsIURI *aURI)
{
return NS_OK;
}
//*****************************************************************************
// nsDocShell: Content Viewer Management
//*****************************************************************************
NS_IMETHODIMP nsDocShell::EnsureContentViewer()
{
if(mContentViewer)
return NS_OK;
return CreateAboutBlankContentViewer();
}
NS_IMETHODIMP nsDocShell::EnsureDeviceContext()
{
if(mDeviceContext)
return NS_OK;
mDeviceContext = do_CreateInstance(kDeviceContextCID);
NS_ENSURE_TRUE(mDeviceContext, NS_ERROR_FAILURE);
nsCOMPtr<nsIWidget> widget;
GetMainWidget(getter_AddRefs(widget));
NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
mDeviceContext->Init(widget->GetNativeData(NS_NATIVE_WIDGET));
float dev2twip;
mDeviceContext->GetDevUnitsToTwips(dev2twip);
mDeviceContext->SetDevUnitsToAppUnits(dev2twip);
float twip2dev;
mDeviceContext->GetTwipsToDevUnits(twip2dev);
mDeviceContext->SetAppUnitsToDevUnits(twip2dev);
mDeviceContext->SetGamma(1.0f);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::CreateAboutBlankContentViewer()
{
// XXX
NS_ERROR("Not Implemented yet");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsDocShell::CreateContentViewer(const char* aContentType,
nsIChannel* aOpenedChannel, nsIStreamListener** aContentHandler)
{
// Can we check the content type of the current content viewer
// and reuse it without destroying it and re-creating it?
nsCOMPtr<nsILoadGroup> loadGroup(do_GetInterface(mLoadCookie));
NS_ENSURE_TRUE(loadGroup, NS_ERROR_FAILURE);
// Instantiate the content viewer object
nsCOMPtr<nsIContentViewer> viewer;
if(NS_FAILED(NewContentViewerObj(aContentType, aOpenedChannel, loadGroup,
aContentHandler, getter_AddRefs(viewer))))
return NS_ERROR_FAILURE;
// let's try resetting the load group if we need to...
nsCOMPtr<nsILoadGroup> currentLoadGroup;
NS_ENSURE_SUCCESS(aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup)),
NS_ERROR_FAILURE);
if(currentLoadGroup.get() != loadGroup.get())
{
nsLoadFlags loadAttribs = 0;
//Cancel any URIs that are currently loading...
/// XXX: Need to do this eventually Stop();
//
// Retarget the document to this loadgroup...
//
if(currentLoadGroup)
currentLoadGroup->RemoveChannel(aOpenedChannel, nsnull, nsnull, nsnull);
aOpenedChannel->SetLoadGroup(loadGroup);
// Mark the channel as being a document URI...
aOpenedChannel->GetLoadAttributes(&loadAttribs);
loadAttribs |= nsIChannel::LOAD_DOCUMENT_URI;
aOpenedChannel->SetLoadAttributes(loadAttribs);
loadGroup->AddChannel(aOpenedChannel, nsnull);
}
#ifdef SH_IN_FRAMES
NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nsnull), NS_ERROR_FAILURE);
#else
NS_ENSURE_SUCCESS(SetupNewViewer(viewer), NS_ERROR_FAILURE);
#endif /* SH_IN_FRAMES */
mEODForCurrentDocument = PR_FALSE; // clear the current flag
return NS_OK;
}
nsresult nsDocShell::NewContentViewerObj(const char* aContentType,
nsIChannel* aOpenedChannel, nsILoadGroup* aLoadGroup,
nsIStreamListener** aContentHandler, nsIContentViewer** aViewer)
{
//XXX This should probably be some category thing....
char id[256];
PR_snprintf(id, sizeof(id), NS_DOCUMENT_LOADER_FACTORY_PROGID_PREFIX "%s/%s",
(const char*)((viewSource == mViewMode) ? "view-source" : "view"),
aContentType);
// Create an instance of the document-loader-factory
nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory(do_CreateInstance(id));
if(!docLoaderFactory)
return NS_ERROR_FAILURE;
// Now create an instance of the content viewer
NS_ENSURE_SUCCESS(docLoaderFactory->CreateInstance(
(viewSource == mViewMode) ? "view-source" : "view",
aOpenedChannel, aLoadGroup, aContentType,
NS_STATIC_CAST(nsIContentViewerContainer*, this), nsnull,
aContentHandler, aViewer), NS_ERROR_FAILURE);
(*aViewer)->SetContainer(NS_STATIC_CAST(nsIContentViewerContainer*, this));
return NS_OK;
}
NS_IMETHODIMP nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer)
{
//
// Copy content viewer state from previous or parent content viewer.
//
// The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
//
// Do NOT to maintain a reference to the old content viewer outside
// of this "copying" block, or it will not be destroyed until the end of
// this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
//
// In this block of code, if we get an error result, we return it
// but if we get a null pointer, that's perfectly legal for parent
// and parentContentViewer.
//
PRInt32 x = 0;
PRInt32 y = 0;
PRInt32 cx = 0;
PRInt32 cy = 0;
// This will get the size from the current content viewer or from the
// Init settings
GetPositionAndSize(&x, &y, &cx, &cy);
nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
NS_ERROR_FAILURE);
nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
if(mContentViewer || parent)
{
nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV;
if(mContentViewer)
{
// Get any interesting state from old content viewer
// XXX: it would be far better to just reuse the document viewer ,
// since we know we're just displaying the same document as before
oldMUDV = do_QueryInterface(mContentViewer);
}
else
{
// No old content viewer, so get state from parent's content viewer
nsCOMPtr<nsIContentViewer> parentContentViewer;
parent->GetContentViewer(getter_AddRefs(parentContentViewer));
oldMUDV = do_QueryInterface(parentContentViewer);
}
nsXPIDLString defaultCharset;
nsXPIDLString forceCharset;
nsXPIDLString hintCharset;
PRInt32 hintCharsetSource;
nsCOMPtr<nsIMarkupDocumentViewer> newMUDV(do_QueryInterface(aNewViewer));
if(oldMUDV && newMUDV)
{
NS_ENSURE_SUCCESS(oldMUDV->GetDefaultCharacterSet(getter_Copies(defaultCharset)),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(oldMUDV->GetForceCharacterSet(getter_Copies(forceCharset)),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(oldMUDV->GetHintCharacterSet(getter_Copies(hintCharset)),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(oldMUDV->GetHintCharacterSetSource(&hintCharsetSource),
NS_ERROR_FAILURE);
// set the old state onto the new content viewer
NS_ENSURE_SUCCESS(newMUDV->SetDefaultCharacterSet(defaultCharset),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(newMUDV->SetForceCharacterSet(forceCharset),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(newMUDV->SetHintCharacterSet(hintCharset),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(newMUDV->SetHintCharacterSetSource(hintCharsetSource),
NS_ERROR_FAILURE);
}
}
mContentViewer = nsnull;
// End copying block (Don't hold content/document viewer ref beyond here!!)
if(mScriptContext)
mScriptContext->GC();
mContentViewer = aNewViewer;
nsCOMPtr<nsIWidget> widget;
NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
nsRect bounds(x, y, cx, cy);
NS_ENSURE_SUCCESS(EnsureDeviceContext(), NS_ERROR_FAILURE);
if(NS_FAILED(mContentViewer->Init(widget,
mDeviceContext, bounds)))
{
mContentViewer = nsnull;
NS_ERROR("ContentViewer Initialization failed");
return NS_ERROR_FAILURE;
}
// XXX: It looks like the LayoutState gets restored again in Embed()
// right after the call to SetupNewViewer(...)
#ifndef SH_IN_FRAMES
// Restore up any HistoryLayoutState this page might have.
nsresult rv = NS_OK;
PRBool updateHistory = PR_TRUE;
// Determine if this type of load should update history
switch(mLoadType)
{
case nsIDocShellLoadInfo::loadHistory:
case nsIDocShellLoadInfo::loadReloadNormal:
case nsIDocShellLoadInfo::loadReloadBypassCache:
case nsIDocShellLoadInfo::loadReloadBypassProxy:
case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
updateHistory = PR_FALSE;
break;
default:
break;
}
if (mSessionHistory && !updateHistory) {
PRInt32 index = 0;
mSessionHistory->GetIndex(&index);
if (-1 < index) {
nsCOMPtr<nsISHEntry> entry;
rv = mSessionHistory->GetEntryAtIndex(index, PR_FALSE, getter_AddRefs(entry));
if (NS_SUCCEEDED(rv) && entry) {
nsCOMPtr<nsILayoutHistoryState> layoutState;
rv = entry->GetLayoutHistoryState(getter_AddRefs(layoutState));
if (NS_SUCCEEDED(rv) && layoutState) {
nsCOMPtr<nsIPresShell> presShell;
rv = GetPresShell(getter_AddRefs(presShell));
if (NS_SUCCEEDED(rv) && presShell) {
rv = presShell->SetHistoryState(layoutState);
}
}
}
}
}
#endif /* SH_IN_FRAMES */
mContentViewer->Show();
// Now that we have switched documents, forget all of our children
DestroyChildren();
return NS_OK;
}
//*****************************************************************************
// nsDocShell: Site Loading
//*****************************************************************************
#ifdef SH_IN_FRAMES
NS_IMETHODIMP nsDocShell::InternalLoad(nsIURI* aURI, nsIURI* aReferrer,
nsISupports* aOwner, const char* aWindowTarget, nsIInputStream* aPostData,
nsDocShellInfoLoadType aLoadType, nsISHEntry * aSHEntry)
#else
NS_IMETHODIMP nsDocShell::InternalLoad(nsIURI* aURI, nsIURI* aReferrer,
nsISupports* aOwner, const char* aWindowTarget, nsIInputStream* aPostData,
nsDocShellInfoLoadType aLoadType)
#endif
{
// Check to see if the new URI is an anchor in the existing document.
if (aLoadType == nsIDocShellLoadInfo::loadNormal ||
aLoadType == nsIDocShellLoadInfo::loadNormalReplace ||
aLoadType == nsIDocShellLoadInfo::loadHistory ||
aLoadType == nsIDocShellLoadInfo::loadLink)
{
PRBool wasAnchor = PR_FALSE;
NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor), NS_ERROR_FAILURE);
if(wasAnchor)
{
mLoadType = aLoadType;
OnNewURI(aURI, nsnull, mLoadType);
return NS_OK;
}
}
NS_ENSURE_SUCCESS(StopLoad(), NS_ERROR_FAILURE);
// Cancel any timers that were set for this loader.
CancelRefreshURITimers();
mLoadType = aLoadType;
#ifdef SH_IN_FRAMES
// XXX: I think that LSHE should *always* be set to the new Entry.
// Even if it is null...
// if (aSHEntry)
LSHE = aSHEntry;
#endif
nsURILoadCommand loadCmd = nsIURILoader::viewNormal;
if(nsIDocShellLoadInfo::loadLink == aLoadType)
loadCmd = nsIURILoader::viewUserClick;
NS_ENSURE_SUCCESS(DoURILoad(aURI, aReferrer, aOwner, loadCmd, aWindowTarget,
aPostData), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::CreateFixupURI(const PRUnichar* aStringURI,
nsIURI** aURI)
{
*aURI = nsnull;
nsAutoString uriString(aStringURI);
uriString.Trim(" "); // Cleanup the empty spaces that might be on each end.
// Just try to create an URL out of it
NS_NewURI(aURI, uriString.GetUnicode(), nsnull);
if(*aURI)
return NS_OK;
// Check for if it is a file URL
FileURIFixup(uriString.GetUnicode(), aURI);
if(*aURI)
return NS_OK;
// See if it is a keyword
KeywordURIFixup(uriString.GetUnicode(), aURI);
if(*aURI)
return NS_OK;
// See if a protocol needs to be added
PRInt32 colon = uriString.FindChar(':');
PRInt32 fSlash = uriString.FindChar('/');
PRUnichar port = nsnull;;
// if no scheme (protocol) is found, assume http.
if (colon == -1 || fSlash == -1 || (fSlash > -1) && (colon+1 != fSlash)) {
if (colon < (((PRInt32)uriString.Length())-1)) {
if (colon != -1) port = uriString.CharAt(colon+1);
if (colon == -1 || uriString.IsDigit(port) ||
uriString.CharAt(0) == '[') {
// find host name
PRInt32 hostPos = uriString.FindCharInSet("./:");
if (hostPos == -1)
hostPos = uriString.Length();
// extract host name
nsAutoString hostSpec;
uriString.Left(hostSpec, hostPos);
// insert url spec corresponding to host name
if (hostSpec.EqualsIgnoreCase("ftp"))
uriString.InsertWithConversion("ftp://", 0, 6);
else
uriString.InsertWithConversion("http://", 0, 7);
}
}
} // end if colon
return NS_NewURI(aURI, uriString.GetUnicode(), nsnull);
}
NS_IMETHODIMP nsDocShell::FileURIFixup(const PRUnichar* aStringURI,
nsIURI** aURI)
{
nsAutoString uriSpecIn(aStringURI);
nsAutoString uriSpecOut(aStringURI);
ConvertFileToStringURI(uriSpecIn, uriSpecOut);
if(0 == uriSpecOut.Find("file:", 0))
{
// if this is file url, we need to convert the URI
// from Unicode to the FS charset
nsCAutoString inFSCharset;
NS_ENSURE_SUCCESS(ConvertStringURIToFileCharset(uriSpecOut, inFSCharset),
NS_ERROR_FAILURE);
if(NS_SUCCEEDED(NS_NewURI(aURI, inFSCharset.GetBuffer(), nsnull)))
return NS_OK;
}
return NS_ERROR_FAILURE;
}
#define FILE_PROTOCOL "file://"
NS_IMETHODIMP nsDocShell::ConvertFileToStringURI(nsString& aIn, nsString& aOut)
{
#ifdef XP_PC
// Check for \ in the url-string or just a drive (PC)
if(kNotFound != aIn.FindChar(PRUnichar('\\')) || ((aIn.Length() == 2 ) && (aIn.Last() == PRUnichar(':') || aIn.Last() == PRUnichar('|'))))
{
#elif XP_UNIX
// Check if it starts with / or \ (UNIX)
const PRUnichar * up = aIn.GetUnicode();
if((PRUnichar('/') == *up) || (PRUnichar('\\') == *up))
{
#else
if(0)
{
// Do nothing (All others for now)
#endif
#ifdef XP_PC
// Translate '\' to '/'
aOut.ReplaceChar(PRUnichar('\\'), PRUnichar('/'));
aOut.ReplaceChar(PRUnichar(':'), PRUnichar('|'));
#endif
// Build the file URL
aOut.InsertWithConversion(FILE_PROTOCOL,0);
}
return NS_OK;
}
NS_IMETHODIMP nsDocShell::ConvertStringURIToFileCharset(nsString& aIn,
nsCString& aOut)
{
aOut = "";
// for file url, we need to convert the nsString to the file system
// charset before we pass to NS_NewURI
static nsAutoString fsCharset;
// find out the file system charset first
if(0 == fsCharset.Length())
{
fsCharset.AssignWithConversion("ISO-8859-1"); // set the fallback first.
nsCOMPtr<nsIPlatformCharset> plat(do_GetService(kPlatformCharsetCID));
NS_ENSURE_TRUE(plat, NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(plat->GetCharset(kPlatformCharsetSel_FileName, fsCharset),
NS_ERROR_FAILURE);
}
// We probably should cache ccm here.
// get a charset converter from the manager
nsCOMPtr<nsICharsetConverterManager> ccm(do_GetService(kCharsetConverterManagerCID));
NS_ENSURE_TRUE(ccm, NS_ERROR_FAILURE);
nsCOMPtr<nsIUnicodeEncoder> fsEncoder;
NS_ENSURE_SUCCESS(ccm->GetUnicodeEncoder(&fsCharset,
getter_AddRefs(fsEncoder)), NS_ERROR_FAILURE);
PRInt32 bufLen = 0;
NS_ENSURE_SUCCESS(fsEncoder->GetMaxLength(aIn.GetUnicode(), aIn.Length(),
&bufLen), NS_ERROR_FAILURE);
aOut.SetCapacity(bufLen+1);
PRInt32 srclen = aIn.Length();
NS_ENSURE_SUCCESS(fsEncoder->Convert(aIn.GetUnicode(), &srclen,
(char*)aOut.GetBuffer(), &bufLen), NS_ERROR_FAILURE);
((char*)aOut.GetBuffer())[bufLen]='\0';
aOut.SetLength(bufLen);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::KeywordURIFixup(const PRUnichar* aStringURI,
nsIURI** aURI)
{
NS_ENSURE_STATE(mPrefs);
PRBool keywordsEnabled = PR_FALSE;
NS_ENSURE_SUCCESS(mPrefs->GetBoolPref("keyword.enabled", &keywordsEnabled),
NS_ERROR_FAILURE);
if(!keywordsEnabled)
return NS_ERROR_FAILURE;
// These are keyword formatted strings
// "what is mozilla"
// "what is mozilla?"
// "?mozilla"
// "?What is mozilla"
// These are not keyword formatted strings
// "www.blah.com" - anything with a dot in it
// "nonQualifiedHost:80" - anything with a colon in it
// "nonQualifiedHost?"
// "nonQualifiedHost?args"
// "nonQualifiedHost?some args"
nsAutoString uriString(aStringURI);
if(uriString.FindChar('.') == -1 && uriString.FindChar(':') == -1)
{
PRInt32 qMarkLoc = uriString.FindChar('?');
PRInt32 spaceLoc = uriString.FindChar(' ');
PRBool keyword = PR_FALSE;
if(qMarkLoc == 0)
keyword = PR_TRUE;
else if((spaceLoc > 0) && ((qMarkLoc == -1) || (spaceLoc < qMarkLoc)))
keyword = PR_TRUE;
if(keyword)
{
nsCAutoString keywordSpec("keyword:");
char *utf8Spec = uriString.ToNewUTF8String();
if(utf8Spec)
{
char* escapedUTF8Spec = nsEscape(utf8Spec, url_Path);
if(escapedUTF8Spec)
{
keywordSpec.Append(escapedUTF8Spec);
NS_NewURI(aURI, keywordSpec.GetBuffer(), nsnull);
nsMemory::Free(escapedUTF8Spec);
} // escapedUTF8Spec
nsMemory::Free(utf8Spec);
} // utf8Spec
} // keyword
} // FindChar
if(*aURI)
return NS_OK;
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsDocShell::GetCurrentDocumentOwner(nsISupports** aOwner)
{
nsresult rv;
*aOwner = nsnull;
nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(mContentViewer));
if (!docv) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocument> doc;
rv = docv->GetDocument(*getter_AddRefs(doc));
if (NS_FAILED(rv) || !doc) return NS_ERROR_FAILURE;
nsCOMPtr<nsIPrincipal> principal;
rv = doc->GetPrincipal(getter_AddRefs(principal));
if (NS_FAILED(rv) || !principal) return NS_ERROR_FAILURE;
rv = principal->QueryInterface(NS_GET_IID(nsISupports),(void**)aOwner);
return rv;
}
NS_IMETHODIMP nsDocShell::DoURILoad(nsIURI* aURI, nsIURI* aReferrerURI,
nsISupports* aOwner, nsURILoadCommand aLoadCmd, const char* aWindowTarget,
nsIInputStream* aPostData)
{
// if the load cmd is a user click....and we are supposed to try using
// external default protocol handlers....then try to see if we have one for
// this protocol
if (mUseExternalProtocolHandler && aLoadCmd == nsIURILoader::viewUserClick)
{
nsXPIDLCString urlScheme;
aURI->GetScheme(getter_Copies(urlScheme));
nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_PROGID));
PRBool haveHandler = PR_FALSE;
extProtService->ExternalProtocolHandlerExists(urlScheme, &haveHandler);
if (haveHandler)
return extProtService->LoadUrl(aURI);
}
nsCOMPtr<nsIURILoader> uriLoader(do_GetService(NS_URI_LOADER_PROGID));
NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
// we need to get the load group from our load cookie so we can pass it into open uri...
nsCOMPtr<nsILoadGroup> loadGroup;
NS_ENSURE_SUCCESS(
uriLoader->GetLoadGroupForContext(NS_STATIC_CAST(nsIDocShell*, this),
getter_AddRefs(loadGroup)), NS_ERROR_FAILURE);
// open a channel for the url
nsCOMPtr<nsIChannel> channel;
nsresult rv;
rv = NS_OpenURI(getter_AddRefs(channel), aURI, nsnull, loadGroup,
NS_STATIC_CAST(nsIInterfaceRequestor*, this));
if(NS_FAILED(rv))
{
if(NS_ERROR_DOM_RETVAL_UNDEFINED == rv) // if causing the channel changed the
return NS_OK; // dom and there is nothing else to do
else
return NS_ERROR_FAILURE;
}
channel->SetOriginalURI(aURI);
nsCOMPtr<nsIHTTPChannel> httpChannel(do_QueryInterface(channel));
if(httpChannel)
{
// figure out if we need to set the post data stream on the channel...
// right now, this is only done for http channels.....
if(aPostData)
{
// XXX it's a bit of a hack to rewind the postdata stream here but
// it has to be done in case the post data is being reused multiple
// times.
nsCOMPtr<nsIRandomAccessStore> postDataRandomAccess(do_QueryInterface(aPostData));
if (postDataRandomAccess)
{
postDataRandomAccess->Seek(PR_SEEK_SET, 0);
}
nsCOMPtr<nsIAtom> method = NS_NewAtom ("POST");
httpChannel->SetRequestMethod(method);
httpChannel->SetUploadStream(aPostData);
}
// Set the referrer explicitly
if(aReferrerURI) // Referrer is currenly only set for link clicks here.
httpChannel->SetReferrer(aReferrerURI,
nsIHTTPChannel::REFERRER_LINK_CLICK);
}
else
{
// If an owner was not provided, we want to inherit the principal from the current document iff we
// are dealing with a JS or a data url.
nsCOMPtr<nsISupports> owner = aOwner;
nsCOMPtr<nsIStreamIOChannel> ioChannel(do_QueryInterface(channel));
if(ioChannel) // Might be a javascript: URL load, need to set owner
{
static const char jsSchemeName[] = "javascript";
char* scheme;
aURI->GetScheme(&scheme);
if (PL_strcasecmp(scheme, jsSchemeName) == 0)
{
if (!owner) // only try to call GetCurrentDocumentOwner if we are a JS url or a data url (hence the code duplication)
GetCurrentDocumentOwner(getter_AddRefs(owner));
channel->SetOwner(owner);
}
if (scheme)
nsCRT::free(scheme);
}
else
{ // Also set owner for data: URLs
nsCOMPtr<nsIDataChannel> dataChannel(do_QueryInterface(channel));
if (dataChannel)
{
if (!owner)
GetCurrentDocumentOwner(getter_AddRefs(owner));
channel->SetOwner(owner);
}
}
}
NS_ENSURE_SUCCESS(DoChannelLoad(channel, aLoadCmd, aWindowTarget, uriLoader), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::DoChannelLoad(nsIChannel *aChannel, nsURILoadCommand aLoadCmd,
const char* aWindowTarget, nsIURILoader *aURILoader)
{
// Mark the channel as being a document URI...
nsLoadFlags loadAttribs = 0;
(void)aChannel->GetLoadAttributes(&loadAttribs);
loadAttribs |= nsIChannel::LOAD_DOCUMENT_URI;
switch ( mLoadType )
{
case nsIDocShellLoadInfo::loadHistory:
loadAttribs |= nsIChannel::VALIDATE_NEVER;
break;
case nsIDocShellLoadInfo::loadReloadNormal:
loadAttribs |= nsIChannel::FORCE_VALIDATION;
break;
case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
loadAttribs |= nsIChannel::FORCE_RELOAD;
break;
case nsIDocShellLoadInfo::loadRefresh:
loadAttribs |= nsIChannel::FORCE_RELOAD;
break;
case nsIDocShellLoadInfo::loadNormal:
case nsIDocShellLoadInfo::loadLink:
// Set cache checking flags
if ( mPrefs )
{
PRInt32 prefSetting;
if ( NS_SUCCEEDED( mPrefs->GetIntPref( "browser.cache.check_doc_frequency" , &prefSetting) ) )
{
switch ( prefSetting )
{
case 0:
loadAttribs |= nsIChannel::VALIDATE_ONCE_PER_SESSION;
break;
case 1:
loadAttribs |= nsIChannel::VALIDATE_ALWAYS;
break;
case 2:
loadAttribs |= nsIChannel::VALIDATE_NEVER;
break;
}
}
}
break;
}
(void) aChannel->SetLoadAttributes(loadAttribs);
NS_ENSURE_SUCCESS(aURILoader->OpenURI(aChannel, aLoadCmd,
aWindowTarget, NS_STATIC_CAST(nsIDocShell*, this)), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::ScrollIfAnchor(nsIURI* aURI, PRBool* aWasAnchor)
{
NS_ASSERTION(aURI, "null uri arg");
NS_ASSERTION(aWasAnchor, "null anchor arg");
if (aURI == nsnull || aWasAnchor == nsnull)
{
return NS_ERROR_FAILURE;
}
*aWasAnchor = PR_FALSE;
if (!mCurrentURI)
{
return NS_OK;
}
nsresult rv;
// NOTE: we assume URIs are absolute for comparison purposes
nsXPIDLCString currentSpec;
NS_ENSURE_SUCCESS(mCurrentURI->GetSpec(getter_Copies(currentSpec)), NS_ERROR_FAILURE);
nsXPIDLCString newSpec;
NS_ENSURE_SUCCESS(aURI->GetSpec(getter_Copies(newSpec)), NS_ERROR_FAILURE);
// Search for hash marks in the current URI and the new URI and
// take a copy of everything to the left of the hash for
// comparison.
const char kHash = '#';
// Split the new URI into a left and right part
nsAutoString sNew; sNew.AssignWithConversion(newSpec);
nsAutoString sNewLeft;
nsAutoString sNewRef;
PRInt32 hashNew = sNew.FindChar(kHash);
if (hashNew == 0)
{
return NS_OK; // Strange URI
}
else if (hashNew > 0)
{
sNew.Left(sNewLeft, hashNew);
sNew.Right(sNewRef, sNew.Length() - hashNew - 1);
}
else
{
sNewLeft = sNew;
}
// Split the current URI in a left and right part
nsAutoString sCurrent; sCurrent.AssignWithConversion(currentSpec);
nsAutoString sCurrentLeft;
PRInt32 hashCurrent = sCurrent.FindChar(kHash);
if (hashCurrent == 0)
{
return NS_OK; // Strange URI
}
else if (hashCurrent > 0)
{
sCurrent.Left(sCurrentLeft, hashCurrent);
}
else
{
sCurrentLeft = sCurrent;
}
// Exit when there are no anchors
if (hashNew <= 0 && hashCurrent <= 0)
{
return NS_OK;
}
// Compare the URIs.
//
// NOTE: this is a case sensitive comparison because some parts of the
// URI are case sensitive, and some are not. i.e. the domain name
// is case insensitive but the the paths are not.
//
// This means that comparing "http://www.ABC.com/" to "http://www.abc.com/"
// will fail this test.
if (sCurrentLeft.CompareWithConversion(sNewLeft, PR_FALSE, -1) != 0)
{
return NS_OK; // URIs not the same
}
// Both the new and current URIs refer to the same page. We can now
// browse to the hash stored in the new URI.
if (!sNewRef.IsEmpty())
{
nsCOMPtr<nsIPresShell> shell = nsnull;
rv = GetPresShell(getter_AddRefs(shell));
if (NS_SUCCEEDED(rv) && shell)
{
*aWasAnchor = PR_TRUE;
rv = shell->GoToAnchor(sNewRef);
}
}
else
{
// A bit of a hack - scroll to the top of the page.
SetCurScrollPosEx(0, 0);
*aWasAnchor = PR_TRUE;
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::OnNewURI(nsIURI *aURI, nsIChannel *aChannel, nsDocShellInfoLoadType aLoadType)
{
NS_ASSERTION(aURI, "uri is null");
UpdateCurrentGlobalHistory();
PRBool updateHistory = PR_TRUE;
// Determine if this type of load should update history
switch(aLoadType)
{
case nsIDocShellLoadInfo::loadHistory:
case nsIDocShellLoadInfo::loadReloadNormal:
case nsIDocShellLoadInfo::loadReloadBypassCache:
case nsIDocShellLoadInfo::loadReloadBypassProxy:
case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
updateHistory = PR_FALSE;
break;
case nsIDocShellLoadInfo::loadNormal:
case nsIDocShellLoadInfo::loadRefresh:
case nsIDocShellLoadInfo::loadNormalReplace:
case nsIDocShellLoadInfo::loadLink:
break;
default:
NS_ERROR("Need to update case");
break;
}
if (updateHistory) { // Page load not from SH
// Update session history if necessary...
if (!LSHE && (mItemType == typeContent)) {
/* This is a fresh page getting loaded for the first time
*.Create a Entry for it and add it to SH, if this is the
* rootDocShell
*/
(void) AddToSessionHistory(aURI, aChannel, getter_AddRefs(LSHE));
}
// Update Global history if necessary...
updateHistory = PR_FALSE;
ShouldAddToGlobalHistory(aURI, &updateHistory);
if(updateHistory) {
AddToGlobalHistory(aURI);
}
}
SetCurrentURI(aURI);
nsCOMPtr<nsIHTTPChannel> httpChannel(do_QueryInterface(aChannel));
if(httpChannel)
{
nsCOMPtr<nsIURI> referrer;
httpChannel->GetReferrer(getter_AddRefs(referrer));
SetReferrerURI(referrer);
nsXPIDLCString refreshHeader;
nsCOMPtr<nsIAtom> refreshAtom ( dont_AddRef( NS_NewAtom("refresh") ) );
httpChannel -> GetResponseHeader (refreshAtom, getter_Copies (refreshHeader));
if (refreshHeader)
{
nsCOMPtr<nsIURI> baseURI = mCurrentURI;
PRInt32 millis = -1;
PRUnichar *uriAttrib = nsnull;
nsString result; result.AssignWithConversion (refreshHeader);
PRInt32 semiColon = result.FindCharInSet(";,");
nsAutoString token;
if (semiColon > -1)
result.Left(token, semiColon);
else
token = result;
PRBool done = PR_FALSE;
while (!done && !token.IsEmpty()) {
token.CompressWhitespace();
if (millis == -1 && nsCRT::IsAsciiDigit(token.First())) {
PRInt32 i = 0;
PRUnichar value = nsnull;
while ((value = token[i++])) {
if (!nsCRT::IsAsciiDigit(value)) {
i = -1;
break;
}
}
if (i > -1) {
PRInt32 err;
millis = token.ToInteger(&err) * 1000;
} else {
done = PR_TRUE;
}
} else {
done = PR_TRUE;
}
if (done) {
PRInt32 loc = token.FindChar('=');
if (loc > -1)
token.Cut(0, loc+1);
token.Trim(" \"'");
uriAttrib = token.ToNewUnicode();
} else {
// Increment to the next token.
if (semiColon > -1) {
semiColon++;
PRInt32 semiColon2 = result.FindCharInSet(";,", semiColon);
if (semiColon2 == -1) semiColon2 = result.Length();
result.Mid(token, semiColon, semiColon2 - semiColon);
semiColon = semiColon2;
} else {
done = PR_TRUE;
}
}
} // end while
nsCOMPtr<nsIURI> uri;
if (!uriAttrib) {
uri = baseURI;
} else {
NS_NewURI(getter_AddRefs(uri), uriAttrib, baseURI);
nsMemory::Free(uriAttrib);
}
RefreshURI (uri, millis, PR_FALSE);
}
}
mInitialPageLoad = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::OnLoadingSite(nsIChannel* aChannel)
{
nsCOMPtr<nsIURI> uri;
aChannel->GetURI(getter_AddRefs(uri));
NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
OnNewURI(uri, aChannel, mLoadType);
return NS_OK;
}
void nsDocShell::SetCurrentURI(nsIURI* aURI)
{
mCurrentURI = aURI; //This assignment addrefs
nsCOMPtr<nsIDocumentLoader> loader(do_GetInterface(mLoadCookie));
NS_ASSERTION(loader, "No document loader");
if (loader) {
loader->FireOnLocationChange(aURI);
}
}
void nsDocShell::SetReferrerURI(nsIURI* aURI)
{
mReferrerURI = aURI; // This assigment addrefs
}
//*****************************************************************************
// nsDocShell: Session History
//*****************************************************************************
PRBool nsDocShell::ShouldAddToSessionHistory(nsIURI* aURI)
{
nsresult rv;
nsXPIDLCString buffer;
nsCAutoString schemeStr;
rv = aURI->GetScheme(getter_Copies(buffer));
if (NS_FAILED(rv)) return PR_FALSE;
schemeStr = buffer;
if(schemeStr.Equals("about")) {
rv = aURI->GetPath(getter_Copies(buffer));
if (NS_FAILED(rv)) return PR_FALSE;
schemeStr = buffer;
if(schemeStr.Equals("blank")) {
return PR_FALSE;
}
}
return PR_TRUE;
}
nsresult nsDocShell::AddToSessionHistory(nsIURI *aURI,
nsIChannel *aChannel,
nsISHEntry **aNewEntry)
{
nsresult rv;
nsCOMPtr<nsISHEntry> entry;
PRBool shouldPersist;
shouldPersist = ShouldAddToSessionHistory(aURI);
//
// If the entry is being replaced in SH, then just use the
// current entry...
//
if(mSessionHistory && nsIDocShellLoadInfo::loadNormalReplace == mLoadType) {
PRInt32 index = 0;
mSessionHistory->GetIndex(&index);
mSessionHistory->GetEntryAtIndex(index, PR_FALSE, getter_AddRefs(entry));
}
// Create a new entry if necessary.
if(!entry) {
entry = do_CreateInstance(NS_SHENTRY_PROGID);
if (!entry) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
// Get the post data
nsCOMPtr<nsIInputStream> inputStream;
if (aChannel) {
nsCOMPtr<nsIHTTPChannel> httpChannel(do_QueryInterface(aChannel));
if(httpChannel) {
httpChannel->GetUploadStream(getter_AddRefs(inputStream));
}
}
//Title is set in nsDocShell::SetTitle()
entry->Create(aURI, // uri
nsnull, // Title
nsnull, // DOMDocument
inputStream, // Post data stream
nsnull); // LayoutHistory state
//
// Add the new entry to session history.
//
// If no Session History component is available in the parent DocShell
// heirarchy, then AddChildSHEntry(...) will fail and the new entry
// will be deleted when it loses scope...
//
if (mSessionHistory) {
rv = mSessionHistory->AddEntry(entry, shouldPersist);
} else {
rv = AddChildSHEntry(nsnull, entry, mChildOffset);
}
// Return the new SH entry...
if (aNewEntry) {
*aNewEntry = nsnull;
if (NS_SUCCEEDED(rv)) {
*aNewEntry = entry;
NS_ADDREF(*aNewEntry);
}
}
return rv;
}
/*
* Save the HistoryLayoutState for this page before we leave it.
*/
NS_IMETHODIMP nsDocShell::UpdateCurrentSessionHistory()
{
nsresult rv = NS_OK;
if(!mInitialPageLoad && mSessionHistory) {
PRInt32 index = 0;
mSessionHistory->GetIndex(&index);
if (-1 < index) {
nsCOMPtr<nsISHEntry> entry;
rv = mSessionHistory->GetEntryAtIndex(index, PR_FALSE, getter_AddRefs(entry));
if (NS_SUCCEEDED(rv) && entry) {
nsCOMPtr<nsIPresShell> shell;
rv = GetPresShell(getter_AddRefs(shell));
if (NS_SUCCEEDED(rv) && shell) {
nsCOMPtr<nsILayoutHistoryState> layoutState;
rv = shell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE);
if (NS_SUCCEEDED(rv) && layoutState) {
rv = entry->SetLayoutHistoryState(layoutState);
}
}
}
}
}
return rv;
}
#ifdef SH_IN_FRAMES
NS_IMETHODIMP nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, nsDocShellInfoLoadType aLoadType)
#else
NS_IMETHODIMP nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry)
#endif
{
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIInputStream> postData;
PRBool repost = PR_TRUE;
NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
NS_ERROR_FAILURE);
/* Ask whether to repost form post data */
if (postData) {
nsCOMPtr<nsIPrompt> prompter;
nsCOMPtr<nsIStringBundle> stringBundle;
GetPromptAndStringBundle(getter_AddRefs(prompter),
getter_AddRefs(stringBundle));
if (stringBundle && prompter) {
nsXPIDLString messageStr;
nsresult rv = stringBundle->GetStringFromName(NS_ConvertASCIItoUCS2("repost").GetUnicode(),
getter_Copies(messageStr));
if (NS_SUCCEEDED(rv) && messageStr) {
prompter->Confirm(nsnull, messageStr, &repost);
if (!repost)
postData = nsnull;
}
}
}
#ifdef SH_IN_FRAMES
NS_ENSURE_SUCCESS(InternalLoad(uri, nsnull, nsnull, nsnull, postData, aLoadType, aEntry),
NS_ERROR_FAILURE);
#else
NS_ENSURE_SUCCESS(InternalLoad(uri, nsnull, nsnull, nsnull, postData, nsIDocShellLoadInfo::loadHistory),
NS_ERROR_FAILURE);
#endif
return NS_OK;
}
/*
NS_IMETHODIMP
nsDocShell::GetSHEForChild(PRInt32 aChildOffset, nsISHEntry ** aResult)
{
if (OSHE) {
nsCOMPtr<nsISHContainer> container(do_QueryInterface(OSHE));
if (container)
return container->GetChildAt(aChildOffset, aResult);
}
return NS_ERROR_FAILURE;
}
*/
NS_IMETHODIMP
nsDocShell::PersistLayoutHistoryState()
{
nsresult rv;
if (OSHE) {
nsCOMPtr<nsIPresShell> shell;
rv = GetPresShell(getter_AddRefs(shell));
if (NS_SUCCEEDED(rv) && shell) {
nsCOMPtr<nsILayoutHistoryState> layoutState;
rv = shell->CaptureHistoryState(getter_AddRefs(layoutState), PR_TRUE);
if (NS_SUCCEEDED(rv) && layoutState) {
rv = OSHE->SetLayoutHistoryState(layoutState);
}
}
}
return rv;
}
#if 0
NS_IMETHODIMP
nsDocShell::CloneAndReplace(nsISHEntry * src, nsISHEntry * cloneRef,
nsISHEntry * replaceEntry, nsISHEntry * dest)
{
nsresult result;
if (!src || !replaceEntry || !cloneRef || !dest)
return NS_ERROR_FAILURE;
// NS_ENSURE_ARG_POINTER(dest, NS_ERROR_FAILURE);
// static PRBool firstTime = PR_TRUE;
// static nsISHEntry * rootSHEntry = nsnull;
if (src == cloneRef) {
// release the original object before assigning a new one.
NS_RELEASE(dest);
dest = replaceEntry;
}
else {
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIInputStream> postdata;
nsCOMPtr<nsILayoutHistoryState> LHS;
PRUnichar * title=nsnull;
nsCOMPtr<nsISHEntry> parent;
src->GetURI(getter_AddRefs(uri));
src->GetPostData(getter_AddRefs(postdata));
src->GetTitle(&title);
src->GetLayoutHistoryState(getter_AddRefs(LHS));
//XXX Is this correct? parent is a weak ref in nsISHEntry
src->GetParent(getter_AddRefs(parent));
// XXX do we care much about valid values for these uri, title etc....
dest->SetURI(uri);
dest->SetPostData(postdata);
dest->SetLayoutHistoryState(LHS);
dest->SetTitle(title);
dest->SetParent(parent);
}
/*
if (firstTime) {
// Save the root of the hierarchy in the result parameter
rootSHEntry = dest;
firstTime = PR_FALSE;
}
*/
PRInt32 childCount= 0;
nsCOMPtr<nsISHContainer> srcContainer(do_QueryInterface(src));
if (!srcContainer)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISHContainer> destContainer(do_QueryInterface(dest));
if (!destContainer)
return NS_ERROR_FAILURE;
srcContainer->GetChildCount(&childCount);
for(PRInt32 i = 0; i<childCount; i++) {
nsCOMPtr<nsISHEntry> srcChild;
srcContainer->GetChildAt(i, getter_AddRefs(srcChild));
if (!srcChild)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISHEntry> destChild(do_CreateInstance(NS_SHENTRY_PROGID));
if (!NS_SUCCEEDED(result))
return result;
result = CloneAndReplace(srcChild, cloneRef, replaceEntry, destChild);
if (!NS_SUCCEEDED(result))
return result;
result = destContainer->AddChild(destChild, i);
if (!NS_SUCCEEDED(result))
return result;
}
return result;
}
#else
NS_IMETHODIMP
nsDocShell::CloneAndReplace(nsISHEntry * src, nsISHEntry * cloneRef,
nsISHEntry * replaceEntry, nsISHEntry ** resultEntry)
{
nsresult result = NS_OK;
NS_ENSURE_ARG_POINTER(resultEntry);
if (!src || !replaceEntry || !cloneRef)
return NS_ERROR_FAILURE;
// NS_ENSURE_ARG_POINTER(dest, NS_ERROR_FAILURE);
// static PRBool firstTime = PR_TRUE;
// static nsISHEntry * rootSHEntry = nsnull;
nsISHEntry * dest = *resultEntry;
dest = (nsISHEntry *) nsnull;
if (src == cloneRef) {
// release the original object before assigning a new one.
//NS_RELEASE(dest);
dest = replaceEntry;
*resultEntry = dest;
NS_IF_ADDREF(*resultEntry);
}
else {
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIInputStream> postdata;
nsCOMPtr<nsILayoutHistoryState> LHS;
PRUnichar * title=nsnull;
nsCOMPtr<nsISHEntry> parent;
result = nsComponentManager::CreateInstance(NS_SHENTRY_PROGID, NULL,
NS_GET_IID(nsISHEntry), (void **) &dest);
if (!NS_SUCCEEDED(result))
return result;
src->GetURI(getter_AddRefs(uri));
src->GetPostData(getter_AddRefs(postdata));
src->GetTitle(&title);
src->GetLayoutHistoryState(getter_AddRefs(LHS));
//XXX Is this correct? parent is a weak ref in nsISHEntry
src->GetParent(getter_AddRefs(parent));
// XXX do we care much about valid values for these uri, title etc....
dest->SetURI(uri);
dest->SetPostData(postdata);
dest->SetLayoutHistoryState(LHS);
dest->SetTitle(title);
dest->SetParent(parent);
*resultEntry = dest;
}
*resultEntry = dest;
/*
if (firstTime) {
// Save the root of the hierarchy in the result parameter
rootSHEntry = dest;
firstTime = PR_FALSE;
}
*/
PRInt32 childCount= 0;
nsCOMPtr<nsISHContainer> srcContainer(do_QueryInterface(src));
if (!srcContainer)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISHContainer> destContainer(do_QueryInterface(dest));
if (!destContainer)
return NS_ERROR_FAILURE;
srcContainer->GetChildCount(&childCount);
for(PRInt32 i = 0; i<childCount; i++) {
nsCOMPtr<nsISHEntry> srcChild;
srcContainer->GetChildAt(i, getter_AddRefs(srcChild));
if (!srcChild)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISHEntry> destChild;
if (!NS_SUCCEEDED(result))
return result;
result = CloneAndReplace(srcChild, cloneRef, replaceEntry, getter_AddRefs(destChild));
if (!NS_SUCCEEDED(result))
return result;
result = destContainer->AddChild(destChild, i);
if (!NS_SUCCEEDED(result))
return result;
}
return result;
}
#endif /* 0 */
//*****************************************************************************
// nsDocShell: Global History
//*****************************************************************************
NS_IMETHODIMP nsDocShell::ShouldAddToGlobalHistory(nsIURI* aURI, PRBool* aShouldAdd)
{
*aShouldAdd = PR_FALSE;
if(!mGlobalHistory || !aURI || (typeContent != mItemType))
return NS_OK;
nsXPIDLCString scheme;
NS_ENSURE_SUCCESS(aURI->GetScheme(getter_Copies(scheme)), NS_ERROR_FAILURE);
nsAutoString schemeStr; schemeStr.AssignWithConversion(scheme);
// The model is really if we don't know differently then add which basically
// means we are suppose to try all the things we know not to allow in and
// then if we don't bail go on and allow it in. But here lets compare
// against the most common case we know to allow in and go on and say yes
// to it.
if(schemeStr.EqualsWithConversion("http") || schemeStr.EqualsWithConversion("https"))
{
*aShouldAdd = PR_TRUE;
return NS_OK;
}
if(schemeStr.EqualsWithConversion("about") || schemeStr.EqualsWithConversion("imap") ||
schemeStr.EqualsWithConversion("news") || schemeStr.EqualsWithConversion("mailbox"))
return NS_OK;
*aShouldAdd = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP nsDocShell::AddToGlobalHistory(nsIURI* aURI)
{
NS_ENSURE_STATE(mGlobalHistory);
nsXPIDLCString spec;
NS_ENSURE_SUCCESS(aURI->GetSpec(getter_Copies(spec)), NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(mGlobalHistory->AddPage(spec, nsnull, PR_Now()),
NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::UpdateCurrentGlobalHistory()
{
// XXX Add code here that needs to update the current history item
return NS_OK;
}
//*****************************************************************************
// nsDocShell: Helper Routines
//*****************************************************************************
nsresult nsDocShell::SetLoadCookie(nsISupports *aCookie)
{
// Remove the DocShell as a listener of the old WebProgress...
if (mLoadCookie) {
nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(mLoadCookie));
if (webProgress) {
webProgress->RemoveProgressListener(this);
}
}
mLoadCookie = aCookie;
// Add the DocShell as a listener to the new WebProgress...
if (mLoadCookie) {
nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(mLoadCookie));
if (webProgress) {
webProgress->AddProgressListener(this);
}
}
return NS_OK;
}
nsresult nsDocShell::GetLoadCookie(nsISupports **aResult)
{
*aResult = mLoadCookie;
NS_IF_ADDREF(*aResult);
return NS_OK;
}
nsDocShellInitInfo* nsDocShell::InitInfo()
{
if(mInitInfo)
return mInitInfo;
return mInitInfo = new nsDocShellInitInfo();
}
#define DIALOG_STRING_URI "chrome://global/locale/appstrings.properties"
NS_IMETHODIMP nsDocShell::GetPromptAndStringBundle(nsIPrompt** aPrompt,
nsIStringBundle** aStringBundle)
{
NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void**)aPrompt), NS_ERROR_FAILURE);
nsCOMPtr<nsILocaleService> localeService(do_GetService(NS_LOCALESERVICE_PROGID));
NS_ENSURE_TRUE(localeService, NS_ERROR_FAILURE);
nsCOMPtr<nsILocale> locale;
localeService->GetSystemLocale(getter_AddRefs(locale));
NS_ENSURE_TRUE(locale, NS_ERROR_FAILURE);
nsCOMPtr<nsIStringBundleService> stringBundleService(do_GetService(NS_STRINGBUNDLE_PROGID));
NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(stringBundleService->CreateBundle(DIALOG_STRING_URI, locale,
getter_AddRefs(aStringBundle)), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::GetChildOffset(nsIDOMNode *aChild, nsIDOMNode* aParent,
PRInt32* aOffset)
{
NS_ENSURE_ARG_POINTER(aChild || aParent);
nsCOMPtr<nsIDOMNodeList> childNodes;
NS_ENSURE_SUCCESS(aParent->GetChildNodes(getter_AddRefs(childNodes)),
NS_ERROR_FAILURE);
NS_ENSURE_TRUE(childNodes, NS_ERROR_FAILURE);
PRInt32 i=0;
for( ; PR_TRUE; i++)
{
nsCOMPtr<nsIDOMNode> childNode;
NS_ENSURE_SUCCESS(childNodes->Item(i, getter_AddRefs(childNode)),
NS_ERROR_FAILURE);
NS_ENSURE_TRUE(childNode, NS_ERROR_FAILURE);
if(childNode.get() == aChild)
{
*aOffset = i;
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsDocShell::GetRootScrollableView(nsIScrollableView** aOutScrollView)
{
NS_ENSURE_ARG_POINTER(aOutScrollView);
nsCOMPtr<nsIPresShell> shell;
NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(shell)), NS_ERROR_FAILURE);
nsCOMPtr<nsIViewManager> viewManager;
NS_ENSURE_SUCCESS(shell->GetViewManager(getter_AddRefs(viewManager)),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(viewManager->GetRootScrollableView(aOutScrollView),
NS_ERROR_FAILURE);
if (*aOutScrollView == nsnull)
{
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP nsDocShell::EnsureContentListener()
{
if(mContentListener)
return NS_OK;
mContentListener = new nsDSURIContentListener();
NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(mContentListener);
mContentListener->DocShell(this);
return NS_OK;
}
NS_IMETHODIMP nsDocShell::EnsureScriptEnvironment()
{
if(mScriptContext)
return NS_OK;
NS_NewScriptGlobalObject(getter_AddRefs(mScriptGlobal));
NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE);
mScriptGlobal->SetDocShell(NS_STATIC_CAST(nsIDocShell*, this));
mScriptGlobal->SetGlobalObjectOwner(
NS_STATIC_CAST(nsIScriptGlobalObjectOwner*, this));
NS_CreateScriptContext(mScriptGlobal, getter_AddRefs(mScriptContext));
NS_ENSURE_TRUE(mScriptContext, NS_ERROR_FAILURE);
return NS_OK;
}
PRBool nsDocShell::IsFrame()
{
if(mParent)
{
PRInt32 parentType = ~mItemType; // Not us
mParent->GetItemType(&parentType);
if(parentType == mItemType) // This is a frame
return PR_TRUE;
}
return PR_FALSE;
}
//*****************************************************************************
//*** nsRefreshTimer: Object Management
//*****************************************************************************
nsRefreshTimer::nsRefreshTimer() : mRepeat(PR_FALSE), mDelay(0)
{
NS_INIT_REFCNT();
}
nsRefreshTimer::~nsRefreshTimer()
{
}
//*****************************************************************************
// nsRefreshTimer::nsISupports
//*****************************************************************************
NS_IMPL_THREADSAFE_ADDREF(nsRefreshTimer)
NS_IMPL_THREADSAFE_RELEASE(nsRefreshTimer)
NS_INTERFACE_MAP_BEGIN(nsRefreshTimer)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
NS_INTERFACE_MAP_END_THREADSAFE
///*****************************************************************************
// nsRefreshTimer::nsITimerCallback
//*****************************************************************************
NS_IMETHODIMP_(void) nsRefreshTimer::Notify(nsITimer *aTimer)
{
NS_ASSERTION(mDocShell, "DocShell is somehow null");
if(mDocShell)
{
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
mDocShell -> CreateLoadInfo (getter_AddRefs (loadInfo));
loadInfo -> SetLoadType(nsIDocShellLoadInfo::loadRefresh);
mDocShell -> LoadURI(mURI, loadInfo);
}
/*
* LoadURL(...) will cancel all refresh timers... This causes the Timer and
* its refreshData instance to be released...
*/
}