/* -*- 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 * Peter Annema * Dan Rosen */ #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 "nsDOMCID.h" #include "nsIDOMScriptObjectFactory.h" #include "nsNetUtil.h" #include "nsRect.h" #include "prprf.h" #include "nsIMarkupDocumentViewer.h" #include "nsXPIDLString.h" #include "nsReadableUtils.h" #include "nsIChromeEventHandler.h" #include "nsIDOMWindowInternal.h" #include "nsIWebBrowserChrome.h" #include "nsPoint.h" #include "nsGfxCIID.h" #include "nsIPrompt.h" #include "nsIAuthPrompt.h" #include "nsTextFormatter.h" #include "nsIHttpEventSink.h" #include "nsIUploadChannel.h" #include "nsISecurityEventSink.h" #include "nsIScriptSecurityManager.h" #include "nsDocumentCharsetInfoCID.h" #include "nsICanvasFrame.h" #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...) #include "nsICategoryManager.h" #include "nsXPCOMCID.h" #include "nsISeekableStream.h" // we want to explore making the document own the load group // so we can associate the document URI with the load group. // until this point, we have an evil hack: #include "nsIHttpChannelInternal.h" // Local Includes #include "nsDocShell.h" #include "nsDocShellLoadInfo.h" #include "nsCDefaultURIFixup.h" #include "nsDocShellEnumerator.h" // Helper Classes #include "nsDOMError.h" #include "nsEscape.h" // Interfaces Needed #include "nsIUploadChannel.h" #include "nsIDataChannel.h" #include "nsIProgressEventSink.h" #include "nsIWebProgress.h" #include "nsILayoutHistoryState.h" #include "nsITimer.h" #include "nsISHistoryInternal.h" #include "nsIPrincipal.h" #include "nsIHistoryEntry.h" #include "nsISHistoryListener.h" #include "nsIDirectoryListing.h" // Pull in various NS_ERROR_* definitions #include "nsIDNSService.h" #include "nsISocketTransportService.h" #include "nsISocketProvider.h" // Editor-related #include "nsIEditingSession.h" #include "nsPIDOMWindow.h" #include "nsIDOMDocument.h" #include "nsICachingChannel.h" #include "nsICacheEntryDescriptor.h" #include "nsIMultiPartChannel.h" #include "nsIWyciwygChannel.h" // The following are for bug #13871: Prevent frameset spoofing #include "nsIHTMLDocument.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" #include "nsIFocusController.h" #include "nsITextToSubURI.h" #include "prlog.h" #include "prmem.h" #include "nsISelectionDisplay.h" // this is going away - see // #include "nsIBrowserHistory.h" #ifdef DEBUG_DOCSHELL_FOCUS #include "nsIEventStateManager.h" #endif #include "nsIFrame.h" // for embedding #include "nsIWebBrowserChromeFocus.h" #include "nsPluginError.h" static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_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(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); #if defined(DEBUG_bryner) //#define DEBUG_DOCSHELL_FOCUS #endif #include "plevent.h" // Number of documents currently loading static PRInt32 gNumberOfDocumentsLoading = 0; // Hint for native dispatch of plevents on how long to delay after // all documents have loaded in milliseconds before favoring normal // native event dispatch priorites over performance #define NS_EVENT_STARVATION_DELAY_HINT 2000 // This is needed for displaying an error message // when navigation is attempted on a document when printing // The value arbitrary as long as it doesn't conflict with // any of the other values in the errors in DisplayLoadError #define NS_ERROR_DOCUMENT_IS_PRINTMODE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL,2001) // // Local function prototypes // /** * Used in AddHeadersToChannel */ static NS_METHOD AHTC_WriteFunc(nsIInputStream * in, void *closure, const char *fromRawSegment, PRUint32 toOffset, PRUint32 count, PRUint32 * writeCount); #ifdef PR_LOGGING static PRLogModuleInfo* gDocShellLog; #endif //***************************************************************************** //*** nsDocShellFocusController //***************************************************************************** class nsDocShellFocusController { public: static nsDocShellFocusController* GetInstance() { return &mDocShellFocusControllerSingleton; } virtual ~nsDocShellFocusController(){} void Focus(nsIDocShell* aDS); void ClosingDown(nsIDocShell* aDS); protected: nsDocShellFocusController(){} nsIDocShell* mFocusedDocShell; // very weak reference private: static nsDocShellFocusController mDocShellFocusControllerSingleton; }; nsDocShellFocusController nsDocShellFocusController::mDocShellFocusControllerSingleton; //***************************************************************************** //*** nsDocShell: Object Management //***************************************************************************** nsDocShell::nsDocShell(): mContentListener(nsnull), mMarginWidth(0), mMarginHeight(0), mItemType(typeContent), mCurrentScrollbarPref(-1, -1), mDefaultScrollbarPref(-1, -1), mAllowSubframes(PR_TRUE), mAllowPlugins(PR_TRUE), mAllowJavascript(PR_TRUE), mAllowMetaRedirects(PR_TRUE), mAllowImages(PR_TRUE), mFocusDocFirst(PR_FALSE), mCreatingDocument(PR_FALSE), mUseErrorPages(PR_FALSE), mAllowAuth(PR_TRUE), mAppType(nsIDocShell::APP_TYPE_UNKNOWN), mBusyFlags(BUSY_FLAGS_NONE), mFiredUnloadEvent(PR_FALSE), mEODForCurrentDocument(PR_FALSE), mURIResultedInDocument(PR_FALSE), mUseExternalProtocolHandler(PR_FALSE), mDisallowPopupWindows(PR_FALSE), mIsBeingDestroyed(PR_FALSE), mIsExecutingOnLoadHandler(PR_FALSE), mEditorData(nsnull), mParent(nsnull), mTreeOwner(nsnull), mChromeEventHandler(nsnull), mIsPrintingOrPP(PR_FALSE) { #ifdef PR_LOGGING if (! gDocShellLog) gDocShellLog = PR_NewLogModule("nsDocShell"); #endif } nsDocShell::~nsDocShell() { nsDocShellFocusController* dsfc = nsDocShellFocusController::GetInstance(); if (dsfc) { dsfc->ClosingDown(this); } 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)); NS_WARN_IF_FALSE(shell, "docshell has null child"); if (shell) { shell->SetParent(nsnull); shell->SetTreeOwner(nsnull); // just clear out the array. When the nsFrameFrame that holds // the subshell is destroyed, then the Destroy() method of // that subshell will actually get called. } } 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(nsIDocCharset) 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_ENTRY(nsIContentViewerContainer) NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell) NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor) NS_INTERFACE_MAP_END_THREADSAFE ///***************************************************************************** // nsDocShell::nsIInterfaceRequestor //***************************************************************************** NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink) { NS_PRECONDITION(aSink, "null out param"); 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(nsPIDOMWindow)) && NS_SUCCEEDED(EnsureScriptEnvironment())) { NS_ENSURE_SUCCESS(mScriptGlobal-> QueryInterface(NS_GET_IID(nsPIDOMWindow), 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); 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(nsIAuthPrompt))) { // if auth is not allowed, bail out if (!mAllowAuth) return NS_NOINTERFACE; nsCOMPtr authPrompter(do_GetInterface(mTreeOwner)); if (authPrompter) { *aSink = authPrompter; 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 if (aIID.Equals(NS_GET_IID(nsISHistory))) { nsCOMPtr shistory; nsresult rv = GetSessionHistory(getter_AddRefs(shistory)); if (NS_SUCCEEDED(rv) && shistory) { *aSink = shistory; NS_ADDREF((nsISupports *) * aSink); return NS_OK; } return NS_NOINTERFACE; } else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) { nsresult rv = EnsureFind(); if (NS_FAILED(rv)) return rv; *aSink = mFind; NS_ADDREF((nsISupports*)*aSink); return NS_OK; } else if (aIID.Equals(NS_GET_IID(nsIEditingSession)) && NS_SUCCEEDED(EnsureEditorData())) { nsCOMPtr editingSession; mEditorData->GetEditingSession(getter_AddRefs(editingSession)); if (editingSession) { *aSink = editingSession; NS_ADDREF((nsISupports *)*aSink); return NS_OK; } return NS_NOINTERFACE; } else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) && NS_SUCCEEDED(EnsureTransferableHookData())) { *aSink = mTransferableHookData; NS_ADDREF((nsISupports *)*aSink); return NS_OK; } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) { nsCOMPtr shell; nsresult rv = GetPresShell(getter_AddRefs(shell)); if (NS_SUCCEEDED(rv) && shell) return shell->QueryInterface(aIID,aSink); } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) { nsCOMPtr treeOwner; nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner)); if (NS_SUCCEEDED(rv) && treeOwner) return treeOwner->QueryInterface(aIID, aSink); } else { return QueryInterface(aIID, aSink); } NS_IF_ADDREF(((nsISupports *) * aSink)); return NS_OK; } PRUint32 nsDocShell:: ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType) { PRUint32 loadType = LOAD_NORMAL; switch (aDocShellLoadType) { case nsIDocShellLoadInfo::loadNormal: loadType = LOAD_NORMAL; break; case nsIDocShellLoadInfo::loadNormalReplace: loadType = LOAD_NORMAL_REPLACE; break; case nsIDocShellLoadInfo::loadHistory: loadType = LOAD_HISTORY; break; case nsIDocShellLoadInfo::loadReloadNormal: loadType = LOAD_RELOAD_NORMAL; break; case nsIDocShellLoadInfo::loadReloadCharsetChange: loadType = LOAD_RELOAD_CHARSET_CHANGE; break; case nsIDocShellLoadInfo::loadReloadBypassCache: loadType = LOAD_RELOAD_BYPASS_CACHE; break; case nsIDocShellLoadInfo::loadReloadBypassProxy: loadType = LOAD_RELOAD_BYPASS_PROXY; break; case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache: loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE; break; case nsIDocShellLoadInfo::loadLink: loadType = LOAD_LINK; break; case nsIDocShellLoadInfo::loadRefresh: loadType = LOAD_REFRESH; break; case nsIDocShellLoadInfo::loadBypassHistory: loadType = LOAD_BYPASS_HISTORY; break; } return loadType; } nsDocShellInfoLoadType nsDocShell::ConvertLoadTypeToDocShellLoadInfo(PRUint32 aLoadType) { nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal; switch (aLoadType) { case LOAD_NORMAL: docShellLoadType = nsIDocShellLoadInfo::loadNormal; break; case LOAD_NORMAL_REPLACE: docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace; break; case LOAD_HISTORY: docShellLoadType = nsIDocShellLoadInfo::loadHistory; break; case LOAD_RELOAD_NORMAL: docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal; break; case LOAD_RELOAD_CHARSET_CHANGE: docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange; break; case LOAD_RELOAD_BYPASS_CACHE: docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache; break; case LOAD_RELOAD_BYPASS_PROXY: docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy; break; case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache; break; case LOAD_LINK: docShellLoadType = nsIDocShellLoadInfo::loadLink; break; case LOAD_REFRESH: docShellLoadType = nsIDocShellLoadInfo::loadRefresh; break; case LOAD_BYPASS_HISTORY: docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory; break; } return docShellLoadType; } //***************************************************************************** // nsDocShell::nsIDocShell //***************************************************************************** NS_IMETHODIMP nsDocShell::LoadURI(nsIURI * aURI, nsIDocShellLoadInfo * aLoadInfo, PRUint32 aLoadFlags, PRBool firstParty) { nsresult rv; nsCOMPtr referrer; nsCOMPtr postStream; nsCOMPtr headersStream; nsCOMPtr owner; PRBool inheritOwner = PR_FALSE; nsCOMPtr shEntry; nsXPIDLString target; PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags); NS_ENSURE_ARG(aURI); // Extract the info from the DocShellLoadInfo struct... if (aLoadInfo) { aLoadInfo->GetReferrer(getter_AddRefs(referrer)); nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal; aLoadInfo->GetLoadType(<); // Get the appropriate loadType from nsIDocShellLoadInfo type loadType = ConvertDocShellLoadInfoToLoadType(lt); aLoadInfo->GetOwner(getter_AddRefs(owner)); aLoadInfo->GetInheritOwner(&inheritOwner); aLoadInfo->GetSHEntry(getter_AddRefs(shEntry)); aLoadInfo->GetTarget(getter_Copies(target)); aLoadInfo->GetPostDataStream(getter_AddRefs(postStream)); aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream)); } #ifdef PR_LOGGING if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) { nsCAutoString uristr; aURI->GetAsciiSpec(uristr); PR_LOG(gDocShellLog, PR_LOG_DEBUG, ("nsDocShell[%p]: loading %s with flags 0x%08x", this, uristr.get(), aLoadFlags)); } #endif if (!shEntry && loadType != LOAD_NORMAL_REPLACE) { // First verify if this is a subframe. nsCOMPtr parentAsItem; GetSameTypeParent(getter_AddRefs(parentAsItem)); nsCOMPtr parentDS(do_QueryInterface(parentAsItem)); PRUint32 parentLoadType; if (parentDS && parentDS != NS_STATIC_CAST(nsIDocShell *, this)) { /* OK. It is a subframe. Checkout the * parent's loadtype. If the parent was loaded thro' a history * mechanism, then get the SH entry for the child from the parent. * This is done to restore frameset navigation while going back/forward. * If the parent was loaded through any other loadType, set the * child's loadType too accordingly, so that session history does not * get confused. */ // Get the parent's load type parentDS->GetLoadType(&parentLoadType); nsCOMPtr parent(do_QueryInterface(parentAsItem)); if (parent) { // Get the ShEntry for the child from the parent parent->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry)); // Make some decisions on the child frame's loadType based on the // parent's loadType. if (mCurrentURI == nsnull) { // This is a newly created frame. Check for exception cases first. // By default the subframe will inherit the parent's loadType. if (shEntry && (parentLoadType == LOAD_NORMAL || parentLoadType == LOAD_LINK)) { // The parent was loaded normally. In this case, this *brand new* child really shouldn't // have a SHEntry. If it does, it could be because the parent is replacing an // existing frame with a new frame, in the onLoadHandler. We don't want this // url to get into session history. Clear off shEntry, and set laod type to // LOAD_BYPASS_HISTORY. PRBool inOnLoadHandler=PR_FALSE; parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler); if (inOnLoadHandler) { loadType = LOAD_NORMAL_REPLACE; shEntry = nsnull; } } else if (parentLoadType == LOAD_REFRESH) { // Clear shEntry. For refresh loads, we have to load // what comes thro' the pipe, not what's in history. shEntry = nsnull; } else if ((parentLoadType == LOAD_BYPASS_HISTORY) || (shEntry && ((parentLoadType & LOAD_CMD_HISTORY) || (parentLoadType == LOAD_RELOAD_NORMAL) || (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE)))) { // If the parent url, bypassed history or was loaded from // history, pass on the parent's loadType to the new child // frame too, so that the child frame will also // avoid getting into history. loadType = parentLoadType; } } else { // This is a pre-existing subframe. If the load was not originally initiated // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null, // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading // a new page in this child. Check parent's and self's busy flag and if it is set, // we don't want this onLoadHandler load to get in to session history. PRUint32 parentBusy=BUSY_FLAGS_NONE, selfBusy = BUSY_FLAGS_NONE; parentDS->GetBusyFlags(&parentBusy); GetBusyFlags(&selfBusy); if (((parentBusy & BUSY_FLAGS_BUSY) || (selfBusy & BUSY_FLAGS_BUSY)) && shEntry) { loadType = LOAD_NORMAL_REPLACE; shEntry = nsnull; } } } // parent } //parentDS else { // This is the root docshell. If we got here while // executing an onLoad Handler,this load will not go // into session history. PRBool inOnLoadHandler=PR_FALSE; GetIsExecutingOnLoadHandler(&inOnLoadHandler); if (inOnLoadHandler) { loadType = LOAD_NORMAL_REPLACE; } } } // !shEntry if (shEntry) { PR_LOG(gDocShellLog, PR_LOG_DEBUG, ("nsDocShell[%p]: loading from session history", this)); rv = LoadHistoryEntry(shEntry, loadType); } // Perform the load... else { // We need an owner (a referring principal). 3 possibilities: // (1) If a principal was passed in, that's what we'll use. // (2) If the caller has allowed inheriting from the current document, // or if we're being called from chrome (if there's system JS on the stack), // then inheritOwner should be true and InternalLoad will get an owner // from the current document. If none of these things are true, then // (3) we pass a null owner into the channel, and an owner will be // created later from the URL. if (!owner && !inheritOwner) { // See if there's system or chrome JS code running nsCOMPtr secMan; secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_SUCCEEDED(rv)) { nsCOMPtr sysPrin; nsCOMPtr subjectPrin; // Just to compare, not to use! rv = secMan->GetSystemPrincipal(getter_AddRefs(sysPrin)); if (NS_SUCCEEDED(rv)) { rv = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrin)); } // If there's no subject principal, there's no JS running, so we're in system code. if (NS_SUCCEEDED(rv) && (!subjectPrin || sysPrin.get() == subjectPrin.get())) { inheritOwner = PR_TRUE; } } } rv = InternalLoad(aURI, referrer, owner, inheritOwner, target.get(), postStream, headersStream, loadType, nsnull, // No SHEntry firstParty, nsnull, // No nsIDocShell nsnull); // No nsIRequest } return rv; } NS_IMETHODIMP nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI, const nsACString &aContentType, const nsACString &aContentCharset, nsIDocShellLoadInfo * aLoadInfo) { NS_ENSURE_ARG(aStream); // 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; // Make sure that the URI spec "looks" like a protocol and path... // For now, just use a bogus protocol called "internal" rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream")); if (NS_FAILED(rv)) return rv; } PRUint32 loadType = LOAD_NORMAL; if (aLoadInfo) { nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal; (void) aLoadInfo->GetLoadType(<); // Get the appropriate LoadType from nsIDocShellLoadInfo type loadType = ConvertDocShellLoadInfoToLoadType(lt); } NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE); mLoadType = loadType; // build up a channel for this stream. nsCOMPtr channel; NS_ENSURE_SUCCESS(NS_NewInputStreamChannel (getter_AddRefs(channel), uri, aStream, aContentType, aContentCharset), NS_ERROR_FAILURE); nsCOMPtr uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID)); NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(DoChannelLoad(channel, 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; } /* * Reset state to a new content model within the current document and the document * viewer. Called by the document before initiating an out of band document.write(). */ NS_IMETHODIMP nsDocShell::PrepareForNewContentModel() { mEODForCurrentDocument = PR_FALSE; return NS_OK; } NS_IMETHODIMP nsDocShell::FireUnloadNotification() { nsresult rv; if (mContentViewer && !mFiredUnloadEvent) { mFiredUnloadEvent = PR_TRUE; rv = mContentViewer->Unload(); PRInt32 i, n = mChildren.Count(); for (i = 0; i < n; i++) { nsIDocShellTreeItem* item = (nsIDocShellTreeItem*) mChildren.ElementAt(i); if(item) { nsCOMPtr shell(do_QueryInterface(item)); if (shell) { rv = shell->FireUnloadNotification(); } } } } return NS_OK; } // // Bug 13871: Prevent frameset spoofing // Check if origin document uri is the equivalent to target's principal. // This takes into account subdomain checking if document.domain is set for // Nav 4.x compatability. // // The following was derived from nsCodeBasePrincipal::Equals but in addition // to the host PL_strcmp, it accepts a subdomain (nsHTMLDocument::SetDomain) // if the document.domain was set. // static PRBool SameOrSubdomainOfTarget(nsIURI* aOriginURI, nsIURI* aTargetURI, PRBool aDocumentDomainSet) { nsCAutoString targetScheme; nsresult rv = aTargetURI->GetScheme(targetScheme); NS_ENSURE_TRUE(NS_SUCCEEDED(rv), PR_TRUE); nsCAutoString originScheme; rv = aOriginURI->GetScheme(originScheme); NS_ENSURE_TRUE(NS_SUCCEEDED(rv), PR_TRUE); if (strcmp(targetScheme.get(), originScheme.get())) return PR_FALSE; // Different schemes - check fails if (! strcmp(targetScheme.get(), "file")) return PR_TRUE; // All file: urls are considered to have the same origin. if (! strcmp(targetScheme.get(), "imap") || ! strcmp(targetScheme.get(), "mailbox") || ! strcmp(targetScheme.get(), "news")) { // Each message is a distinct trust domain; use the whole spec for comparison nsCAutoString targetSpec; rv =aTargetURI->GetAsciiSpec(targetSpec); NS_ENSURE_TRUE(NS_SUCCEEDED(rv), PR_TRUE); nsCAutoString originSpec; rv = aOriginURI->GetAsciiSpec(originSpec); NS_ENSURE_TRUE(NS_SUCCEEDED(rv), PR_TRUE); return (! strcmp(targetSpec.get(), originSpec.get())); // True if full spec is same, false otherwise } // Compare ports. int targetPort, originPort; rv = aTargetURI->GetPort(&targetPort); NS_ENSURE_TRUE(NS_SUCCEEDED(rv), PR_TRUE); rv = aOriginURI->GetPort(&originPort); NS_ENSURE_TRUE(NS_SUCCEEDED(rv), PR_TRUE); if (targetPort != originPort) return PR_FALSE; // Different port - check fails // Need to check the hosts nsCAutoString targetHost; rv = aTargetURI->GetHost(targetHost); NS_ENSURE_TRUE(NS_SUCCEEDED(rv), PR_TRUE); nsCAutoString originHost; rv = aOriginURI->GetHost(originHost); NS_ENSURE_TRUE(NS_SUCCEEDED(rv), PR_TRUE); if (!strcmp(targetHost.get(), originHost.get())) return PR_TRUE; // Hosts are the same - check passed // If document.domain was set, do the relaxed check // Right align hostnames and compare - ensure preceeding char is . or / if (aDocumentDomainSet) { int targetHostLen = targetHost.Length(); int originHostLen = originHost.Length(); int prefixChar = originHostLen-targetHostLen-1; return ((originHostLen > targetHostLen) && (! strcmp((originHost.get()+prefixChar+1), targetHost.get())) && (originHost.CharAt(prefixChar) == '.' || originHost.CharAt(prefixChar) == '/')); } return PR_FALSE; // document.domain not set and hosts not same - check failed } // // Bug 13871: Prevent frameset spoofing // // This routine answers: 'Is origin's document from same domain as target's document?' // Be optimistic that domain is same - error cases all answer 'yes'. // // We have to compare the URI of the actual document loaded in the origin, // ignoring any document.domain that was set, with the principal URI of the // target (including any document.domain that was set). This puts control // of loading in the hands of the target, which is more secure. (per Nav 4.x) // static PRBool ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem, nsIDocShellTreeItem* aTargetTreeItem) { // Get origin document uri (ignoring document.domain) nsCOMPtr originWebNav(do_QueryInterface(aOriginTreeItem)); NS_ENSURE_TRUE(originWebNav, PR_TRUE); nsCOMPtr originDocumentURI; nsresult rv = originWebNav->GetCurrentURI(getter_AddRefs(originDocumentURI)); NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && originDocumentURI, PR_TRUE); // Get target principal uri (including document.domain) nsCOMPtr targetDOMDocument(do_GetInterface(aTargetTreeItem)); NS_ENSURE_TRUE(targetDOMDocument, NS_ERROR_FAILURE); nsCOMPtr targetDocument(do_QueryInterface(targetDOMDocument)); NS_ENSURE_TRUE(targetDocument, NS_ERROR_FAILURE); nsCOMPtr targetPrincipal; rv = targetDocument->GetPrincipal(getter_AddRefs(targetPrincipal)); NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && targetPrincipal, rv); nsCOMPtr targetPrincipalURI; rv = targetPrincipal->GetURI(getter_AddRefs(targetPrincipalURI)); NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && targetPrincipalURI, PR_TRUE); // Find out if document.domain was set for HTML documents PRBool documentDomainSet = PR_FALSE; nsCOMPtr targetHTMLDocument(do_QueryInterface(targetDocument)); // If we don't have an HTML document, fall through with documentDomainSet false if (targetHTMLDocument) { targetHTMLDocument->WasDomainSet(&documentDomainSet); } // Is origin same principal or a subdomain of target's document.domain // Compare actual URI of origin document, not origin principal's URI. (Per Nav 4.x) return SameOrSubdomainOfTarget(originDocumentURI, targetPrincipalURI, documentDomainSet); } nsresult nsDocShell::FindTarget(const PRUnichar *aWindowTarget, PRBool *aIsNewWindow, nsIDocShell **aResult) { nsresult rv; nsAutoString name(aWindowTarget); nsCOMPtr treeItem; PRBool mustMakeNewWindow = PR_FALSE; *aResult = nsnull; *aIsNewWindow = PR_FALSE; if(!name.Length() || name.EqualsIgnoreCase("_self")) { *aResult = this; } else if (name.EqualsIgnoreCase("_blank") || name.EqualsIgnoreCase("_new")) { mustMakeNewWindow = PR_TRUE; name.Assign(NS_LITERAL_STRING("")); } else if(name.EqualsIgnoreCase("_parent")) { GetSameTypeParent(getter_AddRefs(treeItem)); if(!treeItem) *aResult = this; } else if(name.EqualsIgnoreCase("_top")) { GetSameTypeRootTreeItem(getter_AddRefs(treeItem)); if(!treeItem) *aResult = this; } else if(name.EqualsIgnoreCase("_content") || name.EqualsIgnoreCase("_main")) { if (mTreeOwner) { mTreeOwner->FindItemWithName(name.get(), nsnull, getter_AddRefs(treeItem)); } else { NS_ERROR("Someone isn't setting up the tree owner. " "You might like to try that. " "Things will.....you know, work."); } // _content should always exist. If the nsIDocShellTreeOwner did // not find one, then create one... if (!treeItem) { mustMakeNewWindow = PR_TRUE; } } else { // Try to locate the target window... FindItemWithName(name.get(), nsnull, getter_AddRefs(treeItem)); // The named window cannot be found so it must be created to receive // the channel data. if (!treeItem) { mustMakeNewWindow = PR_TRUE; } // Bug 13871: Prevent frameset spoofing // See BugSplat 336170, 338737 and XP_FindNamedContextInList in // the classic codebase // Per Nav's behaviour: // - pref controlled: "browser.frame.validate_origin" // (mValidateOrigin) // - allow load if host of target or target's parent is same // as host of origin // - allow load if target is a top level window // Check to see if pref is true if (mValidateOrigin && treeItem) { // Is origin frame from the same domain as target frame? if (! ValidateOrigin(this, treeItem)) { // No. Is origin frame from the same domain as target's parent? nsCOMPtr targetParentTreeItem; rv = treeItem->GetSameTypeParent(getter_AddRefs(targetParentTreeItem)); if (NS_SUCCEEDED(rv) && targetParentTreeItem) { if (! ValidateOrigin(this, targetParentTreeItem)) { // Neither is from the origin domain, send load to a new window (_blank) mustMakeNewWindow = PR_TRUE; name.Assign(NS_LITERAL_STRING("")); } // else (target's parent from origin domain) allow this load } // else (no parent) allow this load since shell is a toplevel window } // else (target from origin domain) allow this load } // else (pref is false) allow this load } if (mustMakeNewWindow) { nsCOMPtr newWindow; nsCOMPtr parentWindow; // This DocShell is the parent window parentWindow = do_GetInterface(NS_STATIC_CAST(nsIDocShell*, this)); if (!parentWindow) { NS_ASSERTION(0, "Cant get nsIDOMWindowInternal from nsDocShell!"); return NS_ERROR_FAILURE; } rv = parentWindow->Open(NS_LITERAL_STRING(""), // URL to load name, // Window name NS_LITERAL_STRING(""), // Window features getter_AddRefs(newWindow)); if (NS_FAILED(rv)) return rv; // Get the DocShell from the new window... nsCOMPtr sgo; sgo = do_QueryInterface(newWindow, &rv); if (NS_FAILED(rv)) return rv; // This will AddRef() aResult... rv = sgo->GetDocShell(aResult); // If all went well, indicate that a new window has been created. if (*aResult) { *aIsNewWindow = PR_TRUE; // if we just open a new window for this link, charset from current docshell // should be kept, as what we did in js openNewWindowWith(url) nsCOMPtr muCV, target_muCV; nsCOMPtr cv, target_cv; this->GetContentViewer(getter_AddRefs(cv)); (*aResult)->GetContentViewer(getter_AddRefs(target_cv)); if (cv && target_cv) { muCV = do_QueryInterface(cv); target_muCV = do_QueryInterface(target_cv); if (muCV && target_muCV) { nsCAutoString defaultCharset; nsCAutoString prevDocCharset; rv = muCV->GetDefaultCharacterSet(defaultCharset); if(NS_SUCCEEDED(rv)) { target_muCV->SetDefaultCharacterSet(defaultCharset); } rv = muCV->GetPrevDocCharacterSet(prevDocCharset); if(NS_SUCCEEDED(rv)) { target_muCV->SetPrevDocCharacterSet(prevDocCharset); } } } } return rv; } else { if (treeItem) { NS_ASSERTION(!*aResult, "aResult should be null if treeItem is set!"); treeItem->QueryInterface(NS_GET_IID(nsIDocShell), (void **)aResult); } else { NS_IF_ADDREF(*aResult); } } return NS_OK; } NS_IMETHODIMP nsDocShell::GetEldestPresContext(nsIPresContext** aPresContext) { nsresult rv = NS_OK; NS_ENSURE_ARG_POINTER(aPresContext); *aPresContext = nsnull; nsCOMPtr viewer = mContentViewer; while (viewer) { nsCOMPtr prevViewer; viewer->GetPreviousViewer(getter_AddRefs(prevViewer)); if (prevViewer) viewer = prevViewer; else { nsCOMPtr docv(do_QueryInterface(viewer)); if (docv) rv = docv->GetPresContext(aPresContext); break; } } return rv; } 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::GetEldestPresShell(nsIPresShell** aPresShell) { nsresult rv = NS_OK; NS_ENSURE_ARG_POINTER(aPresShell); *aPresShell = nsnull; nsCOMPtr presContext; (void) GetEldestPresContext(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; NS_ASSERTION(!mScriptGlobal, "SetChromeEventHandler() called after the script global " "object was created! This means that the script global " "object in this docshell won't get the right chrome event " "handler. You really don't want to see this assert, FIX " "YOUR CODE!"); 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); } /* [noscript] void setCurrentURI (in nsIURI uri); */ NS_IMETHODIMP nsDocShell::SetCurrentURI(nsIURI *aURI) { mCurrentURI = aURI; //This assignment addrefs PRBool isRoot = PR_FALSE; // Is this the root docshell PRBool isSubFrame = PR_FALSE; // Is this a subframe navigation? if (!mLoadCookie) return NS_OK; nsCOMPtr loader(do_GetInterface(mLoadCookie)); nsCOMPtr webProgress(do_QueryInterface(mLoadCookie)); nsCOMPtr root; GetSameTypeRootTreeItem(getter_AddRefs(root)); if (root.get() == NS_STATIC_CAST(nsIDocShellTreeItem *, this)) { // This is the root docshell isRoot = PR_TRUE; } if (mLSHE) { nsCOMPtr historyEntry(do_QueryInterface(mLSHE)); // Check if this is a subframe navigation if (historyEntry) { historyEntry->GetIsSubFrame(&isSubFrame); } } if (!isSubFrame && !isRoot) { /* * We don't want to send OnLocationChange notifications when * a subframe is being loaded for the first time, while * visiting a frameset page */ return NS_OK; } NS_ASSERTION(loader, "No document loader"); if (loader) { loader->FireOnLocationChange(webProgress, nsnull, aURI); } return NS_OK; } NS_IMETHODIMP nsDocShell::GetCharset(char** aCharset) { NS_ENSURE_ARG_POINTER(aCharset); *aCharset = nsnull; nsCOMPtr presShell; nsCOMPtr doc; GetPresShell(getter_AddRefs(presShell)); NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); presShell->GetDocument(getter_AddRefs(doc)); NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); nsCAutoString charset; NS_ENSURE_SUCCESS(doc->GetDocumentCharacterSet(charset), NS_ERROR_FAILURE); *aCharset = ToNewCString(charset); if (!*aCharset) { return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; } NS_IMETHODIMP nsDocShell::SetCharset(const char* aCharset) { // set the default charset nsCOMPtr viewer; GetContentViewer(getter_AddRefs(viewer)); if (viewer) { nsCOMPtr muDV(do_QueryInterface(viewer)); if (muDV) { NS_ENSURE_SUCCESS(muDV->SetDefaultCharacterSet(nsDependentCString(aCharset)), NS_ERROR_FAILURE); } } // set the charset override nsCOMPtr dcInfo; GetDocumentCharsetInfo(getter_AddRefs(dcInfo)); if (dcInfo) { nsCOMPtr csAtom; csAtom = do_GetAtom(aCharset); dcInfo->SetForcedCharset(csAtom); } return NS_OK; } 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::GetAllowJavascript(PRBool * aAllowJavascript) { NS_ENSURE_ARG_POINTER(aAllowJavascript); *aAllowJavascript = mAllowJavascript; return NS_OK; } NS_IMETHODIMP nsDocShell::SetAllowJavascript(PRBool aAllowJavascript) { mAllowJavascript = aAllowJavascript; return NS_OK; } NS_IMETHODIMP nsDocShell::GetAllowMetaRedirects(PRBool * aReturn) { NS_ENSURE_ARG_POINTER(aReturn); *aReturn = mAllowMetaRedirects; return NS_OK; } NS_IMETHODIMP nsDocShell::SetAllowMetaRedirects(PRBool aValue) { mAllowMetaRedirects = aValue; return NS_OK; } NS_IMETHODIMP nsDocShell::GetAllowSubframes(PRBool * aAllowSubframes) { NS_ENSURE_ARG_POINTER(aAllowSubframes); *aAllowSubframes = mAllowSubframes; return NS_OK; } NS_IMETHODIMP nsDocShell::SetAllowSubframes(PRBool aAllowSubframes) { mAllowSubframes = aAllowSubframes; return NS_OK; } NS_IMETHODIMP nsDocShell::GetAllowImages(PRBool * aAllowImages) { NS_ENSURE_ARG_POINTER(aAllowImages); *aAllowImages = mAllowImages; return NS_OK; } NS_IMETHODIMP nsDocShell::SetAllowImages(PRBool aAllowImages) { mAllowImages = aAllowImages; return NS_OK; } NS_IMETHODIMP nsDocShell::GetDocShellEnumerator(PRInt32 aItemType, PRInt32 aDirection, nsISimpleEnumerator **outEnum) { NS_ENSURE_ARG_POINTER(outEnum); *outEnum = nsnull; nsDocShellEnumerator* docShellEnum; if (aDirection == ENUMERATE_FORWARDS) docShellEnum = new nsDocShellForwardsEnumerator; else docShellEnum = new nsDocShellBackwardsEnumerator; if (!docShellEnum) return NS_ERROR_OUT_OF_MEMORY; nsresult rv = docShellEnum->SetEnumDocShellType(aItemType); if (NS_FAILED(rv)) return rv; rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem *)this); if (NS_FAILED(rv)) return rv; rv = docShellEnum->First(); if (NS_FAILED(rv)) return rv; NS_ADDREF(docShellEnum); // ensure we don't lose the last ref inside the QueryInterface rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)outEnum); NS_RELEASE(docShellEnum); return rv; } NS_IMETHODIMP nsDocShell::GetAppType(PRUint32 * aAppType) { *aAppType = mAppType; return NS_OK; } NS_IMETHODIMP nsDocShell::SetAppType(PRUint32 aAppType) { mAppType = aAppType; return NS_OK; } NS_IMETHODIMP nsDocShell::GetAllowAuth(PRBool * aAllowAuth) { *aAllowAuth = mAllowAuth; return NS_OK; } NS_IMETHODIMP nsDocShell::SetAllowAuth(PRBool aAllowAuth) { mAllowAuth = aAllowAuth; 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; } NS_IMETHODIMP nsDocShell::GetBusyFlags(PRUint32 * aBusyFlags) { NS_ENSURE_ARG_POINTER(aBusyFlags); *aBusyFlags = mBusyFlags; return NS_OK; } NS_IMETHODIMP nsDocShell::TabToTreeOwner(PRBool aForward, PRBool* aTookFocus) { NS_ENSURE_ARG_POINTER(aTookFocus); nsCOMPtr chromeFocus = do_GetInterface(mTreeOwner); if (chromeFocus) { if (aForward) *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement()); else *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement()); } else *aTookFocus = PR_FALSE; return NS_OK; } //***************************************************************************** // nsDocShell::nsIDocShellTreeItem //***************************************************************************** NS_IMETHODIMP nsDocShell::GetName(PRUnichar ** aName) { NS_ENSURE_ARG_POINTER(aName); *aName = ToNewUnicode(mName); return NS_OK; } NS_IMETHODIMP nsDocShell::SetName(const PRUnichar * aName) { mName = aName; // this does a copy of aName return NS_OK; } NS_IMETHODIMP nsDocShell::NameEquals(const PRUnichar *aName, PRBool *_retval) { NS_ENSURE_ARG_POINTER(aName); NS_ENSURE_ARG_POINTER(_retval); *_retval = mName.Equals(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; } static PRBool ItemIsActive(nsIDocShellTreeItem *aItem) { nsCOMPtr tmp(do_GetInterface(aItem)); nsCOMPtr window(do_QueryInterface(tmp)); if (window) { PRBool isClosed; if (NS_SUCCEEDED(window->GetClosed(&isClosed)) && !isClosed) { return PR_TRUE; } } return PR_FALSE; } 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.Equals(aName) && ItemIsActive(this)) { *_retval = 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 may fail, but comparing against null serves the same purpose nsCOMPtr reqAsTreeOwner(do_GetInterface(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; } #ifdef DEBUG_DOCSHELL_FOCUS static void PrintDocTree(nsIDocShellTreeNode * aParentNode, int aLevel) { for (PRInt32 i=0;iGetChildCount(&childWebshellCount); nsCOMPtr parentAsDocShell(do_QueryInterface(aParentNode)); nsCOMPtr parentAsItem(do_QueryInterface(aParentNode)); PRInt32 type; parentAsItem->GetItemType(&type); nsCOMPtr presShell; parentAsDocShell->GetPresShell(getter_AddRefs(presShell)); nsCOMPtr presContext; parentAsDocShell->GetPresContext(getter_AddRefs(presContext)); nsCOMPtr doc; presShell->GetDocument(getter_AddRefs(doc)); nsCOMPtr sgo; doc->GetScriptGlobalObject(getter_AddRefs(sgo)); nsCOMPtr domwin(do_QueryInterface(sgo)); nsCOMPtr widget; nsCOMPtr vm; presShell->GetViewManager(getter_AddRefs(vm)); if (vm) { vm->GetWidget(getter_AddRefs(widget)); } nsCOMPtr esm; presContext->GetEventStateManager(getter_AddRefs(esm)); nsCOMPtr rootContent; doc->GetRootContent(getter_AddRefs(rootContent)); printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n", parentAsDocShell.get(), type==nsIDocShellTreeItem::typeChrome?"Chr":"Con", doc.get(), domwin.get(), esm.get(), rootContent.get()); if (childWebshellCount > 0) { for (PRInt32 i=0;i child; aParentNode->GetChildAt(i, getter_AddRefs(child)); nsCOMPtr childAsNode(do_QueryInterface(child)); PrintDocTree(childAsNode, aLevel+1); } } } static void PrintDocTree(nsIDocShellTreeNode * aParentNode) { NS_ASSERTION(aParentNode, "Pointer is null!"); nsCOMPtr item(do_QueryInterface(aParentNode)); nsCOMPtr parentItem; item->GetParent(getter_AddRefs(parentItem)); while (parentItem) { nsCOMPtrtmp; parentItem->GetParent(getter_AddRefs(tmp)); if (!tmp) { break; } parentItem = tmp; } if (!parentItem) { parentItem = do_QueryInterface(aParentNode); } if (parentItem) { nsCOMPtr parentAsNode(do_QueryInterface(parentItem)); PrintDocTree(parentAsNode, 0); } } #endif NS_IMETHODIMP nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner) { #ifdef DEBUG_DOCSHELL_FOCUS nsCOMPtr node(do_QueryInterface(aTreeOwner)); if (node) { PrintDocTree(node); } #endif // 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, nsIWebProgress::NOTIFY_ALL); } } } 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; // charset and zoom will be inherited in SetupNewViewer() // 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; nsCAutoString parentCS; res = doc->GetDocumentCharacterSet(parentCS); if (NS_FAILED(res)) return NS_OK; // set the child's parentCharset nsCOMPtr parentCSAtom(do_GetAtom(parentCS)); res = dcInfo->SetParentCharset(parentCSAtom); if (NS_FAILED(res)) return NS_OK; PRInt32 charsetSource; res = doc->GetDocumentCharacterSetSource(&charsetSource); if (NS_FAILED(res)) return NS_OK; // set the child's parentCharset res = dcInfo->SetParentCharsetSource(charsetSource); if (NS_FAILED(res)) return NS_OK; // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUCS2toASCII(parentCS).get(), 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_WARN_IF_FALSE(aIndex >=0 && aIndex < mChildren.Count(), "index of child element is out of range!"); *aChild = (nsIDocShellTreeItem *) mChildren.SafeElementAt(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 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; PRBool childNameEquals = PR_FALSE; child->NameEquals(aName, &childNameEquals); if (childNameEquals && ItemIsActive(child)) { *_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 (mLSHE) { /* Before looking for the subframe's url, check * the expiration status of the parent. If the parent * has expired from cache, then subframes will not be * loaded from history in certain situations. */ PRBool parentExpired=PR_FALSE; mLSHE->GetExpirationStatus(&parentExpired); /* Get the parent's Load Type so that it can be set on the child too. * By default give a loadHistory value */ PRUint32 loadType = nsIDocShellLoadInfo::loadHistory; mLSHE->GetLoadType(&loadType); // If the user did a shift-reload on this frameset page, // we don't want to load the subframes from history. if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache || loadType == nsIDocShellLoadInfo::loadReloadBypassProxy || loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache || loadType == nsIDocShellLoadInfo::loadRefresh) return rv; /* If the user pressed reload and the parent frame has expired * from cache, we do not want to load the child frame from history. */ if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) { // The parent has expired. Return null. *aResult = nsnull; return rv; } nsCOMPtr container(do_QueryInterface(mLSHE)); if (container) { // Get the child subframe from session history. rv = container->GetChildAt(aChildOffset, aResult); if (*aResult) (*aResult)->SetLoadType(loadType); } } return rv; } NS_IMETHODIMP nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry, PRInt32 aChildOffset) { nsresult rv; if (mLSHE) { /* You get here if you are currently building a * hierarchy ie.,you just visited a frameset page */ nsCOMPtr container(do_QueryInterface(mLSHE, &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 to clone the current SHEntry hierarchy * and replace the subframe where a new url was loaded with * a new entry. */ PRInt32 index = -1; nsCOMPtr currentHE; mSessionHistory->GetIndex(&index); if (index < 0) return NS_ERROR_FAILURE; rv = mSessionHistory->GetEntryAtIndex(index, PR_FALSE, getter_AddRefs(currentHE)); NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE); nsCOMPtr currentEntry(do_QueryInterface(currentHE)); if (currentEntry) { PRUint32 cloneID = 0; nsCOMPtr nextEntry; //(do_CreateInstance(NS_SHENTRY_CONTRACTID)); // NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); if (aCloneRef) aCloneRef->GetID(&cloneID); rv = CloneAndReplace(currentEntry, cloneID, aNewEntry, getter_AddRefs(nextEntry)); if (NS_SUCCEEDED(rv)) { nsCOMPtr shPrivate(do_QueryInterface(mSessionHistory)); NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE); rv = shPrivate->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 mOSHE in this subframe will be the previous url's * mOSHE. This mOSHE will be used as the identification * for this subframe in the CloneAndReplace function. */ nsCOMPtr parent(do_QueryInterface(mParent, &rv)); if (parent) { if (!aCloneRef) { aCloneRef = mOSHE; } 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; } //------------------------------------- //-- Helper Method for Print discovery //------------------------------------- PRBool nsDocShell::IsPrintingOrPP(PRBool aDisplayErrorDialog) { if (mIsPrintingOrPP && aDisplayErrorDialog) { DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nsnull, nsnull); } return mIsPrintingOrPP; } //***************************************************************************** // nsDocShell::nsIWebNavigation //***************************************************************************** NS_IMETHODIMP nsDocShell::GetCanGoBack(PRBool * aCanGoBack) { if (IsPrintingOrPP(PR_FALSE)) { *aCanGoBack = PR_FALSE; return NS_OK; // JS may not handle returning of an error code } nsresult rv; nsCOMPtr rootSH; rv = GetRootSessionHistory(getter_AddRefs(rootSH)); nsCOMPtr webnav(do_QueryInterface(rootSH)); NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); rv = webnav->GetCanGoBack(aCanGoBack); return rv; } NS_IMETHODIMP nsDocShell::GetCanGoForward(PRBool * aCanGoForward) { if (IsPrintingOrPP(PR_FALSE)) { *aCanGoForward = PR_FALSE; return NS_OK; // JS may not handle returning of an error code } nsresult rv; nsCOMPtr rootSH; rv = GetRootSessionHistory(getter_AddRefs(rootSH)); nsCOMPtr webnav(do_QueryInterface(rootSH)); NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); rv = webnav->GetCanGoForward(aCanGoForward); return rv; } NS_IMETHODIMP nsDocShell::GoBack() { if (IsPrintingOrPP()) { return NS_OK; // JS may not handle returning of an error code } nsresult rv; nsCOMPtr rootSH; rv = GetRootSessionHistory(getter_AddRefs(rootSH)); nsCOMPtr webnav(do_QueryInterface(rootSH)); NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); rv = webnav->GoBack(); return rv; } NS_IMETHODIMP nsDocShell::GoForward() { if (IsPrintingOrPP()) { return NS_OK; // JS may not handle returning of an error code } nsresult rv; nsCOMPtr rootSH; rv = GetRootSessionHistory(getter_AddRefs(rootSH)); nsCOMPtr webnav(do_QueryInterface(rootSH)); NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); rv = webnav->GoForward(); return rv; } NS_IMETHODIMP nsDocShell::GotoIndex(PRInt32 aIndex) { if (IsPrintingOrPP()) { return NS_OK; // JS may not handle returning of an error code } nsresult rv; nsCOMPtr rootSH; rv = GetRootSessionHistory(getter_AddRefs(rootSH)); nsCOMPtr webnav(do_QueryInterface(rootSH)); NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); rv = webnav->GotoIndex(aIndex); return rv; } NS_IMETHODIMP nsDocShell::LoadURI(const PRUnichar * aURI, PRUint32 aLoadFlags, nsIURI * aReferringURI, nsIInputStream * aPostStream, nsIInputStream * aHeaderStream) { if (IsPrintingOrPP()) { return NS_OK; // JS may not handle returning of an error code } nsCOMPtr uri; nsresult rv = NS_OK; // Create the fixup object if necessary if (!mURIFixup) { mURIFixup = do_GetService(NS_URIFIXUP_CONTRACTID); if (!mURIFixup) { // No fixup service so try and create a URI and see what happens nsAutoString uriString(aURI); // Cleanup the empty spaces that might be on each end. uriString.Trim(" "); // Eliminate embedded newlines, which single-line text fields now allow: uriString.StripChars("\r\n"); NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE); rv = NS_NewURI(getter_AddRefs(uri), uriString); } } if (mURIFixup) { // Call the fixup object rv = mURIFixup->CreateFixupURI(NS_ConvertUCS2toUTF8(aURI), nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP, getter_AddRefs(uri)); } if (NS_ERROR_MALFORMED_URI == rv) { DisplayLoadError(rv, uri, aURI); } if (NS_FAILED(rv) || !uri) return NS_ERROR_FAILURE; nsCOMPtr loadInfo; rv = CreateLoadInfo(getter_AddRefs(loadInfo)); if (NS_FAILED(rv)) return rv; PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags); loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType)); loadInfo->SetPostDataStream(aPostStream); loadInfo->SetReferrer(aReferringURI); loadInfo->SetHeadersStream(aHeaderStream); rv = LoadURI(uri, loadInfo, 0, PR_TRUE); return rv; } NS_IMETHODIMP nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI, const PRUnichar *aURL) { // Get prompt and string bundle servcies nsCOMPtr prompter; nsCOMPtr stringBundle; GetPromptAndStringBundle(getter_AddRefs(prompter), getter_AddRefs(stringBundle)); NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE); NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE); nsAutoString error; const PRUint32 kMaxFormatStrArgs = 2; nsAutoString formatStrs[kMaxFormatStrArgs]; PRUint32 formatStrCount = 0; nsresult rv = NS_OK; // Turn the error code into a human readable error message. if (NS_ERROR_UNKNOWN_PROTOCOL == aError) { NS_ENSURE_ARG_POINTER(aURI); // extract the scheme nsCAutoString scheme; aURI->GetScheme(scheme); CopyASCIItoUCS2(scheme, formatStrs[0]); formatStrCount = 1; error.Assign(NS_LITERAL_STRING("protocolNotFound")); } else if (NS_ERROR_FILE_NOT_FOUND == aError) { NS_ENSURE_ARG_POINTER(aURI); nsCAutoString spec; aURI->GetPath(spec); nsCAutoString charset; // unescape and convert from origin charset aURI->GetOriginCharset(charset); nsCOMPtr textToSubURI( do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) rv = textToSubURI->UnEscapeURIForUI(charset, spec, formatStrs[0]); if (NS_FAILED(rv)) { CopyASCIItoUCS2(spec, formatStrs[0]); rv = NS_OK; } formatStrCount = 1; error.Assign(NS_LITERAL_STRING("fileNotFound")); } else if (NS_ERROR_UNKNOWN_HOST == aError) { NS_ENSURE_ARG_POINTER(aURI); // Get the host nsCAutoString host; aURI->GetHost(host); formatStrs[0].Assign(NS_ConvertUTF8toUCS2(host)); formatStrCount = 1; error.Assign(NS_LITERAL_STRING("dnsNotFound")); } else if(NS_ERROR_CONNECTION_REFUSED == aError) { NS_ENSURE_ARG_POINTER(aURI); // Build up the host:port string. nsCAutoString hostport; aURI->GetHostPort(hostport); formatStrs[0].AssignWithConversion(hostport.get()); formatStrCount = 1; error.Assign(NS_LITERAL_STRING("connectionFailure")); } else if(NS_ERROR_NET_INTERRUPT == aError) { NS_ENSURE_ARG_POINTER(aURI); // Build up the host:port string. nsCAutoString hostport; aURI->GetHostPort(hostport); formatStrs[0].AssignWithConversion(hostport.get()); formatStrCount = 1; error.Assign(NS_LITERAL_STRING("netInterrupt")); } else if (NS_ERROR_NET_TIMEOUT == aError) { NS_ENSURE_ARG_POINTER(aURI); // Get the host nsCAutoString host; aURI->GetHost(host); formatStrs[0].Assign(NS_ConvertUTF8toUCS2(host)); formatStrCount = 1; error.Assign(NS_LITERAL_STRING("netTimeout")); } else { // Errors requiring simple formatting switch (aError) { case NS_ERROR_MALFORMED_URI: // URI is malformed error.Assign(NS_LITERAL_STRING("malformedURI")); break; case NS_ERROR_REDIRECT_LOOP: // Doc failed to load because the server generated too many redirects error.Assign(NS_LITERAL_STRING("redirectLoop")); break; case NS_ERROR_UNKNOWN_SOCKET_TYPE: // Doc failed to load because PSM is not installed error.Assign(NS_LITERAL_STRING("unknownSocketType")); break; case NS_ERROR_NET_RESET: // Doc failed to load because the server kept reseting the connection // before we could read any data from it error.Assign(NS_LITERAL_STRING("netReset")); break; case NS_ERROR_DOCUMENT_NOT_CACHED: // Doc falied to load because we are offline and the cache does not // contain a copy of the document. error.Assign(NS_LITERAL_STRING("netOffline")); break; case NS_ERROR_DOCUMENT_IS_PRINTMODE: // Doc navigation attempted while Printing or Print Preview error.Assign(NS_LITERAL_STRING("isprinting")); break; case NS_ERROR_PORT_ACCESS_NOT_ALLOWED: // Port blocked for security reasons error.Assign(NS_LITERAL_STRING("deniedPortAccess")); break; case NS_ERROR_UNKNOWN_PROXY_HOST: // Proxy hostname could not be resolved. error.Assign(NS_LITERAL_STRING("proxyResolveFailure")); break; case NS_ERROR_PROXY_CONNECTION_REFUSED: // Proxy connection was refused. error.Assign(NS_LITERAL_STRING("proxyConnectFailure")); break; } } // Test if the error should be displayed if (error.IsEmpty()) { return NS_OK; } // Test if the error needs to be formatted nsAutoString messageStr; if (formatStrCount > 0) { const PRUnichar *strs[kMaxFormatStrArgs]; for (PRUint32 i = 0; i < formatStrCount; i++) { strs[i] = formatStrs[i].get(); } nsXPIDLString str; rv = stringBundle->FormatStringFromName( error.get(), strs, formatStrCount, getter_Copies(str)); NS_ENSURE_SUCCESS(rv, rv); messageStr.Assign(str.get()); } else { nsXPIDLString str; rv = stringBundle->GetStringFromName( error.get(), getter_Copies(str)); NS_ENSURE_SUCCESS(rv, rv); messageStr.Assign(str.get()); } // Display the error as a page or an alert prompt NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE); if (mUseErrorPages) { // Display an error page LoadErrorPage(aURI, aURL, error.get(), messageStr.get()); } else { // Display a message box prompter->Alert(nsnull, messageStr.get()); } return NS_OK; } NS_IMETHODIMP nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL, const PRUnichar *aErrorType, const PRUnichar *aDescription) { nsAutoString url; if (aURI) { nsCAutoString uri; nsresult rv = aURI->GetSpec(uri); NS_ENSURE_SUCCESS(rv, rv); url.AssignWithConversion(uri.get()); } else if (aURL) { url.Assign(aURL); } else { return NS_ERROR_INVALID_POINTER; } // Create a URL to pass all the error information through to the page. char *escapedUrl = nsEscape(NS_ConvertUCS2toUTF8(url.get()).get(), url_Path); char *escapedError = nsEscape(NS_ConvertUCS2toUTF8(aErrorType).get(), url_Path); char *escapedDescription = nsEscape(NS_ConvertUCS2toUTF8(aDescription).get(), url_Path); nsAutoString errorType(aErrorType); nsAutoString errorPageUrl; errorPageUrl.Assign(NS_LITERAL_STRING("chrome://global/content/netError.xhtml?e=")); errorPageUrl.AppendWithConversion(escapedError); errorPageUrl.Append(NS_LITERAL_STRING("&u=")); errorPageUrl.AppendWithConversion(escapedUrl); errorPageUrl.Append(NS_LITERAL_STRING("&d=")); errorPageUrl.AppendWithConversion(escapedDescription); PR_FREEIF(escapedDescription); PR_FREEIF(escapedError); PR_FREEIF(escapedUrl); return LoadURI(errorPageUrl.get(), // URI string LOAD_FLAGS_BYPASS_HISTORY, nsnull, nsnull, nsnull); } NS_IMETHODIMP nsDocShell::Reload(PRUint32 aReloadFlags) { if (IsPrintingOrPP()) { return NS_OK; // JS may not handle returning of an error code } nsresult rv; NS_ASSERTION(((aReloadFlags & 0xf) == 0), "Reload command not updated to use load flags!"); // XXXTAB Convert reload type to our type LoadType type = LOAD_RELOAD_NORMAL; if (aReloadFlags & LOAD_FLAGS_BYPASS_CACHE && aReloadFlags & LOAD_FLAGS_BYPASS_PROXY) type = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE; else if (aReloadFlags & LOAD_FLAGS_CHARSET_CHANGE) type = LOAD_RELOAD_CHARSET_CHANGE; // Send notifications to the HistoryListener if any, about the impending reload nsCOMPtr rootSH; rv = GetRootSessionHistory(getter_AddRefs(rootSH)); nsCOMPtr shistInt(do_QueryInterface(rootSH)); PRBool canReload = PR_TRUE; if (rootSH) { nsCOMPtr listener; shistInt->GetListener(getter_AddRefs(listener)); if (listener) { listener->OnHistoryReload(mCurrentURI, aReloadFlags, &canReload); } } if (!canReload) return NS_OK; /* If you change this part of code, make sure bug 45297 does not re-occur */ if (mOSHE) rv = LoadHistoryEntry(mOSHE, type); else if (mLSHE) // In case a reload happened before the current load is done rv = LoadHistoryEntry(mLSHE, type); else rv = InternalLoad(mCurrentURI, mReferrerURI, nsnull, // No owner PR_TRUE, // Inherit owner from document nsnull, // No window target nsnull, // No post data nsnull, // No headers data type, // Load type nsnull, // No SHEntry PR_TRUE, nsnull, // No nsIDocShell nsnull); // No nsIRequest return rv; } NS_IMETHODIMP nsDocShell::Stop(PRUint32 aStopFlags) { if (nsIWebNavigation::STOP_CONTENT & aStopFlags) { if (mContentViewer) mContentViewer->Stop(); } if (nsIWebNavigation::STOP_NETWORK & aStopFlags) { // Cancel any timers that were set for this loader. CancelRefreshURITimers(); if (mLoadCookie) { nsCOMPtr uriLoader; 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(aStopFlags); } 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_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE); 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::GetReferringURI(nsIURI ** aURI) { NS_ENSURE_ARG_POINTER(aURI); *aURI = mReferrerURI; 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; nsCOMPtr shPrivate(do_QueryInterface(mSessionHistory)); NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE); shPrivate->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::nsIWebPageDescriptor //***************************************************************************** NS_IMETHODIMP nsDocShell::LoadPage(nsISupports *aPageDescriptor, PRUint32 aDisplayType) { nsresult rv; nsCOMPtr shEntry(do_QueryInterface(aPageDescriptor)); // Currently, the opaque 'page descriptor' is an nsISHEntry... if (!shEntry) { return NS_ERROR_INVALID_POINTER; } // // load the page as view-source // if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) { nsCOMPtr srcHE(do_QueryInterface(shEntry)); nsCOMPtr oldUri, newUri; nsCString spec, newSpec; // Create a new view-source URI and replace the original. rv = srcHE->GetURI(getter_AddRefs(oldUri)); if (NS_FAILED(rv)) return rv; oldUri->GetSpec(spec); newSpec.Append(NS_LITERAL_CSTRING("view-source:")); newSpec.Append(spec); rv = NS_NewURI(getter_AddRefs(newUri), newSpec); if (NS_FAILED(rv)) { return rv; } shEntry->SetURI(newUri); // NULL out inappropriate cloned attributes... shEntry->SetParent(nsnull); shEntry->SetIsSubFrame(PR_FALSE); } rv = LoadHistoryEntry(shEntry, LOAD_HISTORY); return rv; } NS_IMETHODIMP nsDocShell::GetCurrentDescriptor(nsISupports **aPageDescriptor) { nsresult rv; nsCOMPtr src; if (!aPageDescriptor) { return NS_ERROR_NULL_POINTER; } *aPageDescriptor = nsnull; src = mOSHE ? mOSHE : mLSHE; if (src) { nsCOMPtr sup;; nsCOMPtr dest; rv = src->Clone(getter_AddRefs(dest)); if (NS_FAILED(rv)) { return rv; } sup = do_QueryInterface(dest); *aPageDescriptor = sup; NS_ADDREF(*aPageDescriptor); } return (*aPageDescriptor) ? NS_OK : 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() { nsresult rv = NS_ERROR_FAILURE; mPrefs = do_GetService(NS_PREF_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); //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); mPrefs->GetBoolPref("browser.block.target_new_window", &mDisallowPopupWindows); mPrefs->GetBoolPref("browser.frames.enabled", &mAllowSubframes); // Check pref to see if we should prevent frameset spoofing mPrefs->GetBoolPref("browser.frame.validate_origin", &mValidateOrigin); // Should we use XUL error pages instead of alerts if possible? PRBool useErrorPages = PR_FALSE; mPrefs->GetBoolPref("browser.xul.error_pages.enabled", &useErrorPages); mUseErrorPages = useErrorPages; return NS_OK; } NS_IMETHODIMP nsDocShell::Destroy() { //Fire unload event before we blow anything away. (void) FireUnloadNotification(); mIsBeingDestroyed = PR_TRUE; // Stop any URLs that are currently being loaded... Stop(nsIWebNavigation::STOP_ALL); if (mDocLoader) { mDocLoader->Destroy(); mDocLoader->SetContainer(nsnull); } delete mEditorData; mEditorData = 0; mTransferableHookData = 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); if (mContentViewer) { mContentViewer->Close(); mContentViewer->Destroy(); mContentViewer = nsnull; } DestroyChildren(); mDocLoader = nsnull; mParentWidget = nsnull; mPrefs = nsnull; mCurrentURI = nsnull; if (mScriptGlobal) { mScriptGlobal->SetDocShell(nsnull); mScriptGlobal->SetGlobalObjectOwner(nsnull); mScriptGlobal = nsnull; } if (mScriptContext) { mScriptContext->SetOwner(nsnull); mScriptContext = nsnull; } mSessionHistory = nsnull; SetTreeOwner(nsnull); SetLoadCookie(nsnull); if (mContentListener) { mContentListener->DocShell(nsnull); mContentListener->SetParentContentListener(nsnull); NS_RELEASE(mContentListener); } return NS_OK; } NS_IMETHODIMP nsDocShell::SetPosition(PRInt32 x, PRInt32 y) { mBounds.x = x; mBounds.y = y; if (mContentViewer) NS_ENSURE_SUCCESS(mContentViewer->Move(x, y), 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) { mBounds.x = x; mBounds.y = y; mBounds.width = cx; mBounds.height = cy; if (mContentViewer) { //XXX Border figured in here or is that handled elsewhere? NS_ENSURE_SUCCESS(mContentViewer->SetBounds(mBounds), NS_ERROR_FAILURE); } return NS_OK; } NS_IMETHODIMP nsDocShell::GetPositionAndSize(PRInt32 * x, PRInt32 * y, PRInt32 * cx, PRInt32 * cy) { if (x) *x = mBounds.x; if (y) *y = mBounds.y; if (cx) *cx = mBounds.width; if (cy) *cy = mBounds.height; return NS_OK; } 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) { mParentWidget = aParentWidget; if (!mParentWidget) { // If the parent widget is set to null we don't want to hold // on to the current device context any more since it is // associated with the parent widget we no longer own. We'll // need to create a new device context if one is needed again. mDeviceContext = nsnull; } 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 *view = nsnull; // views are not ref counted NS_ENSURE_SUCCESS(vm->GetRootView(view), NS_ERROR_FAILURE); NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); // if our root view is hidden, we are not visible nsViewVisibility vis; NS_ENSURE_SUCCESS(view->GetVisibility(vis), NS_ERROR_FAILURE); if (vis == nsViewVisibility_kHide) { *aVisibility = PR_FALSE; return NS_OK; } // otherwise, we must walk up the document and view trees checking // for a hidden view. nsCOMPtr treeItem = this; nsCOMPtr parentItem; treeItem->GetParent(getter_AddRefs(parentItem)); while (parentItem) { nsCOMPtr docShell(do_QueryInterface(treeItem)); docShell->GetPresShell(getter_AddRefs(presShell)); nsCOMPtr doc; presShell->GetDocument(getter_AddRefs(doc)); nsCOMPtr parentDS = do_QueryInterface(parentItem); nsCOMPtr pPresShell; parentDS->GetPresShell(getter_AddRefs(pPresShell)); nsCOMPtr pDoc; pPresShell->GetDocument(getter_AddRefs(pDoc)); nsCOMPtr shellContent; nsCOMPtr shellISupports = do_QueryInterface(treeItem); pDoc->FindContentForSubDocument(doc, getter_AddRefs(shellContent)); NS_ASSERTION(shellContent, "subshell not in the map"); nsIFrame* frame; pPresShell->GetPrimaryFrameFor(shellContent, &frame); if (frame) { nsCOMPtr pc; pPresShell->GetPresContext(getter_AddRefs(pc)); if (!frame->AreAncestorViewsVisible(pc)) { *aVisibility = PR_FALSE; return NS_OK; } } treeItem = parentItem; treeItem->GetParent(getter_AddRefs(parentItem)); } *aVisibility = 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::GetEnabled(PRBool *aEnabled) { NS_ENSURE_ARG_POINTER(aEnabled); *aEnabled = PR_TRUE; return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocShell::SetEnabled(PRBool aEnabled) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocShell::GetBlurSuppression(PRBool *aBlurSuppression) { NS_ENSURE_ARG_POINTER(aBlurSuppression); *aBlurSuppression = PR_FALSE; return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocShell::SetBlurSuppression(PRBool aBlurSuppression) { return NS_ERROR_NOT_IMPLEMENTED; } 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() { #ifdef DEBUG_DOCSHELL_FOCUS printf("nsDocShell::SetFocus %p\n", (nsIDocShell*)this); #endif // Tell itself (and the DocShellFocusController) who has focus // this way focus gets removed from the currently focused DocShell SetHasFocus(PR_TRUE); return NS_OK; } NS_IMETHODIMP nsDocShell::GetTitle(PRUnichar ** aTitle) { NS_ENSURE_ARG_POINTER(aTitle); *aTitle = ToNewUnicode(mTitle); 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) { nsCAutoString url; mCurrentURI->GetSpec(url); nsCOMPtr browserHistory = do_QueryInterface(mGlobalHistory); if (browserHistory) browserHistory->SetPageTitle(url.get(), aTitle); } // Update SessionHistory with the document's title. If the // page was loaded from history or the page bypassed history, // there is no need to update the title. There is no need to // go to mSessionHistory to update the title. Setting it in mOSHE // would suffice. if (mOSHE && (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_HISTORY)) { mOSHE->SetTitle(mTitle.get()); } 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); x = 0; y = 0; // fix compiler warning, not actually executed } 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.