/* -*- 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 "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 "nsIProgressEventSink.h" #include "nsILayoutHistoryState.h" #include "nsILocaleService.h" #include "nsIPlatformCharset.h" #include "nsITimer.h" #include "nsIFileStream.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" 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); //***************************************************************************** //*** nsDocShell: Object Management //***************************************************************************** nsDocShell::nsDocShell() : mContentListener(nsnull), mWebProgressListener(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), mParent(nsnull), mTreeOwner(nsnull), 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(nsIWebNavigation) NS_INTERFACE_MAP_ENTRY(nsIWebProgress) 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(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(nsIWebProgressListener)) && NS_SUCCEEDED(EnsureWebProgressListener())) *aSink = mWebProgressListener; 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 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))) { nsCOMPtr uriLoader(do_GetService(NS_URI_LOADER_PROGID)); 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) return docLoader->QueryInterface(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) { NS_ENSURE_ARG(aURI); nsCOMPtr referrer; PRBool replace = PR_FALSE; PRBool refresh = PR_FALSE; if(aLoadInfo) { aLoadInfo->GetReferrer(getter_AddRefs(referrer)); aLoadInfo->GetReplaceSessionHistorySlot(&replace); aLoadInfo->GetRefresh(&refresh); } NS_ENSURE_SUCCESS(InternalLoad(aURI, referrer, nsnull, nsnull, replace ? loadNormalReplace : (refresh ? loadRefresh : loadNormal)), 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() { if(mLoadCookie) { nsCOMPtr 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 shell(do_QueryInterface(shellItem)); if(shell) shell->StopLoad(); } return NS_OK; } // SetDocument is only meaningful for doc shells that support DOM documents. Not all do. NS_IMETHODIMP nsDocShell::SetDocument(nsIDOMDocument *aDOMDoc, nsIDOMElement *aRootNode) { // The tricky part is bypassing the normal load process and just putting a document into // the webshell. This is particularly nasty, since webshells don't normally even know // about their documents // (1) Create a document viewer nsCOMPtr documentViewer; nsCOMPtr docFactory; static NS_DEFINE_CID(kLayoutDocumentLoaderFactoryCID, NS_LAYOUT_DOCUMENT_LOADER_FACTORY_CID); NS_ENSURE_SUCCESS(nsComponentManager::CreateInstance(kLayoutDocumentLoaderFactoryCID, nsnull, NS_GET_IID(nsIDocumentLoaderFactory), (void**)getter_AddRefs(docFactory)), NS_ERROR_FAILURE); nsCOMPtr doc = do_QueryInterface(aDOMDoc); NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(docFactory->CreateInstanceForDocument(NS_STATIC_CAST(nsIContentViewerContainer*, this), doc, "view", getter_AddRefs(documentViewer)), NS_ERROR_FAILURE); // (2) Feed the docshell to the content viewer NS_ENSURE_SUCCESS(documentViewer->SetContainer((nsIDocShell*)this), NS_ERROR_FAILURE); // (3) Tell the content viewer container to setup the content viewer. // (This step causes everything to be set up for an initial flow.) NS_ENSURE_SUCCESS(SetupNewViewer(documentViewer), NS_ERROR_FAILURE); // XXX: It would be great to get rid of this dummy channel! nsCOMPtr uri; NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(uri), NS_ConvertASCIItoUCS2("about:blank")), NS_ERROR_FAILURE); NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY); nsCOMPtr dummyChannel; NS_ENSURE_SUCCESS(NS_OpenURI(getter_AddRefs(dummyChannel), uri, nsnull), NS_ERROR_FAILURE); // (4) fire start document load notification nsCOMPtr outStreamListener; NS_ENSURE_SUCCESS(doc->StartDocumentLoad("view", dummyChannel, nsnull, NS_STATIC_CAST(nsIContentViewerContainer*, this), getter_AddRefs(outStreamListener), PR_TRUE), NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(FireStartDocumentLoad(mDocLoader, uri, "load"), NS_ERROR_FAILURE); // (5) hook up the document and its content nsCOMPtr rootContent = do_QueryInterface(aRootNode); NS_ENSURE_TRUE(doc, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_SUCCESS(rootContent->SetDocument(doc, PR_FALSE, PR_TRUE), NS_ERROR_FAILURE); doc->SetRootContent(rootContent); // (6) reflow the document PRInt32 i; PRInt32 ns = doc->GetNumberOfShells(); for (i = 0; i < ns; i++) { nsCOMPtr shell(dont_AddRef(doc->GetShellAt(i))); if (shell) { // Make shell an observer for next time NS_ENSURE_SUCCESS(shell->BeginObservingDocument(), NS_ERROR_FAILURE); // Resize-reflow this time nsCOMPtr docViewer = do_QueryInterface(documentViewer); NS_ENSURE_TRUE(docViewer, NS_ERROR_OUT_OF_MEMORY); nsCOMPtr presContext; NS_ENSURE_SUCCESS(docViewer->GetPresContext(*(getter_AddRefs(presContext))), NS_ERROR_FAILURE); NS_ENSURE_TRUE(presContext, NS_ERROR_OUT_OF_MEMORY); float p2t; presContext->GetScaledPixelsToTwips(&p2t); nsRect r; NS_ENSURE_SUCCESS(GetPosition(&r.x, &r.y), NS_ERROR_FAILURE);; NS_ENSURE_SUCCESS(GetSize(&r.width, &r.height), NS_ERROR_FAILURE);; NS_ENSURE_SUCCESS(shell->InitialReflow(NSToCoordRound(r.width * p2t), NSToCoordRound(r.height * p2t)), NS_ERROR_FAILURE); // Now trigger a refresh nsCOMPtr vm; NS_ENSURE_SUCCESS(shell->GetViewManager(getter_AddRefs(vm)), NS_ERROR_FAILURE); if (vm) { PRBool enabled; documentViewer->GetEnableRendering(&enabled); if (enabled) { vm->EnableRefresh(NS_VMREFRESH_IMMEDIATE); } NS_ENSURE_SUCCESS(vm->SetWindowDimensions(NSToCoordRound(r.width * p2t), NSToCoordRound(r.height * p2t)), NS_ERROR_FAILURE); } } } // (7) fire end document load notification nsresult rv = NS_OK; NS_ENSURE_SUCCESS(FireEndDocumentLoad(mDocLoader, dummyChannel, rv), NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); // test the resulting out-param separately return NS_OK; } 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) { NS_ENSURE_ARG_POINTER(aPresContext); *aPresContext = nsnull; NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE); nsCOMPtr docv(do_QueryInterface(mContentViewer)); NS_ENSURE_TRUE(docv, NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(docv->GetPresContext(*aPresContext), NS_ERROR_FAILURE); return NS_OK; } NS_IMETHODIMP nsDocShell::GetPresShell(nsIPresShell** aPresShell) { NS_ENSURE_ARG_POINTER(aPresShell); *aPresShell = nsnull; nsCOMPtr presContext; NS_ENSURE_SUCCESS(GetPresContext(getter_AddRefs(presContext)), NS_ERROR_FAILURE); if(!presContext) return NS_OK; NS_ENSURE_SUCCESS(presContext->GetShell(aPresShell), NS_ERROR_FAILURE); return NS_OK; } 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(reloadNormal); 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) { mTreeOwner = aTreeOwner; // Weak reference per API // Don't automatically set the progress based on the tree owner for frames if(!IsFrame()) { nsCOMPtr progressListener(do_QueryInterface(aTreeOwner)); mOwnerProgressListener = progressListener; // Weak reference per API } else mOwnerProgressListener = nsnull; 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; } //***************************************************************************** // 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); 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); } } 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::nsIWebNavigation //***************************************************************************** NS_IMETHODIMP nsDocShell::GetCanGoBack(PRBool* aCanGoBack) { 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; return NS_OK; } NS_IMETHODIMP nsDocShell::GetCanGoForward(PRBool* aCanGoForward) { 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; return NS_OK; } NS_IMETHODIMP nsDocShell::GoBack() { if (mSessionHistory == nsnull) { return NS_OK; } nsCOMPtr root; GetSameTypeRootTreeItem(getter_AddRefs(root)); if(root.get() != NS_STATIC_CAST(nsIDocShellTreeItem*, this)) { nsCOMPtr rootAsNav(do_QueryInterface(root)); return rootAsNav->GoBack(); } NS_ENSURE_STATE(mSessionHistory); UpdateCurrentSessionHistory(); nsCOMPtr 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); return NS_OK; } NS_IMETHODIMP nsDocShell::GoForward() { if (mSessionHistory == nsnull) { return NS_OK; } nsCOMPtr root; GetSameTypeRootTreeItem(getter_AddRefs(root)); if(root.get() != NS_STATIC_CAST(nsIDocShellTreeItem*, this)) { nsCOMPtr rootAsNav(do_QueryInterface(root)); return rootAsNav->GoForward(); } NS_ENSURE_STATE(mSessionHistory); UpdateCurrentSessionHistory(); nsCOMPtr 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); return NS_OK; } 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) { // XXX Honor the reload type NS_ENSURE_STATE(mCurrentURI); // XXXTAB Convert reload type to our type loadType type = loadReloadNormal; if ( aReloadType == nsIWebNavigation::reloadBypassProxyAndCache ) type = loadReloadBypassProxyAndCache; NS_ENSURE_SUCCESS(InternalLoad(mCurrentURI, mReferrerURI, nsnull, nsnull, type), NS_ERROR_FAILURE); return NS_OK; } 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_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 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); nsCOMPtr docv(do_QueryInterface(mContentViewer)); NS_ENSURE_TRUE(docv, NS_ERROR_FAILURE); nsCOMPtrdoc; NS_ENSURE_SUCCESS(docv->GetDocument(*getter_AddRefs(doc)), NS_ERROR_FAILURE); NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER); // the result's addref comes from this QueryInterface call NS_ENSURE_SUCCESS(CallQueryInterface(doc.get(), aDocument), NS_ERROR_FAILURE); return NS_OK; } 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; return NS_OK; } NS_IMETHODIMP nsDocShell::GetSessionHistory(nsISHistory** aSessionHistory) { NS_ENSURE_ARG_POINTER(aSessionHistory); *aSessionHistory = mSessionHistory; NS_IF_ADDREF(*aSessionHistory); return NS_OK; } //***************************************************************************** // nsDocShell::nsIWebProgress //***************************************************************************** NS_IMETHODIMP nsDocShell::AddProgressListener(nsIWebProgressListener* aListener) { if(!mWebProgressListenerList) NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mWebProgressListenerList)), NS_ERROR_FAILURE); // Make sure it isn't already in the list... This is bad! NS_ENSURE_ARG(mWebProgressListenerList->IndexOf(aListener) == -1); NS_ENSURE_SUCCESS(mWebProgressListenerList->AppendElement(aListener), NS_ERROR_FAILURE); return NS_OK; } NS_IMETHODIMP nsDocShell::RemoveProgressListener(nsIWebProgressListener* aListener) { NS_ENSURE_STATE(mWebProgressListenerList); NS_ENSURE_ARG(aListener); NS_ENSURE_TRUE(mWebProgressListenerList->RemoveElement(aListener), NS_ERROR_INVALID_ARG); return NS_OK; } NS_IMETHODIMP nsDocShell::GetProgressStatusFlags(PRInt32* aProgressStatusFlags) { //XXXTAB First Check //XXX First Check /* Current connection Status of the browser. This will be one of the enumerated connection progress steps. */ return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::GetCurSelfProgress(PRInt32* curSelfProgress) { //XXXTAB First Check //XXX First Check /* The current position of progress. This is between 0 and maxSelfProgress. This is the position of only this progress object. It doesn not include the progress of all children. */ return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::GetMaxSelfProgress(PRInt32* maxSelfProgress) { //XXXTAB First Check //XXX First Check /* The maximum position that progress will go to. This sets a relative position point for the current progress to relate to. This is the max position of only this progress object. It does not include the progress of all the children. */ return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::GetCurTotalProgress(PRInt32* curTotalProgress) { //XXXTAB First Check //XXX First Check /* The current position of progress for this object and all children added together. This is between 0 and maxTotalProgress. */ return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocShell::GetMaxTotalProgress(PRInt32* maxTotalProgress) { //XXXTAB First Check //XXX First Check /* The maximum position that progress will go to for the max of this progress object and all children. This sets the relative position point for the current progress to relate to. */ 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_PROGID); mGlobalHistory = do_GetService(NS_GLOBALHISTORY_PROGID); 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); // 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; mWebProgressListenerList = nsnull; if(mScriptGlobal) { mScriptGlobal->SetDocShell(nsnull); mScriptGlobal = nsnull; } if(mScriptContext) { mScriptContext->SetOwner(nsnull); mScriptContext = nsnull; } mScriptGlobal = nsnull; mScriptContext = nsnull; mSessionHistory = nsnull; mLoadCookie = nsnull; SetTreeOwner(nsnull); if(mInitInfo) { delete mInitInfo; mInitInfo = nsnull; } if(mContentListener) { mContentListener->DocShell(nsnull); NS_RELEASE(mContentListener); } if(mWebProgressListener) { mWebProgressListener->DocShell(nsnull); NS_RELEASE(mWebProgressListener); } 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) 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 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 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)); NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE); 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.