/* -*- 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 * Pierre Phaneuf */ #include "nsIComponentManager.h" #include "nsIContent.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" #include "nsIDocumentViewer.h" #include "nsIDocumentLoaderFactory.h" #include "nsIPluginHost.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 "nsIDOMWindowInternal.h" #include "nsIWebBrowserChrome.h" #include "nsPoint.h" #include "nsGfxCIID.h" #include "nsIPrompt.h" #include "nsTextFormatter.h" #include "nsIHTTPEventSink.h" #include "nsISecurityEventSink.h" #include "nsScriptSecurityManager.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" #include "nsPIDOMWindow.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" // XXX Very unfortunate dependencies. These are required to fix // some serious focus bugs. Please read my comment in // SetupNewViewer. -- hyatt #include "nsIDOMXULDocument.h" #include "nsIDOMXULCommandDispatcher.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); static NS_DEFINE_CID(kDocumentCharsetInfoCID, NS_DOCUMENTCHARSETINFO_CID); static NS_DEFINE_CID(kPluginManagerCID, NS_PLUGINMANAGER_CID); static NS_DEFINE_CID(kSecurityManagerCID, NS_SCRIPTSECURITYMANAGER_CID); // // Local function prototypes // /** * Used in AddHeadersToChannel */ static NS_METHOD AHTC_WriteFunc(nsIInputStream* in, void* closure, const char* fromRawSegment, PRUint32 toOffset, PRUint32 count, PRUint32 *writeCount); //***************************************************************************** //*** 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), mLastViewMode(viewNormal), mRestoreViewMode(PR_FALSE), mEODForCurrentDocument (PR_FALSE), mUseExternalProtocolHandler (PR_FALSE), mParent(nsnull), mTreeOwner(nsnull), mURIResultedInDocument(PR_FALSE), mChromeEventHandler(nsnull) { NS_INIT_REFCNT(); } nsDocShell::~nsDocShell() { Destroy(); } NS_IMETHODIMP nsDocShell::DestroyChildren() { PRInt32 i, n = mChildren.Count(); nsCOMPtr 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 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(nsIDOMWindowInternal)) && NS_SUCCEEDED(EnsureScriptEnvironment())) { NS_ENSURE_SUCCESS(mScriptGlobal->QueryInterface(NS_GET_IID(nsIDOMWindowInternal), aSink), NS_ERROR_FAILURE); return NS_OK; } 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(nsIDOMDocument)) && NS_SUCCEEDED(EnsureContentViewer())) { mContentViewer->GetDOMDocument((nsIDOMDocument**) aSink); } else if(aIID.Equals(NS_GET_IID(nsIPrompt))) { nsCOMPtr 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(nsIHTTPEventSink)) || aIID.Equals(NS_GET_IID(nsIWebProgress)) || aIID.Equals(NS_GET_IID(nsISecurityEventSink)) ) { nsCOMPtr uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID)); NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE); nsCOMPtr docLoader; NS_ENSURE_SUCCESS(uriLoader->GetDocumentLoaderForContext(NS_STATIC_CAST(nsIDocShell*, this), getter_AddRefs(docLoader)), NS_ERROR_FAILURE); if (docLoader) { nsCOMPtr 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 referrer; nsCOMPtr owner; PRBool inheritOwner = PR_FALSE; PRBool stopActiveDoc = PR_FALSE; nsCOMPtr 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->GetInheritOwner(&inheritOwner); aLoadInfo->GetStopActiveDocument(&stopActiveDoc); aLoadInfo->GetSHEntry(getter_AddRefs(shEntry)); } if (!shEntry && loadType != nsIDocShellLoadInfo::loadNormalReplace) { /* 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 parentAsItem; GetSameTypeParent(getter_AddRefs(parentAsItem)); // Try to get your SHEntry from your parent if (parentAsItem) { nsCOMPtr 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, inheritOwner, stopActiveDoc, nsnull, 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 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 channel; NS_ENSURE_SUCCESS(NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, aStream, aContentType, aContentLen), NS_ERROR_FAILURE); nsCOMPtr uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID)); 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 localRef(loadInfo); *aLoadInfo = localRef; NS_ADDREF(*aLoadInfo); return NS_OK; } NS_IMETHODIMP nsDocShell::StopLoad() { // Cancel any timers that were set for this loader. CancelRefreshURITimers(); if(mLoadCookie) { nsCOMPtr uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID); if(uriLoader) uriLoader->Stop(mLoadCookie); } PRInt32 n; PRInt32 count = mChildren.Count(); for(n = 0; n < count; n++) { nsIDocShellTreeItem* shellItem = (nsIDocShellTreeItem*)mChildren.ElementAt(n); nsCOMPtr shell(do_QueryInterface(shellItem)); if(shell) shell->StopLoad(); } 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 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 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); // if the mDocumentCharsetInfo does not exist already, we create it now if (!mDocumentCharsetInfo) { nsresult res = nsComponentManager::CreateInstance(kDocumentCharsetInfoCID, NULL, NS_GET_IID(nsIDocumentCharsetInfo), getter_AddRefs(mDocumentCharsetInfo)); if (NS_FAILED(res)) return NS_ERROR_FAILURE; } *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 presShell; NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); // get the view manager nsCOMPtr 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 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 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 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 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 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 webProgress(do_QueryInterface(mLoadCookie)); if (webProgress) { nsCOMPtr oldListener(do_QueryInterface(mTreeOwner)); nsCOMPtr 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); /* Set the child's global history if the parent has one */ if (mGlobalHistory) { nsCOMPtr dsHistoryChild(do_QueryInterface(aChild)); if (dsHistoryChild) dsHistoryChild->SetGlobalHistory(mGlobalHistory); } 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 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 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 childCV; NS_ENSURE_SUCCESS(childAsDocShell->GetContentViewer(getter_AddRefs(childCV)), NS_ERROR_FAILURE); if(childCV) { nsCOMPtr childmuDV = do_QueryInterface(childCV); if(childmuDV) { NS_ENSURE_SUCCESS(childmuDV->SetDefaultCharacterSet(defaultCharset), NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(childmuDV->SetForceCharacterSet(forceCharset), NS_ERROR_FAILURE); } } // Now take this document's charset and set the parentCharset field of the // child's DocumentCharsetInfo to it. We'll later use that field, in the // loading process, for the charset choosing algorithm. // If we fail, at any point, we just return NS_OK. // This code has some performance impact. But this will be reduced when // the current charset will finally be stored as an Atom, avoiding the // alias resolution extra look-up. // we are NOT going to propagate the charset is this Chrome's docshell if (mItemType == nsIDocShellTreeItem::typeChrome) return NS_OK; nsresult res = NS_OK; // get the child's docCSInfo object nsCOMPtr dcInfo = NULL; res = childAsDocShell->GetDocumentCharsetInfo(getter_AddRefs(dcInfo)); if (NS_FAILED(res) || (!dcInfo)) return NS_OK; // get the parent's current charset nsCOMPtr docv(do_QueryInterface(mContentViewer)); if (!docv) return NS_OK; nsCOMPtr doc; res = docv->GetDocument(*getter_AddRefs(doc)); if (NS_FAILED(res) || (!doc)) return NS_OK; nsAutoString parentCS; res = doc->GetDocumentCharacterSet(parentCS); if (NS_FAILED(res)) return NS_OK; // set the child's parentCharset res = dcInfo->SetParentCharset(&parentCS); if (NS_FAILED(res)) return NS_OK; // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", parentCS.ToNewCString(), mItemType); 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 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 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 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 currentEntry; mSessionHistory->GetIndex(&index); if (index < 0) return NS_ERROR_FAILURE; rv = mSessionHistory->GetEntryAtIndex(index, PR_FALSE, getter_AddRefs(currentEntry)); if (currentEntry) { nsCOMPtr nextEntry; //(do_CreateInstance(NS_SHENTRY_CONTRACTID)); // 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 parent(do_QueryInterface(mParent, &rv)); if (parent) { if (!aCloneRef) { aCloneRef = OSHE; } rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset); } } return rv; } NS_IMETHODIMP nsDocShell::SetGlobalHistory(nsIGlobalHistory* aGlobalHistory) { mGlobalHistory = aGlobalHistory; return NS_OK; } NS_IMETHODIMP nsDocShell::GetGlobalHistory(nsIGlobalHistory** aGlobalHistory) { NS_ENSURE_ARG_POINTER(aGlobalHistory); *aGlobalHistory = mGlobalHistory; NS_IF_ADDREF(*aGlobalHistory); return NS_OK; } //***************************************************************************** // nsDocShell::nsIWebNavigation //***************************************************************************** NS_IMETHODIMP nsDocShell::GetCanGoBack(PRBool* aCanGoBack) { nsCOMPtr root; //Get the root docshell GetSameTypeRootTreeItem(getter_AddRefs(root)); NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); // QI to nsIWebNavigation nsCOMPtr rootAsWebnav(do_QueryInterface(root)); if (rootAsWebnav) { // Get the handle to SH from the root docshell nsCOMPtr rootSH; rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH)); NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE); // QI SH to nsIWebNavigation nsCOMPtr webNav(do_QueryInterface(rootSH)); if (webNav) return webNav->GetCanGoBack(aCanGoBack); } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::GetCanGoForward(PRBool* aCanGoForward) { nsCOMPtr root; //Get the root docshell GetSameTypeRootTreeItem(getter_AddRefs(root)); NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); // QI to nsIWebNavigation nsCOMPtr rootAsWebnav(do_QueryInterface(root)); if (rootAsWebnav) { // Get the handle to SH from the root docshell nsCOMPtr rootSH; rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH)); NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE); // QI SH to nsIWebNavigation nsCOMPtr webNav(do_QueryInterface(rootSH)); if (webNav) return webNav->GetCanGoForward(aCanGoForward); } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::GoBack() { nsCOMPtr root; //Get the root docshell GetSameTypeRootTreeItem(getter_AddRefs(root)); NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); // QI to nsIWebNavigation nsCOMPtr rootAsWebnav(do_QueryInterface(root)); if (rootAsWebnav) { // Get the handle to SH from the root docshell nsCOMPtr rootSH; rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH)); NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE); // QI SH to nsIWebNavigation nsCOMPtr webNav(do_QueryInterface(rootSH)); if (webNav) return webNav->GoBack(); } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::GoForward() { nsCOMPtr root; //Get the root docshell GetSameTypeRootTreeItem(getter_AddRefs(root)); NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); // QI to nsIWebNavigation nsCOMPtr rootAsWebnav(do_QueryInterface(root)); if (rootAsWebnav) { // Get the handle to SH from the root docshell nsCOMPtr rootSH; rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH)); NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE); // QI SH to nsIWebNavigation nsCOMPtr webNav(do_QueryInterface(rootSH)); if (webNav) return webNav->GoForward(); } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::GotoIndex(PRInt32 aIndex) { nsCOMPtr root; //Get the root docshell GetSameTypeRootTreeItem(getter_AddRefs(root)); NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); // QI to nsIWebNavigation nsCOMPtr rootAsWebnav(do_QueryInterface(root)); if (rootAsWebnav) { // Get the handle to SH from the root docshell nsCOMPtr rootSH; rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH)); NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE); // QI SH to nsIWebNavigation nsCOMPtr webNav(do_QueryInterface(rootSH)); if (webNav) return webNav->GotoIndex(aIndex); } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::LoadURI(const PRUnichar* aURI) { nsCOMPtr uri; nsresult rv = CreateFixupURI(aURI, getter_AddRefs(uri)); if(NS_ERROR_UNKNOWN_PROTOCOL == rv) { // we weren't able to find a protocol handler nsCOMPtr prompter; nsCOMPtr 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; #if 0 nsCOMPtr entry; if (OSHE) { /* We should fall here in most cases including subframes & refreshes */ entry = OSHE; } else if (mSessionHistory) { /* In case we fail above, as a last ditch effort, we * reload the whole page. */ 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); } else { //May be one of those charset reloads in a composer or Messenger return InternalLoad(mCurrentURI, mReferrerURI, nsnull, PR_TRUE, PR_FALSE, nsnull, nsnull, nsnull, type); } #else // OK. Atleast for the heck of it, pollmann says that he doesn't crash // in bug 45297 if he just did the following, instead of the one in #if 0. // If this really keeps the crash from re-occuring, may be this can stay. However // there is no major difference between this one and the one inside #if 0 return InternalLoad(mCurrentURI, mReferrerURI, nsnull, PR_TRUE, PR_FALSE, nsnull, nsnull, nsnull, type); #endif /* 0 */ // return LoadHistoryEntry(entry, type); #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, PR_TRUE, PR_FALSE, nsnull, nsnull, nsnull, type), NS_ERROR_FAILURE); return NS_OK; #endif /* SH_IN_FRAMES */ } NS_IMETHODIMP nsDocShell::Stop() { // Cancel any timers that were set for this loader. CancelRefreshURITimers(); if(mContentViewer) mContentViewer->Stop(); if(mLoadCookie) { nsCOMPtr uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID); if(uriLoader) uriLoader->Stop(mLoadCookie); } PRInt32 n; PRInt32 count = mChildren.Count(); for(n = 0; n < count; n++) { nsIDocShellTreeItem* shell = (nsIDocShellTreeItem*)mChildren.ElementAt(n); nsCOMPtr 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(nsIURI** aURI) { NS_ENSURE_ARG_POINTER(aURI); *aURI = mCurrentURI; NS_IF_ADDREF(*aURI); return NS_OK; } NS_IMETHODIMP nsDocShell::SetSessionHistory(nsISHistory* aSessionHistory) { NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE); // make sure that we are the root docshell and // set a handle to root docshell in SH. nsCOMPtr root; /* Get the root docshell. If *this* is the root docshell * then save a handle to *this* in SH. SH needs it to do * traversions thro' its entries */ GetSameTypeRootTreeItem(getter_AddRefs(root)); NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); if (root.get() == NS_STATIC_CAST(nsIDocShellTreeItem *, this)) { mSessionHistory = aSessionHistory; mSessionHistory->SetRootDocShell(this); return NS_OK; } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::GetSessionHistory(nsISHistory** aSessionHistory) { NS_ENSURE_ARG_POINTER(aSessionHistory); if (mSessionHistory) { *aSessionHistory = mSessionHistory; NS_IF_ADDREF(*aSessionHistory); return NS_OK; } return NS_ERROR_FAILURE; } //***************************************************************************** // 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_CONTRACTID); //GlobalHistory is now set in SetGlobalHistory // mGlobalHistory = do_GetService(NS_GLOBALHISTORY_CONTRACTID); // 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 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 docViewer(do_QueryInterface(mContentViewer)); NS_ENSURE_TRUE(docViewer, NS_ERROR_FAILURE); nsCOMPtr context; docViewer->GetPresContext(*getter_AddRefs(context)); NS_ENSURE_TRUE(context, NS_ERROR_FAILURE); nsCOMPtr shell; context->GetShell(getter_AddRefs(shell)); NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE); nsCOMPtr 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 presShell; NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); // get the view manager nsCOMPtr 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 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 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) { nsresult ret = nextCallWin->FocusAvailable(aCurrentFocus, aTookFocus); if (NS_SUCCEEDED(ret) && *aTookFocus) return NS_OK; } if (!mChildren.Count()) { //If we don't have children and our parent didn't want //the focus then we should just stop now. 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 child(do_QueryInterface((nsISupports*)mChildren.ElementAt(i))); //If we have focus we offer it to our first child. if(aCurrentFocus == NS_STATIC_CAST(nsIBaseWindow*, this)) { if(NS_SUCCEEDED(child->SetFocus())) { *aTookFocus = PR_TRUE; return NS_OK; } else { return NS_ERROR_FAILURE; } } //If we don't have focus, find the child that does then //offer focus to the next one. 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; } else { return NS_ERROR_FAILURE; } } } } //Reached the end of our child list. Call again to offer focus //upwards and to start at the beginning of our child list if //no one above us wants focus. return FocusAvailable(this, aTookFocus); } 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 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 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 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 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 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 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 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.