Back to index

lightning-sunbird  0.9+nobinonly
nsDocShell.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim: ft=cpp tw=78 sw=4 et ts=4 sts=4 cin
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Travis Bogard <travis@netscape.com>
00025  *   Pierre Phaneuf <pp@ludusdesign.com>
00026  *   Peter Annema <disttsc@bart.nl>
00027  *   Dan Rosen <dr@netscape.com>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either of the GNU General Public License Version 2 or later (them "GPL"),
00031  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 #ifdef MOZ_LOGGING
00044 // so we can get logging even in release builds (but only for some things)
00045 #define FORCE_PR_LOG 1
00046 #endif
00047 
00048 #include "nsIBrowserDOMWindow.h"
00049 #include "nsIComponentManager.h"
00050 #include "nsIContent.h"
00051 #include "nsIDocument.h"
00052 #include "nsIDOMDocument.h"
00053 #include "nsIDOMNSDocument.h"
00054 #include "nsIDOMElement.h"
00055 #include "nsIDOMStorage.h"
00056 #include "nsPIDOMStorage.h"
00057 #include "nsIDocumentViewer.h"
00058 #include "nsIDocumentLoaderFactory.h"
00059 #include "nsCURILoader.h"
00060 #include "nsDocShellCID.h"
00061 #include "nsLayoutCID.h"
00062 #include "nsDOMCID.h"
00063 #include "nsIDOMScriptObjectFactory.h"
00064 #include "nsNetUtil.h"
00065 #include "nsRect.h"
00066 #include "prprf.h"
00067 #include "nsIMarkupDocumentViewer.h"
00068 #include "nsXPIDLString.h"
00069 #include "nsReadableUtils.h"
00070 #include "nsIChromeEventHandler.h"
00071 #include "nsIDOMChromeWindow.h"
00072 #include "nsIDOMWindowInternal.h"
00073 #include "nsIWebBrowserChrome.h"
00074 #include "nsPoint.h"
00075 #include "nsGfxCIID.h"
00076 #include "nsIObserverService.h"
00077 #include "nsIPrompt.h"
00078 #include "nsIAuthPrompt.h"
00079 #include "nsTextFormatter.h"
00080 #include "nsIChannelEventSink.h"
00081 #include "nsIUploadChannel.h"
00082 #include "nsISecurityEventSink.h"
00083 #include "nsIScriptSecurityManager.h"
00084 #include "nsIJSContextStack.h"
00085 #include "nsIScriptObjectPrincipal.h"
00086 #include "nsDocumentCharsetInfoCID.h"
00087 #include "nsICanvasFrame.h"
00088 #include "nsIScrollableFrame.h"
00089 #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
00090 #include "nsICategoryManager.h"
00091 #include "nsXPCOMCID.h"
00092 #include "nsISeekableStream.h"
00093 #include "nsAutoPtr.h"
00094 #include "nsIPrefService.h"
00095 #include "nsIWritablePropertyBag2.h"
00096 #include "nsObserverService.h"
00097 #include "nsIDOMStorage.h"
00098 #include "nsPIDOMStorage.h"
00099 
00100 // we want to explore making the document own the load group
00101 // so we can associate the document URI with the load group.
00102 // until this point, we have an evil hack:
00103 #include "nsIHttpChannelInternal.h"  
00104 
00105 
00106 // Local Includes
00107 #include "nsDocShell.h"
00108 #include "nsDocShellLoadInfo.h"
00109 #include "nsCDefaultURIFixup.h"
00110 #include "nsDocShellEnumerator.h"
00111 
00112 // Helper Classes
00113 #include "nsDOMError.h"
00114 #include "nsEscape.h"
00115 
00116 // Interfaces Needed
00117 #include "nsIUploadChannel.h"
00118 #include "nsIDataChannel.h"
00119 #include "nsIProgressEventSink.h"
00120 #include "nsIWebProgress.h"
00121 #include "nsILayoutHistoryState.h"
00122 #include "nsITimer.h"
00123 #include "nsISHistoryInternal.h"
00124 #include "nsIPrincipal.h"
00125 #include "nsIHistoryEntry.h"
00126 #include "nsISHistoryListener.h"
00127 #include "nsIWindowWatcher.h"
00128 
00129 // Editor-related
00130 #include "nsIEditingSession.h"
00131 
00132 #include "nsPIDOMWindow.h"
00133 #include "nsIDOMDocument.h"
00134 #include "nsICachingChannel.h"
00135 #include "nsICacheVisitor.h"
00136 #include "nsIMultiPartChannel.h"
00137 #include "nsIWyciwygChannel.h"
00138 
00139 // The following are for bug #13871: Prevent frameset spoofing
00140 #include "nsIHTMLDocument.h"
00141 
00142 // For reporting errors with the console service.
00143 // These can go away if error reporting is propagated up past nsDocShell.
00144 #include "nsIConsoleService.h"
00145 #include "nsIScriptError.h"
00146 
00147 // used to dispatch urls to default protocol handlers
00148 #include "nsCExternalHandlerService.h"
00149 #include "nsIExternalProtocolService.h"
00150 
00151 #include "nsIFocusController.h"
00152 
00153 #include "nsITextToSubURI.h"
00154 
00155 #include "nsIJARChannel.h"
00156 
00157 #include "prlog.h"
00158 #include "prmem.h"
00159 
00160 #include "nsISelectionDisplay.h"
00161 
00162 #include "nsIGlobalHistory2.h"
00163 #include "nsIGlobalHistory3.h"
00164 
00165 #ifdef DEBUG_DOCSHELL_FOCUS
00166 #include "nsIEventStateManager.h"
00167 #endif
00168 
00169 #include "nsIFrame.h"
00170 
00171 // for embedding
00172 #include "nsIWebBrowserChromeFocus.h"
00173 
00174 #include "nsPluginError.h"
00175 
00176 static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID);
00177 static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
00178 static NS_DEFINE_CID(kDocumentCharsetInfoCID, NS_DOCUMENTCHARSETINFO_CID);
00179 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
00180                      NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
00181 
00182 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
00183 //#define DEBUG_DOCSHELL_FOCUS
00184 #define DEBUG_PAGE_CACHE
00185 #endif
00186 
00187 #include "plevent.h"
00188 #include "nsGUIEvent.h"
00189 #include "nsEventQueueUtils.h"
00190 
00191 // Number of documents currently loading
00192 static PRInt32 gNumberOfDocumentsLoading = 0;
00193 
00194 // Global count of existing docshells.
00195 static PRInt32 gDocShellCount = 0;
00196 
00197 // Global reference to the URI fixup service.
00198 nsIURIFixup *nsDocShell::sURIFixup = 0;
00199 
00200 // True means we validate window targets to prevent frameset
00201 // spoofing. Initialize this to a non-bolean value so we know to check
00202 // the pref on the creation of the first docshell.
00203 static PRBool gValidateOrigin = (PRBool)0xffffffff;
00204 
00205 // Hint for native dispatch of plevents on how long to delay after 
00206 // all documents have loaded in milliseconds before favoring normal
00207 // native event dispatch priorites over performance
00208 #define NS_EVENT_STARVATION_DELAY_HINT 2000
00209 
00210 // This is needed for displaying an error message 
00211 // when navigation is attempted on a document when printing
00212 // The value arbitrary as long as it doesn't conflict with
00213 // any of the other values in the errors in DisplayLoadError
00214 #define NS_ERROR_DOCUMENT_IS_PRINTMODE  NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL,2001)
00215 
00216 #ifdef PR_LOGGING
00217 #ifdef DEBUG
00218 static PRLogModuleInfo* gDocShellLog;
00219 #endif
00220 static PRLogModuleInfo* gDocShellLeakLog;
00221 #endif
00222 
00223 //*****************************************************************************
00224 //***    nsDocShellFocusController
00225 //*****************************************************************************
00226 
00227 class nsDocShellFocusController
00228 {
00229 
00230 public:
00231   static nsDocShellFocusController* GetInstance() { return &mDocShellFocusControllerSingleton; }
00232   virtual ~nsDocShellFocusController(){}
00233 
00234   void Focus(nsIDocShell* aDS);
00235   void ClosingDown(nsIDocShell* aDS);
00236 
00237 protected:
00238   nsDocShellFocusController(){}
00239 
00240   nsIDocShell* mFocusedDocShell; // very weak reference
00241 
00242 private:
00243   static nsDocShellFocusController mDocShellFocusControllerSingleton;
00244 };
00245 
00246 nsDocShellFocusController nsDocShellFocusController::mDocShellFocusControllerSingleton;
00247 
00248 //*****************************************************************************
00249 //***    nsDocShell: Object Management
00250 //*****************************************************************************
00251 
00252 nsDocShell::nsDocShell():
00253     nsDocLoader(),
00254     mAllowSubframes(PR_TRUE),
00255     mAllowPlugins(PR_TRUE),
00256     mAllowJavascript(PR_TRUE),
00257     mAllowMetaRedirects(PR_TRUE),
00258     mAllowImages(PR_TRUE),
00259     mFocusDocFirst(PR_FALSE),
00260     mHasFocus(PR_FALSE),
00261     mCreatingDocument(PR_FALSE),
00262     mUseErrorPages(PR_FALSE),
00263     mAllowAuth(PR_TRUE),
00264     mAllowKeywordFixup(PR_FALSE),
00265     mFiredUnloadEvent(PR_FALSE),
00266     mEODForCurrentDocument(PR_FALSE),
00267     mURIResultedInDocument(PR_FALSE),
00268     mIsBeingDestroyed(PR_FALSE),
00269     mIsExecutingOnLoadHandler(PR_FALSE),
00270     mIsPrintingOrPP(PR_FALSE),
00271     mSavingOldViewer(PR_FALSE),
00272     mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
00273     mChildOffset(0),
00274     mBusyFlags(BUSY_FLAGS_NONE),
00275     mMarginWidth(0),
00276     mMarginHeight(0),
00277     mItemType(typeContent),
00278     mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
00279     mPreviousTransIndex(-1),
00280     mLoadedTransIndex(-1),
00281     mEditorData(nsnull),
00282     mTreeOwner(nsnull),
00283     mChromeEventHandler(nsnull)
00284 {
00285     if (gDocShellCount++ == 0) {
00286         NS_ASSERTION(sURIFixup == nsnull,
00287                      "Huh, sURIFixup not null in first nsDocShell ctor!");
00288 
00289         CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
00290     }
00291 
00292 #ifdef PR_LOGGING
00293 #ifdef DEBUG
00294     if (! gDocShellLog)
00295         gDocShellLog = PR_NewLogModule("nsDocShell");
00296 #endif
00297     if (nsnull == gDocShellLeakLog)
00298         gDocShellLeakLog = PR_NewLogModule("nsDocShellLeak");
00299     if (gDocShellLeakLog)
00300         PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p created\n", this));
00301 #endif
00302 }
00303 
00304 nsDocShell::~nsDocShell()
00305 {
00306     nsDocShellFocusController* dsfc = nsDocShellFocusController::GetInstance();
00307     if (dsfc) {
00308       dsfc->ClosingDown(this);
00309     }
00310     Destroy();
00311 
00312     if (--gDocShellCount == 0) {
00313         NS_IF_RELEASE(sURIFixup);
00314     }
00315 
00316 #ifdef PR_LOGGING
00317     if (gDocShellLeakLog)
00318         PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p destroyed\n", this));
00319 #endif
00320 }
00321 
00322 nsresult
00323 nsDocShell::Init()
00324 {
00325     nsresult rv = nsDocLoader::Init();
00326     NS_ENSURE_SUCCESS(rv, rv);
00327 
00328     NS_ASSERTION(mLoadGroup, "Something went wrong!");
00329 
00330     mContentListener = new nsDSURIContentListener(this);
00331     NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY);
00332 
00333     rv = mContentListener->Init();
00334     NS_ENSURE_SUCCESS(rv, rv);
00335 
00336     if (!mStorages.Init())
00337         return NS_ERROR_OUT_OF_MEMORY;
00338 
00339     // We want to hold a strong ref to the loadgroup, so it better hold a weak
00340     // ref to us...  use an InterfaceRequestorProxy to do this.
00341     nsCOMPtr<InterfaceRequestorProxy> proxy =
00342         new InterfaceRequestorProxy(NS_STATIC_CAST(nsIInterfaceRequestor*,
00343                                                    this));
00344     NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
00345     mLoadGroup->SetNotificationCallbacks(proxy);
00346 
00347     rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
00348     NS_ENSURE_SUCCESS(rv, rv);
00349     
00350     // Add as |this| a progress listener to itself.  A little weird, but
00351     // simpler than reproducing all the listener-notification logic in
00352     // overrides of the various methods via which nsDocLoader can be
00353     // notified.   Note that this holds an nsWeakPtr to ourselves, so it's ok.
00354     return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
00355                                      nsIWebProgress::NOTIFY_STATE_NETWORK);
00356     
00357 }
00358 
00359 void
00360 nsDocShell::DestroyChildren()
00361 {
00362     nsCOMPtr<nsIDocShellTreeItem> shell;
00363     PRInt32 n = mChildList.Count();
00364     for (PRInt32 i = 0; i < n; i++) {
00365         shell = do_QueryInterface(ChildAt(i));
00366         NS_WARN_IF_FALSE(shell, "docshell has null child");
00367 
00368         if (shell) {
00369             shell->SetTreeOwner(nsnull);
00370         }
00371     }
00372 
00373     nsDocLoader::DestroyChildren();
00374 }
00375 
00376 //*****************************************************************************
00377 // nsDocShell::nsISupports
00378 //*****************************************************************************   
00379 
00380 NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
00381 NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
00382 
00383 NS_INTERFACE_MAP_BEGIN(nsDocShell)
00384     NS_INTERFACE_MAP_ENTRY(nsIDocShell)
00385     NS_INTERFACE_MAP_ENTRY(nsIDocShell_MOZILLA_1_8_BRANCH)
00386     NS_INTERFACE_MAP_ENTRY(nsIDocShell_MOZILLA_1_8_BRANCH2)
00387     NS_INTERFACE_MAP_ENTRY(nsIDocShell_MOZILLA_1_8_BRANCH3)
00388     NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
00389     NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode)
00390     NS_INTERFACE_MAP_ENTRY(nsIDocShellHistory)
00391     NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
00392     NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
00393     NS_INTERFACE_MAP_ENTRY(nsIScrollable)
00394     NS_INTERFACE_MAP_ENTRY(nsITextScroll)
00395     NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
00396     NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
00397     NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
00398     NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
00399     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00400     NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
00401     NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell)
00402     NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
00403     NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
00404 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
00405 
00407 // nsDocShell::nsIInterfaceRequestor
00408 //*****************************************************************************   
00409 NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
00410 {
00411     NS_PRECONDITION(aSink, "null out param");
00412 
00413     *aSink = nsnull;
00414 
00415     if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
00416         *aSink = mContentListener;
00417     }
00418     else if (aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) &&
00419              NS_SUCCEEDED(EnsureScriptEnvironment())) {
00420         *aSink = mScriptGlobal;
00421     }
00422     else if ((aIID.Equals(NS_GET_IID(nsIDOMWindowInternal)) ||
00423               aIID.Equals(NS_GET_IID(nsPIDOMWindow)) ||
00424               aIID.Equals(NS_GET_IID(nsIDOMWindow))) &&
00425              NS_SUCCEEDED(EnsureScriptEnvironment())) {
00426         return mScriptGlobal->QueryInterface(aIID, aSink);
00427     }
00428     else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
00429              NS_SUCCEEDED(EnsureContentViewer())) {
00430         mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
00431         return *aSink ? NS_OK : NS_NOINTERFACE;
00432     }
00433     else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
00434              NS_SUCCEEDED(EnsureScriptEnvironment())) {
00435         nsresult rv;
00436         nsCOMPtr<nsIWindowWatcher> wwatch =
00437             do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
00438         NS_ENSURE_SUCCESS(rv, rv);
00439 
00440         nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(mScriptGlobal));
00441 
00442         // Get the an auth prompter for our window so that the parenting
00443         // of the dialogs works as it should when using tabs.
00444 
00445         nsIPrompt *prompt;
00446         rv = wwatch->GetNewPrompter(window, &prompt);
00447         NS_ENSURE_SUCCESS(rv, rv);
00448 
00449         *aSink = prompt;
00450         return NS_OK;
00451     }
00452     else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
00453         return NS_SUCCEEDED(
00454                 GetAuthPrompt(PROMPT_NORMAL, (nsIAuthPrompt **) aSink)) ?
00455                 NS_OK : NS_NOINTERFACE;
00456 
00457     }
00458     else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
00459         nsCOMPtr<nsISHistory> shistory;
00460         nsresult
00461             rv =
00462             GetSessionHistory(getter_AddRefs(shistory));
00463         if (NS_SUCCEEDED(rv) && shistory) {
00464             *aSink = shistory;
00465             NS_ADDREF((nsISupports *) * aSink);
00466             return NS_OK;
00467         }
00468         return NS_NOINTERFACE;
00469     }
00470     else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
00471         nsresult rv = EnsureFind();
00472         if (NS_FAILED(rv)) return rv;
00473 
00474         *aSink = mFind;
00475         NS_ADDREF((nsISupports*)*aSink);
00476         return NS_OK;
00477     }
00478     else if (aIID.Equals(NS_GET_IID(nsIEditingSession)) && NS_SUCCEEDED(EnsureEditorData())) {
00479       nsCOMPtr<nsIEditingSession> editingSession;
00480       mEditorData->GetEditingSession(getter_AddRefs(editingSession));
00481       if (editingSession)
00482       {
00483         *aSink = editingSession;
00484         NS_ADDREF((nsISupports *)*aSink);
00485         return NS_OK;
00486       }  
00487 
00488       return NS_NOINTERFACE;   
00489     }
00490     else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) 
00491             && NS_SUCCEEDED(EnsureTransferableHookData())) {
00492         *aSink = mTransferableHookData;
00493         NS_ADDREF((nsISupports *)*aSink);
00494         return NS_OK;
00495     }
00496     else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
00497       nsCOMPtr<nsIPresShell> shell;
00498       nsresult rv = GetPresShell(getter_AddRefs(shell));
00499       if (NS_SUCCEEDED(rv) && shell)
00500         return shell->QueryInterface(aIID,aSink);    
00501     }
00502     else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
00503       nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
00504       nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
00505       if (NS_SUCCEEDED(rv) && treeOwner)
00506         return treeOwner->QueryInterface(aIID, aSink);
00507     }
00508     else {
00509         return nsDocLoader::GetInterface(aIID, aSink);
00510     }
00511 
00512     NS_IF_ADDREF(((nsISupports *) * aSink));
00513     return *aSink ? NS_OK : NS_NOINTERFACE;
00514 }
00515 
00516 PRUint32
00517 nsDocShell::
00518 ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType)
00519 {
00520     PRUint32 loadType = LOAD_NORMAL;
00521 
00522     switch (aDocShellLoadType) {
00523     case nsIDocShellLoadInfo::loadNormal:
00524         loadType = LOAD_NORMAL;
00525         break;
00526     case nsIDocShellLoadInfo::loadNormalReplace:
00527         loadType = LOAD_NORMAL_REPLACE;
00528         break;
00529     case nsIDocShellLoadInfo::loadNormalExternal:
00530         loadType = LOAD_NORMAL_EXTERNAL;
00531         break;
00532     case nsIDocShellLoadInfo::loadHistory:
00533         loadType = LOAD_HISTORY;
00534         break;
00535     case nsIDocShellLoadInfo::loadReloadNormal:
00536         loadType = LOAD_RELOAD_NORMAL;
00537         break;
00538     case nsIDocShellLoadInfo::loadReloadCharsetChange:
00539         loadType = LOAD_RELOAD_CHARSET_CHANGE;
00540         break;
00541     case nsIDocShellLoadInfo::loadReloadBypassCache:
00542         loadType = LOAD_RELOAD_BYPASS_CACHE;
00543         break;
00544     case nsIDocShellLoadInfo::loadReloadBypassProxy:
00545         loadType = LOAD_RELOAD_BYPASS_PROXY;
00546         break;
00547     case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
00548         loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
00549         break;
00550     case nsIDocShellLoadInfo::loadLink:
00551         loadType = LOAD_LINK;
00552         break;
00553     case nsIDocShellLoadInfo::loadRefresh:
00554         loadType = LOAD_REFRESH;
00555         break;
00556     case nsIDocShellLoadInfo::loadBypassHistory:
00557         loadType = LOAD_BYPASS_HISTORY;
00558         break;
00559     case nsIDocShellLoadInfo::loadStopContent:
00560         loadType = LOAD_STOP_CONTENT;
00561         break;
00562     case nsIDocShellLoadInfo::loadStopContentAndReplace:
00563         loadType = LOAD_STOP_CONTENT_AND_REPLACE;
00564         break;
00565     }
00566 
00567     return loadType;
00568 }
00569 
00570 
00571 nsDocShellInfoLoadType
00572 nsDocShell::ConvertLoadTypeToDocShellLoadInfo(PRUint32 aLoadType)
00573 {
00574     nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal;
00575     switch (aLoadType) {
00576     case LOAD_NORMAL:
00577         docShellLoadType = nsIDocShellLoadInfo::loadNormal;
00578         break;
00579     case LOAD_NORMAL_REPLACE:
00580         docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace;
00581         break;
00582     case LOAD_NORMAL_EXTERNAL:
00583         docShellLoadType = nsIDocShellLoadInfo::loadNormalExternal;
00584         break;
00585     case LOAD_HISTORY:
00586         docShellLoadType = nsIDocShellLoadInfo::loadHistory;
00587         break;
00588     case LOAD_RELOAD_NORMAL:
00589         docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal;
00590         break;
00591     case LOAD_RELOAD_CHARSET_CHANGE:
00592         docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
00593         break;
00594     case LOAD_RELOAD_BYPASS_CACHE:
00595         docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache;
00596         break;
00597     case LOAD_RELOAD_BYPASS_PROXY:
00598         docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
00599         break;
00600     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
00601         docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
00602         break;
00603     case LOAD_LINK:
00604         docShellLoadType = nsIDocShellLoadInfo::loadLink;
00605         break;
00606     case LOAD_REFRESH:
00607         docShellLoadType = nsIDocShellLoadInfo::loadRefresh;
00608         break;
00609     case LOAD_BYPASS_HISTORY:
00610     case LOAD_ERROR_PAGE:
00611         docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory;
00612         break;
00613     case LOAD_STOP_CONTENT:
00614         docShellLoadType = nsIDocShellLoadInfo::loadStopContent;
00615         break;
00616     case LOAD_STOP_CONTENT_AND_REPLACE:
00617         docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
00618         break;
00619     }
00620 
00621     return docShellLoadType;
00622 }                                                                               
00623 
00624 //*****************************************************************************
00625 // nsDocShell::nsIDocShell
00626 //*****************************************************************************   
00627 NS_IMETHODIMP
00628 nsDocShell::LoadURI(nsIURI * aURI,
00629                     nsIDocShellLoadInfo * aLoadInfo,
00630                     PRUint32 aLoadFlags,
00631                     PRBool aFirstParty)
00632 {
00633     if (mFiredUnloadEvent) {
00634       return NS_OK; // JS may not handle returning of an error code
00635     }
00636     nsresult rv;
00637     nsCOMPtr<nsIURI> referrer;
00638     nsCOMPtr<nsIInputStream> postStream;
00639     nsCOMPtr<nsIInputStream> headersStream;
00640     nsCOMPtr<nsISupports> owner;
00641     PRBool inheritOwner = PR_FALSE;
00642     PRBool sendReferrer = PR_TRUE;
00643     nsCOMPtr<nsISHEntry> shEntry;
00644     nsXPIDLString target;
00645     PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);    
00646 
00647     NS_ENSURE_ARG(aURI);
00648 
00649     // Extract the info from the DocShellLoadInfo struct...
00650     if (aLoadInfo) {
00651         aLoadInfo->GetReferrer(getter_AddRefs(referrer));
00652 
00653         nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
00654         aLoadInfo->GetLoadType(&lt);
00655         // Get the appropriate loadType from nsIDocShellLoadInfo type
00656         loadType = ConvertDocShellLoadInfoToLoadType(lt);
00657 
00658         aLoadInfo->GetOwner(getter_AddRefs(owner));
00659         aLoadInfo->GetInheritOwner(&inheritOwner);
00660         aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
00661         aLoadInfo->GetTarget(getter_Copies(target));
00662         aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
00663         aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
00664         aLoadInfo->GetSendReferrer(&sendReferrer);
00665     }
00666 
00667 #if defined(PR_LOGGING) && defined(DEBUG)
00668     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
00669         nsCAutoString uristr;
00670         aURI->GetAsciiSpec(uristr);
00671         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
00672                ("nsDocShell[%p]: loading %s with flags 0x%08x",
00673                 this, uristr.get(), aLoadFlags));
00674     }
00675 #endif
00676 
00677     if (!shEntry &&
00678         !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
00679         // First verify if this is a subframe.
00680         nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
00681         GetSameTypeParent(getter_AddRefs(parentAsItem));
00682         nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
00683         PRUint32 parentLoadType;
00684 
00685         if (parentDS && parentDS != NS_STATIC_CAST(nsIDocShell *, this)) {
00686             /* OK. It is a subframe. Checkout the 
00687              * parent's loadtype. If the parent was loaded thro' a history
00688              * mechanism, then get the SH entry for the child from the parent.
00689              * This is done to restore frameset navigation while going back/forward.
00690              * If the parent was loaded through any other loadType, set the
00691              * child's loadType too accordingly, so that session history does not
00692              * get confused. 
00693              */
00694             
00695             // Get the parent's load type
00696             parentDS->GetLoadType(&parentLoadType);            
00697 
00698             nsCOMPtr<nsIDocShellHistory> parent(do_QueryInterface(parentAsItem));
00699             if (parent) {
00700                 // Get the ShEntry for the child from the parent
00701                 parent->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
00702                 // Make some decisions on the child frame's loadType based on the 
00703                 // parent's loadType. 
00704                 if (mCurrentURI == nsnull) {
00705                     // This is a newly created frame. Check for exception cases first. 
00706                     // By default the subframe will inherit the parent's loadType.
00707                     if (shEntry && (parentLoadType == LOAD_NORMAL ||
00708                                     parentLoadType == LOAD_LINK   ||
00709                                     parentLoadType == LOAD_NORMAL_EXTERNAL)) {
00710                         // The parent was loaded normally. In this case, this *brand new* child really shouldn't
00711                         // have a SHEntry. If it does, it could be because the parent is replacing an
00712                         // existing frame with a new frame, in the onLoadHandler. We don't want this
00713                         // url to get into session history. Clear off shEntry, and set laod type to
00714                         // LOAD_BYPASS_HISTORY. 
00715                         PRBool inOnLoadHandler=PR_FALSE;
00716                         parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
00717                         if (inOnLoadHandler) {
00718                             loadType = LOAD_NORMAL_REPLACE;
00719                             shEntry = nsnull;
00720                         }
00721                     }   
00722                     else if (parentLoadType == LOAD_REFRESH) {
00723                         // Clear shEntry. For refresh loads, we have to load
00724                         // what comes thro' the pipe, not what's in history.
00725                         shEntry = nsnull;
00726                     }
00727                     else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
00728                              (parentLoadType == LOAD_ERROR_PAGE) ||
00729                               (shEntry && 
00730                                ((parentLoadType & LOAD_CMD_HISTORY) || 
00731                                 (parentLoadType == LOAD_RELOAD_NORMAL) || 
00732                                 (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE)))) {
00733                         // If the parent url, bypassed history or was loaded from
00734                         // history, pass on the parent's loadType to the new child 
00735                         // frame too, so that the child frame will also
00736                         // avoid getting into history. 
00737                         loadType = parentLoadType;
00738                     }
00739                 }
00740                 else {
00741                     // This is a pre-existing subframe. If the load was not originally initiated
00742                     // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null,
00743                     // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading 
00744                     // a new page in this child. Check parent's and self's busy flag  and if it is set,
00745                     // we don't want this onLoadHandler load to get in to session history.
00746                     PRUint32 parentBusy = BUSY_FLAGS_NONE;
00747                     PRUint32 selfBusy = BUSY_FLAGS_NONE;
00748                     parentDS->GetBusyFlags(&parentBusy);                    
00749                     GetBusyFlags(&selfBusy);
00750                     if (((parentBusy & BUSY_FLAGS_BUSY) ||
00751                          (selfBusy & BUSY_FLAGS_BUSY)) &&
00752                         shEntry) {
00753                         loadType = LOAD_NORMAL_REPLACE;
00754                         shEntry = nsnull; 
00755                     }
00756                 }
00757             } // parent
00758         } //parentDS
00759         else {  
00760             // This is the root docshell. If we got here while  
00761             // executing an onLoad Handler,this load will not go 
00762             // into session history.
00763             PRBool inOnLoadHandler=PR_FALSE;
00764             GetIsExecutingOnLoadHandler(&inOnLoadHandler);
00765             if (inOnLoadHandler) {
00766                 loadType = LOAD_NORMAL_REPLACE;
00767             }
00768         } 
00769     } // !shEntry
00770 
00771     if (shEntry) {
00772 #ifdef DEBUG
00773         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
00774               ("nsDocShell[%p]: loading from session history", this));
00775 #endif
00776 
00777         rv = LoadHistoryEntry(shEntry, loadType);
00778     }
00779     // Perform the load...
00780     else {
00781         // We need an owner (a referring principal). 4 possibilities:
00782         // (1) If the system principal was passed in and we're a typeContent
00783         //     docshell, inherit the principal from the current document
00784         //     instead.
00785         // (2) In all other cases when the principal passed in is not null,
00786         //     use that principal.
00787         // (3) If the caller has allowed inheriting from the current
00788         //     document, or if we're being called from chrome (if there's
00789         //     system JS on the stack), then inheritOwner should be true and
00790         //     InternalLoad will get an owner from the current document. If
00791         //     none of these things are true, then
00792         // (4) we pass a null owner into the channel, and an owner will be
00793         //     created later from the channel's internal data.
00794         nsCOMPtr<nsIScriptSecurityManager> secMan =
00795             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
00796         NS_ENSURE_SUCCESS(rv, rv);
00797 
00798         // Just to compare, not to use!
00799         nsCOMPtr<nsIPrincipal> sysPrin;
00800         rv = secMan->GetSystemPrincipal(getter_AddRefs(sysPrin));
00801         NS_ENSURE_SUCCESS(rv, rv);
00802         
00803         if (owner == sysPrin && mItemType != typeChrome) {
00804             owner = nsnull;
00805             inheritOwner = PR_TRUE;
00806         }
00807         else if (!owner && !inheritOwner) {
00808             // See if there's system or chrome JS code running
00809             if (NS_SUCCEEDED(rv)) {
00810                 nsCOMPtr<nsIPrincipal> subjectPrin;
00811 
00812                 rv = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrin));
00813                 // If there's no subject principal, there's no JS running, so
00814                 // we're in system code.
00815                 if (NS_SUCCEEDED(rv) &&
00816                     (!subjectPrin || sysPrin == subjectPrin)) {
00817                     inheritOwner = PR_TRUE;
00818                 }
00819             }
00820         }
00821 
00822         PRUint32 flags = 0;
00823 
00824         if (inheritOwner)
00825             flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
00826 
00827         if (!sendReferrer)
00828             flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
00829             
00830         if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP)
00831             flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
00832 
00833         if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD)
00834             flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
00835 
00836         rv = InternalLoad(aURI,
00837                           referrer,
00838                           owner,
00839                           flags,
00840                           target.get(),
00841                           nsnull,         // No type hint
00842                           postStream,
00843                           headersStream,
00844                           loadType,
00845                           nsnull,         // No SHEntry
00846                           aFirstParty,
00847                           nsnull,         // No nsIDocShell
00848                           nsnull);        // No nsIRequest
00849     }
00850 
00851     return rv;
00852 }
00853 
00854 NS_IMETHODIMP
00855 nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI,
00856                        const nsACString &aContentType,
00857                        const nsACString &aContentCharset,
00858                        nsIDocShellLoadInfo * aLoadInfo)
00859 {
00860     NS_ENSURE_ARG(aStream);
00861 
00862     mAllowKeywordFixup = PR_FALSE;
00863 
00864     // if the caller doesn't pass in a URI we need to create a dummy URI. necko
00865     // currently requires a URI in various places during the load. Some consumers
00866     // do as well.
00867     nsCOMPtr<nsIURI> uri = aURI;
00868     if (!uri) {
00869         // HACK ALERT
00870         nsresult rv = NS_OK;
00871         uri = do_CreateInstance(kSimpleURICID, &rv);
00872         if (NS_FAILED(rv))
00873             return rv;
00874         // Make sure that the URI spec "looks" like a protocol and path...
00875         // For now, just use a bogus protocol called "internal"
00876         rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
00877         if (NS_FAILED(rv))
00878             return rv;
00879     }
00880 
00881     PRUint32 loadType = LOAD_NORMAL;
00882     if (aLoadInfo) {
00883         nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
00884         (void) aLoadInfo->GetLoadType(&lt);
00885         // Get the appropriate LoadType from nsIDocShellLoadInfo type
00886         loadType = ConvertDocShellLoadInfoToLoadType(lt);
00887     }
00888 
00889     NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
00890 
00891     mLoadType = loadType;
00892 
00893     // build up a channel for this stream.
00894     nsCOMPtr<nsIChannel> channel;
00895     NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
00896                       (getter_AddRefs(channel), uri, aStream,
00897                        aContentType, aContentCharset),
00898                       NS_ERROR_FAILURE);
00899 
00900     nsCOMPtr<nsIURILoader>
00901         uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
00902     NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
00903 
00904     NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader), NS_ERROR_FAILURE);
00905     return NS_OK;
00906 }
00907 
00908 NS_IMETHODIMP
00909 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo ** aLoadInfo)
00910 {
00911     nsDocShellLoadInfo *loadInfo = new nsDocShellLoadInfo();
00912     NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
00913     nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
00914 
00915     *aLoadInfo = localRef;
00916     NS_ADDREF(*aLoadInfo);
00917     return NS_OK;
00918 }
00919 
00920 
00921 /*
00922  * Reset state to a new content model within the current document and the document
00923  * viewer.  Called by the document before initiating an out of band document.write().
00924  */
00925 NS_IMETHODIMP
00926 nsDocShell::PrepareForNewContentModel()
00927 {
00928   mEODForCurrentDocument = PR_FALSE;
00929   return NS_OK;
00930 }
00931 
00932 
00933 NS_IMETHODIMP
00934 nsDocShell::FirePageHideNotification(PRBool aIsUnload)
00935 {
00936     if (mContentViewer && !mFiredUnloadEvent) {
00937         // Keep an explicit reference since calling PageHide could release
00938         // mContentViewer
00939         nsCOMPtr<nsIContentViewer> kungFuDeathGrip(mContentViewer);
00940         mFiredUnloadEvent = PR_TRUE;
00941 
00942         mContentViewer->PageHide(aIsUnload);
00943 
00944         PRInt32 i, n = mChildList.Count();
00945         for (i = 0; i < n; i++) {
00946             nsCOMPtr<nsIDocShell> shell(do_QueryInterface(ChildAt(i)));
00947             if (shell) {
00948                 shell->FirePageHideNotification(aIsUnload);
00949             }
00950         }
00951     }
00952     // Now make sure our editor, if any, is torn down before we go
00953     // any farther.
00954     if (mEditorData && aIsUnload) {
00955         mEditorData->TearDownEditor();
00956     }
00957 
00958     return NS_OK;
00959 }
00960 
00961 
00962 //
00963 // Bug 13871: Prevent frameset spoofing
00964 // Check if origin document uri is the equivalent to target's principal.
00965 // This takes into account subdomain checking if document.domain is set for
00966 // Nav 4.x compatability.
00967 //
00968 // The following was derived from nsScriptSecurityManager::SecurityCompareURIs
00969 // but in addition to the host PL_strcmp, it accepts a subdomain
00970 // (nsHTMLDocument::SetDomain) if the document.domain was set.
00971 //
00972 // XXXbz this method also subtracts the checks for jar: URIs, default ports,
00973 // etc.  This should SO not be living here.  If we need a better security
00974 // manager method, we should add one.
00975 //
00976 static PRBool
00977 SameOrSubdomainOfTarget(nsIURI* aOriginURI, nsIURI* aTargetURI,
00978                         PRBool aDocumentDomainSet)
00979 {
00980   if (aOriginURI == aTargetURI) {
00981     return PR_TRUE;
00982   }
00983   
00984   nsCAutoString targetScheme;
00985   nsresult rv = aTargetURI->GetScheme(targetScheme);
00986   NS_ENSURE_SUCCESS(rv, PR_TRUE);
00987 
00988   nsCAutoString originScheme;
00989   rv = aOriginURI->GetScheme(originScheme);
00990   NS_ENSURE_SUCCESS(rv, PR_TRUE);
00991 
00992   if (targetScheme != originScheme)
00993     return PR_FALSE; // Different schemes - check fails
00994 
00995   if (targetScheme.EqualsLiteral("file"))
00996     return PR_TRUE; // All file: urls are considered to have the same origin.
00997 
00998   if (targetScheme.EqualsLiteral("imap") ||
00999       targetScheme.EqualsLiteral("mailbox") ||
01000       targetScheme.EqualsLiteral("news"))
01001   {
01002 
01003     // Each message is a distinct trust domain; use the whole spec for comparison
01004     nsCAutoString targetSpec;
01005     rv =aTargetURI->GetAsciiSpec(targetSpec);
01006     NS_ENSURE_SUCCESS(rv, PR_TRUE);
01007 
01008     nsCAutoString originSpec;
01009     rv = aOriginURI->GetAsciiSpec(originSpec);
01010     NS_ENSURE_SUCCESS(rv, PR_TRUE);
01011 
01012     return (targetSpec == originSpec); // True if full spec is same, false otherwise
01013   }
01014 
01015   // Compare ports.  Note that failure to get this means we should return
01016   // false; such failure happens all the time for non-nsIURL nsIURI impls.
01017   int targetPort, originPort;
01018   rv = aTargetURI->GetPort(&targetPort);
01019   NS_ENSURE_SUCCESS(rv, PR_FALSE);
01020 
01021   rv = aOriginURI->GetPort(&originPort);
01022   NS_ENSURE_SUCCESS(rv, PR_FALSE);
01023 
01024   if (targetPort != originPort)
01025     return PR_FALSE; // Different port - check fails
01026 
01027   // Need to check the hosts.  Note that failure to get this means we should
01028   // return false; such failure happens all the time for non-nsIURL nsIURI
01029   // impls.
01030   nsCAutoString targetHost;
01031   rv = aTargetURI->GetHost(targetHost);
01032   NS_ENSURE_SUCCESS(rv, PR_FALSE);
01033 
01034   nsCAutoString originHost;
01035   rv = aOriginURI->GetHost(originHost);
01036   NS_ENSURE_SUCCESS(rv, PR_FALSE);
01037 
01038   if (targetHost.Equals(originHost, nsCaseInsensitiveCStringComparator()))
01039     return PR_TRUE; // Hosts are the same - check passed
01040   
01041   // If document.domain was set, do the relaxed check
01042   // Right align hostnames and compare - ensure preceeding char is . or /
01043   if (aDocumentDomainSet)
01044   {
01045     int targetHostLen = targetHost.Length();
01046     int originHostLen = originHost.Length();
01047     int prefixChar = originHostLen-targetHostLen-1;
01048 
01049     return ((originHostLen > targetHostLen) &&
01050             (! strcmp((originHost.get()+prefixChar+1), targetHost.get())) &&
01051             (originHost.CharAt(prefixChar) == '.' || originHost.CharAt(prefixChar) == '/'));
01052   }
01053 
01054   return PR_FALSE; // document.domain not set and hosts not same - check failed
01055 }
01056 
01057 //
01058 // Bug 13871: Prevent frameset spoofing
01059 //
01060 // This routine answers: 'Is origin's document from same domain as
01061 // target's document?'
01062 // Be optimistic that domain is same - error cases all answer 'yes'.
01063 // XXXbz why?  That seems wrong to me
01064 //
01065 // We have to compare the URI of the actual document loaded in the
01066 // origin, ignoring any document.domain that was set, with the
01067 // principal URI of the target (including any document.domain that was
01068 // set).  This puts control of loading in the hands of the target,
01069 // which is more secure. (per Nav 4.x)
01070 //
01071 /* static */
01072 PRBool
01073 nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
01074                            nsIDocShellTreeItem* aTargetTreeItem)
01075 {
01076     nsCOMPtr<nsIScriptSecurityManager> securityManager =
01077         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
01078     NS_ENSURE_TRUE(securityManager, PR_FALSE);
01079 
01080     nsCOMPtr<nsIPrincipal> subjectPrincipal;
01081     nsresult rv =
01082         securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
01083     NS_ENSURE_SUCCESS(rv, PR_TRUE);
01084 
01085     if (subjectPrincipal) {
01086         // We're called from JS, check if UniversalBrowserWrite is
01087         // enabled.
01088         PRBool ubwEnabled = PR_FALSE;
01089         rv = securityManager->IsCapabilityEnabled("UniversalBrowserWrite",
01090                                                   &ubwEnabled);
01091         NS_ENSURE_SUCCESS(rv, PR_FALSE);
01092 
01093         if (ubwEnabled) {
01094             return PR_TRUE;
01095         }
01096     }
01097 
01098     // Get origin document uri (ignoring document.domain)
01099     nsCOMPtr<nsIWebNavigation> originWebNav =
01100         do_QueryInterface(aOriginTreeItem);
01101     NS_ENSURE_TRUE(originWebNav, PR_TRUE);
01102 
01103     nsCOMPtr<nsIURI> originDocumentURI;
01104     rv = originWebNav->GetCurrentURI(getter_AddRefs(originDocumentURI));
01105     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && originDocumentURI, PR_TRUE);
01106 
01107     // This may be wyciwyg URI... if so, we need to extract the actual
01108     // URI from it.
01109     if (sURIFixup) {
01110         PRBool isWyciwyg = PR_FALSE;
01111         rv = originDocumentURI->SchemeIs("wyciwyg", &isWyciwyg);      
01112         if (isWyciwyg && NS_SUCCEEDED(rv)) {
01113             nsCOMPtr<nsIURI> temp;
01114             sURIFixup->CreateExposableURI(originDocumentURI,
01115                                           getter_AddRefs(temp));
01116             originDocumentURI = temp;
01117         }
01118     }
01119 
01120     // Get target principal uri (including document.domain)
01121     nsCOMPtr<nsIDOMDocument> targetDOMDocument =
01122         do_GetInterface(aTargetTreeItem);
01123     nsCOMPtr<nsIDocument> targetDocument(do_QueryInterface(targetDOMDocument));
01124     NS_ENSURE_TRUE(targetDocument, PR_TRUE);
01125 
01126     nsIPrincipal *targetPrincipal = targetDocument->GetPrincipal();
01127     NS_ENSURE_TRUE(targetPrincipal, PR_TRUE);
01128 
01129     nsCOMPtr<nsIURI> targetPrincipalURI;
01130     rv = targetPrincipal->GetURI(getter_AddRefs(targetPrincipalURI));
01131     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && targetPrincipalURI, PR_TRUE);
01132 
01133     // Find out if document.domain was set for HTML documents
01134     PRBool documentDomainSet = PR_FALSE;
01135     nsCOMPtr<nsIHTMLDocument> targetHTMLDocument =
01136         do_QueryInterface(targetDocument);
01137 
01138     // If we don't have an HTML document, fall through with
01139     // documentDomainSet false
01140     if (targetHTMLDocument) {
01141         documentDomainSet = targetHTMLDocument->WasDomainSet();
01142     }
01143 
01144     // Is origin same principal or a subdomain of target's
01145     // document.domain Compare actual URI of origin document, not origin
01146     // principal's URI. (Per Nav 4.x)
01147     // XXXbz what do modern browsers do?
01148     return SameOrSubdomainOfTarget(originDocumentURI, targetPrincipalURI,
01149                                    documentDomainSet);
01150 }
01151 
01152 NS_IMETHODIMP
01153 nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
01154 {
01155     nsresult rv = NS_OK;
01156 
01157     NS_ENSURE_ARG_POINTER(aPresContext);
01158     *aPresContext = nsnull;
01159 
01160     nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
01161     while (viewer) {
01162         nsCOMPtr<nsIContentViewer> prevViewer;
01163         viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
01164         if (prevViewer)
01165             viewer = prevViewer;
01166         else {
01167             nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(viewer));
01168             if (docv)
01169                 rv = docv->GetPresContext(aPresContext);
01170             break;
01171         }
01172     }
01173 
01174     return rv;
01175 }
01176 
01177 NS_IMETHODIMP
01178 nsDocShell::GetPresContext(nsPresContext ** aPresContext)
01179 {
01180     NS_ENSURE_ARG_POINTER(aPresContext);
01181     *aPresContext = nsnull;
01182 
01183     if (!mContentViewer)
01184       return NS_OK;
01185 
01186     nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(mContentViewer));
01187     NS_ENSURE_TRUE(docv, NS_ERROR_NO_INTERFACE);
01188 
01189     return docv->GetPresContext(aPresContext);
01190 }
01191 
01192 NS_IMETHODIMP
01193 nsDocShell::GetPresShell(nsIPresShell ** aPresShell)
01194 {
01195     nsresult rv = NS_OK;
01196 
01197     NS_ENSURE_ARG_POINTER(aPresShell);
01198     *aPresShell = nsnull;
01199 
01200     nsCOMPtr<nsPresContext> presContext;
01201     (void) GetPresContext(getter_AddRefs(presContext));
01202 
01203     if (presContext) {
01204         NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
01205     }
01206 
01207     return rv;
01208 }
01209 
01210 NS_IMETHODIMP
01211 nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell)
01212 {
01213     nsresult rv = NS_OK;
01214 
01215     NS_ENSURE_ARG_POINTER(aPresShell);
01216     *aPresShell = nsnull;
01217 
01218     nsCOMPtr<nsPresContext> presContext;
01219     (void) GetEldestPresContext(getter_AddRefs(presContext));
01220 
01221     if (presContext) {
01222         NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
01223     }
01224 
01225     return rv;
01226 }
01227 
01228 NS_IMETHODIMP
01229 nsDocShell::GetContentViewer(nsIContentViewer ** aContentViewer)
01230 {
01231     NS_ENSURE_ARG_POINTER(aContentViewer);
01232 
01233     *aContentViewer = mContentViewer;
01234     NS_IF_ADDREF(*aContentViewer);
01235     return NS_OK;
01236 }
01237 
01238 NS_IMETHODIMP
01239 nsDocShell::SetChromeEventHandler(nsIChromeEventHandler * aChromeEventHandler)
01240 {
01241     // Weak reference. Don't addref.
01242     mChromeEventHandler = aChromeEventHandler;
01243 
01244     NS_ASSERTION(!mScriptGlobal,
01245                  "SetChromeEventHandler() called after the script global "
01246                  "object was created! This means that the script global "
01247                  "object in this docshell won't get the right chrome event "
01248                  "handler. You really don't want to see this assert, FIX "
01249                  "YOUR CODE!");
01250 
01251     return NS_OK;
01252 }
01253 
01254 NS_IMETHODIMP
01255 nsDocShell::GetChromeEventHandler(nsIChromeEventHandler ** aChromeEventHandler)
01256 {
01257     NS_ENSURE_ARG_POINTER(aChromeEventHandler);
01258 
01259     *aChromeEventHandler = mChromeEventHandler;
01260     NS_IF_ADDREF(*aChromeEventHandler);
01261     return NS_OK;
01262 }
01263 
01264 /* [noscript] void setCurrentURI (in nsIURI uri); */
01265 NS_IMETHODIMP
01266 nsDocShell::SetCurrentURI(nsIURI *aURI)
01267 {
01268     SetCurrentURI(aURI, nsnull, PR_TRUE);
01269     return NS_OK;
01270 }
01271 
01272 PRBool
01273 nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
01274                           PRBool aFireOnLocationChange)
01275 {
01276 #ifdef PR_LOGGING
01277     if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
01278         nsCAutoString spec;
01279         if (aURI)
01280             aURI->GetSpec(spec);
01281         PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get());
01282     }
01283 #endif
01284 
01285     // We don't want to send a location change when we're displaying an error
01286     // page, and we don't want to change our idea of "current URI" either
01287     if (mLoadType == LOAD_ERROR_PAGE) {
01288         return PR_FALSE;
01289     }
01290 
01291     mCurrentURI = aURI;         //This assignment addrefs
01292     PRBool isRoot = PR_FALSE;   // Is this the root docshell
01293     PRBool isSubFrame = PR_FALSE;  // Is this a subframe navigation?
01294 
01295     nsCOMPtr<nsIDocShellTreeItem> root;
01296 
01297     GetSameTypeRootTreeItem(getter_AddRefs(root));
01298     if (root.get() == NS_STATIC_CAST(nsIDocShellTreeItem *, this)) 
01299     {
01300         // This is the root docshell
01301         isRoot = PR_TRUE;
01302     }
01303     if (mLSHE) {
01304         mLSHE->GetIsSubFrame(&isSubFrame);
01305     }
01306 
01307     if (!isSubFrame && !isRoot) {
01308       /* 
01309        * We don't want to send OnLocationChange notifications when
01310        * a subframe is being loaded for the first time, while
01311        * visiting a frameset page
01312        */
01313       return PR_FALSE; 
01314     }
01315 
01316     if (aFireOnLocationChange) {
01317         FireOnLocationChange(this, aRequest, aURI);
01318     }
01319     return !aFireOnLocationChange;
01320 }
01321 
01322 NS_IMETHODIMP
01323 nsDocShell::GetCharset(char** aCharset)
01324 {
01325     NS_ENSURE_ARG_POINTER(aCharset);
01326     *aCharset = nsnull; 
01327 
01328     nsCOMPtr<nsIPresShell> presShell;
01329     GetPresShell(getter_AddRefs(presShell));
01330     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
01331     nsIDocument *doc = presShell->GetDocument();
01332     NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
01333     *aCharset = ToNewCString(doc->GetDocumentCharacterSet());
01334     if (!*aCharset) {
01335         return NS_ERROR_OUT_OF_MEMORY;
01336     }
01337 
01338     return NS_OK;
01339 }
01340 
01341 NS_IMETHODIMP
01342 nsDocShell::SetCharset(const char* aCharset)
01343 {
01344     // set the default charset
01345     nsCOMPtr<nsIContentViewer> viewer;
01346     GetContentViewer(getter_AddRefs(viewer));
01347     if (viewer) {
01348       nsCOMPtr<nsIMarkupDocumentViewer> muDV(do_QueryInterface(viewer));
01349       if (muDV) {
01350         NS_ENSURE_SUCCESS(muDV->SetDefaultCharacterSet(nsDependentCString(aCharset)),
01351                           NS_ERROR_FAILURE);
01352       }
01353     }
01354 
01355     // set the charset override
01356     nsCOMPtr<nsIDocumentCharsetInfo> dcInfo;
01357     GetDocumentCharsetInfo(getter_AddRefs(dcInfo));
01358     if (dcInfo) {
01359       nsCOMPtr<nsIAtom> csAtom;
01360       csAtom = do_GetAtom(aCharset);
01361       dcInfo->SetForcedCharset(csAtom);
01362     }
01363 
01364     return NS_OK;
01365 } 
01366 
01367 NS_IMETHODIMP
01368 nsDocShell::GetDocumentCharsetInfo(nsIDocumentCharsetInfo **
01369                                    aDocumentCharsetInfo)
01370 {
01371     NS_ENSURE_ARG_POINTER(aDocumentCharsetInfo);
01372 
01373     // if the mDocumentCharsetInfo does not exist already, we create it now
01374     if (!mDocumentCharsetInfo) {
01375         mDocumentCharsetInfo = do_CreateInstance(kDocumentCharsetInfoCID);
01376         if (!mDocumentCharsetInfo)
01377             return NS_ERROR_FAILURE;
01378     }
01379 
01380     *aDocumentCharsetInfo = mDocumentCharsetInfo;
01381     NS_IF_ADDREF(*aDocumentCharsetInfo);
01382     return NS_OK;
01383 }
01384 
01385 NS_IMETHODIMP
01386 nsDocShell::SetDocumentCharsetInfo(nsIDocumentCharsetInfo *
01387                                    aDocumentCharsetInfo)
01388 {
01389     mDocumentCharsetInfo = aDocumentCharsetInfo;
01390     return NS_OK;
01391 }
01392 
01393 NS_IMETHODIMP
01394 nsDocShell::GetChannelIsUnsafe(PRBool *aUnsafe)
01395 {
01396     *aUnsafe = PR_FALSE;
01397 
01398     nsCOMPtr<nsIChannel> channel;
01399     GetCurrentDocumentChannel(getter_AddRefs(channel));
01400     if (!channel) {
01401         return NS_OK;
01402     }
01403 
01404     nsCOMPtr<nsIJARChannel_MOZILLA_1_8_BRANCH> jarChannel = do_QueryInterface(channel);
01405     if (!jarChannel) {
01406         return NS_OK;
01407     }
01408 
01409     return jarChannel->GetIsUnsafe(aUnsafe);
01410 }
01411 
01412 NS_IMETHODIMP
01413 nsDocShell::GetAllowPlugins(PRBool * aAllowPlugins)
01414 {
01415     NS_ENSURE_ARG_POINTER(aAllowPlugins);
01416 
01417     *aAllowPlugins = mAllowPlugins;
01418     if (!mAllowPlugins) {
01419         return NS_OK;
01420     }
01421 
01422     PRBool unsafe;
01423     *aAllowPlugins = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
01424     return NS_OK;
01425 }
01426 
01427 NS_IMETHODIMP
01428 nsDocShell::SetAllowPlugins(PRBool aAllowPlugins)
01429 {
01430     mAllowPlugins = aAllowPlugins;
01431     //XXX should enable or disable a plugin host
01432     return NS_OK;
01433 }
01434 
01435 NS_IMETHODIMP
01436 nsDocShell::GetAllowJavascript(PRBool * aAllowJavascript)
01437 {
01438     NS_ENSURE_ARG_POINTER(aAllowJavascript);
01439 
01440     *aAllowJavascript = mAllowJavascript;
01441     if (!mAllowJavascript) {
01442         return NS_OK;
01443     }
01444 
01445     PRBool unsafe;
01446     *aAllowJavascript = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
01447     return NS_OK;
01448 }
01449 
01450 NS_IMETHODIMP
01451 nsDocShell::SetAllowJavascript(PRBool aAllowJavascript)
01452 {
01453     mAllowJavascript = aAllowJavascript;
01454     return NS_OK;
01455 }
01456 
01457 NS_IMETHODIMP nsDocShell::GetAllowMetaRedirects(PRBool * aReturn)
01458 {
01459     NS_ENSURE_ARG_POINTER(aReturn);
01460 
01461     *aReturn = mAllowMetaRedirects;
01462     if (!mAllowMetaRedirects) {
01463         return NS_OK;
01464     }
01465 
01466     PRBool unsafe;
01467     *aReturn = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
01468     return NS_OK;
01469 }
01470 
01471 NS_IMETHODIMP nsDocShell::SetAllowMetaRedirects(PRBool aValue)
01472 {
01473     mAllowMetaRedirects = aValue;
01474     return NS_OK;
01475 }
01476 
01477 NS_IMETHODIMP nsDocShell::GetAllowSubframes(PRBool * aAllowSubframes)
01478 {
01479     NS_ENSURE_ARG_POINTER(aAllowSubframes);
01480 
01481     *aAllowSubframes = mAllowSubframes;
01482     return NS_OK;
01483 }
01484 
01485 NS_IMETHODIMP nsDocShell::SetAllowSubframes(PRBool aAllowSubframes)
01486 {
01487     mAllowSubframes = aAllowSubframes;
01488     return NS_OK;
01489 }
01490 
01491 NS_IMETHODIMP nsDocShell::GetAllowImages(PRBool * aAllowImages)
01492 {
01493     NS_ENSURE_ARG_POINTER(aAllowImages);
01494 
01495     *aAllowImages = mAllowImages;
01496     return NS_OK;
01497 }
01498 
01499 NS_IMETHODIMP nsDocShell::SetAllowImages(PRBool aAllowImages)
01500 {
01501     mAllowImages = aAllowImages;
01502     return NS_OK;
01503 }
01504 
01505 NS_IMETHODIMP
01506 nsDocShell::GetDocShellEnumerator(PRInt32 aItemType, PRInt32 aDirection, nsISimpleEnumerator **outEnum)
01507 {
01508     NS_ENSURE_ARG_POINTER(outEnum);
01509     *outEnum = nsnull;
01510     
01511     nsRefPtr<nsDocShellEnumerator> docShellEnum;
01512     if (aDirection == ENUMERATE_FORWARDS)
01513         docShellEnum = new nsDocShellForwardsEnumerator;
01514     else
01515         docShellEnum = new nsDocShellBackwardsEnumerator;
01516     
01517     if (!docShellEnum) return NS_ERROR_OUT_OF_MEMORY;
01518     
01519     nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
01520     if (NS_FAILED(rv)) return rv;
01521 
01522     rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem *)this);
01523     if (NS_FAILED(rv)) return rv;
01524 
01525     rv = docShellEnum->First();
01526     if (NS_FAILED(rv)) return rv;
01527 
01528     rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)outEnum);
01529 
01530     return rv;
01531 }
01532 
01533 NS_IMETHODIMP
01534 nsDocShell::GetAppType(PRUint32 * aAppType)
01535 {
01536     *aAppType = mAppType;
01537     return NS_OK;
01538 }
01539 
01540 NS_IMETHODIMP
01541 nsDocShell::SetAppType(PRUint32 aAppType)
01542 {
01543     mAppType = aAppType;
01544     return NS_OK;
01545 }
01546 
01547 
01548 NS_IMETHODIMP
01549 nsDocShell::GetAllowAuth(PRBool * aAllowAuth)
01550 {
01551     *aAllowAuth = mAllowAuth;
01552     return NS_OK;
01553 }
01554 
01555 NS_IMETHODIMP
01556 nsDocShell::SetAllowAuth(PRBool aAllowAuth)
01557 {
01558     mAllowAuth = aAllowAuth;
01559     return NS_OK;
01560 }
01561 
01562 NS_IMETHODIMP
01563 nsDocShell::GetZoom(float *zoom)
01564 {
01565     NS_ENSURE_ARG_POINTER(zoom);
01566     NS_ENSURE_SUCCESS(EnsureDeviceContext(), NS_ERROR_FAILURE);
01567 
01568     NS_ENSURE_SUCCESS(mDeviceContext->GetZoom(*zoom), NS_ERROR_FAILURE);
01569 
01570     return NS_OK;
01571 }
01572 
01573 NS_IMETHODIMP
01574 nsDocShell::SetZoom(float zoom)
01575 {
01576     NS_ENSURE_SUCCESS(EnsureDeviceContext(), NS_ERROR_FAILURE);
01577     mDeviceContext->SetZoom(zoom);
01578 
01579     // get the pres shell
01580     nsCOMPtr<nsIPresShell> presShell;
01581     NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)),
01582                       NS_ERROR_FAILURE);
01583     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
01584 
01585     // get the view manager
01586     nsIViewManager* vm = presShell->GetViewManager();
01587     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
01588 
01589     // get the root view
01590     nsIView *rootView = nsnull; // views are not ref counted
01591     vm->GetRootView(rootView);
01592     if (rootView)
01593         vm->UpdateView(rootView, 0);
01594 
01595     return NS_OK;
01596 }
01597 
01598 NS_IMETHODIMP
01599 nsDocShell::GetMarginWidth(PRInt32 * aWidth)
01600 {
01601     NS_ENSURE_ARG_POINTER(aWidth);
01602 
01603     *aWidth = mMarginWidth;
01604     return NS_OK;
01605 }
01606 
01607 NS_IMETHODIMP
01608 nsDocShell::SetMarginWidth(PRInt32 aWidth)
01609 {
01610     mMarginWidth = aWidth;
01611     return NS_OK;
01612 }
01613 
01614 NS_IMETHODIMP
01615 nsDocShell::GetMarginHeight(PRInt32 * aHeight)
01616 {
01617     NS_ENSURE_ARG_POINTER(aHeight);
01618 
01619     *aHeight = mMarginHeight;
01620     return NS_OK;
01621 }
01622 
01623 NS_IMETHODIMP
01624 nsDocShell::SetMarginHeight(PRInt32 aHeight)
01625 {
01626     mMarginHeight = aHeight;
01627     return NS_OK;
01628 }
01629 
01630 NS_IMETHODIMP
01631 nsDocShell::GetBusyFlags(PRUint32 * aBusyFlags)
01632 {
01633     NS_ENSURE_ARG_POINTER(aBusyFlags);
01634 
01635     *aBusyFlags = mBusyFlags;
01636     return NS_OK;
01637 }
01638 
01639 NS_IMETHODIMP
01640 nsDocShell::TabToTreeOwner(PRBool aForward, PRBool* aTookFocus)
01641 {
01642     NS_ENSURE_ARG_POINTER(aTookFocus);
01643     
01644     nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner);
01645     if (chromeFocus) {
01646         if (aForward)
01647             *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement());
01648         else
01649             *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement());
01650     } else
01651         *aTookFocus = PR_FALSE;
01652     
01653     return NS_OK;
01654 }
01655 
01656 NS_IMETHODIMP
01657 nsDocShell::GetSecurityUI(nsISecureBrowserUI **aSecurityUI)
01658 {
01659     NS_IF_ADDREF(*aSecurityUI = mSecurityUI);
01660     return NS_OK;
01661 }
01662 
01663 NS_IMETHODIMP
01664 nsDocShell::SetSecurityUI(nsISecureBrowserUI *aSecurityUI)
01665 {
01666     mSecurityUI = aSecurityUI;
01667     return NS_OK;
01668 }
01669 
01670 NS_IMETHODIMP
01671 nsDocShell::GetUseErrorPages(PRBool *aUseErrorPages)
01672 {
01673     *aUseErrorPages = mUseErrorPages;
01674     return NS_OK;
01675 }
01676 
01677 NS_IMETHODIMP
01678 nsDocShell::SetUseErrorPages(PRBool aUseErrorPages)
01679 {
01680     mUseErrorPages = aUseErrorPages;
01681     return NS_OK;
01682 }
01683 
01684 NS_IMETHODIMP
01685 nsDocShell::GetPreviousTransIndex(PRInt32 *aPreviousTransIndex)
01686 {
01687     *aPreviousTransIndex = mPreviousTransIndex;
01688     return NS_OK;
01689 }
01690 
01691 NS_IMETHODIMP
01692 nsDocShell::GetLoadedTransIndex(PRInt32 *aLoadedTransIndex)
01693 {
01694     *aLoadedTransIndex = mLoadedTransIndex;
01695     return NS_OK;
01696 }
01697 
01698 NS_IMETHODIMP
01699 nsDocShell::HistoryPurged(PRInt32 aNumEntries)
01700 {
01701     // These indices are used for fastback cache eviction, to determine
01702     // which session history entries are candidates for content viewer
01703     // eviction.  We need to adjust by the number of entries that we
01704     // just purged from history, so that we look at the right session history
01705     // entries during eviction.
01706     mPreviousTransIndex = PR_MAX(-1, mPreviousTransIndex - aNumEntries);
01707     mLoadedTransIndex = PR_MAX(0, mLoadedTransIndex - aNumEntries);
01708 
01709     PRInt32 count = mChildList.Count();
01710     for (PRInt32 i = 0; i < count; ++i) {
01711         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
01712         if (shell) {
01713             shell->HistoryPurged(aNumEntries);
01714         }
01715     }
01716 
01717     return NS_OK;
01718 }
01719 
01720 NS_IMETHODIMP
01721 nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
01722                                     nsIDOMStorage** aStorage)
01723 {
01724     NS_ENSURE_ARG_POINTER(aStorage);
01725 
01726     *aStorage = nsnull;
01727 
01728     nsCOMPtr<nsIDocShellTreeItem> topItem;
01729     nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
01730     if (NS_FAILED(rv))
01731         return rv;
01732 
01733     if (!topItem)
01734         return NS_ERROR_FAILURE;
01735 
01736     nsCOMPtr<nsIDocShell_MOZILLA_1_8_BRANCH> topDocShell =
01737         do_QueryInterface(topItem);
01738     if (topDocShell != this)
01739         return topDocShell->GetSessionStorageForURI(aURI, aStorage);
01740 
01741     nsCAutoString currentDomain;
01742     rv = aURI->GetAsciiHost(currentDomain);
01743     NS_ENSURE_SUCCESS(rv, rv);
01744 
01745     if (currentDomain.IsEmpty())
01746         return NS_OK;
01747 
01748     if (!mStorages.Get(currentDomain, aStorage)) {
01749         nsCOMPtr<nsIDOMStorage> newstorage =
01750             do_CreateInstance("@mozilla.org/dom/storage;1");
01751         if (!newstorage)
01752             return NS_ERROR_OUT_OF_MEMORY;
01753 
01754         nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(newstorage);
01755         if (!pistorage)
01756             return NS_ERROR_FAILURE;
01757         pistorage->Init(aURI, NS_ConvertUTF8toUTF16(currentDomain), PR_FALSE);
01758 
01759         if (!mStorages.Put(currentDomain, newstorage))
01760             return NS_ERROR_OUT_OF_MEMORY;
01761               
01762         *aStorage = newstorage;
01763         NS_ADDREF(*aStorage);
01764     }
01765 
01766     return NS_OK;
01767 }
01768 
01769 nsresult
01770 nsDocShell::AddSessionStorage(const nsACString& aDomain,
01771                               nsIDOMStorage* aStorage)
01772 {
01773     NS_ENSURE_ARG_POINTER(aStorage);
01774 
01775     if (aDomain.IsEmpty())
01776         return NS_OK;
01777 
01778     nsCOMPtr<nsIDocShellTreeItem> topItem;
01779     nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
01780     if (NS_FAILED(rv))
01781         return rv;
01782 
01783     if (topItem) {
01784         nsCOMPtr<nsIDocShell_MOZILLA_1_8_BRANCH> topDocShell =
01785             do_QueryInterface(topItem);
01786         if (topDocShell == this) {
01787             if (!mStorages.Put(aDomain, aStorage))
01788                 return NS_ERROR_OUT_OF_MEMORY;
01789         }
01790         else {
01791             return topDocShell->AddSessionStorage(aDomain, aStorage);
01792         }
01793     }
01794 
01795     return NS_OK;
01796 }
01797 
01798 NS_IMETHODIMP
01799 nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
01800 {
01801     *aResult = nsnull;
01802     if (!mContentViewer)
01803         return NS_OK;
01804 
01805     nsCOMPtr<nsIDOMDocument> domDoc;
01806     nsresult rv = mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
01807     if (NS_FAILED(rv))
01808         return rv;
01809 
01810     nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
01811     if (doc) {
01812         *aResult = doc->GetChannel();
01813         NS_IF_ADDREF(*aResult);
01814     }
01815   
01816     return NS_OK;
01817 }
01818 
01819 //*****************************************************************************
01820 // nsDocShell::nsIDocShellTreeItem
01821 //*****************************************************************************   
01822 
01823 NS_IMETHODIMP
01824 nsDocShell::GetName(PRUnichar ** aName)
01825 {
01826     NS_ENSURE_ARG_POINTER(aName);
01827     *aName = ToNewUnicode(mName);
01828     return NS_OK;
01829 }
01830 
01831 NS_IMETHODIMP
01832 nsDocShell::SetName(const PRUnichar * aName)
01833 {
01834     mName = aName;              // this does a copy of aName
01835     return NS_OK;
01836 }
01837 
01838 NS_IMETHODIMP
01839 nsDocShell::NameEquals(const PRUnichar *aName, PRBool *_retval)
01840 {
01841     NS_ENSURE_ARG_POINTER(aName);
01842     NS_ENSURE_ARG_POINTER(_retval);
01843     *_retval = mName.Equals(aName);
01844     return NS_OK;
01845 }
01846 
01847 NS_IMETHODIMP
01848 nsDocShell::GetItemType(PRInt32 * aItemType)
01849 {
01850     NS_ENSURE_ARG_POINTER(aItemType);
01851 
01852     *aItemType = mItemType;
01853     return NS_OK;
01854 }
01855 
01856 NS_IMETHODIMP
01857 nsDocShell::SetItemType(PRInt32 aItemType)
01858 {
01859     NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
01860 
01861     // Only allow setting the type on root docshells.  Those would be the ones
01862     // that have the docloader service as mParent or have no mParent at all.
01863     nsCOMPtr<nsIDocumentLoader> docLoaderService =
01864         do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
01865     NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED);
01866     
01867     NS_ENSURE_STATE(!mParent || mParent == docLoaderService);
01868 
01869     mItemType = aItemType;
01870 
01871     // disable auth prompting for anything but content
01872     mAllowAuth = mItemType == typeContent; 
01873 
01874     return NS_OK;
01875 }
01876 
01877 NS_IMETHODIMP
01878 nsDocShell::GetParent(nsIDocShellTreeItem ** aParent)
01879 {
01880     if (!mParent) {
01881         *aParent = nsnull;
01882     } else {
01883         CallQueryInterface(mParent, aParent);
01884     }
01885     // Note that in the case when the parent is not an nsIDocShellTreeItem we
01886     // don't want to throw; we just want to return null.
01887     return NS_OK;
01888 }
01889 
01890 nsresult
01891 nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
01892 {
01893     nsDocLoader::SetDocLoaderParent(aParent);
01894 
01895     // Curse ambiguous nsISupports inheritance!
01896     nsISupports* parent = GetAsSupports(aParent);
01897 
01898     // If parent is another docshell, we inherit all their flags for
01899     // allowing plugins, scripting etc.
01900     nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
01901     if (parentAsDocShell)
01902     {
01903         PRBool value;
01904         if (NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value)))
01905         {
01906             SetAllowPlugins(value);
01907         }
01908         if (NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value)))
01909         {
01910             SetAllowJavascript(value);
01911         }
01912         if (NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value)))
01913         {
01914             SetAllowMetaRedirects(value);
01915         }
01916         if (NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value)))
01917         {
01918             SetAllowSubframes(value);
01919         }
01920         if (NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value)))
01921         {
01922             SetAllowImages(value);
01923         }
01924     }
01925 
01926     nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
01927     if (parentURIListener)
01928         mContentListener->SetParentContentListener(parentURIListener);
01929     return NS_OK;
01930 }
01931 
01932 NS_IMETHODIMP
01933 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem ** aParent)
01934 {
01935     NS_ENSURE_ARG_POINTER(aParent);
01936     *aParent = nsnull;
01937 
01938     nsCOMPtr<nsIDocShellTreeItem> parent =
01939         do_QueryInterface(GetAsSupports(mParent));
01940     if (!parent)
01941         return NS_OK;
01942 
01943     PRInt32 parentType;
01944     NS_ENSURE_SUCCESS(parent->GetItemType(&parentType), NS_ERROR_FAILURE);
01945 
01946     if (parentType == mItemType) {
01947         parent.swap(*aParent);
01948     }
01949     return NS_OK;
01950 }
01951 
01952 NS_IMETHODIMP
01953 nsDocShell::GetRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
01954 {
01955     NS_ENSURE_ARG_POINTER(aRootTreeItem);
01956     *aRootTreeItem = NS_STATIC_CAST(nsIDocShellTreeItem *, this);
01957 
01958     nsCOMPtr<nsIDocShellTreeItem> parent;
01959     NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
01960     while (parent) {
01961         *aRootTreeItem = parent;
01962         NS_ENSURE_SUCCESS((*aRootTreeItem)->GetParent(getter_AddRefs(parent)),
01963                           NS_ERROR_FAILURE);
01964     }
01965     NS_ADDREF(*aRootTreeItem);
01966     return NS_OK;
01967 }
01968 
01969 NS_IMETHODIMP
01970 nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
01971 {
01972     NS_ENSURE_ARG_POINTER(aRootTreeItem);
01973     *aRootTreeItem = NS_STATIC_CAST(nsIDocShellTreeItem *, this);
01974 
01975     nsCOMPtr<nsIDocShellTreeItem> parent;
01976     NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)),
01977                       NS_ERROR_FAILURE);
01978     while (parent) {
01979         *aRootTreeItem = parent;
01980         NS_ENSURE_SUCCESS((*aRootTreeItem)->
01981                           GetSameTypeParent(getter_AddRefs(parent)),
01982                           NS_ERROR_FAILURE);
01983     }
01984     NS_ADDREF(*aRootTreeItem);
01985     return NS_OK;
01986 }
01987 
01988 /* static */
01989 PRBool
01990 nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
01991                           nsIDocShellTreeItem* aAccessingItem,
01992                           PRBool aConsiderOpener)
01993 {
01994     NS_PRECONDITION(aTargetItem, "Must have target item!");
01995 
01996     if (!gValidateOrigin || !aAccessingItem) {
01997         // Good to go
01998         return PR_TRUE;
01999     }
02000 
02001     // XXXbz should we care if aAccessingItem or the document therein is
02002     // chrome?  Should those get extra privileges?
02003 
02004     // Now do a security check
02005     // Bug 13871: Prevent frameset spoofing
02006     //     See BugSplat 336170, 338737 and XP_FindNamedContextInList in
02007     //     the classic codebase
02008     //     Nav's behaviour was:
02009     //         - pref controlled: "browser.frame.validate_origin" 
02010     //           (gValidateOrigin)
02011     //         - allow load if host of target or target's parent is same
02012     //           as host of origin
02013     //         - allow load if target is a top level window
02014     
02015     //     We are going to be a little more restrictive, with the
02016     //     following algorithm:
02017     //         - pref controlled in the same way
02018     //         - allow access if the two treeitems are in the same tree
02019     //         - allow access if the aTargetItem or one of its ancestors
02020     //           has the same origin as aAccessingItem
02021     //         - allow access if the target is a toplevel window and we can
02022     //           access its opener.  Note that we only allow one level of
02023     //           recursion there.
02024 
02025     nsCOMPtr<nsIDocShellTreeItem> targetRoot;
02026     aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
02027 
02028     nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
02029     aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
02030 
02031     if (targetRoot == accessingRoot) {
02032         return PR_TRUE;
02033     }
02034 
02035     nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
02036     do {
02037         if (ValidateOrigin(aAccessingItem, target)) {
02038             return PR_TRUE;
02039         }
02040             
02041         nsCOMPtr<nsIDocShellTreeItem> parent;
02042         target->GetSameTypeParent(getter_AddRefs(parent));
02043         parent.swap(target);
02044     } while (target);
02045 
02046     if (aTargetItem != targetRoot) {
02047         // target is a subframe, not in accessor's frame hierarchy, and all its
02048         // ancestors have origins different from that of the accessor. Don't
02049         // allow access.
02050         return PR_FALSE;
02051     }
02052 
02053     if (!aConsiderOpener) {
02054         // All done here
02055         return PR_FALSE;
02056     }
02057 
02058     nsCOMPtr<nsIDOMWindow> targetWindow(do_GetInterface(aTargetItem));
02059     nsCOMPtr<nsIDOMWindowInternal> targetInternal(do_QueryInterface(targetWindow));
02060     if (!targetInternal) {
02061         NS_ERROR("This should not happen, really");
02062         return PR_FALSE;
02063     }
02064 
02065     nsCOMPtr<nsIDOMWindowInternal> targetOpener;
02066     targetInternal->GetOpener(getter_AddRefs(targetOpener));
02067     nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
02068     nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
02069 
02070     if (!openerItem) {
02071         return PR_FALSE;
02072     }
02073 
02074     return CanAccessItem(openerItem, aAccessingItem, PR_FALSE);    
02075 }
02076 
02077 static PRBool
02078 ItemIsActive(nsIDocShellTreeItem *aItem)
02079 {
02080     nsCOMPtr<nsIDOMWindow> tmp(do_GetInterface(aItem));
02081     nsCOMPtr<nsIDOMWindowInternal> window(do_QueryInterface(tmp));
02082 
02083     if (window) {
02084         PRBool isClosed;
02085 
02086         if (NS_SUCCEEDED(window->GetClosed(&isClosed)) && !isClosed) {
02087             return PR_TRUE;
02088         }
02089     }
02090 
02091     return PR_FALSE;
02092 }
02093 
02094 NS_IMETHODIMP
02095 nsDocShell::FindItemWithName(const PRUnichar * aName,
02096                              nsISupports * aRequestor,
02097                              nsIDocShellTreeItem * aOriginalRequestor,
02098                              nsIDocShellTreeItem ** _retval)
02099 {
02100     NS_ENSURE_ARG(aName);
02101     NS_ENSURE_ARG_POINTER(_retval);
02102 
02103     // If we don't find one, we return NS_OK and a null result
02104     *_retval = nsnull;
02105 
02106     if (!*aName)
02107         return NS_OK;
02108 
02109     if (!aRequestor)
02110     {
02111         nsCOMPtr<nsIDocShellTreeItem> foundItem;
02112 
02113         // This is the entry point into the target-finding algorithm.  Check
02114         // for special names.  This should only be done once, hence the check
02115         // for a null aRequestor.
02116 
02117         nsDependentString name(aName);
02118         if (name.LowerCaseEqualsLiteral("_self")) {
02119             foundItem = this;
02120         }
02121         else if (name.LowerCaseEqualsLiteral("_blank") ||
02122                  name.LowerCaseEqualsLiteral("_new"))
02123         {
02124             // Just return null.  Caller must handle creating a new window with
02125             // a blank name himself.
02126             return NS_OK;
02127         }
02128         else if (name.LowerCaseEqualsLiteral("_parent"))
02129         {
02130             GetSameTypeParent(getter_AddRefs(foundItem));
02131             if(!foundItem)
02132                 foundItem = this;
02133         }
02134         else if (name.LowerCaseEqualsLiteral("_top"))
02135         {
02136             GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
02137             NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
02138         }
02139         // _main is an IE target which should be case-insensitive but isn't
02140         // see bug 217886 for details
02141         else if (name.LowerCaseEqualsLiteral("_content") ||
02142                  name.EqualsLiteral("_main"))
02143         {
02144             // Must pass our same type root as requestor to the
02145             // treeowner to make sure things work right.
02146             nsCOMPtr<nsIDocShellTreeItem> root;
02147             GetSameTypeRootTreeItem(getter_AddRefs(root));
02148             if (mTreeOwner) {
02149                 NS_ASSERTION(root, "Must have this; worst case it's us!");
02150                 mTreeOwner->FindItemWithName(aName, root, aOriginalRequestor,
02151                                              getter_AddRefs(foundItem));
02152             }
02153 #ifdef DEBUG
02154             else {
02155                 NS_ERROR("Someone isn't setting up the tree owner.  "
02156                          "You might like to try that.  "
02157                          "Things will.....you know, work.");
02158                 // Note: _content should always exist.  If we don't have one
02159                 // hanging off the treeowner, just create a named window....
02160                 // so don't return here, in case we did that and can now find
02161                 // it.                
02162                 // XXXbz should we be using |root| instead of creating
02163                 // a new window?
02164             }
02165 #endif
02166         }
02167 
02168         if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
02169             foundItem = nsnull;
02170         }
02171 
02172         if (foundItem) {
02173             // We return foundItem here even if it's not an active
02174             // item since all the names we've dealt with so far are
02175             // special cases that we won't bother looking for further.
02176 
02177             foundItem.swap(*_retval);
02178             return NS_OK;
02179         }
02180     }
02181 
02182     // Keep looking
02183         
02184     // First we check our name.
02185     if (mName.Equals(aName) && ItemIsActive(this) &&
02186         CanAccessItem(this, aOriginalRequestor)) {
02187         NS_ADDREF(*_retval = this);
02188         return NS_OK;
02189     }
02190 
02191     // This QI may fail, but the places where we want to compare, comparing
02192     // against nsnull serves the same purpose.
02193     nsCOMPtr<nsIDocShellTreeItem> reqAsTreeItem(do_QueryInterface(aRequestor));
02194 
02195     // Second we check our children making sure not to ask a child if
02196     // it is the aRequestor.
02197 #ifdef DEBUG
02198     nsresult rv =
02199 #endif
02200     FindChildWithName(aName, PR_TRUE, PR_TRUE, reqAsTreeItem,
02201                       aOriginalRequestor, _retval);
02202     NS_ASSERTION(NS_SUCCEEDED(rv),
02203                  "FindChildWithName should not be failing here.");
02204     if (*_retval)
02205         return NS_OK;
02206         
02207     // Third if we have a parent and it isn't the requestor then we
02208     // should ask it to do the search.  If it is the requestor we
02209     // should just stop here and let the parent do the rest.  If we
02210     // don't have a parent, then we should ask the
02211     // docShellTreeOwner to do the search.
02212     nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
02213         do_QueryInterface(GetAsSupports(mParent));
02214     if (parentAsTreeItem) {
02215         if (parentAsTreeItem == reqAsTreeItem)
02216             return NS_OK;
02217 
02218         PRInt32 parentType;
02219         parentAsTreeItem->GetItemType(&parentType);
02220         if (parentType == mItemType) {
02221             return parentAsTreeItem->
02222                 FindItemWithName(aName,
02223                                  NS_STATIC_CAST(nsIDocShellTreeItem*,
02224                                                 this),
02225                                  aOriginalRequestor,
02226                                  _retval);
02227         }
02228     }
02229 
02230     // If the parent is null or not of the same type fall through and ask tree
02231     // owner.
02232 
02233     // This may fail, but comparing against null serves the same purpose
02234     nsCOMPtr<nsIDocShellTreeOwner>
02235         reqAsTreeOwner(do_QueryInterface(aRequestor));
02236 
02237     if (mTreeOwner && mTreeOwner != reqAsTreeOwner) {
02238         return mTreeOwner->
02239             FindItemWithName(aName, this, aOriginalRequestor, _retval);
02240     }
02241 
02242     return NS_OK;
02243 }
02244 
02245 NS_IMETHODIMP
02246 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner ** aTreeOwner)
02247 {
02248     NS_ENSURE_ARG_POINTER(aTreeOwner);
02249 
02250     *aTreeOwner = mTreeOwner;
02251     NS_IF_ADDREF(*aTreeOwner);
02252     return NS_OK;
02253 }
02254 
02255 #ifdef DEBUG_DOCSHELL_FOCUS
02256 static void 
02257 PrintDocTree(nsIDocShellTreeNode * aParentNode, int aLevel)
02258 {
02259   for (PRInt32 i=0;i<aLevel;i++) printf("  ");
02260 
02261   PRInt32 childWebshellCount;
02262   aParentNode->GetChildCount(&childWebshellCount);
02263   nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode));
02264   nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(aParentNode));
02265   PRInt32 type;
02266   parentAsItem->GetItemType(&type);
02267   nsCOMPtr<nsIPresShell> presShell;
02268   parentAsDocShell->GetPresShell(getter_AddRefs(presShell));
02269   nsCOMPtr<nsPresContext> presContext;
02270   parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
02271   nsIDocument *doc = presShell->GetDocument();
02272 
02273   nsCOMPtr<nsIScriptGlobalObject> sgo;
02274   doc->GetScriptGlobalObject(getter_AddRefs(sgo));
02275   nsCOMPtr<nsIDOMWindowInternal> domwin(do_QueryInterface(sgo));
02276 
02277   nsCOMPtr<nsIWidget> widget;
02278   nsIViewManager* vm = presShell->GetViewManager();
02279   if (vm) {
02280     vm->GetWidget(getter_AddRefs(widget));
02281   }
02282   nsCOMPtr<nsIContent> rootContent;
02283   doc->GetRootContent(getter_AddRefs(rootContent));
02284 
02285   printf("DS %p  Ty %s  Doc %p DW %p EM %p CN %p\n",  
02286     parentAsDocShell.get(), 
02287     type==nsIDocShellTreeItem::typeChrome?"Chr":"Con", 
02288      doc.get(), domwin.get(),
02289      presContext->EventStateManager(), rootContent.get());
02290 
02291   if (childWebshellCount > 0) {
02292     for (PRInt32 i=0;i<childWebshellCount;i++) {
02293       nsCOMPtr<nsIDocShellTreeItem> child;
02294       aParentNode->GetChildAt(i, getter_AddRefs(child));
02295       nsCOMPtr<nsIDocShellTreeNode> childAsNode(do_QueryInterface(child));
02296       PrintDocTree(childAsNode, aLevel+1);
02297     }
02298   }
02299 }
02300 
02301 static void 
02302 PrintDocTree(nsIDocShellTreeNode * aParentNode)
02303 {
02304   NS_ASSERTION(aParentNode, "Pointer is null!");
02305 
02306   nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aParentNode));
02307   nsCOMPtr<nsIDocShellTreeItem> parentItem;
02308   item->GetParent(getter_AddRefs(parentItem));
02309   while (parentItem) {
02310     nsCOMPtr<nsIDocShellTreeItem>tmp;
02311     parentItem->GetParent(getter_AddRefs(tmp));
02312     if (!tmp) {
02313       break;
02314     }
02315     parentItem = tmp;
02316   }
02317 
02318   if (!parentItem) {
02319     parentItem = do_QueryInterface(aParentNode);
02320   }
02321 
02322   if (parentItem) {
02323     nsCOMPtr<nsIDocShellTreeNode> parentAsNode(do_QueryInterface(parentItem));
02324     PrintDocTree(parentAsNode, 0);
02325   }
02326 }
02327 #endif
02328 
02329 NS_IMETHODIMP
02330 nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner)
02331 {
02332 #ifdef DEBUG_DOCSHELL_FOCUS
02333     nsCOMPtr<nsIDocShellTreeNode> node(do_QueryInterface(aTreeOwner));
02334     if (node) {
02335       PrintDocTree(node);
02336     }
02337 #endif
02338 
02339     // Don't automatically set the progress based on the tree owner for frames
02340     if (!IsFrame()) {
02341         nsCOMPtr<nsIWebProgress> webProgress =
02342             do_QueryInterface(GetAsSupports(this));
02343 
02344         if (webProgress) {
02345             nsCOMPtr<nsIWebProgressListener>
02346                 oldListener(do_QueryInterface(mTreeOwner));
02347             nsCOMPtr<nsIWebProgressListener>
02348                 newListener(do_QueryInterface(aTreeOwner));
02349 
02350             if (oldListener) {
02351                 webProgress->RemoveProgressListener(oldListener);
02352             }
02353 
02354             if (newListener) {
02355                 webProgress->AddProgressListener(newListener,
02356                                                  nsIWebProgress::NOTIFY_ALL);
02357             }
02358         }
02359     }
02360 
02361     mTreeOwner = aTreeOwner;    // Weak reference per API
02362 
02363     PRInt32 i, n = mChildList.Count();
02364     for (i = 0; i < n; i++) {
02365         nsCOMPtr<nsIDocShellTreeItem> child = do_QueryInterface(ChildAt(i));
02366         NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
02367         PRInt32 childType = ~mItemType; // Set it to not us in case the get fails
02368         child->GetItemType(&childType); // We don't care if this fails, if it does we won't set the owner
02369         if (childType == mItemType)
02370             child->SetTreeOwner(aTreeOwner);
02371     }
02372 
02373     return NS_OK;
02374 }
02375 
02376 NS_IMETHODIMP
02377 nsDocShell::SetChildOffset(PRInt32 aChildOffset)
02378 {
02379     mChildOffset = aChildOffset;
02380     return NS_OK;
02381 }
02382 
02383 NS_IMETHODIMP
02384 nsDocShell::GetChildOffset(PRInt32 * aChildOffset)
02385 {
02386     NS_ENSURE_ARG_POINTER(aChildOffset);
02387     *aChildOffset = mChildOffset;
02388     return NS_OK;
02389 }
02390 
02391 NS_IMETHODIMP
02392 nsDocShell::GetIsInUnload(PRBool* aIsInUnload)
02393 {
02394     *aIsInUnload = mFiredUnloadEvent;
02395     return NS_OK;
02396 }
02397 
02398 //*****************************************************************************
02399 // nsDocShell::nsIDocShellTreeNode
02400 //*****************************************************************************   
02401 
02402 NS_IMETHODIMP
02403 nsDocShell::GetChildCount(PRInt32 * aChildCount)
02404 {
02405     NS_ENSURE_ARG_POINTER(aChildCount);
02406     *aChildCount = mChildList.Count();
02407     return NS_OK;
02408 }
02409 
02410 
02411 
02412 NS_IMETHODIMP
02413 nsDocShell::AddChild(nsIDocShellTreeItem * aChild)
02414 {
02415     NS_ENSURE_ARG_POINTER(aChild);
02416 
02417     nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
02418     NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
02419 
02420     // Make sure we're not creating a loop in the docshell tree
02421     nsDocLoader* ancestor = this;
02422     do {
02423         if (childAsDocLoader == ancestor) {
02424             return NS_ERROR_ILLEGAL_VALUE;
02425         }
02426         ancestor = ancestor->GetParent();
02427     } while (ancestor);
02428     
02429     // Make sure to remove the child from its current parent.
02430     nsDocLoader* childsParent = childAsDocLoader->GetParent();
02431     if (childsParent) {
02432         childsParent->RemoveChildLoader(childAsDocLoader);
02433     }
02434 
02435     // Make sure to clear the treeowner in case this child is a different type
02436     // from us.
02437     aChild->SetTreeOwner(nsnull);
02438     
02439     nsresult res = AddChildLoader(childAsDocLoader);
02440     NS_ENSURE_SUCCESS(res, res);
02441 
02442     // Set the child's index in the parent's children list 
02443     // XXX What if the parent had different types of children?
02444     // XXX in that case docshell hierarchy and SH hierarchy won't match.
02445     aChild->SetChildOffset(mChildList.Count() - 1);
02446 
02447     /* Set the child's global history if the parent has one */
02448     if (mGlobalHistory) {
02449         nsCOMPtr<nsIDocShellHistory>
02450             dsHistoryChild(do_QueryInterface(aChild));
02451         if (dsHistoryChild)
02452             dsHistoryChild->SetUseGlobalHistory(PR_TRUE);
02453     }
02454 
02455 
02456     PRInt32 childType = ~mItemType;     // Set it to not us in case the get fails
02457     aChild->GetItemType(&childType);
02458     if (childType != mItemType)
02459         return NS_OK;
02460     // Everything below here is only done when the child is the same type.
02461 
02462 
02463     aChild->SetTreeOwner(mTreeOwner);
02464 
02465     nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
02466     if (!childAsDocShell)
02467         return NS_OK;
02468 
02469     // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
02470 
02471     // Now take this document's charset and set the parentCharset field of the 
02472     // child's DocumentCharsetInfo to it. We'll later use that field, in the 
02473     // loading process, for the charset choosing algorithm.
02474     // If we fail, at any point, we just return NS_OK.
02475     // This code has some performance impact. But this will be reduced when 
02476     // the current charset will finally be stored as an Atom, avoiding the
02477     // alias resolution extra look-up.
02478 
02479     // we are NOT going to propagate the charset is this Chrome's docshell
02480     if (mItemType == nsIDocShellTreeItem::typeChrome)
02481         return NS_OK;
02482 
02483     // get the child's docCSInfo object
02484     nsCOMPtr<nsIDocumentCharsetInfo> dcInfo = NULL;
02485     res = childAsDocShell->GetDocumentCharsetInfo(getter_AddRefs(dcInfo));
02486     if (NS_FAILED(res) || (!dcInfo))
02487         return NS_OK;
02488 
02489     // get the parent's current charset
02490     nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(mContentViewer));
02491     if (!docv)
02492         return NS_OK;
02493     nsCOMPtr<nsIDocument> doc;
02494     res = docv->GetDocument(getter_AddRefs(doc));
02495     if (NS_FAILED(res) || (!doc))
02496         return NS_OK;
02497     const nsACString &parentCS = doc->GetDocumentCharacterSet();
02498 
02499     PRBool isWyciwyg = PR_FALSE;
02500 
02501     if (mCurrentURI) {
02502         // Check if the url is wyciwyg
02503         mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);      
02504     }
02505 
02506     if (!isWyciwyg) {
02507         // If this docshell is loaded from a wyciwyg: URI, don't
02508         // advertise our charset since it does not in any way reflect
02509         // the actual source charset, which is what we're trying to
02510         // expose here.
02511 
02512         // set the child's parentCharset
02513         nsCOMPtr<nsIAtom> parentCSAtom(do_GetAtom(parentCS));
02514         res = dcInfo->SetParentCharset(parentCSAtom);
02515         if (NS_FAILED(res))
02516             return NS_OK;
02517 
02518         PRInt32 charsetSource = doc->GetDocumentCharacterSetSource();
02519 
02520         // set the child's parentCharset
02521         res = dcInfo->SetParentCharsetSource(charsetSource);
02522         if (NS_FAILED(res))
02523             return NS_OK;
02524     }
02525 
02526     // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUCS2toASCII(parentCS).get(), mItemType);
02527 
02528     return NS_OK;
02529 }
02530 
02531 NS_IMETHODIMP
02532 nsDocShell::RemoveChild(nsIDocShellTreeItem * aChild)
02533 {
02534     NS_ENSURE_ARG_POINTER(aChild);
02535 
02536     nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
02537     NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
02538     
02539     nsresult rv = RemoveChildLoader(childAsDocLoader);
02540     NS_ENSURE_SUCCESS(rv, rv);
02541     
02542     aChild->SetTreeOwner(nsnull);
02543 
02544     return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
02545 }
02546 
02547 NS_IMETHODIMP
02548 nsDocShell::GetChildAt(PRInt32 aIndex, nsIDocShellTreeItem ** aChild)
02549 {
02550     NS_ENSURE_ARG_POINTER(aChild);
02551 
02552     NS_WARN_IF_FALSE(aIndex >=0 && aIndex < mChildList.Count(),
02553                      "index of child element is out of range!");
02554 
02555     nsIDocumentLoader* child = SafeChildAt(aIndex);
02556     NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
02557     
02558     return CallQueryInterface(child, aChild);
02559 }
02560 
02561 NS_IMETHODIMP
02562 nsDocShell::FindChildWithName(const PRUnichar * aName,
02563                               PRBool aRecurse, PRBool aSameType,
02564                               nsIDocShellTreeItem * aRequestor,
02565                               nsIDocShellTreeItem * aOriginalRequestor,
02566                               nsIDocShellTreeItem ** _retval)
02567 {
02568     NS_ENSURE_ARG(aName);
02569     NS_ENSURE_ARG_POINTER(_retval);
02570 
02571     *_retval = nsnull;          // if we don't find one, we return NS_OK and a null result 
02572 
02573     if (!*aName)
02574         return NS_OK;
02575 
02576     nsXPIDLString childName;
02577     PRInt32 i, n = mChildList.Count();
02578     for (i = 0; i < n; i++) {
02579         nsCOMPtr<nsIDocShellTreeItem> child = do_QueryInterface(ChildAt(i));
02580         NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
02581         PRInt32 childType;
02582         child->GetItemType(&childType);
02583 
02584         if (aSameType && (childType != mItemType))
02585             continue;
02586 
02587         PRBool childNameEquals = PR_FALSE;
02588         child->NameEquals(aName, &childNameEquals);
02589         if (childNameEquals && ItemIsActive(child) &&
02590             CanAccessItem(child, aOriginalRequestor)) {
02591             child.swap(*_retval);
02592             break;
02593         }
02594 
02595         if (childType != mItemType)     //Only ask it to check children if it is same type
02596             continue;
02597 
02598         if (aRecurse && (aRequestor != child))  // Only ask the child if it isn't the requestor
02599         {
02600             // See if child contains the shell with the given name
02601             nsCOMPtr<nsIDocShellTreeNode>
02602                 childAsNode(do_QueryInterface(child));
02603             if (childAsNode) {
02604 #ifdef DEBUG
02605                 nsresult rv =
02606 #endif
02607                 childAsNode->FindChildWithName(aName, PR_TRUE,
02608                                                aSameType,
02609                                                NS_STATIC_CAST(nsIDocShellTreeItem*,
02610                                                               this),
02611                                                aOriginalRequestor,
02612                                                _retval);
02613                 NS_ASSERTION(NS_SUCCEEDED(rv),
02614                              "FindChildWithName should not fail here");
02615                 if (*_retval)           // found it
02616                     return NS_OK;
02617             }
02618         }
02619     }
02620     return NS_OK;
02621 }
02622 
02623 //*****************************************************************************
02624 // nsDocShell::nsIDocShellHistory
02625 //*****************************************************************************   
02626 NS_IMETHODIMP
02627 nsDocShell::GetChildSHEntry(PRInt32 aChildOffset, nsISHEntry ** aResult)
02628 {
02629     nsresult rv = NS_OK;
02630 
02631     NS_ENSURE_ARG_POINTER(aResult);
02632     *aResult = nsnull;
02633 
02634     
02635     // A nsISHEntry for a child is *only* available when the parent is in
02636     // the progress of loading a document too...
02637     
02638     if (mLSHE) {
02639         /* Before looking for the subframe's url, check
02640          * the expiration status of the parent. If the parent
02641          * has expired from cache, then subframes will not be 
02642          * loaded from history in certain situations.  
02643          */
02644         PRBool parentExpired=PR_FALSE;
02645         mLSHE->GetExpirationStatus(&parentExpired);
02646         
02647         /* Get the parent's Load Type so that it can be set on the child too.
02648          * By default give a loadHistory value
02649          */
02650         PRUint32 loadType = nsIDocShellLoadInfo::loadHistory;
02651         mLSHE->GetLoadType(&loadType);  
02652         // If the user did a shift-reload on this frameset page, 
02653         // we don't want to load the subframes from history.         
02654         if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache ||
02655             loadType == nsIDocShellLoadInfo::loadReloadBypassProxy ||
02656             loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache ||
02657             loadType == nsIDocShellLoadInfo::loadRefresh)
02658             return rv;
02659         
02660         /* If the user pressed reload and the parent frame has expired
02661          *  from cache, we do not want to load the child frame from history.
02662          */
02663         if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) {
02664             // The parent has expired. Return null.
02665             *aResult = nsnull;
02666             return rv;
02667         }
02668 
02669         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE));
02670         if (container) {
02671             // Get the child subframe from session history.
02672             rv = container->GetChildAt(aChildOffset, aResult);            
02673             if (*aResult) 
02674                 (*aResult)->SetLoadType(loadType);            
02675         }
02676     }
02677     return rv;
02678 }
02679 
02680 NS_IMETHODIMP
02681 nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
02682                             PRInt32 aChildOffset)
02683 {
02684     nsresult rv;
02685 
02686     if (mLSHE) {
02687         /* You get here if you are currently building a 
02688          * hierarchy ie.,you just visited a frameset page
02689          */
02690         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
02691         if (container) {
02692             rv = container->AddChild(aNewEntry, aChildOffset);
02693         }
02694     }
02695     else if (!aCloneRef) {
02696         /* This is an initial load in some subframe.  Just append it if we can */
02697         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv));
02698         if (container) {
02699             rv = container->AddChild(aNewEntry, aChildOffset);
02700         }
02701     }
02702     else if (mSessionHistory) {
02703         /* You are currently in the rootDocShell.
02704          * You will get here when a subframe has a new url
02705          * to load and you have walked up the tree all the 
02706          * way to the top to clone the current SHEntry hierarchy
02707          * and replace the subframe where a new url was loaded with
02708          * a new entry.
02709          */
02710         PRInt32 index = -1;
02711         nsCOMPtr<nsIHistoryEntry> currentHE;
02712         mSessionHistory->GetIndex(&index);
02713         if (index < 0)
02714             return NS_ERROR_FAILURE;
02715 
02716         rv = mSessionHistory->GetEntryAtIndex(index, PR_FALSE,
02717                                               getter_AddRefs(currentHE));
02718         NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
02719 
02720         nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE));
02721         if (currentEntry) {
02722             PRUint32 cloneID = 0;
02723             nsCOMPtr<nsISHEntry> nextEntry;
02724             aCloneRef->GetID(&cloneID);
02725             rv = CloneAndReplace(currentEntry, this, cloneID, aNewEntry,
02726                                  getter_AddRefs(nextEntry));
02727 
02728             if (NS_SUCCEEDED(rv)) {
02729                 nsCOMPtr<nsISHistoryInternal>
02730                     shPrivate(do_QueryInterface(mSessionHistory));
02731                 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
02732                 rv = shPrivate->AddEntry(nextEntry, PR_TRUE);
02733             }
02734         }
02735     }
02736     else {
02737         /* Just pass this along */
02738         nsCOMPtr<nsIDocShellHistory> parent =
02739             do_QueryInterface(GetAsSupports(mParent), &rv);
02740         if (parent) {
02741             rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset);
02742         }          
02743     }
02744     return rv;
02745 }
02746 
02747 nsresult
02748 nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, PRInt32 aChildOffset)
02749 {
02750     /* You will get here when you are in a subframe and
02751      * a new url has been loaded on you. 
02752      * The mOSHE in this subframe will be the previous url's
02753      * mOSHE. This mOSHE will be used as the identification
02754      * for this subframe in the  CloneAndReplace function.
02755      */
02756 
02757     // In this case, we will end up calling AddEntry, which increases the
02758     // current index by 1
02759     nsCOMPtr<nsISHistory> rootSH;
02760     GetRootSessionHistory(getter_AddRefs(rootSH));
02761     if (rootSH) {
02762         rootSH->GetIndex(&mPreviousTransIndex);
02763     }
02764 
02765     nsresult rv;
02766     nsCOMPtr<nsIDocShellHistory> parent =
02767         do_QueryInterface(GetAsSupports(mParent), &rv);
02768     if (parent) {
02769         rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset);
02770     }
02771 
02772 
02773     if (rootSH) {
02774         rootSH->GetIndex(&mLoadedTransIndex);
02775 #ifdef DEBUG_PAGE_CACHE
02776         printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
02777                mLoadedTransIndex);
02778 #endif
02779     }
02780 
02781     return rv;
02782 }
02783 
02784 NS_IMETHODIMP
02785 nsDocShell::SetUseGlobalHistory(PRBool aUseGlobalHistory)
02786 {
02787     nsresult rv;
02788 
02789     if (!aUseGlobalHistory) {
02790         mGlobalHistory = nsnull;
02791         return NS_OK;
02792     }
02793 
02794     if (mGlobalHistory) {
02795         return NS_OK;
02796     }
02797 
02798     mGlobalHistory = do_GetService(NS_GLOBALHISTORY2_CONTRACTID, &rv);
02799     return rv;
02800 }
02801 
02802 NS_IMETHODIMP
02803 nsDocShell::GetUseGlobalHistory(PRBool *aUseGlobalHistory)
02804 {
02805     *aUseGlobalHistory = (mGlobalHistory != nsnull);
02806     return NS_OK;
02807 }
02808 
02809 //-------------------------------------
02810 //-- Helper Method for Print discovery
02811 //-------------------------------------
02812 PRBool 
02813 nsDocShell::IsPrintingOrPP(PRBool aDisplayErrorDialog)
02814 {
02815   if (mIsPrintingOrPP && aDisplayErrorDialog) {
02816     DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nsnull, nsnull);
02817   }
02818 
02819   return mIsPrintingOrPP;
02820 }
02821 
02822 PRBool
02823 nsDocShell::IsNavigationAllowed(PRBool aDisplayPrintErrorDialog)
02824 {
02825     return !IsPrintingOrPP(aDisplayPrintErrorDialog) && !mFiredUnloadEvent;
02826 }
02827 
02828 //*****************************************************************************
02829 // nsDocShell::nsIWebNavigation
02830 //*****************************************************************************   
02831 
02832 NS_IMETHODIMP
02833 nsDocShell::GetCanGoBack(PRBool * aCanGoBack)
02834 {
02835     if (!IsNavigationAllowed(PR_FALSE)) {
02836       *aCanGoBack = PR_FALSE;
02837       return NS_OK; // JS may not handle returning of an error code
02838     }
02839     nsresult rv;
02840     nsCOMPtr<nsISHistory> rootSH;
02841     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
02842     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
02843     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
02844     rv = webnav->GetCanGoBack(aCanGoBack);   
02845     return rv;
02846 
02847 }
02848 
02849 NS_IMETHODIMP
02850 nsDocShell::GetCanGoForward(PRBool * aCanGoForward)
02851 {
02852     if (!IsNavigationAllowed(PR_FALSE)) {
02853       *aCanGoForward = PR_FALSE;
02854       return NS_OK; // JS may not handle returning of an error code
02855     }
02856     nsresult rv;
02857     nsCOMPtr<nsISHistory> rootSH;
02858     rv = GetRootSessionHistory(getter_AddRefs(rootSH)); 
02859     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
02860     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
02861     rv = webnav->GetCanGoForward(aCanGoForward);
02862     return rv;
02863 
02864 }
02865 
02866 NS_IMETHODIMP
02867 nsDocShell::GoBack()
02868 {
02869     if (!IsNavigationAllowed()) {
02870       return NS_OK; // JS may not handle returning of an error code
02871     }
02872     nsresult rv;
02873     nsCOMPtr<nsISHistory> rootSH;
02874     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
02875     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
02876     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
02877     rv = webnav->GoBack();
02878     return rv;
02879 
02880 }
02881 
02882 NS_IMETHODIMP
02883 nsDocShell::GoForward()
02884 {
02885     if (!IsNavigationAllowed()) {
02886       return NS_OK; // JS may not handle returning of an error code
02887     }
02888     nsresult rv;
02889     nsCOMPtr<nsISHistory> rootSH;
02890     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
02891     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
02892     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
02893     rv = webnav->GoForward();
02894     return rv;
02895 
02896 }
02897 
02898 NS_IMETHODIMP nsDocShell::GotoIndex(PRInt32 aIndex)
02899 {
02900     if (!IsNavigationAllowed()) {
02901       return NS_OK; // JS may not handle returning of an error code
02902     }
02903     nsresult rv;
02904     nsCOMPtr<nsISHistory> rootSH;
02905     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
02906     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
02907     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
02908     rv = webnav->GotoIndex(aIndex);
02909     return rv;
02910 
02911 }
02912 
02913 
02914 NS_IMETHODIMP
02915 nsDocShell::LoadURI(const PRUnichar * aURI,
02916                     PRUint32 aLoadFlags,
02917                     nsIURI * aReferringURI,
02918                     nsIInputStream * aPostStream,
02919                     nsIInputStream * aHeaderStream)
02920 {
02921     if (!IsNavigationAllowed()) {
02922       return NS_OK; // JS may not handle returning of an error code
02923     }
02924     nsCOMPtr<nsIURI> uri;
02925     nsresult rv = NS_OK;
02926 
02927     // Create a URI from our string; if that succeeds, we want to
02928     // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
02929     // flag.
02930 
02931     NS_ConvertUTF16toUTF8 uriString(aURI);
02932     // Cleanup the empty spaces that might be on each end.
02933     uriString.Trim(" ");
02934     // Eliminate embedded newlines, which single-line text fields now allow:
02935     uriString.StripChars("\r\n");
02936     NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
02937 
02938     rv = NS_NewURI(getter_AddRefs(uri), uriString);
02939     if (uri) {
02940         aLoadFlags = aLoadFlags & ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
02941     }
02942     
02943     if (sURIFixup) {
02944         // Call the fixup object.  This will clobber the rv from NS_NewURI
02945         // above, but that's fine with us.  Note that we need to do this even
02946         // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
02947         // (things like view-source:mozilla.org for example).
02948         PRUint32 fixupFlags = 0;
02949         if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
02950           fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
02951         }
02952         rv = sURIFixup->CreateFixupURI(uriString, fixupFlags,
02953                                        getter_AddRefs(uri));
02954     }
02955     // else no fixup service so just use the URI we created and see
02956     // what happens
02957 
02958     if (NS_ERROR_MALFORMED_URI == rv) {
02959         DisplayLoadError(rv, uri, aURI);
02960     }
02961 
02962     if (NS_FAILED(rv) || !uri)
02963         return NS_ERROR_FAILURE;
02964 
02965     nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
02966     rv = CreateLoadInfo(getter_AddRefs(loadInfo));
02967     if (NS_FAILED(rv)) return rv;
02968     
02969     PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags); 
02970     loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType));
02971     loadInfo->SetPostDataStream(aPostStream);
02972     loadInfo->SetReferrer(aReferringURI);
02973     loadInfo->SetHeadersStream(aHeaderStream);
02974 
02975     rv = LoadURI(uri, loadInfo,
02976                  aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP, PR_TRUE);
02977     
02978     return rv;
02979 }
02980 
02981 NS_IMETHODIMP
02982 nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
02983                              const PRUnichar *aURL,
02984                              nsIChannel* aFailedChannel)
02985 {
02986     // Get prompt and string bundle servcies
02987     nsCOMPtr<nsIPrompt> prompter;
02988     nsCOMPtr<nsIStringBundle> stringBundle;
02989     GetPromptAndStringBundle(getter_AddRefs(prompter),
02990                              getter_AddRefs(stringBundle));
02991 
02992     NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
02993     NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
02994 
02995     nsAutoString error;
02996     const PRUint32 kMaxFormatStrArgs = 2;
02997     nsAutoString formatStrs[kMaxFormatStrArgs];
02998     PRUint32 formatStrCount = 0;
02999     nsresult rv = NS_OK;
03000 
03001     // Turn the error code into a human readable error message.
03002     if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
03003         NS_ENSURE_ARG_POINTER(aURI);
03004         // extract the scheme
03005         nsCAutoString scheme;
03006         aURI->GetScheme(scheme);
03007         CopyASCIItoUCS2(scheme, formatStrs[0]);
03008         formatStrCount = 1;
03009         error.AssignLiteral("protocolNotFound");
03010     }
03011     else if (NS_ERROR_FILE_NOT_FOUND == aError) {
03012         NS_ENSURE_ARG_POINTER(aURI);
03013         nsCAutoString spec;
03014         aURI->GetPath(spec);
03015         nsCAutoString charset;
03016         // unescape and convert from origin charset
03017         aURI->GetOriginCharset(charset);
03018         nsCOMPtr<nsITextToSubURI> textToSubURI(
03019                 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
03020         if (NS_SUCCEEDED(rv))
03021             // UnEscapeURIForUI always succeeds 
03022             textToSubURI->UnEscapeURIForUI(charset, spec, formatStrs[0]);
03023         else 
03024             CopyUTF8toUTF16(spec, formatStrs[0]);
03025         rv = NS_OK;
03026         formatStrCount = 1;
03027         error.AssignLiteral("fileNotFound");
03028     }
03029     else if (NS_ERROR_UNKNOWN_HOST == aError) {
03030         NS_ENSURE_ARG_POINTER(aURI);
03031         // Get the host
03032         nsCAutoString host;
03033         aURI->GetHost(host);
03034         CopyUTF8toUTF16(host, formatStrs[0]);
03035         formatStrCount = 1;
03036         error.AssignLiteral("dnsNotFound");
03037     }
03038     else if(NS_ERROR_CONNECTION_REFUSED == aError) {
03039         NS_ENSURE_ARG_POINTER(aURI);
03040         // Build up the host:port string.
03041         nsCAutoString hostport;
03042         aURI->GetHostPort(hostport);
03043         CopyUTF8toUTF16(hostport, formatStrs[0]);
03044         formatStrCount = 1;
03045         error.AssignLiteral("connectionFailure");
03046     }
03047     else if(NS_ERROR_NET_INTERRUPT == aError) {
03048         NS_ENSURE_ARG_POINTER(aURI);
03049         // Build up the host:port string.
03050         nsCAutoString hostport;
03051         aURI->GetHostPort(hostport);
03052         CopyUTF8toUTF16(hostport, formatStrs[0]);
03053         formatStrCount = 1;
03054         error.AssignLiteral("netInterrupt");
03055     }
03056     else if (NS_ERROR_NET_TIMEOUT == aError) {
03057         NS_ENSURE_ARG_POINTER(aURI);
03058         // Get the host
03059         nsCAutoString host;
03060         aURI->GetHost(host);
03061         CopyUTF8toUTF16(host, formatStrs[0]);
03062         formatStrCount = 1;
03063         error.AssignLiteral("netTimeout");
03064     }
03065     else {
03066         // Errors requiring simple formatting
03067         switch (aError) {
03068         case NS_ERROR_MALFORMED_URI:
03069             // URI is malformed
03070             error.AssignLiteral("malformedURI");
03071             break;
03072         case NS_ERROR_REDIRECT_LOOP:
03073             // Doc failed to load because the server generated too many redirects
03074             error.AssignLiteral("redirectLoop");
03075             break;
03076         case NS_ERROR_UNKNOWN_SOCKET_TYPE:
03077             // Doc failed to load because PSM is not installed
03078             error.AssignLiteral("unknownSocketType");
03079             break;
03080         case NS_ERROR_NET_RESET:
03081             // Doc failed to load because the server kept reseting the connection
03082             // before we could read any data from it
03083             error.AssignLiteral("netReset");
03084             break;
03085         case NS_ERROR_DOCUMENT_NOT_CACHED:
03086             // Doc falied to load because we are offline and the cache does not
03087             // contain a copy of the document.
03088             error.AssignLiteral("netOffline");
03089             break;
03090         case NS_ERROR_DOCUMENT_IS_PRINTMODE:
03091             // Doc navigation attempted while Printing or Print Preview
03092             error.AssignLiteral("isprinting");
03093             break;
03094         case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
03095             // Port blocked for security reasons
03096             error.AssignLiteral("deniedPortAccess");
03097             break;
03098         case NS_ERROR_UNKNOWN_PROXY_HOST:
03099             // Proxy hostname could not be resolved.
03100             error.AssignLiteral("proxyResolveFailure");
03101             break;
03102         case NS_ERROR_PROXY_CONNECTION_REFUSED:
03103             // Proxy connection was refused.
03104             error.AssignLiteral("proxyConnectFailure");
03105             break;
03106         case NS_ERROR_UNSAFE_CONTENT_TYPE:
03107             // XXX: We can't add new strings on the branch, abuse
03108             // malformedURI
03109             error.AssignLiteral("malformedURI");
03110             break;
03111         }
03112     }
03113 
03114     // Test if the error should be displayed
03115     if (error.IsEmpty()) {
03116         return NS_OK;
03117     }
03118 
03119     // Test if the error needs to be formatted
03120     nsAutoString messageStr;
03121     if (formatStrCount > 0) {
03122         const PRUnichar *strs[kMaxFormatStrArgs];
03123         for (PRUint32 i = 0; i < formatStrCount; i++) {
03124             strs[i] = formatStrs[i].get();
03125         }
03126         nsXPIDLString str;
03127         rv = stringBundle->FormatStringFromName(
03128             error.get(),
03129             strs, formatStrCount, getter_Copies(str));
03130         NS_ENSURE_SUCCESS(rv, rv);
03131         messageStr.Assign(str.get());
03132     }
03133     else
03134     {
03135         nsXPIDLString str;
03136         rv = stringBundle->GetStringFromName(
03137                 error.get(),
03138                 getter_Copies(str));
03139         NS_ENSURE_SUCCESS(rv, rv);
03140         messageStr.Assign(str.get());
03141     }
03142 
03143     // Display the error as a page or an alert prompt
03144     NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
03145     // Note: For now, display an alert instead of an error page if we have no
03146     // URI object. Missing URI objects are handled badly by session history.
03147     if (mUseErrorPages && aURI && aFailedChannel) {
03148         // Display an error page
03149         LoadErrorPage(aURI, aURL, error.get(), messageStr.get(),
03150                       aFailedChannel);
03151     } 
03152     else
03153     {
03154         // Display a message box
03155         prompter->Alert(nsnull, messageStr.get());
03156     }
03157 
03158     return NS_OK;
03159 }
03160 
03161 
03162 NS_IMETHODIMP
03163 nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
03164                           const PRUnichar *aErrorType,
03165                           const PRUnichar *aDescription,
03166                           nsIChannel* aFailedChannel)
03167 {
03168 #if defined(PR_LOGGING) && defined(DEBUG)
03169     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
03170         nsCAutoString spec;
03171         aURI->GetSpec(spec);
03172 
03173         nsCAutoString chanName;
03174         if (aFailedChannel)
03175             aFailedChannel->GetName(chanName);
03176         else
03177             chanName.AssignLiteral("<no channel>");
03178 
03179         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
03180                ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
03181                 spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
03182     }
03183 #endif
03184     // Create an shistory entry for the old load, if we have a channel
03185     if (aFailedChannel) {
03186         mURIResultedInDocument = PR_TRUE;
03187         OnLoadingSite(aFailedChannel, PR_TRUE, PR_FALSE);
03188     } else if (aURI) {
03189         mURIResultedInDocument = PR_TRUE;
03190         OnNewURI(aURI, nsnull, mLoadType, PR_TRUE, PR_FALSE);
03191     }
03192 
03193     nsCAutoString url;
03194     nsCAutoString charset;
03195     if (aURI)
03196     {
03197         // Set our current URI
03198         SetCurrentURI(aURI);
03199 
03200         nsresult rv = aURI->GetSpec(url);
03201         rv |= aURI->GetOriginCharset(charset);
03202         NS_ENSURE_SUCCESS(rv, rv);
03203     }
03204     else if (aURL)
03205     {
03206         CopyUTF16toUTF8(aURL, url);
03207     }
03208     else
03209     {
03210         return NS_ERROR_INVALID_POINTER;
03211     }
03212 
03213     // Create a URL to pass all the error information through to the page.
03214 
03215     char *escapedUrl = nsEscape(url.get(), url_Path);
03216     char *escapedCharset = nsEscape(charset.get(), url_Path);
03217     char *escapedError = nsEscape(NS_ConvertUTF16toUTF8(aErrorType).get(), url_Path);
03218     char *escapedDescription = nsEscape(NS_ConvertUTF16toUTF8(aDescription).get(), url_Path);
03219 
03220     nsCString errorPageUrl("about:neterror?e=");
03221 
03222     errorPageUrl.AppendASCII(escapedError);
03223     errorPageUrl.AppendLiteral("&u=");
03224     errorPageUrl.AppendASCII(escapedUrl);
03225     errorPageUrl.AppendLiteral("&c=");
03226     errorPageUrl.AppendASCII(escapedCharset);
03227     errorPageUrl.AppendLiteral("&d=");
03228     errorPageUrl.AppendASCII(escapedDescription);
03229 
03230     nsMemory::Free(escapedDescription);
03231     nsMemory::Free(escapedError);
03232     nsMemory::Free(escapedUrl);
03233     nsMemory::Free(escapedCharset);
03234 
03235     nsCOMPtr<nsIURI> errorPageURI;
03236     nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
03237     NS_ENSURE_SUCCESS(rv, rv);
03238 
03239     return InternalLoad(errorPageURI, nsnull, nsnull, PR_TRUE, nsnull, nsnull,
03240                         nsnull, nsnull, LOAD_ERROR_PAGE,
03241                         nsnull, PR_TRUE, nsnull, nsnull);
03242 }
03243 
03244 
03245 NS_IMETHODIMP
03246 nsDocShell::Reload(PRUint32 aReloadFlags)
03247 {
03248     if (!IsNavigationAllowed()) {
03249       return NS_OK; // JS may not handle returning of an error code
03250     }
03251     nsresult rv;
03252     NS_ASSERTION(((aReloadFlags & 0xf) == 0),
03253                  "Reload command not updated to use load flags!");
03254 
03255     // XXXTAB Convert reload type to our type
03256     LoadType type = LOAD_RELOAD_NORMAL;
03257     if (aReloadFlags & LOAD_FLAGS_BYPASS_CACHE &&
03258         aReloadFlags & LOAD_FLAGS_BYPASS_PROXY)
03259         type = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
03260     else if (aReloadFlags & LOAD_FLAGS_CHARSET_CHANGE)
03261         type = LOAD_RELOAD_CHARSET_CHANGE;
03262     // Send notifications to the HistoryListener if any, about the impending reload
03263     nsCOMPtr<nsISHistory> rootSH;
03264     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
03265     nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH));
03266     PRBool canReload = PR_TRUE; 
03267     if (rootSH) {
03268       nsCOMPtr<nsISHistoryListener> listener;
03269       shistInt->GetListener(getter_AddRefs(listener));
03270       if (listener) {
03271         listener->OnHistoryReload(mCurrentURI, aReloadFlags, &canReload);
03272       }
03273     }
03274 
03275     if (!canReload)
03276       return NS_OK;
03277     
03278     /* If you change this part of code, make sure bug 45297 does not re-occur */
03279     if (mOSHE) {
03280         rv = LoadHistoryEntry(mOSHE, type);
03281     }
03282     else if (mLSHE) { // In case a reload happened before the current load is done
03283         rv = LoadHistoryEntry(mLSHE, type);
03284     }
03285     else {
03286         nsCOMPtr<nsIDOMDocument> domDoc(do_GetInterface(GetAsSupports(this)));
03287         nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
03288 
03289         nsIPrincipal* principal = nsnull;
03290         nsAutoString contentTypeHint;
03291         if (doc) {
03292             principal = doc->GetPrincipal();
03293             doc->GetContentType(contentTypeHint);
03294         }
03295 
03296         rv = InternalLoad(mCurrentURI,
03297                           mReferrerURI,
03298                           principal,
03299                           INTERNAL_LOAD_FLAGS_NONE, // Do not inherit owner from document
03300                           nsnull,         // No window target
03301                           NS_LossyConvertUCS2toASCII(contentTypeHint).get(),
03302                           nsnull,         // No post data
03303                           nsnull,         // No headers data
03304                           type,           // Load type
03305                           nsnull,         // No SHEntry
03306                           PR_TRUE,
03307                           nsnull,         // No nsIDocShell
03308                           nsnull);        // No nsIRequest
03309     }
03310     
03311     return rv;
03312 }
03313 
03314 NS_IMETHODIMP
03315 nsDocShell::Stop(PRUint32 aStopFlags)
03316 {
03317     if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
03318         // Revoke any pending plevents related to content viewer restoration
03319         nsCOMPtr<nsIEventQueue> uiThreadQueue;
03320         NS_GetMainEventQ(getter_AddRefs(uiThreadQueue));
03321         if (uiThreadQueue)
03322             uiThreadQueue->RevokeEvents(this);
03323 
03324         // Stop the document loading
03325         if (mContentViewer)
03326             mContentViewer->Stop();
03327     }
03328 
03329     if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
03330         // Suspend any timers that were set for this loader.  We'll clear
03331         // them out for good in CreateContentViewer.
03332         if (mRefreshURIList) {
03333             SuspendRefreshURIs();
03334             mSavedRefreshURIList.swap(mRefreshURIList);
03335             mRefreshURIList = nsnull;
03336         }
03337 
03338         // XXXbz We could also pass |this| to nsIURILoader::Stop.  That will
03339         // just call Stop() on us as an nsIDocumentLoader... We need fewer
03340         // redundant apis!
03341         Stop();
03342     }
03343 
03344     PRInt32 n;
03345     PRInt32 count = mChildList.Count();
03346     for (n = 0; n < count; n++) {
03347         nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryInterface(ChildAt(n)));
03348         if (shellAsNav)
03349             shellAsNav->Stop(aStopFlags);
03350     }
03351 
03352     return NS_OK;
03353 }
03354 
03355 /*
03356 NS_IMETHODIMP nsDocShell::SetDocument(nsIDOMDocument* aDocument,
03357    const PRUnichar* aContentType)
03358 {
03359    //XXX First Checkin
03360    NS_ERROR("Not Yet Implemented");
03361    return NS_ERROR_FAILURE;
03362 }
03363 */
03364 
03365 NS_IMETHODIMP
03366 nsDocShell::GetDocument(nsIDOMDocument ** aDocument)
03367 {
03368     NS_ENSURE_ARG_POINTER(aDocument);
03369     NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
03370 
03371     return mContentViewer->GetDOMDocument(aDocument);
03372 }
03373 
03374 NS_IMETHODIMP
03375 nsDocShell::GetCurrentURI(nsIURI ** aURI)
03376 {
03377     NS_ENSURE_ARG_POINTER(aURI);
03378 
03379     *aURI = mCurrentURI;
03380     NS_IF_ADDREF(*aURI);
03381 
03382     return NS_OK;
03383 }
03384 
03385 NS_IMETHODIMP
03386 nsDocShell::GetReferringURI(nsIURI ** aURI)
03387 {
03388     NS_ENSURE_ARG_POINTER(aURI);
03389 
03390     *aURI = mReferrerURI;
03391     NS_IF_ADDREF(*aURI);
03392 
03393     return NS_OK;
03394 }
03395 
03396 NS_IMETHODIMP
03397 nsDocShell::SetSessionHistory(nsISHistory * aSessionHistory)
03398 {
03399 
03400     NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE);
03401     // make sure that we are the root docshell and
03402     // set a handle to root docshell in SH.
03403 
03404     nsCOMPtr<nsIDocShellTreeItem> root;
03405     /* Get the root docshell. If *this* is the root docshell
03406      * then save a handle to *this* in SH. SH needs it to do
03407      * traversions thro' its entries
03408      */
03409     GetSameTypeRootTreeItem(getter_AddRefs(root));
03410     NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
03411     if (root.get() == NS_STATIC_CAST(nsIDocShellTreeItem *, this)) {
03412         mSessionHistory = aSessionHistory;
03413         nsCOMPtr<nsISHistoryInternal>
03414             shPrivate(do_QueryInterface(mSessionHistory));
03415         NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
03416         shPrivate->SetRootDocShell(this);
03417         return NS_OK;
03418     }
03419     return NS_ERROR_FAILURE;
03420 
03421 }
03422 
03423 
03424 NS_IMETHODIMP
03425 nsDocShell::GetSessionHistory(nsISHistory ** aSessionHistory)
03426 {
03427     NS_ENSURE_ARG_POINTER(aSessionHistory);
03428     *aSessionHistory = mSessionHistory;
03429     NS_IF_ADDREF(*aSessionHistory);
03430     return NS_OK;
03431 }
03432 
03433 //*****************************************************************************
03434 // nsDocShell::nsIWebPageDescriptor
03435 //*****************************************************************************   
03436 NS_IMETHODIMP
03437 nsDocShell::LoadPage(nsISupports *aPageDescriptor, PRUint32 aDisplayType)
03438 {
03439     nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor));
03440 
03441     // Currently, the opaque 'page descriptor' is an nsISHEntry...
03442     if (!shEntryIn) {
03443         return NS_ERROR_INVALID_POINTER;
03444     }
03445 
03446     // Now clone shEntryIn, since we might end up modifying it later on, and we
03447     // want a page descriptor to be reusable.
03448     nsCOMPtr<nsISHEntry> shEntry;
03449     nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
03450     NS_ENSURE_SUCCESS(rv, rv);
03451     
03452     //
03453     // load the page as view-source
03454     //
03455     if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) {
03456         nsCOMPtr<nsIURI> oldUri, newUri;
03457         nsCString spec, newSpec;
03458 
03459         // Create a new view-source URI and replace the original.
03460         rv = shEntry->GetURI(getter_AddRefs(oldUri));
03461         if (NS_FAILED(rv))
03462               return rv;
03463 
03464         oldUri->GetSpec(spec);
03465         newSpec.AppendLiteral("view-source:");
03466         newSpec.Append(spec);
03467 
03468         rv = NS_NewURI(getter_AddRefs(newUri), newSpec);
03469         if (NS_FAILED(rv)) {
03470             return rv;
03471         }
03472         shEntry->SetURI(newUri);
03473     }
03474 
03475     rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
03476     return rv;
03477 }
03478 
03479 NS_IMETHODIMP
03480 nsDocShell::GetCurrentDescriptor(nsISupports **aPageDescriptor)
03481 {
03482     NS_PRECONDITION(aPageDescriptor, "Null out param?");
03483 
03484     *aPageDescriptor = nsnull;
03485 
03486     nsISHEntry* src = mOSHE ? mOSHE : mLSHE;
03487     if (src) {
03488         nsCOMPtr<nsISHEntry> dest;
03489 
03490         nsresult rv = src->Clone(getter_AddRefs(dest));
03491         if (NS_FAILED(rv)) {
03492             return rv;
03493         }
03494 
03495         // null out inappropriate cloned attributes...
03496         dest->SetParent(nsnull);
03497         dest->SetIsSubFrame(PR_FALSE);
03498         
03499         return CallQueryInterface(dest, aPageDescriptor);
03500     }
03501 
03502     return NS_ERROR_NOT_AVAILABLE;
03503 }
03504 
03505 
03506 //*****************************************************************************
03507 // nsDocShell::nsIBaseWindow
03508 //*****************************************************************************   
03509 
03510 NS_IMETHODIMP
03511 nsDocShell::InitWindow(nativeWindow parentNativeWindow,
03512                        nsIWidget * parentWidget, PRInt32 x, PRInt32 y,
03513                        PRInt32 cx, PRInt32 cy)
03514 {
03515     NS_ENSURE_ARG(parentWidget);        // DocShells must get a widget for a parent
03516 
03517     SetParentWidget(parentWidget);
03518     SetPositionAndSize(x, y, cx, cy, PR_FALSE);
03519 
03520     return NS_OK;
03521 }
03522 
03523 NS_IMETHODIMP
03524 nsDocShell::Create()
03525 {
03526     NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
03527                  "Unexpected item type in docshell");
03528 
03529     nsresult rv = NS_ERROR_FAILURE;
03530     mPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
03531     NS_ENSURE_SUCCESS(rv, rv);
03532 
03533     PRBool tmpbool;
03534 
03535     rv = mPrefs->GetBoolPref("browser.frames.enabled", &tmpbool);
03536     if (NS_SUCCEEDED(rv))
03537         mAllowSubframes = tmpbool;
03538 
03539     if (gValidateOrigin == (PRBool)0xffffffff) {
03540         // Check pref to see if we should prevent frameset spoofing
03541         rv = mPrefs->GetBoolPref("browser.frame.validate_origin", &tmpbool);
03542         if (NS_SUCCEEDED(rv)) {
03543             gValidateOrigin = tmpbool;
03544         } else {
03545             gValidateOrigin = PR_TRUE;
03546         }
03547     }
03548 
03549     // Should we use XUL error pages instead of alerts if possible?
03550     rv = mPrefs->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool);
03551     if (NS_SUCCEEDED(rv))
03552         mUseErrorPages = tmpbool;
03553 
03554     nsCOMPtr<nsIObserverService> serv = do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
03555     if (serv) {
03556         const char* msg = mItemType == typeContent ?
03557             NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE;
03558         serv->NotifyObservers(GetAsSupports(this), msg, nsnull);
03559     }    
03560 
03561     return NS_OK;
03562 }
03563 
03564 NS_IMETHODIMP
03565 nsDocShell::Destroy()
03566 {
03567     NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
03568                  "Unexpected item type in docshell");
03569 
03570     if (!mIsBeingDestroyed) {
03571         nsCOMPtr<nsIObserverService> serv =
03572             do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
03573         if (serv) {
03574             const char* msg = mItemType == typeContent ?
03575                 NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
03576             serv->NotifyObservers(GetAsSupports(this), msg, nsnull);
03577         }
03578     }
03579     
03580     mIsBeingDestroyed = PR_TRUE;
03581 
03582     //Fire unload event before we blow anything away.
03583     (void) FirePageHideNotification(PR_TRUE);
03584 
03585     // Stop any URLs that are currently being loaded...
03586     Stop(nsIWebNavigation::STOP_ALL);
03587 
03588     delete mEditorData;
03589     mEditorData = 0;
03590 
03591     mTransferableHookData = nsnull;
03592 
03593     // Save the state of the current document, before destroying the window.
03594     // This is needed to capture the state of a frameset when the new document
03595     // causes the frameset to be destroyed...
03596     PersistLayoutHistoryState();
03597 
03598     // Remove this docshell from its parent's child list
03599     nsCOMPtr<nsIDocShellTreeNode> docShellParentAsNode =
03600         do_QueryInterface(GetAsSupports(mParent));
03601     if (docShellParentAsNode)
03602         docShellParentAsNode->RemoveChild(this);
03603 
03604     if (mContentViewer) {
03605         mContentViewer->Close(nsnull);
03606         mContentViewer->Destroy();
03607         mContentViewer = nsnull;
03608     }
03609 
03610     nsDocLoader::Destroy();
03611     
03612     mParentWidget = nsnull;
03613     mCurrentURI = nsnull;
03614 
03615     if (mScriptGlobal) {
03616         mScriptGlobal->SetDocShell(nsnull);
03617         mScriptGlobal->SetGlobalObjectOwner(nsnull);
03618         mScriptGlobal = nsnull;
03619     }
03620 
03621     mSessionHistory = nsnull;
03622     SetTreeOwner(nsnull);
03623 
03624     // Note: mContentListener can be null if Init() failed and we're being
03625     // called from the destructor.
03626     if (mContentListener) {
03627         mContentListener->DropDocShellreference();
03628         mContentListener->SetParentContentListener(nsnull);
03629     }
03630 
03631     // required to break ref cycle
03632     mSecurityUI = nsnull;
03633 
03634     // Cancel any timers that were set for this docshell; this is needed
03635     // to break the cycle between us and the timers.
03636     CancelRefreshURITimers();
03637 
03638     return NS_OK;
03639 }
03640 
03641 NS_IMETHODIMP
03642 nsDocShell::SetPosition(PRInt32 x, PRInt32 y)
03643 {
03644     mBounds.x = x;
03645     mBounds.y = y;
03646 
03647     if (mContentViewer)
03648         NS_ENSURE_SUCCESS(mContentViewer->Move(x, y), NS_ERROR_FAILURE);
03649 
03650     return NS_OK;
03651 }
03652 
03653 NS_IMETHODIMP
03654 nsDocShell::GetPosition(PRInt32 * aX, PRInt32 * aY)
03655 {
03656     PRInt32 dummyHolder;
03657     return GetPositionAndSize(aX, aY, &dummyHolder, &dummyHolder);
03658 }
03659 
03660 NS_IMETHODIMP
03661 nsDocShell::SetSize(PRInt32 aCX, PRInt32 aCY, PRBool aRepaint)
03662 {
03663     PRInt32 x = 0, y = 0;
03664     GetPosition(&x, &y);
03665     return SetPositionAndSize(x, y, aCX, aCY, aRepaint);
03666 }
03667 
03668 NS_IMETHODIMP
03669 nsDocShell::GetSize(PRInt32 * aCX, PRInt32 * aCY)
03670 {
03671     PRInt32 dummyHolder;
03672     return GetPositionAndSize(&dummyHolder, &dummyHolder, aCX, aCY);
03673 }
03674 
03675 NS_IMETHODIMP
03676 nsDocShell::SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx,
03677                                PRInt32 cy, PRBool fRepaint)
03678 {
03679     mBounds.x = x;
03680     mBounds.y = y;
03681     mBounds.width = cx;
03682     mBounds.height = cy;
03683 
03684     if (mContentViewer) {
03685         //XXX Border figured in here or is that handled elsewhere?
03686         NS_ENSURE_SUCCESS(mContentViewer->SetBounds(mBounds), NS_ERROR_FAILURE);
03687     }
03688 
03689     return NS_OK;
03690 }
03691 
03692 NS_IMETHODIMP
03693 nsDocShell::GetPositionAndSize(PRInt32 * x, PRInt32 * y, PRInt32 * cx,
03694                                PRInt32 * cy)
03695 {
03696     if (x)
03697         *x = mBounds.x;
03698     if (y)
03699         *y = mBounds.y;
03700     if (cx)
03701         *cx = mBounds.width;
03702     if (cy)
03703         *cy = mBounds.height;
03704 
03705     return NS_OK;
03706 }
03707 
03708 NS_IMETHODIMP
03709 nsDocShell::Repaint(PRBool aForce)
03710 {
03711     nsCOMPtr<nsPresContext> context;
03712     GetPresContext(getter_AddRefs(context));
03713     NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
03714 
03715     nsIViewManager* viewManager = context->GetViewManager();
03716     NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
03717 
03718     // what about aForce ?
03719     NS_ENSURE_SUCCESS(viewManager->UpdateAllViews(0), NS_ERROR_FAILURE);
03720     return NS_OK;
03721 }
03722 
03723 NS_IMETHODIMP
03724 nsDocShell::GetParentWidget(nsIWidget ** parentWidget)
03725 {
03726     NS_ENSURE_ARG_POINTER(parentWidget);
03727 
03728     *parentWidget = mParentWidget;
03729     NS_IF_ADDREF(*parentWidget);
03730 
03731     return NS_OK;
03732 }
03733 
03734 NS_IMETHODIMP
03735 nsDocShell::SetParentWidget(nsIWidget * aParentWidget)
03736 {
03737     mParentWidget = aParentWidget;
03738 
03739     if (!mParentWidget) {
03740         // If the parent widget is set to null we don't want to hold
03741         // on to the current device context any more since it is
03742         // associated with the parent widget we no longer own. We'll
03743         // need to create a new device context if one is needed again.
03744 
03745         mDeviceContext = nsnull;
03746     }
03747 
03748     return NS_OK;
03749 }
03750 
03751 NS_IMETHODIMP
03752 nsDocShell::GetParentNativeWindow(nativeWindow * parentNativeWindow)
03753 {
03754     NS_ENSURE_ARG_POINTER(parentNativeWindow);
03755 
03756     if (mParentWidget)
03757         *parentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
03758     else
03759         *parentNativeWindow = nsnull;
03760 
03761     return NS_OK;
03762 }
03763 
03764 NS_IMETHODIMP
03765 nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow)
03766 {
03767     return NS_ERROR_NOT_IMPLEMENTED;
03768 }
03769 
03770 NS_IMETHODIMP
03771 nsDocShell::GetVisibility(PRBool * aVisibility)
03772 {
03773     NS_ENSURE_ARG_POINTER(aVisibility);
03774     if (!mContentViewer) {
03775         *aVisibility = PR_FALSE;
03776         return NS_OK;
03777     }
03778 
03779     // get the pres shell
03780     nsCOMPtr<nsIPresShell> presShell;
03781     NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(presShell)),
03782                       NS_ERROR_FAILURE);
03783     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
03784 
03785     // get the view manager
03786     nsIViewManager* vm = presShell->GetViewManager();
03787     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
03788 
03789     // get the root view
03790     nsIView *view = nsnull; // views are not ref counted
03791     NS_ENSURE_SUCCESS(vm->GetRootView(view), NS_ERROR_FAILURE);
03792     NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
03793 
03794     // if our root view is hidden, we are not visible
03795     if (view->GetVisibility() == nsViewVisibility_kHide) {
03796         *aVisibility = PR_FALSE;
03797         return NS_OK;
03798     }
03799 
03800     // otherwise, we must walk up the document and view trees checking
03801     // for a hidden view.
03802 
03803     nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
03804     nsCOMPtr<nsIDocShellTreeItem> parentItem;
03805     treeItem->GetParent(getter_AddRefs(parentItem));
03806     while (parentItem) {
03807         nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(treeItem));
03808         docShell->GetPresShell(getter_AddRefs(presShell));
03809 
03810         nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentItem);
03811         nsCOMPtr<nsIPresShell> pPresShell;
03812         parentDS->GetPresShell(getter_AddRefs(pPresShell));
03813 
03814         // Null-check for crash in bug 267804
03815         if (!pPresShell) {
03816             NS_NOTREACHED("docshell has null pres shell");
03817             *aVisibility = PR_FALSE;
03818             return NS_OK;
03819         }
03820 
03821         nsIContent *shellContent =
03822             pPresShell->GetDocument()->FindContentForSubDocument(presShell->GetDocument());
03823         NS_ASSERTION(shellContent, "subshell not in the map");
03824 
03825         nsIFrame* frame;
03826         pPresShell->GetPrimaryFrameFor(shellContent, &frame);
03827         if (frame && !frame->AreAncestorViewsVisible()) {
03828             *aVisibility = PR_FALSE;
03829             return NS_OK;
03830         }
03831 
03832         treeItem = parentItem;
03833         treeItem->GetParent(getter_AddRefs(parentItem));
03834     }
03835 
03836     nsCOMPtr<nsIBaseWindow>
03837         treeOwnerAsWin(do_QueryInterface(mTreeOwner));
03838     if (!treeOwnerAsWin) {
03839         *aVisibility = PR_TRUE;
03840         return NS_OK;
03841     }
03842 
03843     // Check with the tree owner as well to give embedders a chance to
03844     // expose visibility as well.
03845     return treeOwnerAsWin->GetVisibility(aVisibility);
03846 }
03847 
03848 NS_IMETHODIMP
03849 nsDocShell::SetVisibility(PRBool aVisibility)
03850 {
03851     if (!mContentViewer)
03852         return NS_OK;
03853     if (aVisibility) {
03854         mContentViewer->Show();
03855     }
03856     else {
03857         mContentViewer->Hide();
03858     }
03859     
03860     return NS_OK;
03861 }
03862 
03863 NS_IMETHODIMP
03864 nsDocShell::GetEnabled(PRBool *aEnabled)
03865 {
03866   NS_ENSURE_ARG_POINTER(aEnabled);
03867   *aEnabled = PR_TRUE;
03868   return NS_ERROR_NOT_IMPLEMENTED;
03869 }
03870 
03871 NS_IMETHODIMP
03872 nsDocShell::SetEnabled(PRBool aEnabled)
03873 {
03874   return NS_ERROR_NOT_IMPLEMENTED;
03875 }
03876 
03877 NS_IMETHODIMP
03878 nsDocShell::GetBlurSuppression(PRBool *aBlurSuppression)
03879 {
03880   NS_ENSURE_ARG_POINTER(aBlurSuppression);
03881   *aBlurSuppression = PR_FALSE;
03882   return NS_ERROR_NOT_IMPLEMENTED;
03883 }
03884 
03885 NS_IMETHODIMP
03886 nsDocShell::SetBlurSuppression(PRBool aBlurSuppression)
03887 {
03888   return NS_ERROR_NOT_IMPLEMENTED;
03889 }
03890 
03891 NS_IMETHODIMP
03892 nsDocShell::GetMainWidget(nsIWidget ** aMainWidget)
03893 {
03894     // We don't create our own widget, so simply return the parent one. 
03895     return GetParentWidget(aMainWidget);
03896 }
03897 
03898 NS_IMETHODIMP
03899 nsDocShell::SetFocus()
03900 {
03901 #ifdef DEBUG_DOCSHELL_FOCUS
03902   printf("nsDocShell::SetFocus %p\n", (nsIDocShell*)this);
03903 #endif
03904 
03905   // Tell itself (and the DocShellFocusController) who has focus
03906   // this way focus gets removed from the currently focused DocShell
03907 
03908   SetHasFocus(PR_TRUE);
03909 
03910   return NS_OK;
03911 }
03912 
03913 NS_IMETHODIMP
03914 nsDocShell::GetTitle(PRUnichar ** aTitle)
03915 {
03916     NS_ENSURE_ARG_POINTER(aTitle);
03917 
03918     *aTitle = ToNewUnicode(mTitle);
03919     return NS_OK;
03920 }
03921 
03922 NS_IMETHODIMP
03923 nsDocShell::SetTitle(const PRUnichar * aTitle)
03924 {
03925     // Store local title
03926     mTitle = aTitle;
03927 
03928     nsCOMPtr<nsIDocShellTreeItem> parent;
03929     GetSameTypeParent(getter_AddRefs(parent));
03930 
03931     // When title is set on the top object it should then be passed to the 
03932     // tree owner.
03933     if (!parent) {
03934         nsCOMPtr<nsIBaseWindow>
03935             treeOwnerAsWin(do_QueryInterface(mTreeOwner));
03936         if (treeOwnerAsWin)
03937             treeOwnerAsWin->SetTitle(aTitle);
03938     }
03939 
03940     if (mGlobalHistory && mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
03941         mGlobalHistory->SetPageTitle(mCurrentURI, nsDependentString(aTitle));
03942     }
03943 
03944 
03945     // Update SessionHistory with the document's title. If the
03946     // page was loaded from history or the page bypassed history,
03947     // there is no need to update the title. There is no need to
03948     // go to mSessionHistory to update the title. Setting it in mOSHE 
03949     // would suffice. 
03950     if (mOSHE && (mLoadType != LOAD_BYPASS_HISTORY) &&
03951         (mLoadType != LOAD_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) {
03952         mOSHE->SetTitle(mTitle);    
03953     }
03954 
03955 
03956     return NS_OK;
03957 }
03958 
03959 //*****************************************************************************
03960 // nsDocShell::nsIScrollable
03961 //*****************************************************************************   
03962 
03963 NS_IMETHODIMP
03964 nsDocShell::GetCurScrollPos(PRInt32 scrollOrientation, PRInt32 * curPos)
03965 {
03966     NS_ENSURE_ARG_POINTER(curPos);
03967 
03968     nsIScrollableView* scrollView;
03969     NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView),
03970                       NS_ERROR_FAILURE);
03971     if (!scrollView) {
03972         return NS_ERROR_FAILURE;
03973     }
03974 
03975     nscoord x, y;
03976     NS_ENSURE_SUCCESS(scrollView->GetScrollPosition(x, y), NS_ERROR_FAILURE);
03977 
03978     switch (scrollOrientation) {
03979     case ScrollOrientation_X:
03980         *curPos = x;
03981         return NS_OK;
03982 
03983     case ScrollOrientation_Y:
03984         *curPos = y;
03985         return NS_OK;
03986 
03987     default:
03988         NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
03989     }
03990     return NS_ERROR_FAILURE;
03991 }
03992 
03993 NS_IMETHODIMP
03994 nsDocShell::SetCurScrollPos(PRInt32 scrollOrientation, PRInt32 curPos)
03995 {
03996     nsIScrollableView* scrollView;
03997     NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView),
03998                       NS_ERROR_FAILURE);
03999     if (!scrollView) {
04000         return NS_ERROR_FAILURE;
04001     }
04002 
04003     PRInt32 other;
04004     PRInt32 x;
04005     PRInt32 y;
04006 
04007     GetCurScrollPos(scrollOrientation, &other);
04008 
04009     switch (scrollOrientation) {
04010     case ScrollOrientation_X:
04011         x = curPos;
04012         y = other;
04013         break;
04014 
04015     case ScrollOrientation_Y:
04016         x = other;
04017         y = curPos;
04018         break;
04019 
04020     default:
04021         NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
04022         x = 0;
04023         y = 0;                  // fix compiler warning, not actually executed
04024     }
04025 
04026     NS_ENSURE_SUCCESS(scrollView->ScrollTo(x, y, NS_VMREFRESH_IMMEDIATE),
04027                       NS_ERROR_FAILURE);
04028     return NS_OK;
04029 }
04030 
04031 NS_IMETHODIMP
04032 nsDocShell::SetCurScrollPosEx(PRInt32 curHorizontalPos, PRInt32 curVerticalPos)
04033 {
04034     nsIScrollableView* scrollView;
04035     NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView),
04036                       NS_ERROR_FAILURE);
04037     if (!scrollView) {
04038         return NS_ERROR_FAILURE;
04039     }
04040 
04041     NS_ENSURE_SUCCESS(scrollView->ScrollTo(curHorizontalPos, curVerticalPos,
04042                                            NS_VMREFRESH_IMMEDIATE),
04043                       NS_ERROR_FAILURE);
04044     return NS_OK;
04045 }
04046 
04047 // XXX This is wrong
04048 NS_IMETHODIMP
04049 nsDocShell::GetScrollRange(PRInt32 scrollOrientation,
04050                            PRInt32 * minPos, PRInt32 * maxPos)
04051 {
04052     NS_ENSURE_ARG_POINTER(minPos && maxPos);
04053 
04054     nsIScrollableView* scrollView;
04055     NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView),
04056                       NS_ERROR_FAILURE);
04057     if (!scrollView) {
04058         return NS_ERROR_FAILURE;
04059     }
04060 
04061     PRInt32 cx;
04062     PRInt32 cy;
04063 
04064     NS_ENSURE_SUCCESS(scrollView->GetContainerSize(&cx, &cy), NS_ERROR_FAILURE);
04065     *minPos = 0;
04066 
04067     switch (scrollOrientation) {
04068     case ScrollOrientation_X:
04069         *maxPos = cx;
04070         return NS_OK;
04071 
04072     case ScrollOrientation_Y:
04073         *maxPos = cy;
04074         return NS_OK;
04075 
04076     default:
04077         NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
04078     }
04079 
04080     return NS_ERROR_FAILURE;
04081 }
04082 
04083 NS_IMETHODIMP
04084 nsDocShell::SetScrollRange(PRInt32 scrollOrientation,
04085                            PRInt32 minPos, PRInt32 maxPos)
04086 {
04087     //XXX First Check
04088     /*
04089        Retrieves or Sets the valid ranges for the thumb.  When maxPos is set to 
04090        something less than the current thumb position, curPos is set = to maxPos.
04091 
04092        @return NS_OK - Setting or Getting completed successfully.
04093        NS_ERROR_INVALID_ARG - returned when curPos is not within the
04094        minPos and maxPos.
04095      */
04096     return NS_ERROR_FAILURE;
04097 }
04098 
04099 NS_IMETHODIMP
04100 nsDocShell::SetScrollRangeEx(PRInt32 minHorizontalPos,
04101                              PRInt32 maxHorizontalPos, PRInt32 minVerticalPos,
04102                              PRInt32 maxVerticalPos)
04103 {
04104     //XXX First Check
04105     /*
04106        Retrieves or Sets the valid ranges for the thumb.  When maxPos is set to 
04107        something less than the current thumb position, curPos is set = to maxPos.
04108 
04109        @return NS_OK - Setting or Getting completed successfully.
04110        NS_ERROR_INVALID_ARG - returned when curPos is not within the
04111        minPos and maxPos.
04112      */
04113     return NS_ERROR_FAILURE;
04114 }
04115 
04116 // This returns setting for all documents in this webshell
04117 NS_IMETHODIMP
04118 nsDocShell::GetDefaultScrollbarPreferences(PRInt32 scrollOrientation,
04119                                            PRInt32 * scrollbarPref)
04120 {
04121     NS_ENSURE_ARG_POINTER(scrollbarPref);
04122     switch (scrollOrientation) {
04123     case ScrollOrientation_X:
04124         *scrollbarPref = mDefaultScrollbarPref.x;
04125         return NS_OK;
04126 
04127     case ScrollOrientation_Y:
04128         *scrollbarPref = mDefaultScrollbarPref.y;
04129         return NS_OK;
04130 
04131     default:
04132         NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
04133     }
04134     return NS_ERROR_FAILURE;
04135 }
04136 
04137 // Set scrolling preference for all documents in this shell
04138 //
04139 // There are three possible values stored in the shell:
04140 //  1) nsIScrollable::Scrollbar_Never = no scrollbar
04141 //  2) nsIScrollable::Scrollbar_Auto = scrollbar appears if the document
04142 //     being displayed would normally have scrollbar
04143 //  3) nsIScrollable::Scrollbar_Always = scrollbar always appears
04144 //
04145 // One important client is nsHTMLFrameInnerFrame::CreateWebShell()
04146 NS_IMETHODIMP
04147 nsDocShell::SetDefaultScrollbarPreferences(PRInt32 scrollOrientation,
04148                                            PRInt32 scrollbarPref)
04149 {
04150     switch (scrollOrientation) {
04151     case ScrollOrientation_X:
04152         mDefaultScrollbarPref.x = scrollbarPref;
04153         return NS_OK;
04154 
04155     case ScrollOrientation_Y:
04156         mDefaultScrollbarPref.y = scrollbarPref;
04157         return NS_OK;
04158 
04159     default:
04160         NS_ENSURE_TRUE(PR_FALSE, NS_ERROR_INVALID_ARG);
04161     }
04162     return NS_ERROR_FAILURE;
04163 }
04164 
04165 NS_IMETHODIMP
04166 nsDocShell::GetScrollbarVisibility(PRBool * verticalVisible,
04167                                    PRBool * horizontalVisible)
04168 {
04169     nsIScrollableView* scrollView;
04170     NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView),
04171                       NS_ERROR_FAILURE);
04172     if (!scrollView)
04173         return NS_ERROR_FAILURE;
04174 
04175     // We should now call nsLayoutUtils::GetScrollableFrameFor,
04176     // but we can't because of stupid linkage!
04177     nsIFrame* scrollFrame =
04178         NS_STATIC_CAST(nsIFrame*, scrollView->View()->GetParent()->GetClientData());
04179     if (!scrollFrame)
04180         return NS_ERROR_FAILURE;
04181     nsIScrollableFrame* scrollable = nsnull;
04182     CallQueryInterface(scrollFrame, &scrollable);
04183     if (!scrollable)
04184         return NS_ERROR_FAILURE;
04185 
04186     nsMargin scrollbars = scrollable->GetActualScrollbarSizes();
04187     if (verticalVisible)
04188         *verticalVisible = scrollbars.left != 0 || scrollbars.right != 0;
04189     if (horizontalVisible)
04190         *horizontalVisible = scrollbars.top != 0 || scrollbars.bottom != 0;
04191 
04192     return NS_OK;
04193 }
04194 
04195 //*****************************************************************************
04196 // nsDocShell::nsITextScroll
04197 //*****************************************************************************   
04198 
04199 NS_IMETHODIMP
04200 nsDocShell::ScrollByLines(PRInt32 numLines)
04201 {
04202     nsIScrollableView* scrollView;
04203 
04204     NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView),
04205                       NS_ERROR_FAILURE);
04206     if (!scrollView) {
04207         return NS_ERROR_FAILURE;
04208     }
04209 
04210     NS_ENSURE_SUCCESS(scrollView->ScrollByLines(0, numLines), NS_ERROR_FAILURE);
04211 
04212     return NS_OK;
04213 }
04214 
04215 NS_IMETHODIMP
04216 nsDocShell::ScrollByPages(PRInt32 numPages)
04217 {
04218     nsIScrollableView* scrollView;
04219 
04220     NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView),
04221                       NS_ERROR_FAILURE);
04222     if (!scrollView) {
04223         return NS_ERROR_FAILURE;
04224     }
04225 
04226     NS_ENSURE_SUCCESS(scrollView->ScrollByPages(0, numPages), NS_ERROR_FAILURE);
04227 
04228     return NS_OK;
04229 }
04230 
04231 //*****************************************************************************
04232 // nsDocShell::nsIScriptGlobalObjectOwner
04233 //*****************************************************************************   
04234 
04235 nsIScriptGlobalObject*
04236 nsDocShell::GetScriptGlobalObject()
04237 {
04238     NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nsnull);
04239 
04240     return mScriptGlobal;
04241 }
04242 
04243 //*****************************************************************************
04244 // nsDocShell::nsIRefreshURI
04245 //*****************************************************************************   
04246 
04247 NS_IMETHODIMP
04248 nsDocShell::RefreshURI(nsIURI * aURI, PRInt32 aDelay, PRBool aRepeat, PRBool aMetaRefresh)
04249 {
04250     NS_ENSURE_ARG(aURI);
04251 
04252     nsRefreshTimer *refreshTimer = new nsRefreshTimer();
04253     NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY);
04254     PRUint32 busyFlags = 0;
04255     GetBusyFlags(&busyFlags);
04256 
04257     nsCOMPtr<nsISupports> dataRef = refreshTimer;    // Get the ref count to 1
04258 
04259     refreshTimer->mDocShell = this;
04260     refreshTimer->mURI = aURI;
04261     refreshTimer->mDelay = aDelay;
04262     refreshTimer->mRepeat = aRepeat;
04263     refreshTimer->mMetaRefresh = aMetaRefresh;
04264 
04265     if (!mRefreshURIList) {
04266         NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList)),
04267                           NS_ERROR_FAILURE);
04268     }
04269 
04270     if (busyFlags & BUSY_FLAGS_BUSY) {
04271         // We are busy loading another page. Don't create the
04272         // timer right now. Instead queue up the request and trigger the
04273         // timer in EndPageLoad(). 
04274         mRefreshURIList->AppendElement(refreshTimer);
04275     }
04276     else {
04277         // There is no page loading going on right now.  Create the
04278         // timer and fire it right away.
04279         nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
04280         NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
04281 
04282         mRefreshURIList->AppendElement(timer);      // owning timer ref
04283         timer->InitWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT);
04284     }
04285     return NS_OK;
04286 }
04287 
04288 
04289 nsresult
04290 nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI,
04291                                       const nsACString & aHeader)
04292 {
04293     // Refresh headers are parsed with the following format in mind
04294     // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
04295     // By the time we are here, the following is true:
04296     // header = "REFRESH"
04297     // content = "5; URL=http://uri" // note the URL attribute is
04298     // optional, if it is absent, the currently loaded url is used.
04299     // Also note that the seconds and URL separator can be either
04300     // a ';' or a ','. The ',' separator should be illegal but CNN
04301     // is using it.
04302     // 
04303     // We need to handle the following strings, where
04304     //  - X is a set of digits
04305     //  - URI is either a relative or absolute URI
04306     //
04307     // Note that URI should start with "url=" but we allow omission
04308     //
04309     // "" || ";" || "," 
04310     //  empty string. use the currently loaded URI
04311     //  and refresh immediately.
04312     // "X" || "X;" || "X,"
04313     //  Refresh the currently loaded URI in X seconds.
04314     // "X; URI" || "X, URI"
04315     //  Refresh using URI as the destination in X seconds.
04316     // "URI" || "; URI" || ", URI"
04317     //  Refresh immediately using URI as the destination.
04318     // 
04319     // Currently, anything immediately following the URI, if
04320     // separated by any char in the set "'\"\t\r\n " will be
04321     // ignored. So "10; url=go.html ; foo=bar" will work,
04322     // and so will "10; url='go.html'; foo=bar". However,
04323     // "10; url=go.html; foo=bar" will result in the uri
04324     // "go.html;" since ';' and ',' are valid uri characters.
04325     // 
04326     // Note that we need to remove any tokens wrapping the URI.
04327     // These tokens currently include spaces, double and single
04328     // quotes.
04329 
04330     // when done, seconds is 0 or the given number of seconds
04331     //            uriAttrib is empty or the URI specified
04332     nsCAutoString uriAttrib;
04333     PRInt32 seconds = 0;
04334     PRBool specifiesSeconds = PR_FALSE;
04335 
04336     nsACString::const_iterator iter, tokenStart, doneIterating;
04337 
04338     aHeader.BeginReading(iter);
04339     aHeader.EndReading(doneIterating);
04340 
04341     // skip leading whitespace
04342     while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
04343         ++iter;
04344 
04345     tokenStart = iter;
04346 
04347     // skip leading + and -
04348     if (iter != doneIterating && (*iter == '-' || *iter == '+'))
04349         ++iter;
04350 
04351     // parse number
04352     while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
04353         seconds = seconds * 10 + (*iter - '0');
04354         specifiesSeconds = PR_TRUE;
04355         ++iter;
04356     }
04357 
04358     if (iter != doneIterating) {
04359         // if we started with a '-', number is negative
04360         if (*tokenStart == '-')
04361             seconds = -seconds;
04362 
04363         // skip to next ';' or ','
04364         nsACString::const_iterator iterAfterDigit = iter;
04365         while (iter != doneIterating && !(*iter == ';' || *iter == ','))
04366         {
04367             if (specifiesSeconds)
04368             {
04369                 // Non-whitespace characters here mean that the string is
04370                 // malformed but tolerate sites that specify a decimal point,
04371                 // even though meta refresh only works on whole seconds.
04372                 if (iter == iterAfterDigit &&
04373                     !nsCRT::IsAsciiSpace(*iter) && *iter != '.')
04374                 {
04375                     // The characters between the seconds and the next
04376                     // section are just garbage!
04377                     //   e.g. content="2a0z+,URL=http://www.mozilla.org/"
04378                     // Just ignore this redirect.
04379                     return NS_ERROR_FAILURE;
04380                 }
04381                 else if (nsCRT::IsAsciiSpace(*iter))
04382                 {
04383                     // We've had at least one whitespace so tolerate the mistake
04384                     // and drop through.
04385                     // e.g. content="10 foo"
04386                     ++iter;
04387                     break;
04388                 }
04389             }
04390             ++iter;
04391         }
04392 
04393         // skip any remaining whitespace
04394         while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
04395             ++iter;
04396 
04397         // skip ';' or ','
04398         if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
04399             ++iter;
04400         }
04401 
04402         // skip whitespace
04403         while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
04404             ++iter;
04405     }
04406 
04407     // possible start of URI
04408     tokenStart = iter;
04409 
04410     // skip "url = " to real start of URI
04411     if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
04412         ++iter;
04413         if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
04414             ++iter;
04415             if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
04416                 ++iter;
04417 
04418                 // skip whitespace
04419                 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
04420                     ++iter;
04421 
04422                 if (iter != doneIterating && *iter == '=') {
04423                     ++iter;
04424 
04425                     // skip whitespace
04426                     while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
04427                         ++iter;
04428 
04429                     // found real start of URI
04430                     tokenStart = iter;
04431                 }
04432             }
04433         }
04434     }
04435 
04436     // skip a leading '"' or '\''.
04437 
04438     PRBool isQuotedURI = PR_FALSE;
04439     if (tokenStart != doneIterating && (*tokenStart == '"' || *tokenStart == '\''))
04440     {
04441         isQuotedURI = PR_TRUE;
04442         ++tokenStart;
04443     }
04444 
04445     // set iter to start of URI
04446     iter = tokenStart;
04447 
04448     // tokenStart here points to the beginning of URI
04449 
04450     // grab the rest of the URI
04451     while (iter != doneIterating)
04452     {
04453         if (isQuotedURI && (*iter == '"' || *iter == '\''))
04454             break;
04455         ++iter;
04456     }
04457 
04458     // move iter one back if the last character is a '"' or '\''
04459     if (iter != tokenStart && isQuotedURI) {
04460         --iter;
04461         if (!(*iter == '"' || *iter == '\''))
04462             ++iter;
04463     }
04464 
04465     // URI is whatever's contained from tokenStart to iter.
04466     // note: if tokenStart == doneIterating, so is iter.
04467 
04468     nsresult rv = NS_OK;
04469 
04470     nsCOMPtr<nsIURI> uri;
04471     PRBool specifiesURI = PR_FALSE;
04472     if (tokenStart == iter) {
04473         uri = aBaseURI;
04474     }
04475     else {
04476         uriAttrib = Substring(tokenStart, iter);
04477         // NS_NewURI takes care of any whitespace surrounding the URL
04478         rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nsnull, aBaseURI);
04479         specifiesURI = PR_TRUE;
04480     }
04481 
04482     // No URI or seconds were specified
04483     if (!specifiesSeconds && !specifiesURI)
04484     {
04485         // Do nothing because the alternative is to spin around in a refresh
04486         // loop forever!
04487         return NS_ERROR_FAILURE;
04488     }
04489 
04490     if (NS_SUCCEEDED(rv)) {
04491         nsCOMPtr<nsIScriptSecurityManager>
04492             securityManager(do_GetService
04493                             (NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
04494         if (NS_SUCCEEDED(rv)) {
04495             rv = securityManager->CheckLoadURI(aBaseURI, uri,
04496                                                nsIScriptSecurityManager::
04497                                                DISALLOW_FROM_MAIL);
04498             if (NS_SUCCEEDED(rv)) {
04499                 // Since we can't travel back in time yet, just pretend
04500                 // negative numbers do nothing at all.
04501                 if (seconds < 0)
04502                     return NS_ERROR_FAILURE;
04503 
04504                 rv = RefreshURI(uri, seconds * 1000, PR_FALSE, PR_TRUE);
04505             }
04506         }
04507     }
04508     return rv;
04509 }
04510 
04511 NS_IMETHODIMP nsDocShell::SetupRefreshURI(nsIChannel * aChannel)
04512 {
04513     nsresult rv;
04514     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv));
04515     if (NS_SUCCEEDED(rv)) {
04516         nsCAutoString refreshHeader;
04517         rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
04518                                             refreshHeader);
04519 
04520         if (!refreshHeader.IsEmpty()) {
04521             SetupReferrerFromChannel(aChannel);
04522             rv = SetupRefreshURIFromHeader(mCurrentURI, refreshHeader);
04523             if (NS_SUCCEEDED(rv)) {
04524                 return NS_REFRESHURI_HEADER_FOUND;
04525             }
04526         }
04527     }
04528     return rv;
04529 }
04530 
04531 static void
04532 DoCancelRefreshURITimers(nsISupportsArray* aTimerList)
04533 {
04534     if (!aTimerList)
04535         return;
04536 
04537     PRUint32 n=0;
04538     aTimerList->Count(&n);
04539 
04540     while (n) {
04541         nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
04542 
04543         aTimerList->RemoveElementAt(n);    // bye bye owning timer ref
04544 
04545         if (timer)
04546             timer->Cancel();        
04547     }
04548 }
04549 
04550 NS_IMETHODIMP
04551 nsDocShell::CancelRefreshURITimers()
04552 {
04553     DoCancelRefreshURITimers(mRefreshURIList);
04554     DoCancelRefreshURITimers(mSavedRefreshURIList);
04555     mRefreshURIList = nsnull;
04556     mSavedRefreshURIList = nsnull;
04557 
04558     return NS_OK;
04559 }
04560 
04561 NS_IMETHODIMP
04562 nsDocShell::SuspendRefreshURIs()
04563 {
04564     if (mRefreshURIList) {
04565         PRUint32 n = 0;
04566         mRefreshURIList->Count(&n);
04567 
04568         for (PRUint32 i = 0;  i < n; ++i) {
04569             nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
04570             if (!timer)
04571                 continue;  // this must be a nsRefreshURI already
04572 
04573             // Replace this timer object with a nsRefreshTimer object.
04574             nsCOMPtr<nsITimerCallback> callback;
04575             timer->GetCallback(getter_AddRefs(callback));
04576 
04577             timer->Cancel();
04578 
04579             nsCOMPtr<nsRefreshTimer> rt = do_QueryInterface(callback);
04580             NS_ASSERTION(rt, "RefreshURIList timer callbacks should only be RefreshTimer objects");
04581 
04582             mRefreshURIList->ReplaceElementAt(rt, i);
04583         }
04584     }
04585 
04586     // Suspend refresh URIs for our child shells as well.
04587     PRInt32 n = mChildList.Count();
04588 
04589     for (PRInt32 i = 0; i < n; ++i) {
04590         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
04591         if (shell)
04592             shell->SuspendRefreshURIs();
04593     }
04594 
04595     return NS_OK;
04596 }
04597 
04598 NS_IMETHODIMP
04599 nsDocShell::ResumeRefreshURIs()
04600 {
04601     RefreshURIFromQueue();
04602 
04603     // Resume refresh URIs for our child shells as well.
04604     PRInt32 n = mChildList.Count();
04605 
04606     for (PRInt32 i = 0; i < n; ++i) {
04607         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
04608         if (shell)
04609             shell->ResumeRefreshURIs();
04610     }
04611 
04612     return NS_OK;
04613 }
04614 
04615 nsresult
04616 nsDocShell::RefreshURIFromQueue()
04617 {
04618     if (!mRefreshURIList)
04619         return NS_OK;
04620     PRUint32 n = 0;
04621     mRefreshURIList->Count(&n);
04622 
04623     while (n) {
04624         nsCOMPtr<nsISupports> element;
04625         mRefreshURIList->GetElementAt(--n, getter_AddRefs(element));
04626         nsCOMPtr<nsRefreshTimer> refreshInfo(do_QueryInterface(element));
04627 
04628         if (refreshInfo) {   
04629             // This is the nsRefreshTimer object, waiting to be
04630             // setup in a timer object and fired.                         
04631             // Create the timer and  trigger it.
04632             PRUint32 delay = refreshInfo->GetDelay();
04633             nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
04634             if (timer) {    
04635                 // Replace the nsRefreshTimer element in the queue with
04636                 // its corresponding timer object, so that in case another
04637                 // load comes through before the timer can go off, the timer will
04638                 // get cancelled in CancelRefreshURITimer()
04639                 mRefreshURIList->ReplaceElementAt(timer, n);
04640                 timer->InitWithCallback(refreshInfo, delay, nsITimer::TYPE_ONE_SHOT);
04641             }           
04642         }        
04643     }  // while
04644  
04645     return NS_OK;
04646 }
04647 
04648 //*****************************************************************************
04649 // nsDocShell::nsIContentViewerContainer
04650 //*****************************************************************************   
04651 
04652 NS_IMETHODIMP
04653 nsDocShell::Embed(nsIContentViewer * aContentViewer,
04654                   const char *aCommand, nsISupports * aExtraInfo)
04655 {
04656     // Save the LayoutHistoryState of the previous document, before
04657     // setting up new document
04658     PersistLayoutHistoryState();
04659 
04660     nsresult rv = SetupNewViewer(aContentViewer);
04661 
04662     // If we are loading a wyciwyg url from history, change the base URI for 
04663     // the document to the original http url that created the document.write().
04664     // This makes sure that all relative urls in a document.written page loaded
04665     // via history work properly.
04666     if (mCurrentURI &&
04667        (mLoadType & LOAD_CMD_HISTORY ||
04668         mLoadType == LOAD_RELOAD_NORMAL ||
04669         mLoadType == LOAD_RELOAD_CHARSET_CHANGE)){
04670         PRBool isWyciwyg = PR_FALSE;
04671         // Check if the url is wyciwyg
04672         rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);      
04673         if (isWyciwyg && NS_SUCCEEDED(rv))
04674             SetBaseUrlForWyciwyg(aContentViewer);
04675     }
04676     // XXX What if SetupNewViewer fails?
04677     if (mLSHE)
04678         SetHistoryEntry(&mOSHE, mLSHE);
04679 
04680     PRBool updateHistory = PR_TRUE;
04681 
04682     // Determine if this type of load should update history   
04683     switch (mLoadType) {
04684     case LOAD_RELOAD_CHARSET_CHANGE:  //don't perserve history in charset reload
04685     case LOAD_NORMAL_REPLACE:
04686     case LOAD_STOP_CONTENT_AND_REPLACE:
04687     case LOAD_RELOAD_BYPASS_CACHE:
04688     case LOAD_RELOAD_BYPASS_PROXY:
04689     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
04690         updateHistory = PR_FALSE;
04691         break;
04692     default:
04693         break;
04694     }
04695 
04696     if (!updateHistory)
04697         SetLayoutHistoryState(nsnull);
04698 
04699     return NS_OK;
04700 }
04701 
04702 /* void setIsPrinting (in boolean aIsPrinting); */
04703 NS_IMETHODIMP 
04704 nsDocShell::SetIsPrinting(PRBool aIsPrinting)
04705 {
04706     mIsPrintingOrPP = aIsPrinting;
04707     return NS_OK;
04708 }
04709 
04710 //*****************************************************************************
04711 // nsDocShell::nsIWebProgressListener
04712 //*****************************************************************************   
04713 
04714 NS_IMETHODIMP
04715 nsDocShell::OnProgressChange(nsIWebProgress * aProgress,
04716                              nsIRequest * aRequest,
04717                              PRInt32 aCurSelfProgress,
04718                              PRInt32 aMaxSelfProgress,
04719                              PRInt32 aCurTotalProgress,
04720                              PRInt32 aMaxTotalProgress)
04721 {
04722     return NS_OK;
04723 }
04724 
04725 NS_IMETHODIMP
04726 nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
04727                           PRUint32 aStateFlags, nsresult aStatus)
04728 {
04729     nsresult rv;
04730 
04731     // Update the busy cursor
04732     if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
04733         nsCOMPtr<nsIWyciwygChannel>  wcwgChannel(do_QueryInterface(aRequest));
04734         nsCOMPtr<nsIWebProgress> webProgress =
04735             do_QueryInterface(GetAsSupports(this));
04736 
04737         // Was the wyciwyg document loaded on this docshell?
04738         if (wcwgChannel && !mLSHE && (mItemType == typeContent) && aProgress == webProgress.get()) {
04739             nsCOMPtr<nsIURI> uri;
04740             wcwgChannel->GetURI(getter_AddRefs(uri));
04741         
04742             PRBool equalUri = PR_TRUE;
04743             // Store the wyciwyg url in session history, only if it is
04744             // being loaded fresh for the first time. We don't want 
04745             // multiple entries for successive loads
04746             if (mCurrentURI &&
04747                 NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
04748                 !equalUri) {
04749                 // This is a document.write(). Get the made-up url
04750                 // from the channel and store it in session history.
04751                 rv = AddToSessionHistory(uri, wcwgChannel, getter_AddRefs(mLSHE));
04752                 SetCurrentURI(uri, aRequest, PR_TRUE);
04753                 // Save history state of the previous page
04754                 rv = PersistLayoutHistoryState();
04755                 if (mOSHE)
04756                     SetHistoryEntry(&mOSHE, mLSHE);
04757             }
04758         
04759         }
04760         // Page has begun to load
04761         mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD;
04762         nsCOMPtr<nsIWidget> mainWidget;
04763         GetMainWidget(getter_AddRefs(mainWidget));
04764         if (mainWidget) {
04765             mainWidget->SetCursor(eCursor_spinning);
04766         }
04767     }
04768     else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
04769         // Page is loading
04770         mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING;
04771     }
04772     else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
04773         // Page has finished loading
04774         mBusyFlags = BUSY_FLAGS_NONE;
04775         nsCOMPtr<nsIWidget> mainWidget;
04776         GetMainWidget(getter_AddRefs(mainWidget));
04777         if (mainWidget) {
04778             mainWidget->SetCursor(eCursor_standard);
04779         }
04780     }
04781     if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
04782         nsCOMPtr<nsIWebProgress> webProgress =
04783             do_QueryInterface(GetAsSupports(this));
04784         // Is the document stop notification for this document?
04785         if (aProgress == webProgress.get()) {
04786             nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
04787             EndPageLoad(aProgress, channel, aStatus);
04788         }
04789     }
04790     // note that redirect state changes will go through here as well, but it
04791     // is better to handle those in OnRedirectStateChange where more
04792     // information is available.
04793     return NS_OK;
04794 }
04795 
04796 NS_IMETHODIMP
04797 nsDocShell::OnLocationChange(nsIWebProgress * aProgress,
04798                              nsIRequest * aRequest, nsIURI * aURI)
04799 {
04800     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
04801     return NS_OK;
04802 }
04803 
04804 void
04805 nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
04806                                   nsIChannel* aNewChannel,
04807                                   PRUint32 aRedirectFlags,
04808                                   PRUint32 aStateFlags)
04809 {
04810     NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
04811                  "Calling OnRedirectStateChange when there is no redirect");
04812     if (!(aStateFlags & STATE_IS_DOCUMENT))
04813         return; // not a toplevel document
04814 
04815     nsCOMPtr<nsIGlobalHistory3> history3(do_QueryInterface(mGlobalHistory));
04816     nsresult result = NS_ERROR_NOT_IMPLEMENTED;
04817     if (history3) {
04818         // notify global history of this redirect
04819         result = history3->AddDocumentRedirect(aOldChannel, aNewChannel,
04820                                                aRedirectFlags, !IsFrame());
04821     }
04822 
04823     if (result == NS_ERROR_NOT_IMPLEMENTED) {
04824         // when there is no GlobalHistory3, or it doesn't implement
04825         // AddToplevelRedirect, we fall back to GlobalHistory2.  Just notify
04826         // that the redirecting page was a redirect so it will be link colored
04827         // but not visible.
04828         nsCOMPtr<nsIURI> oldURI;
04829         aOldChannel->GetURI(getter_AddRefs(oldURI));
04830         if (! oldURI)
04831             return; // nothing to tell anybody about
04832         AddToGlobalHistory(oldURI, PR_TRUE, aOldChannel);
04833     }
04834 }
04835 
04836 NS_IMETHODIMP
04837 nsDocShell::OnStatusChange(nsIWebProgress * aWebProgress,
04838                            nsIRequest * aRequest,
04839                            nsresult aStatus, const PRUnichar * aMessage)
04840 {
04841     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
04842     return NS_OK;
04843 }
04844 
04845 NS_IMETHODIMP
04846 nsDocShell::OnSecurityChange(nsIWebProgress * aWebProgress,
04847                              nsIRequest * aRequest, PRUint32 state)
04848 {
04849     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
04850     return NS_OK;
04851 }
04852 
04853 
04854 nsresult
04855 nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
04856                         nsIChannel * aChannel, nsresult aStatus)
04857 {
04858     //
04859     // one of many safeguards that prevent death and destruction if
04860     // someone is so very very rude as to bring this window down
04861     // during this load handler.
04862     //
04863     nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
04864     //
04865     // Notify the ContentViewer that the Document has finished loading...
04866     //
04867     // This will cause any OnLoad(...) handlers to fire, if it is a HTML
04868     // document...
04869     //
04870     if (!mEODForCurrentDocument && mContentViewer) {
04871         mIsExecutingOnLoadHandler = PR_TRUE;
04872         mContentViewer->LoadComplete(aStatus);
04873         mIsExecutingOnLoadHandler = PR_FALSE;
04874 
04875         mEODForCurrentDocument = PR_TRUE;
04876 
04877         // If all documents have completed their loading
04878         // favor native event dispatch priorities
04879         // over performance
04880         if (--gNumberOfDocumentsLoading == 0) {
04881           // Hint to use normal native event dispatch priorities 
04882           PL_FavorPerformanceHint(PR_FALSE, NS_EVENT_STARVATION_DELAY_HINT);
04883         }
04884     }
04885     /* Check if the httpChannel has any cache-control related response headers,
04886      * like no-store, no-cache. If so, update SHEntry so that 
04887      * when a user goes back/forward to this page, we appropriately do 
04888      * form value restoration or load from server.
04889      */
04890     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
04891     if (!httpChannel) // HttpChannel could be hiding underneath a Multipart channel.    
04892         GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
04893 
04894     if (httpChannel) {
04895         // figure out if SH should be saving layout state.
04896         PRBool discardLayoutState = ShouldDiscardLayoutState(httpChannel);       
04897         if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
04898             (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE))
04899             mLSHE->SetSaveLayoutStateFlag(PR_FALSE);            
04900     }
04901 
04902     // Clear mLSHE after calling the onLoadHandlers. This way, if the
04903     // onLoadHandler tries to load something different in
04904     // itself or one of its children, we can deal with it appropriately.
04905     if (mLSHE) {
04906         mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
04907 
04908         // Clear the mLSHE reference to indicate document loading is done one
04909         // way or another.
04910         SetHistoryEntry(&mLSHE, nsnull);
04911     }
04912     // if there's a refresh header in the channel, this method
04913     // will set it up for us. 
04914     RefreshURIFromQueue();
04915 
04916     return NS_OK;
04917 }
04918 
04919 
04920 //*****************************************************************************
04921 // nsDocShell: Content Viewer Management
04922 //*****************************************************************************   
04923 
04924 NS_IMETHODIMP
04925 nsDocShell::EnsureContentViewer()
04926 {
04927     if (mContentViewer)
04928         return NS_OK;
04929     if (mIsBeingDestroyed)
04930         return NS_ERROR_FAILURE;
04931 
04932     nsIPrincipal* principal = nsnull;
04933 
04934     nsCOMPtr<nsPIDOMWindow_MOZILLA_1_8_BRANCH2> piDOMWindow =
04935       do_QueryInterface(mScriptGlobal);
04936     if (piDOMWindow) {
04937         principal = piDOMWindow->GetOpenerScriptPrincipal();
04938     }
04939 
04940     if (!principal) {
04941         principal = GetInheritedPrincipal(PR_FALSE);
04942     }
04943 
04944     nsresult rv = CreateAboutBlankContentViewer();
04945 
04946     if (NS_SUCCEEDED(rv)) {
04947         nsCOMPtr<nsIDOMDocument> domDoc;
04948         mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
04949         nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
04950         nsCOMPtr<nsIDocument_MOZILLA_1_8_BRANCH2> doc_MOZILLA_1_8_BRANCH2 =
04951             do_QueryInterface(domDoc);
04952         NS_ASSERTION(doc && doc_MOZILLA_1_8_BRANCH2,
04953                      "Should have doc if CreateAboutBlankContentViewer "
04954                      "succeeded!");
04955 
04956         doc_MOZILLA_1_8_BRANCH2->SetIsInitialDocument(PR_TRUE);
04957 
04958         if (principal) {
04959             doc->SetPrincipal(principal);
04960         }
04961     }
04962 
04963     return rv;
04964 }
04965 
04966 NS_IMETHODIMP
04967 nsDocShell::EnsureDeviceContext()
04968 {
04969     if (mDeviceContext)
04970         return NS_OK;
04971 
04972     mDeviceContext = do_CreateInstance(kDeviceContextCID);
04973     NS_ENSURE_TRUE(mDeviceContext, NS_ERROR_FAILURE);
04974 
04975     nsCOMPtr<nsIWidget> widget;
04976     GetMainWidget(getter_AddRefs(widget));
04977     NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
04978 
04979     mDeviceContext->Init(widget->GetNativeData(NS_NATIVE_WIDGET));
04980     float dev2twip;
04981     dev2twip = mDeviceContext->DevUnitsToTwips();
04982     mDeviceContext->SetDevUnitsToAppUnits(dev2twip);
04983     float twip2dev;
04984     twip2dev = mDeviceContext->TwipsToDevUnits();
04985     mDeviceContext->SetAppUnitsToDevUnits(twip2dev);
04986 
04987     return NS_OK;
04988 }
04989 
04990 nsresult
04991 nsDocShell::CreateAboutBlankContentViewer()
04992 {
04993   nsCOMPtr<nsIDocument> blankDoc;
04994   nsCOMPtr<nsIContentViewer> viewer;
04995   nsresult rv = NS_ERROR_FAILURE;
04996 
04997   /* mCreatingDocument should never be true at this point. However, it's
04998      a theoretical possibility. We want to know about it and make it stop,
04999      and this sounds like a job for an assertion. */
05000   NS_ASSERTION(!mCreatingDocument, "infinite(?) loop creating document averted");
05001   if (mCreatingDocument)
05002     return NS_ERROR_FAILURE;
05003 
05004   mCreatingDocument = PR_TRUE;
05005 
05006   // mContentViewer->PermitUnload may release |this| docshell.
05007   nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
05008   
05009   if (mContentViewer) {
05010     // We've got a content viewer already. Make sure the user
05011     // permits us to discard the current document and replace it
05012     // with about:blank. And also ensure we fire the unload events
05013     // in the current document.
05014 
05015     PRBool okToUnload;
05016     rv = mContentViewer->PermitUnload(&okToUnload);
05017 
05018     if (NS_SUCCEEDED(rv) && !okToUnload) {
05019       // The user chose not to unload the page, interrupt the load.
05020       return NS_ERROR_FAILURE;
05021     }
05022 
05023     mSavingOldViewer = CanSavePresentation(LOAD_NORMAL, nsnull, nsnull);
05024 
05025     // Notify the current document that it is about to be unloaded!!
05026     //
05027     // It is important to fire the unload() notification *before* any state
05028     // is changed within the DocShell - otherwise, javascript will get the
05029     // wrong information :-(
05030     //
05031     (void) FirePageHideNotification(!mSavingOldViewer);
05032   }
05033 
05034   // Now make sure we don't think we're in the middle of firing unload after
05035   // this point.  This will make us fire unload when the about:blank document
05036   // unloads... but that's ok, more or less.  Would be nice if it fired load
05037   // too, of course.
05038   mFiredUnloadEvent = PR_FALSE;
05039 
05040   // one helper factory, please
05041   nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
05042   if (!catMan)
05043     return NS_ERROR_FAILURE;
05044 
05045   nsXPIDLCString contractId;
05046   rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "text/html", getter_Copies(contractId));
05047   if (NS_FAILED(rv))
05048     return rv;
05049 
05050   nsCOMPtr<nsIDocumentLoaderFactory> docFactory(do_GetService(contractId));
05051   if (docFactory) {
05052     // generate (about:blank) document to load
05053     docFactory->CreateBlankDocument(mLoadGroup, getter_AddRefs(blankDoc));
05054     if (blankDoc) {
05055       blankDoc->SetContainer(NS_STATIC_CAST(nsIDocShell *, this));
05056 
05057       // create a content viewer for us and the new document
05058       docFactory->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell *, this),
05059                     blankDoc, "view", getter_AddRefs(viewer));
05060 
05061       // hook 'em up
05062       if (viewer) {
05063         viewer->SetContainer(NS_STATIC_CAST(nsIContentViewerContainer *,this));
05064         nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(blankDoc));
05065         Embed(viewer, "", 0);
05066         viewer->SetDOMDocument(domdoc);
05067 
05068         SetCurrentURI(blankDoc->GetDocumentURI(), nsnull, PR_TRUE);
05069         rv = NS_OK;
05070       }
05071     }
05072   }
05073   mCreatingDocument = PR_FALSE;
05074 
05075   // The transient about:blank viewer doesn't have a session history entry.
05076   SetHistoryEntry(&mOSHE, nsnull);
05077 
05078   return rv;
05079 }
05080 
05081 PRBool
05082 nsDocShell::CanSavePresentation(PRUint32 aLoadType,
05083                                 nsIRequest *aNewRequest,
05084                                 nsIDocument *aNewDocument)
05085 {
05086     if (!mOSHE)
05087         return PR_FALSE; // no entry to save into
05088 
05089     // Only save presentation for "normal" loads and link loads.  Anything else
05090     // probably wants to refetch the page, so caching the old presentation
05091     // would be incorrect.
05092     if (aLoadType != LOAD_NORMAL &&
05093         aLoadType != LOAD_HISTORY &&
05094         aLoadType != LOAD_LINK &&
05095         aLoadType != LOAD_STOP_CONTENT &&
05096         aLoadType != LOAD_STOP_CONTENT_AND_REPLACE &&
05097         aLoadType != LOAD_ERROR_PAGE)
05098         return PR_FALSE;
05099 
05100     // If the session history entry has the saveLayoutState flag set to false,
05101     // then we should not cache the presentation.
05102     PRBool canSaveState;
05103     mOSHE->GetSaveLayoutStateFlag(&canSaveState);
05104     if (canSaveState == PR_FALSE)
05105         return PR_FALSE;
05106 
05107     // If the document is not done loading, don't cache it.
05108     nsCOMPtr<nsPIDOMWindow> pWin = do_QueryInterface(mScriptGlobal);
05109     if (!pWin || pWin->IsLoading())
05110         return PR_FALSE;
05111 
05112     if (pWin->WouldReuseInnerWindow(aNewDocument))
05113         return PR_FALSE;
05114 
05115     // Avoid doing the work of saving the presentation state in the case where
05116     // the content viewer cache is disabled.
05117     nsCOMPtr<nsISHistory> rootSH;
05118     GetRootSessionHistory(getter_AddRefs(rootSH));
05119     if (rootSH) {
05120       nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH));
05121       PRInt32 maxViewers;
05122       shistInt->GetHistoryMaxTotalViewers(&maxViewers);
05123       if (maxViewers == 0)
05124         return PR_FALSE;
05125     }
05126 
05127     // Don't cache the content viewer if we're in a subframe and the subframe
05128     // pref is disabled.
05129     PRBool cacheFrames = PR_FALSE;
05130     mPrefs->GetBoolPref("browser.sessionhistory.cache_subframes",
05131                         &cacheFrames);
05132     if (!cacheFrames) {
05133         nsCOMPtr<nsIDocShellTreeItem> root;
05134         GetSameTypeParent(getter_AddRefs(root));
05135         if (root && root != this) {
05136             return PR_FALSE;  // this is a subframe load
05137         }
05138     }
05139 
05140     // If the document does not want its presentation cached, then don't.
05141     nsCOMPtr<nsIDocument> doc = do_QueryInterface(pWin->GetExtantDocument());
05142     if (!doc || !doc->CanSavePresentation(aNewRequest))
05143         return PR_FALSE;
05144 
05145     return PR_TRUE;
05146 }
05147 
05148 nsresult
05149 nsDocShell::CaptureState()
05150 {
05151     if (!mOSHE || mOSHE == mLSHE) {
05152         // No entry to save into, or we're replacing the existing entry.
05153         return NS_ERROR_FAILURE;
05154     }
05155 
05156     nsCOMPtr<nsPIDOMWindow> privWin = do_QueryInterface(mScriptGlobal);
05157     if (!privWin)
05158         return NS_ERROR_FAILURE;
05159 
05160     nsCOMPtr<nsISupports> windowState;
05161     nsresult rv = privWin->SaveWindowState(getter_AddRefs(windowState));
05162     NS_ENSURE_SUCCESS(rv, rv);
05163 
05164 #ifdef DEBUG_PAGE_CACHE
05165     nsCOMPtr<nsIURI> uri;
05166     mOSHE->GetURI(getter_AddRefs(uri));
05167     nsCAutoString spec;
05168     if (uri)
05169         uri->GetSpec(spec);
05170     printf("Saving presentation into session history\n");
05171     printf("  SH URI: %s\n", spec.get());
05172 #endif
05173 
05174     rv = mOSHE->SetWindowState(windowState);
05175     NS_ENSURE_SUCCESS(rv, rv);
05176 
05177     // Suspend refresh URIs and save off the timer queue
05178     rv = mOSHE->SetRefreshURIList(mSavedRefreshURIList);
05179     NS_ENSURE_SUCCESS(rv, rv);
05180 
05181     // Capture the current content viewer bounds.
05182     nsCOMPtr<nsIPresShell> shell;
05183     nsDocShell::GetPresShell(getter_AddRefs(shell));
05184     if (shell) {
05185         nsIViewManager *vm = shell->GetViewManager();
05186         if (vm) {
05187             nsIView *rootView = nsnull;
05188             vm->GetRootView(rootView);
05189             if (rootView) {
05190                 nsIWidget *widget = rootView->GetWidget();
05191                 if (widget) {
05192                     nsRect bounds(0, 0, 0, 0);
05193                     widget->GetBounds(bounds);
05194                     rv = mOSHE->SetViewerBounds(bounds);
05195                 }
05196             }
05197         }
05198     }
05199 
05200     // Capture the docshell hierarchy.
05201     mOSHE->ClearChildShells();
05202 
05203     PRInt32 childCount = mChildList.Count();
05204     for (PRInt32 i = 0; i < childCount; ++i) {
05205         nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
05206         NS_ASSERTION(childShell, "null child shell");
05207 
05208         mOSHE->AddChildShell(childShell);
05209     }
05210 
05211     return NS_OK;
05212 }
05213 
05214 class RestorePresentationEvent : public PLEvent
05215 {
05216 public:
05217     RestorePresentationEvent(nsDocShell *aShell);
05218 
05219     nsRefPtr<nsDocShell> mDocShell;
05220 };
05221 
05222 PR_STATIC_CALLBACK(void*)
05223 HandleRestorePresentationEvent(PLEvent *aEvent)
05224 {
05225     RestorePresentationEvent *event =
05226         NS_STATIC_CAST(RestorePresentationEvent*, aEvent);
05227 
05228     nsresult rv = event->mDocShell->RestoreFromHistory();
05229     NS_ASSERTION(NS_SUCCEEDED(rv), "RestoreFromHistory failed");
05230     return nsnull;
05231 }
05232 
05233 PR_STATIC_CALLBACK(void)
05234 DestroyRestorePresentationEvent(PLEvent *aEvent)
05235 {
05236     delete NS_STATIC_CAST(RestorePresentationEvent*, aEvent);
05237 }
05238 
05239 RestorePresentationEvent::RestorePresentationEvent(nsDocShell *aShell)
05240     : mDocShell(aShell)
05241 {
05242     PL_InitEvent(this, mDocShell, ::HandleRestorePresentationEvent,
05243                  ::DestroyRestorePresentationEvent);
05244 }
05245 
05246 NS_IMETHODIMP
05247 nsDocShell::BeginRestore(nsIContentViewer *aContentViewer, PRBool aTop)
05248 {
05249     nsresult rv;
05250     if (!aContentViewer) {
05251         rv = EnsureContentViewer();
05252         NS_ENSURE_SUCCESS(rv, rv);
05253 
05254         aContentViewer = mContentViewer;
05255     }
05256 
05257     // Dispatch events for restoring the presentation.  We try to simulate
05258     // the progress notifications loading the document would cause, so we add
05259     // the document's channel to the loadgroup to initiate stateChange
05260     // notifications.
05261 
05262     nsCOMPtr<nsIDOMDocument> domDoc;
05263     aContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
05264     nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
05265     if (doc) {
05266         nsIChannel *channel = doc->GetChannel();
05267         if (channel) {
05268             mEODForCurrentDocument = PR_FALSE;
05269             mIsRestoringDocument = PR_TRUE;
05270             mLoadGroup->AddRequest(channel, nsnull);
05271             mIsRestoringDocument = PR_FALSE;
05272         }
05273     }
05274 
05275     if (!aTop) {
05276         // This point corresponds to us having gotten OnStartRequest or
05277         // STATE_START, so do the same thing that CreateContentViewer does at
05278         // this point to ensure that unload/pagehide events for this document
05279         // will fire when it's unloaded again.
05280         mFiredUnloadEvent = PR_FALSE;
05281         
05282         // For non-top frames, there is no notion of making sure that the
05283         // previous document is in the domwindow when STATE_START notifications
05284         // happen.  We can just call BeginRestore for all of the child shells
05285         // now.
05286         rv = BeginRestoreChildren();
05287         NS_ENSURE_SUCCESS(rv, rv);
05288     }
05289 
05290     return NS_OK;
05291 }
05292 
05293 nsresult
05294 nsDocShell::BeginRestoreChildren()
05295 {
05296     PRInt32 n = mChildList.Count();
05297     for (PRInt32 i = 0; i < n; ++i) {
05298         nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
05299         if (child) {
05300             nsresult rv = child->BeginRestore(nsnull, PR_FALSE);
05301             NS_ENSURE_SUCCESS(rv, rv);
05302         }
05303     }
05304     return NS_OK;
05305 }
05306 
05307 NS_IMETHODIMP
05308 nsDocShell::FinishRestore()
05309 {
05310     // First we call finishRestore() on our children.  In the simulated load,
05311     // all of the child frames finish loading before the main document.
05312 
05313     PRInt32 n = mChildList.Count();
05314     for (PRInt32 i = 0; i < n; ++i) {
05315         nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
05316         if (child) {
05317             child->FinishRestore();
05318         }
05319     }
05320 
05321     if (mContentViewer) {
05322         nsCOMPtr<nsIDOMDocument> domDoc;
05323         mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
05324 
05325         nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
05326         if (doc) {
05327             // Finally, we remove the request from the loadgroup.  This will
05328             // cause onStateChange(STATE_STOP) to fire, which will fire the
05329             // pageshow event to the chrome.
05330 
05331             nsIChannel *channel = doc->GetChannel();
05332             if (channel) {
05333                 mIsRestoringDocument = PR_TRUE;
05334                 mLoadGroup->RemoveRequest(channel, nsnull, NS_OK);
05335                 mIsRestoringDocument = PR_FALSE;
05336             }
05337         }
05338     }
05339 
05340     return NS_OK;
05341 }
05342 
05343 NS_IMETHODIMP
05344 nsDocShell::GetRestoringDocument(PRBool *aRestoring)
05345 {
05346     *aRestoring = mIsRestoringDocument;
05347     return NS_OK;
05348 }
05349 
05350 nsresult
05351 nsDocShell::RestorePresentation(nsISHEntry *aSHEntry, PRBool *aRestoring)
05352 {
05353     NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
05354                  "RestorePresentation should only be called for history loads");
05355 
05356     nsCOMPtr<nsIContentViewer> viewer;
05357     aSHEntry->GetContentViewer(getter_AddRefs(viewer));
05358 
05359 #ifdef DEBUG_PAGE_CACHE
05360     nsCOMPtr<nsIURI> uri;
05361     aSHEntry->GetURI(getter_AddRefs(uri));
05362 
05363     nsCAutoString spec;
05364     if (uri)
05365         uri->GetSpec(spec);
05366 #endif
05367 
05368     *aRestoring = PR_FALSE;
05369 
05370     if (!viewer) {
05371 #ifdef DEBUG_PAGE_CACHE
05372         printf("no saved presentation for uri: %s\n", spec.get());
05373 #endif
05374         return NS_OK;
05375     }
05376 
05377     // We need to make sure the content viewer's container is this docshell.
05378     // In subframe navigation, it's possible for the docshell that the
05379     // content viewer was originally loaded into to be replaced with a
05380     // different one.  We don't currently support restoring the presentation
05381     // in that case.
05382 
05383     nsCOMPtr<nsISupports> container;
05384     viewer->GetContainer(getter_AddRefs(container));
05385     if (!::SameCOMIdentity(container, GetAsSupports(this))) {
05386 #ifdef DEBUG_PAGE_CACHE
05387         printf("No valid container, clearing presentation\n");
05388 #endif
05389         aSHEntry->SetContentViewer(nsnull);
05390         return NS_ERROR_FAILURE;
05391     }
05392 
05393     NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation");
05394 
05395 #ifdef DEBUG_PAGE_CACHE
05396     printf("restoring presentation from session history: %s\n", spec.get());
05397 #endif
05398 
05399     SetHistoryEntry(&mLSHE, aSHEntry);
05400 
05401     // Add the request to our load group.  We do this before swapping out
05402     // the content viewers so that consumers of STATE_START can access
05403     // the old document.  We only deal with the toplevel load at this time --
05404     // to be consistent with normal document loading, subframes cannot start
05405     // loading until after data arrives, which is after STATE_START completes.
05406 
05407     BeginRestore(viewer, PR_TRUE);
05408 
05409     // Post a PLEvent that will remove the request after we've returned
05410     // to the event loop.  This mimics the way it is called by nsIChannel
05411     // implementations.
05412 
05413     nsCOMPtr<nsIEventQueue> uiThreadQueue;
05414     NS_GetMainEventQ(getter_AddRefs(uiThreadQueue));
05415     NS_ENSURE_TRUE(uiThreadQueue, NS_ERROR_UNEXPECTED);
05416 
05417     PLEvent *evt = new RestorePresentationEvent(this);
05418     NS_ENSURE_TRUE(evt, NS_ERROR_OUT_OF_MEMORY);
05419 
05420     nsresult rv = uiThreadQueue->PostEvent(evt);
05421     if (NS_SUCCEEDED(rv)) {
05422         // The rest of the restore processing will happen on our PLEvent
05423         // callback.
05424         *aRestoring = PR_TRUE;
05425     } else {
05426         PL_DestroyEvent(evt);
05427     }
05428 
05429     return NS_OK;
05430 }
05431 
05432 nsresult
05433 nsDocShell::RestoreFromHistory()
05434 {
05435     // This section of code follows the same ordering as CreateContentViewer.
05436     if (!mLSHE)
05437         return NS_ERROR_FAILURE;
05438 
05439     nsCOMPtr<nsIContentViewer> viewer;
05440     mLSHE->GetContentViewer(getter_AddRefs(viewer));
05441     if (!viewer)
05442         return NS_ERROR_FAILURE;
05443 
05444     if (mSavingOldViewer) {
05445         // We determined that it was safe to cache the document presentation
05446         // at the time we initiated the new load.  We need to check whether
05447         // it's still safe to do so, since there may have been DOM mutations
05448         // or new requests initiated.
05449         nsCOMPtr<nsIDOMDocument> domDoc;
05450         viewer->GetDOMDocument(getter_AddRefs(domDoc));
05451         nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
05452         nsIRequest *request = nsnull;
05453         if (doc)
05454             request = doc->GetChannel();
05455         mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
05456     }
05457 
05458     nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV(do_QueryInterface(mContentViewer));
05459     nsCOMPtr<nsIMarkupDocumentViewer> newMUDV(do_QueryInterface(viewer));
05460     float zoom = 1.0;
05461     if (oldMUDV && newMUDV)
05462         oldMUDV->GetTextZoom(&zoom);
05463 
05464     // Protect against mLSHE going away via a load triggered from
05465     // pagehide or unload.
05466     nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
05467 
05468     // Notify the old content viewer that it's being hidden.
05469     FirePageHideNotification(!mSavingOldViewer);
05470 
05471     // If mLSHE was changed as a result of the pagehide event, then
05472     // something else was loaded.  Don't finish restoring.
05473     if (mLSHE != origLSHE)
05474       return NS_OK;
05475 
05476     // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
05477     // *new* document will fire.
05478     mFiredUnloadEvent = PR_FALSE;
05479 
05480     mURIResultedInDocument = PR_TRUE;
05481     nsCOMPtr<nsISHistory> rootSH;
05482     GetRootSessionHistory(getter_AddRefs(rootSH));
05483     if (rootSH) {
05484         nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH);
05485         rootSH->GetIndex(&mPreviousTransIndex);
05486         hist->UpdateIndex();
05487         rootSH->GetIndex(&mLoadedTransIndex);
05488 #ifdef DEBUG_PAGE_CACHE
05489         printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
05490                    mLoadedTransIndex);
05491 #endif
05492     }
05493 
05494     // Rather than call Embed(), we will retrieve the viewer from the session
05495     // history entry and swap it in.
05496     // XXX can we refactor this so that we can just call Embed()?
05497     // XXX PersistLayoutHistoryState() ?
05498     nsresult rv;
05499     if (mContentViewer) {
05500         if (mSavingOldViewer && NS_FAILED(CaptureState())) {
05501             if (mOSHE) {
05502                 mOSHE->SyncPresentationState();
05503             }
05504             mSavingOldViewer = PR_FALSE;
05505         }
05506     }
05507 
05508     mSavedRefreshURIList = nsnull;
05509 
05510     // In cases where we use a transient about:blank viewer between loads,
05511     // we never show the transient viewer, so _its_ previous viewer is never
05512     // unhooked from the view hierarchy.  Destroy any such previous viewer now,
05513     // before we grab the root view sibling, so that we don't grab a view
05514     // that's about to go away.
05515 
05516     if (mContentViewer) {
05517         nsCOMPtr<nsIContentViewer> previousViewer;
05518         mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
05519         if (previousViewer) {
05520             mContentViewer->SetPreviousViewer(nsnull);
05521             previousViewer->Destroy();
05522         }
05523     }
05524 
05525     // Save off the root view's parent and sibling so that we can insert the
05526     // new content viewer's root view at the same position.  Also save the
05527     // bounds of the root view's widget.
05528 
05529     nsIView *rootViewSibling = nsnull, *rootViewParent = nsnull;
05530     nsRect newBounds(0, 0, 0, 0);
05531 
05532     nsCOMPtr<nsIPresShell> oldPresShell;
05533     nsDocShell::GetPresShell(getter_AddRefs(oldPresShell));
05534     if (oldPresShell) {
05535         nsIViewManager *vm = oldPresShell->GetViewManager();
05536         if (vm) {
05537             nsIView *oldRootView = nsnull;
05538             vm->GetRootView(oldRootView);
05539 
05540             if (oldRootView) {
05541                 rootViewSibling = oldRootView->GetNextSibling();
05542                 rootViewParent = oldRootView->GetParent();
05543 
05544                 nsIWidget *widget = oldRootView->GetWidget();
05545                 if (widget) {
05546                     widget->GetBounds(newBounds);
05547                 }
05548             }
05549         }
05550     }
05551 
05552     // Transfer ownership to mContentViewer.  By ensuring that either the
05553     // docshell or the session history, but not both, have references to the
05554     // content viewer, we prevent the viewer from being torn down after
05555     // Destroy() is called.
05556 
05557     if (mContentViewer) {
05558         mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nsnull);
05559         viewer->SetPreviousViewer(mContentViewer);
05560     }
05561 
05562     mContentViewer.swap(viewer);
05563     viewer = nsnull; // force a release to complete ownership transfer
05564 
05565     // Grab all of the related presentation from the SHEntry now.
05566     // mLSHE may be cleared before we need this data.
05567     nsCOMPtr<nsISupports> windowState;
05568     mLSHE->GetWindowState(getter_AddRefs(windowState));
05569     mLSHE->SetWindowState(nsnull);
05570 
05571     PRBool sticky;
05572     mLSHE->GetSticky(&sticky);
05573 
05574     nsCOMPtr<nsIDOMDocument> domDoc;
05575     mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
05576 
05577     // get the previous content viewer size
05578     nsRect oldBounds(0, 0, 0, 0);
05579     mLSHE->GetViewerBounds(oldBounds);
05580 
05581     nsCOMPtr<nsISupportsArray> refreshURIList;
05582     mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIList));
05583     mLSHE->SetRefreshURIList(nsnull);
05584 
05585     // Reattach to the window object.
05586     nsCOMPtr<nsIContentViewer_MOZILLA_1_8_BRANCH> cv18 =
05587         do_QueryInterface(mContentViewer);
05588     rv = cv18->OpenWithEntry(windowState, mLSHE);
05589 
05590     // Now that we're done calling OpenWithEntry, we can grab the child
05591     // shell list off of mLSHE as well.
05592     nsCOMArray<nsIDocShellTreeItem> childShells;
05593     PRInt32 i = 0;
05594     nsCOMPtr<nsIDocShellTreeItem> child;
05595     while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
05596            child) {
05597         childShells.AppendObject(child);
05598     }
05599     mLSHE->ClearChildShells();
05600 
05601     // Now remove it from the cached presentation.
05602     mLSHE->SetContentViewer(nsnull);
05603     mEODForCurrentDocument = PR_FALSE;
05604 
05605     // Restore the sticky state of the viewer.  The viewer has set this state
05606     // on the history entry in Destroy() just before marking itself non-sticky,
05607     // to avoid teardown of the presentation.
05608     mContentViewer->SetSticky(sticky);
05609 
05610     // Now that we have switched documents, forget all of our children.
05611     DestroyChildren();
05612     NS_ENSURE_SUCCESS(rv, rv);
05613 
05614     // mLSHE is now our currently-loaded document.
05615     SetHistoryEntry(&mOSHE, mLSHE);
05616     
05617     // XXX special wyciwyg handling in Embed()?
05618 
05619     // We aren't going to restore any items from the LayoutHistoryState,
05620     // but we don't want them to stay around in case the page is reloaded.
05621     SetLayoutHistoryState(nsnull);
05622 
05623     // This is the end of our Embed() replacement
05624 
05625     mSavingOldViewer = PR_FALSE;
05626     mEODForCurrentDocument = PR_FALSE;
05627 
05628     // Tell the event loop to favor plevents over user events, see comments
05629     // in CreateContentViewer.
05630     if (++gNumberOfDocumentsLoading == 1)
05631         PL_FavorPerformanceHint(PR_TRUE, NS_EVENT_STARVATION_DELAY_HINT);
05632 
05633 
05634     if (oldMUDV && newMUDV)
05635         newMUDV->SetTextZoom(zoom);
05636 
05637     nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
05638     if (document) {
05639         // Use the uri from the mLSHE we had when we entered this function
05640         // (which need not match the document's URI if anchors are involved),
05641         // since that's the history entry we're loading.  Note that if we use
05642         // origLSHE we don't have to worry about whether the entry in question
05643         // is still mLSHE or whether it's now mOSHE.
05644         nsCOMPtr<nsIURI> uri;
05645         origLSHE->GetURI(getter_AddRefs(uri));
05646         SetCurrentURI(uri, document->GetChannel(), PR_TRUE);
05647     }
05648 
05649     // This is the end of our CreateContentViewer() replacement.
05650     // Now we simulate a load.  First, we restore the state of the javascript
05651     // window object.
05652     nsCOMPtr<nsPIDOMWindow> privWin =
05653         do_GetInterface(NS_STATIC_CAST(nsIInterfaceRequestor*, this));
05654     NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
05655 
05656     rv = privWin->RestoreWindowState(windowState);
05657     NS_ENSURE_SUCCESS(rv, rv);
05658 
05659     // Now, dispatch a title change event which would happed as the
05660     // <head> is parsed.
05661     nsCOMPtr<nsIDOMNSDocument> nsDoc = do_QueryInterface(document);
05662     if (nsDoc) {
05663         const nsAFlatString &title = document->GetDocumentTitle();
05664         nsDoc->SetTitle(title);
05665     }
05666 
05667     // Now we simulate appending child docshells for subframes.
05668     for (i = 0; i < childShells.Count(); ++i) {
05669         nsIDocShellTreeItem *childItem = childShells.ObjectAt(i);
05670         nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem);
05671 
05672         // Make sure to not clobber the state of the child.  Since AddChild
05673         // always clobbers it, save it off first.
05674         PRBool allowPlugins;
05675         childShell->GetAllowPlugins(&allowPlugins);
05676 
05677         PRBool allowJavascript;
05678         childShell->GetAllowJavascript(&allowJavascript);
05679 
05680         PRBool allowRedirects;
05681         childShell->GetAllowMetaRedirects(&allowRedirects);
05682 
05683         PRBool allowSubframes;
05684         childShell->GetAllowSubframes(&allowSubframes);
05685 
05686         PRBool allowImages;
05687         childShell->GetAllowImages(&allowImages);
05688         
05689         AddChild(childItem);
05690 
05691         childShell->SetAllowPlugins(allowPlugins);
05692         childShell->SetAllowJavascript(allowJavascript);
05693         childShell->SetAllowMetaRedirects(allowRedirects);
05694         childShell->SetAllowSubframes(allowSubframes);
05695         childShell->SetAllowImages(allowImages);
05696 
05697         rv = childShell->BeginRestore(nsnull, PR_FALSE);
05698         NS_ENSURE_SUCCESS(rv, rv);
05699     }
05700 
05701     nsCOMPtr<nsIPresShell> shell;
05702     nsDocShell::GetPresShell(getter_AddRefs(shell));
05703 
05704     nsIViewManager *newVM = shell ? shell->GetViewManager() : nsnull;
05705     nsIView *newRootView = nsnull;
05706     if (newVM)
05707         newVM->GetRootView(newRootView);
05708 
05709     // Insert the new root view at the correct location in the view tree.
05710     if (rootViewParent) {
05711         nsIViewManager *parentVM = rootViewParent->GetViewManager();
05712 
05713         if (parentVM && newRootView) {
05714             // InsertChild(parent, child, sib, PR_TRUE) inserts the child after
05715             // sib in content order, which is before sib in view order. BUT
05716             // when sib is null it inserts at the end of the the document
05717             // order, i.e., first in view order.  But when oldRootSibling is
05718             // null, the old root as at the end of the view list --- last in
05719             // content order --- and we want to call InsertChild(parent, child,
05720             // nsnull, PR_FALSE) in that case.
05721             parentVM->InsertChild(rootViewParent, newRootView,
05722                                   rootViewSibling,
05723                                   rootViewSibling ? PR_TRUE : PR_FALSE);
05724 
05725             NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
05726                          "error in InsertChild");
05727         }
05728     }
05729 
05730     // Now that all of the child docshells have been put into place, we can
05731     // restart the timers for the window and all of the child frames.
05732     privWin->ResumeTimeouts();
05733 
05734     // Restore the refresh URI list.  The refresh timers will be restarted
05735     // when EndPageLoad() is called.
05736     mRefreshURIList = refreshURIList;
05737 
05738     // Meta-refresh timers have been restarted for this shell, but not
05739     // for our children.  Walk the child shells and restart their timers.
05740     PRInt32 n = mChildList.Count();
05741     for (i = 0; i < n; ++i) {
05742         nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
05743         if (child)
05744             child->ResumeRefreshURIs();
05745     }
05746 
05747     // Make sure this presentation is the same size as the previous
05748     // presentation.  If this is not the same size we showed it at last time,
05749     // then we need to resize the widget.
05750 
05751     // XXXbryner   This interacts poorly with Firefox's infobar.  If the old
05752     // presentation had the infobar visible, then we will resize the new
05753     // presentation to that smaller size.  However, firing the locationchanged
05754     // event will hide the infobar, which will immediately resize the window
05755     // back to the larger size.  A future optimization might be to restore
05756     // the presentation at the "wrong" size, then fire the locationchanged
05757     // event and check whether the docshell's new size is the same as the
05758     // cached viewer size (skipping the resize if they are equal).
05759 
05760     if (newRootView) {
05761         nsIWidget *widget = newRootView->GetWidget();
05762         if (widget && !newBounds.IsEmpty() && newBounds != oldBounds) {
05763 #ifdef DEBUG_PAGE_CACHE
05764             printf("resize widget(%d, %d, %d, %d)\n", newBounds.x,
05765                    newBounds.y, newBounds.width, newBounds.height);
05766 #endif
05767 
05768             widget->Resize(newBounds.x, newBounds.y, newBounds.width,
05769                            newBounds.height, PR_FALSE);
05770         }
05771     }
05772 
05773     // Simulate the completion of the load.
05774     nsDocShell::FinishRestore();
05775 
05776     // Restart plugins, and paint the content.
05777     if (shell)
05778         shell->Thaw();
05779 
05780     nsCOMPtr<nsPIDOMWindow_MOZILLA_1_8_BRANCH> win18 = do_QueryInterface(privWin);
05781     NS_ENSURE_STATE(win18);
05782     return win18->FireDelayedDOMEvents();
05783 }
05784 
05785 NS_IMETHODIMP
05786 nsDocShell::CreateContentViewer(const char *aContentType,
05787                                 nsIRequest * request,
05788                                 nsIStreamListener ** aContentHandler)
05789 {
05790     *aContentHandler = nsnull;
05791 
05792     // Can we check the content type of the current content viewer
05793     // and reuse it without destroying it and re-creating it?
05794 
05795     NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?");
05796 
05797     // Instantiate the content viewer object
05798     nsCOMPtr<nsIContentViewer> viewer;
05799     nsresult rv = NewContentViewerObj(aContentType, request, mLoadGroup,
05800                                       aContentHandler, getter_AddRefs(viewer));
05801 
05802     if (NS_FAILED(rv))
05803         return NS_ERROR_FAILURE;
05804 
05805     // Notify the current document that it is about to be unloaded!!
05806     //
05807     // It is important to fire the unload() notification *before* any state
05808     // is changed within the DocShell - otherwise, javascript will get the
05809     // wrong information :-(
05810     //
05811 
05812     if (mSavingOldViewer) {
05813         // We determined that it was safe to cache the document presentation
05814         // at the time we initiated the new load.  We need to check whether
05815         // it's still safe to do so, since there may have been DOM mutations
05816         // or new requests initiated.
05817         nsCOMPtr<nsIDOMDocument> domDoc;
05818         viewer->GetDOMDocument(getter_AddRefs(domDoc));
05819         nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
05820         mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
05821     }
05822 
05823     FirePageHideNotification(!mSavingOldViewer);
05824 
05825     // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
05826     // *new* document will fire.
05827     mFiredUnloadEvent = PR_FALSE;
05828 
05829     // we've created a new document so go ahead and call
05830     // OnLoadingSite(), but don't fire OnLocationChange()
05831     // notifications before we've called Embed(). See bug 284993.
05832     mURIResultedInDocument = PR_TRUE;
05833 
05834     nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
05835 
05836     PRBool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, PR_FALSE);
05837 
05838     // let's try resetting the load group if we need to...
05839     nsCOMPtr<nsILoadGroup> currentLoadGroup;
05840     NS_ENSURE_SUCCESS(aOpenedChannel->
05841                       GetLoadGroup(getter_AddRefs(currentLoadGroup)),
05842                       NS_ERROR_FAILURE);
05843 
05844     if (currentLoadGroup != mLoadGroup) {
05845         nsLoadFlags loadFlags = 0;
05846 
05847         //Cancel any URIs that are currently loading...
05849         //
05850         // Retarget the document to this loadgroup...
05851         //
05852         /* First attach the channel to the right loadgroup
05853          * and then remove from the old loadgroup. This 
05854          * puts the notifications in the right order and
05855          * we don't null-out mLSHE in OnStateChange() for 
05856          * all redirected urls
05857          */
05858         aOpenedChannel->SetLoadGroup(mLoadGroup);
05859 
05860         // Mark the channel as being a document URI...
05861         aOpenedChannel->GetLoadFlags(&loadFlags);
05862         loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
05863 
05864         aOpenedChannel->SetLoadFlags(loadFlags);
05865 
05866         mLoadGroup->AddRequest(request, nsnull);
05867         if (currentLoadGroup)
05868             currentLoadGroup->RemoveRequest(request, nsnull,
05869                                             NS_BINDING_RETARGETED);
05870 
05871         // Update the notification callbacks, so that progress and
05872         // status information are sent to the right docshell...
05873         aOpenedChannel->SetNotificationCallbacks(this);
05874     }
05875 
05876     NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nsnull),
05877                       NS_ERROR_FAILURE);
05878 
05879     mSavedRefreshURIList = nsnull;
05880     mSavingOldViewer = PR_FALSE;
05881     mEODForCurrentDocument = PR_FALSE;
05882 
05883     // if this document is part of a multipart document,
05884     // the ID can be used to distinguish it from the other parts.
05885     nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(request));
05886     if (multiPartChannel) {
05887       nsCOMPtr<nsIPresShell> shell;
05888       rv = GetPresShell(getter_AddRefs(shell));
05889       if (NS_SUCCEEDED(rv) && shell) {
05890         nsIDocument *doc = shell->GetDocument();
05891         if (doc) {
05892           PRUint32 partID;
05893           multiPartChannel->GetPartID(&partID);
05894           doc->SetPartID(partID);
05895         }
05896       }
05897     }
05898 
05899     // Give hint to native plevent dispatch mechanism. If a document
05900     // is loading the native plevent dispatch mechanism should favor
05901     // performance over normal native event dispatch priorities.
05902     if (++gNumberOfDocumentsLoading == 1) {
05903       // Hint to favor performance for the plevent notification mechanism.
05904       // We want the pages to load as fast as possible even if its means 
05905       // native messages might be starved.
05906       PL_FavorPerformanceHint(PR_TRUE, NS_EVENT_STARVATION_DELAY_HINT);
05907     }
05908 
05909     if (onLocationChangeNeeded) {
05910       FireOnLocationChange(this, request, mCurrentURI);
05911     }
05912   
05913     return NS_OK;
05914 }
05915 
05916 nsresult
05917 nsDocShell::NewContentViewerObj(const char *aContentType,
05918                                 nsIRequest * request, nsILoadGroup * aLoadGroup,
05919                                 nsIStreamListener ** aContentHandler,
05920                                 nsIContentViewer ** aViewer)
05921 {
05922     nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
05923 
05924     nsresult rv;
05925     nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
05926     if (NS_FAILED(rv))
05927       return rv;
05928     
05929     nsXPIDLCString contractId;
05930     rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", aContentType, getter_Copies(contractId));
05931 
05932     // Create an instance of the document-loader-factory
05933     nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory;
05934     if (NS_SUCCEEDED(rv))
05935         docLoaderFactory = do_GetService(contractId.get());
05936 
05937     if (!docLoaderFactory) {
05938         return NS_ERROR_FAILURE;
05939     }
05940 
05941     // Now create an instance of the content viewer
05942     // nsLayoutDLF makes the determination if it should be a "view-source" instead of "view"
05943     NS_ENSURE_SUCCESS(docLoaderFactory->CreateInstance("view",
05944                                                        aOpenedChannel,
05945                                                        aLoadGroup, aContentType,
05946                                                        NS_STATIC_CAST
05947                                                        (nsIContentViewerContainer
05948                                                         *, this), nsnull,
05949                                                        aContentHandler,
05950                                                        aViewer),
05951                       NS_ERROR_FAILURE);
05952 
05953     (*aViewer)->SetContainer(NS_STATIC_CAST(nsIContentViewerContainer *, this));
05954     return NS_OK;
05955 }
05956 
05957 NS_IMETHODIMP
05958 nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
05959 {
05960     //
05961     // Copy content viewer state from previous or parent content viewer.
05962     //
05963     // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
05964     //
05965     // Do NOT to maintain a reference to the old content viewer outside
05966     // of this "copying" block, or it will not be destroyed until the end of
05967     // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
05968     //
05969     // In this block of code, if we get an error result, we return it
05970     // but if we get a null pointer, that's perfectly legal for parent
05971     // and parentContentViewer.
05972     //
05973 
05974     PRInt32 x = 0;
05975     PRInt32 y = 0;
05976     PRInt32 cx = 0;
05977     PRInt32 cy = 0;
05978 
05979     // This will get the size from the current content viewer or from the
05980     // Init settings
05981     GetPositionAndSize(&x, &y, &cx, &cy);
05982 
05983     nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
05984     NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
05985                       NS_ERROR_FAILURE);
05986     nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
05987 
05988     nsCAutoString defaultCharset;
05989     nsCAutoString forceCharset;
05990     nsCAutoString hintCharset;
05991     PRInt32 hintCharsetSource;
05992     nsCAutoString prevDocCharset;
05993     float textZoom;
05994     PRBool styleDisabled;
05995     // |newMUDV| also serves as a flag to set the data from the above vars
05996     nsCOMPtr<nsIMarkupDocumentViewer> newMUDV;
05997 
05998     if (mContentViewer || parent) {
05999         nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV;
06000         if (mContentViewer) {
06001             // Get any interesting state from old content viewer
06002             // XXX: it would be far better to just reuse the document viewer ,
06003             //      since we know we're just displaying the same document as before
06004             oldMUDV = do_QueryInterface(mContentViewer);
06005 
06006             // Tell the old content viewer to hibernate in session history when
06007             // it is destroyed.
06008 
06009             if (mSavingOldViewer && NS_FAILED(CaptureState())) {
06010                 if (mOSHE) {
06011                     mOSHE->SyncPresentationState();
06012                 }
06013                 mSavingOldViewer = PR_FALSE;
06014             }
06015         }
06016         else {
06017             // No old content viewer, so get state from parent's content viewer
06018             nsCOMPtr<nsIContentViewer> parentContentViewer;
06019             parent->GetContentViewer(getter_AddRefs(parentContentViewer));
06020             oldMUDV = do_QueryInterface(parentContentViewer);
06021         }
06022 
06023         if (oldMUDV) {
06024             nsresult rv;
06025 
06026             newMUDV = do_QueryInterface(aNewViewer,&rv);
06027             if (newMUDV) {
06028                 NS_ENSURE_SUCCESS(oldMUDV->
06029                                   GetDefaultCharacterSet(defaultCharset),
06030                                   NS_ERROR_FAILURE);
06031                 NS_ENSURE_SUCCESS(oldMUDV->
06032                                   GetForceCharacterSet(forceCharset),
06033                                   NS_ERROR_FAILURE);
06034                 NS_ENSURE_SUCCESS(oldMUDV->
06035                                   GetHintCharacterSet(hintCharset),
06036                                   NS_ERROR_FAILURE);
06037                 NS_ENSURE_SUCCESS(oldMUDV->
06038                                   GetHintCharacterSetSource(&hintCharsetSource),
06039                                   NS_ERROR_FAILURE);
06040                 NS_ENSURE_SUCCESS(oldMUDV->
06041                                   GetTextZoom(&textZoom),
06042                                   NS_ERROR_FAILURE);
06043                 NS_ENSURE_SUCCESS(oldMUDV->
06044                                   GetAuthorStyleDisabled(&styleDisabled),
06045                                   NS_ERROR_FAILURE);
06046                 NS_ENSURE_SUCCESS(oldMUDV->
06047                                   GetPrevDocCharacterSet(prevDocCharset),
06048                                   NS_ERROR_FAILURE);
06049             }
06050         }
06051     }
06052 
06053     // It is necessary to obtain the focus controller to utilize its ability
06054     // to suppress focus.  This is necessary to fix Win32-only bugs related to
06055     // a loss of focus when mContentViewer is set to null.  The internal window
06056     // is destroyed, and the OS focuses the parent window.  This call ends up
06057     // notifying the focus controller that the outer window should focus
06058     // and this hoses us on any link traversal.
06059     //
06060     // Please do not touch any of the focus controller code here without
06061     // testing bugs #28580 and 50509.  These are immensely important bugs,
06062     // so PLEASE take care not to regress them if you decide to alter this 
06063     // code later              -- hyatt
06064     nsIFocusController *focusController = nsnull;
06065     if (mScriptGlobal) {
06066         nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(mScriptGlobal);
06067         focusController = ourWindow->GetRootFocusController();
06068         if (focusController) {
06069             // Suppress the command dispatcher.
06070             focusController->SetSuppressFocus(PR_TRUE,
06071                                               "Win32-Only Link Traversal Issue");
06072             // Remove focus from the element that has it
06073             nsCOMPtr<nsIDOMWindowInternal> focusedWindow;
06074             focusController->GetFocusedWindow(getter_AddRefs(focusedWindow));
06075 
06076             // We want to null out the last focused element if the document containing
06077             // it is going away.  If the last focused element is in a descendent
06078             // window of our domwindow, its document will be destroyed when we
06079             // destroy our children.  So, check for this case and null out the
06080             // last focused element.  See bug 70484.
06081 
06082             PRBool isSubWindow = PR_FALSE;
06083             nsCOMPtr<nsIDOMWindow> curwin;
06084             if (focusedWindow)
06085               focusedWindow->GetParent(getter_AddRefs(curwin));
06086             while (curwin) {
06087               if (curwin == ourWindow) {
06088                 isSubWindow = PR_TRUE;
06089                 break;
06090               }
06091 
06092               // don't use nsCOMPtr here to avoid extra addref
06093               // when assigning to curwin
06094               nsIDOMWindow* temp;
06095               curwin->GetParent(&temp);
06096               if (curwin == temp) {
06097                 NS_RELEASE(temp);
06098                 break;
06099               }
06100               curwin = dont_AddRef(temp);
06101             }
06102 
06103             if (ourWindow == focusedWindow || isSubWindow)
06104               focusController->ResetElementFocus();
06105         }
06106     }
06107 
06108     nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
06109     PRBool bgSet = PR_FALSE;
06110 
06111     // Ensure that the content viewer is destroyed *after* the GC - bug 71515
06112     nsCOMPtr<nsIContentViewer> kungfuDeathGrip = mContentViewer;
06113     if (mContentViewer) {
06114         // Stop any activity that may be happening in the old document before
06115         // releasing it...
06116         mContentViewer->Stop();
06117 
06118         // Try to extract the default background color from the old
06119         // view manager, so we can use it for the next document.
06120         nsCOMPtr<nsIDocumentViewer> docviewer =
06121         do_QueryInterface(mContentViewer);
06122 
06123         if (docviewer) {
06124             nsCOMPtr<nsIPresShell> shell;
06125             docviewer->GetPresShell(getter_AddRefs(shell));
06126 
06127             if (shell) {
06128                 nsIViewManager* vm = shell->GetViewManager();
06129 
06130                 if (vm) {
06131                     vm->GetDefaultBackgroundColor(&bgcolor);
06132                     // If the background color is not known, don't propagate it.
06133                     bgSet = NS_GET_A(bgcolor) != 0;
06134                 }
06135             }
06136         }
06137 
06138         mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nsnull);
06139         aNewViewer->SetPreviousViewer(mContentViewer);
06140 
06141         mContentViewer = nsnull;
06142     }
06143 
06144     mContentViewer = aNewViewer;
06145 
06146     nsCOMPtr<nsIWidget> widget;
06147     NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
06148 
06149     if (widget) {
06150         NS_ENSURE_SUCCESS(EnsureDeviceContext(), NS_ERROR_FAILURE);
06151     }
06152 
06153     nsRect bounds(x, y, cx, cy);
06154 
06155     if (NS_FAILED(mContentViewer->Init(widget, mDeviceContext, bounds))) {
06156         mContentViewer = nsnull;
06157         NS_ERROR("ContentViewer Initialization failed");
06158         return NS_ERROR_FAILURE;
06159     }
06160 
06161     // If we have old state to copy, set the old state onto the new content
06162     // viewer
06163     if (newMUDV) {
06164         NS_ENSURE_SUCCESS(newMUDV->SetDefaultCharacterSet(defaultCharset),
06165                           NS_ERROR_FAILURE);
06166         NS_ENSURE_SUCCESS(newMUDV->SetForceCharacterSet(forceCharset),
06167                           NS_ERROR_FAILURE);
06168         NS_ENSURE_SUCCESS(newMUDV->SetHintCharacterSet(hintCharset),
06169                           NS_ERROR_FAILURE);
06170         NS_ENSURE_SUCCESS(newMUDV->
06171                           SetHintCharacterSetSource(hintCharsetSource),
06172                           NS_ERROR_FAILURE);
06173         NS_ENSURE_SUCCESS(newMUDV->SetPrevDocCharacterSet(prevDocCharset),
06174                           NS_ERROR_FAILURE);
06175         NS_ENSURE_SUCCESS(newMUDV->SetTextZoom(textZoom),
06176                           NS_ERROR_FAILURE);
06177         NS_ENSURE_SUCCESS(newMUDV->SetAuthorStyleDisabled(styleDisabled),
06178                           NS_ERROR_FAILURE);
06179     }
06180 
06181     // End copying block (Don't mess with the old content/document viewer
06182     // beyond here!!)
06183 
06184     // See the book I wrote above regarding why the focus controller is 
06185     // being used here.  -- hyatt
06186 
06187     /* Note it's important that focus suppression be turned off no earlier
06188        because in cases where the docshell is lazily creating an about:blank
06189        document, mContentViewer->Init finally puts a reference to that
06190        document into the DOM window, which prevents an infinite recursion
06191        attempting to lazily create the document as focus is unsuppressed
06192        (bug 110856). */
06193     if (focusController)
06194         focusController->SetSuppressFocus(PR_FALSE,
06195                                           "Win32-Only Link Traversal Issue");
06196 
06197     if (bgSet && widget) {
06198         // Stuff the bgcolor from the last view manager into the new
06199         // view manager. This improves page load continuity.
06200         nsCOMPtr<nsIDocumentViewer> docviewer =
06201             do_QueryInterface(mContentViewer);
06202 
06203         if (docviewer) {
06204             nsCOMPtr<nsIPresShell> shell;
06205             docviewer->GetPresShell(getter_AddRefs(shell));
06206 
06207             if (shell) {
06208                 nsIViewManager* vm = shell->GetViewManager();
06209 
06210                 if (vm) {
06211                     vm->SetDefaultBackgroundColor(bgcolor);
06212                 }
06213             }
06214         }
06215     }
06216 
06217 // XXX: It looks like the LayoutState gets restored again in Embed()
06218 //      right after the call to SetupNewViewer(...)
06219 
06220     // We don't show the mContentViewer yet, since we want to draw the old page
06221     // until we have enough of the new page to show.  Just return with the new
06222     // viewer still set to hidden.
06223 
06224     // Now that we have switched documents, forget all of our children
06225     DestroyChildren();
06226 
06227     return NS_OK;
06228 }
06229 
06230 
06231 nsresult
06232 nsDocShell::CheckLoadingPermissions()
06233 {
06234     // This method checks whether the caller may load content into
06235     // this docshell. Even though we've done our best to hide windows
06236     // from code that doesn't have the right to access them, it's
06237     // still possible for an evil site to open a window and access
06238     // frames in the new window through window.frames[] (which is
06239     // allAccess for historic reasons), so we still need to do this
06240     // check on load.
06241     nsresult rv = NS_OK, sameOrigin = NS_OK;
06242 
06243     if (!gValidateOrigin || !IsFrame()) {
06244         // Origin validation was turned off, or we're not a frame.
06245         // Permit all loads.
06246 
06247         return rv;
06248     }
06249 
06250     // We're a frame. Check that the caller has write permission to
06251     // the parent before allowing it to load anything into this
06252     // docshell.
06253 
06254     nsCOMPtr<nsIScriptSecurityManager> securityManager =
06255         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
06256     NS_ENSURE_SUCCESS(rv, rv);
06257 
06258     PRBool ubwEnabled = PR_FALSE;
06259     rv = securityManager->IsCapabilityEnabled("UniversalBrowserWrite",
06260                                               &ubwEnabled);
06261     if (NS_FAILED(rv) || ubwEnabled) {
06262         return rv;
06263     }
06264 
06265     nsCOMPtr<nsIPrincipal> subjPrincipal;
06266     rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjPrincipal));
06267     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && subjPrincipal, rv);
06268 
06269     // Check if the caller is from the same origin as this docshell,
06270     // or any of it's ancestors.
06271     nsCOMPtr<nsIDocShellTreeItem> item(this);
06272     do {
06273         nsCOMPtr<nsIScriptGlobalObject> sgo(do_GetInterface(item));
06274         nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
06275 
06276         nsIPrincipal *p;
06277         if (!sop || !(p = sop->GetPrincipal())) {
06278             return NS_ERROR_UNEXPECTED;
06279         }
06280 
06281         // Compare origins
06282         sameOrigin =
06283             securityManager->CheckSameOriginPrincipal(subjPrincipal, p);
06284         if (NS_SUCCEEDED(sameOrigin)) {
06285             // Same origin, permit load
06286 
06287             return sameOrigin;
06288         }
06289 
06290         nsCOMPtr<nsIDocShellTreeItem> tmp;
06291         item->GetSameTypeParent(getter_AddRefs(tmp));
06292         item.swap(tmp);
06293     } while (item);
06294 
06295     // The caller is not from the same origin as this item, or any if
06296     // this items ancestors. Only permit loading content if both are
06297     // part of the same window, assuming we can find the window of the
06298     // caller.
06299 
06300     nsCOMPtr<nsIJSContextStack> stack =
06301         do_GetService("@mozilla.org/js/xpc/ContextStack;1");
06302     if (!stack) {
06303         // No context stack available. Should never happen, but in
06304         // case it does, return the sameOrigin error from the security
06305         // check above.
06306 
06307         return sameOrigin;
06308     }
06309 
06310     JSContext *cx = nsnull;
06311     stack->Peek(&cx);
06312 
06313     if (!cx) {
06314         // No caller docshell reachable, return the sameOrigin error
06315         // from the security check above.
06316 
06317         return sameOrigin;
06318     }
06319 
06320     nsIScriptContext *currentCX = GetScriptContextFromJSContext(cx);
06321     nsCOMPtr<nsIDocShellTreeItem> callerTreeItem;
06322     nsIScriptGlobalObject *sgo;
06323     if (currentCX &&
06324         (sgo = currentCX->GetGlobalObject()) &&
06325         (callerTreeItem = do_QueryInterface(sgo->GetDocShell()))) {
06326         nsCOMPtr<nsIDocShellTreeItem> callerRoot;
06327         callerTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(callerRoot));
06328 
06329         nsCOMPtr<nsIDocShellTreeItem> ourRoot;
06330         GetSameTypeRootTreeItem(getter_AddRefs(ourRoot));
06331 
06332         if (ourRoot == callerRoot) {
06333             // The running JS is in the same window as the target
06334             // frame, permit load.
06335             sameOrigin = NS_OK;
06336         }
06337     }
06338 
06339     return sameOrigin;
06340 }
06341 
06342 //*****************************************************************************
06343 // nsDocShell: Site Loading
06344 //*****************************************************************************   
06345 NS_IMETHODIMP
06346 nsDocShell::InternalLoad(nsIURI * aURI,
06347                          nsIURI * aReferrer,
06348                          nsISupports * aOwner,
06349                          PRUint32 aFlags,
06350                          const PRUnichar *aWindowTarget,
06351                          const char* aTypeHint,
06352                          nsIInputStream * aPostData,
06353                          nsIInputStream * aHeadersData,
06354                          PRUint32 aLoadType,
06355                          nsISHEntry * aSHEntry,
06356                          PRBool aFirstParty,
06357                          nsIDocShell** aDocShell,
06358                          nsIRequest** aRequest)
06359 {
06360     if (mFiredUnloadEvent) {
06361       return NS_OK; // JS may not handle returning of an error code
06362     }
06363 
06364     nsresult rv = NS_OK;
06365 
06366 #ifdef PR_LOGGING
06367     if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
06368         nsCAutoString spec;
06369         if (aURI)
06370             aURI->GetSpec(spec);
06371         PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec.get());
06372     }
06373 #endif
06374     
06375     // Initialize aDocShell/aRequest
06376     if (aDocShell) {
06377         *aDocShell = nsnull;
06378     }
06379     if (aRequest) {
06380         *aRequest = nsnull;
06381     }
06382 
06383     if (!aURI) {
06384         return NS_ERROR_NULL_POINTER;
06385     }
06386 
06387     NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
06388 
06389     // wyciwyg urls can only be loaded through history. Any normal load of
06390     // wyciwyg through docshell is  illegal. Disallow such loads.
06391     if (aLoadType & LOAD_CMD_NORMAL) {
06392         PRBool isWyciwyg = PR_FALSE;
06393         rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);   
06394         if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) 
06395             return NS_ERROR_FAILURE;
06396     }
06397 
06398     PRBool bIsJavascript = PR_FALSE;
06399     if (NS_FAILED(aURI->SchemeIs("javascript", &bIsJavascript))) {
06400         bIsJavascript = PR_FALSE;
06401     }
06402 
06403     //
06404     // First, notify any nsIContentPolicy listeners about the document load.
06405     // Only abort the load if a content policy listener explicitly vetos it!
06406     //
06407     nsCOMPtr<nsIDOMElement> requestingElement;
06408     // Use nsPIDOMWindow since we _want_ to cross the chrome boundary if needed
06409     nsCOMPtr<nsPIDOMWindow> privateWin(do_QueryInterface(mScriptGlobal));
06410     if (privateWin)
06411         requestingElement = privateWin->GetFrameElementInternal();
06412 
06413     PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
06414     PRUint32 contentType;
06415     if (IsFrame()) {
06416         NS_ASSERTION(requestingElement, "A frame but no DOM element!?");
06417         contentType = nsIContentPolicy::TYPE_SUBDOCUMENT;
06418     } else {
06419         contentType = nsIContentPolicy::TYPE_DOCUMENT;
06420     }
06421 
06422     nsISupports* context = requestingElement;
06423     if (!context) {
06424         context =  mScriptGlobal;
06425     }
06426     rv = NS_CheckContentLoadPolicy(contentType,
06427                                    aURI,
06428                                    aReferrer,
06429                                    context,
06430                                    EmptyCString(), //mime guess
06431                                    nsnull,         //extra
06432                                    &shouldLoad);
06433 
06434     if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
06435         if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
06436             return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
06437         }
06438 
06439         return NS_ERROR_CONTENT_BLOCKED;
06440     }
06441 
06442     nsCOMPtr<nsISupports> owner(aOwner);
06443     //
06444     // Get an owner from the current document if necessary.  Note that we only
06445     // do this for URIs that inherit a security context; in particular we do
06446     // NOT do this for about:blank.  This way, random about:blank loads that
06447     // have no owner (which basically means they were done by someone from
06448     // chrome manually messing with our nsIWebNavigation or by C++ setting
06449     // document.location) don't get a funky principal.  If callers want
06450     // something interesting to happen with the about:blank principal in this
06451     // case, they should pass an owner in.
06452     //
06453     if (aLoadType != LOAD_NORMAL_EXTERNAL && !owner &&
06454         (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_OWNER)) {
06455         PRBool inherits;
06456         PRBool isScheme;
06457         inherits =
06458             (NS_SUCCEEDED(aURI->SchemeIs("javascript", &isScheme)) &&
06459              isScheme) ||
06460             (NS_SUCCEEDED(aURI->SchemeIs("data", &isScheme)) &&
06461              isScheme);
06462         if (inherits) {
06463             // Don't allow loads that would inherit our security context
06464             // if this document came from an unsafe channel.
06465             nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
06466             do {
06467                 nsCOMPtr<nsIDocShell_MOZILLA_1_8_BRANCH3> itemDocShell =
06468                     do_QueryInterface(treeItem);
06469                 PRBool isUnsafe;
06470                 if (itemDocShell &&
06471                     NS_SUCCEEDED(itemDocShell->GetChannelIsUnsafe(&isUnsafe)) &&
06472                     isUnsafe) {
06473                     return NS_ERROR_DOM_SECURITY_ERR;
06474                 }
06475 
06476                 nsCOMPtr<nsIDocShellTreeItem> parent;
06477                 treeItem->GetSameTypeParent(getter_AddRefs(parent));
06478                 parent.swap(treeItem);
06479             } while (treeItem);
06480 
06481             owner = GetInheritedPrincipal(PR_TRUE);
06482         }
06483     }
06484 
06485     //
06486     // Resolve the window target before going any further...
06487     // If the load has been targeted to another DocShell, then transfer the
06488     // load to it...
06489     //
06490     if (aWindowTarget && *aWindowTarget) {
06491         // Locate the target DocShell.
06492         // This may involve creating a new toplevel window - if necessary.
06493         //
06494         nsCOMPtr<nsIDocShellTreeItem> targetItem;
06495         FindItemWithName(aWindowTarget, nsnull, this,
06496                          getter_AddRefs(targetItem));
06497 
06498         nsCOMPtr<nsIDocShell> targetDocShell = do_QueryInterface(targetItem);
06499         
06500         PRBool isNewWindow = PR_FALSE;
06501         if (!targetDocShell) {
06502             nsCOMPtr<nsIDOMWindowInternal> win =
06503                 do_GetInterface(GetAsSupports(this));
06504             NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
06505 
06506             nsDependentString name(aWindowTarget);
06507             nsCOMPtr<nsIDOMWindow> newWin;
06508             rv = win->Open(EmptyString(), // URL to load
06509                            name,          // window name
06510                            EmptyString(), // Features
06511                            getter_AddRefs(newWin));
06512 
06513             // In some cases the Open call doesn't actually result in a new
06514             // window being opened (i.e. browser.link.open_newwindow is set
06515             // to 1, forcing us to reuse the current window).  This will
06516             // protect us against that use case but still isn't totally
06517             // ideal since perhaps in some future use case newWin could be
06518             // some other, already open window.
06519             if (win != newWin) {
06520                 isNewWindow = PR_TRUE;
06521                 aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
06522             }
06523 
06524             nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
06525             targetDocShell = do_QueryInterface(webNav);
06526 
06527             nsCOMPtr<nsIScriptObjectPrincipal> sop =
06528                 do_QueryInterface(mScriptGlobal);
06529             nsCOMPtr<nsIURI> currentCodebase;
06530 
06531             if (sop) {
06532                 nsIPrincipal *principal = sop->GetPrincipal();
06533 
06534                 if (principal) {
06535                     principal->GetURI(getter_AddRefs(currentCodebase));
06536                 }
06537             }
06538 
06539             // We opened a new window for the target, clone the
06540             // session storage if the current URI's domain matches
06541             // that of the loading URI.
06542 
06543             if (targetDocShell && currentCodebase && aURI) {
06544                 nsCAutoString thisDomain, newDomain;
06545                 nsresult gethostrv = currentCodebase->GetAsciiHost(thisDomain);
06546                 gethostrv |= aURI->GetAsciiHost(newDomain);
06547                 if (NS_SUCCEEDED(gethostrv) && thisDomain.Equals(newDomain)) {
06548                     nsCOMPtr<nsIDOMStorage> storage;
06549                     GetSessionStorageForURI(currentCodebase,
06550                                             getter_AddRefs(storage));
06551                     nsCOMPtr<nsPIDOMStorage> piStorage =
06552                         do_QueryInterface(storage);
06553                     nsCOMPtr<nsIDocShell_MOZILLA_1_8_BRANCH> tmp =
06554                         do_QueryInterface(targetDocShell);
06555                     if (piStorage && tmp) {
06556                         nsCOMPtr<nsIDOMStorage> newstorage =
06557                             piStorage->Clone(currentCodebase);
06558                         tmp->AddSessionStorage(thisDomain, newstorage);
06559                     }
06560                 }
06561             }
06562         }
06563         
06564         //
06565         // Transfer the load to the target DocShell...  Pass nsnull as the
06566         // window target name from to prevent recursive retargeting!
06567         //
06568         if (NS_SUCCEEDED(rv) && targetDocShell) {
06569             rv = targetDocShell->InternalLoad(aURI,
06570                                               aReferrer,
06571                                               owner,
06572                                               aFlags,
06573                                               nsnull,         // No window target
06574                                               aTypeHint,
06575                                               aPostData,
06576                                               aHeadersData,
06577                                               aLoadType,
06578                                               aSHEntry,
06579                                               aFirstParty,
06580                                               aDocShell,
06581                                               aRequest);
06582             if (rv == NS_ERROR_NO_CONTENT) {
06583                 // XXXbz except we never reach this code!
06584                 if (isNewWindow) {
06585                     //
06586                     // At this point, a new window has been created, but the
06587                     // URI did not have any data associated with it...
06588                     //
06589                     // So, the best we can do, is to tear down the new window
06590                     // that was just created!
06591                     //
06592                     nsCOMPtr<nsIDOMWindowInternal> domWin =
06593                         do_GetInterface(targetDocShell);
06594                     if (domWin) {
06595                         domWin->Close();
06596                     }
06597                 }
06598                 //
06599                 // NS_ERROR_NO_CONTENT should not be returned to the
06600                 // caller... This is an internal error code indicating that
06601                 // the URI had no data associated with it - probably a 
06602                 // helper-app style protocol (ie. mailto://)
06603                 //
06604                 rv = NS_OK;
06605             }
06606             else if (isNewWindow) {
06607                 // XXX: Once new windows are created hidden, the new
06608                 //      window will need to be made visible...  For now,
06609                 //      do nothing.
06610             }
06611         }
06612 
06613         // Else we ran out of memory, or were a popup and got blocked,
06614         // or something.
06615         
06616         return rv;
06617     }
06618 
06619     //
06620     // Load is being targetted at this docshell so return an error if the
06621     // docshell is in the process of being destroyed.
06622     //
06623     if (mIsBeingDestroyed) {
06624         return NS_ERROR_FAILURE;
06625     }
06626 
06627     // Before going any further vet loads initiated by external programs.
06628     if (aLoadType == LOAD_NORMAL_EXTERNAL) {
06629         // Disallow external chrome: loads targetted at content windows
06630         PRBool isChrome = PR_FALSE;
06631         if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
06632             NS_WARNING("blocked external chrome: url -- use '-chrome' option");
06633             return NS_ERROR_FAILURE;
06634         }
06635 
06636         // clear the decks to prevent context bleed-through (bug 298255)
06637         rv = CreateAboutBlankContentViewer();
06638         if (NS_FAILED(rv))
06639             return NS_ERROR_FAILURE;
06640 
06641         // reset loadType so we don't have to add lots of tests for
06642         // LOAD_NORMAL_EXTERNAL after this point
06643         aLoadType = LOAD_NORMAL;
06644     }
06645 
06646     rv = CheckLoadingPermissions();
06647     if (NS_FAILED(rv)) {
06648         return rv;
06649     }
06650 
06651     mAllowKeywordFixup =
06652       (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
06653     mURIResultedInDocument = PR_FALSE;  // reset the clock...
06654    
06655     //
06656     // First:
06657     // Check to see if the new URI is an anchor in the existing document.
06658     // Skip this check if we're doing some sort of abnormal load, if the
06659     // new load is a non-history load and has postdata, or if we're doing
06660     // a history load and the page identifiers of mOSHE and aSHEntry
06661     // don't match.
06662     //
06663     PRBool allowScroll = PR_TRUE;
06664     if (!aSHEntry) {
06665         allowScroll = (aPostData == nsnull);
06666     } else if (mOSHE) {
06667         PRUint32 ourPageIdent;
06668         mOSHE->GetPageIdentifier(&ourPageIdent);
06669         PRUint32 otherPageIdent;
06670         aSHEntry->GetPageIdentifier(&otherPageIdent);
06671         allowScroll = (ourPageIdent == otherPageIdent);
06672 #ifdef DEBUG
06673         if (allowScroll) {
06674             nsCOMPtr<nsIInputStream> currentPostData;
06675             mOSHE->GetPostData(getter_AddRefs(currentPostData));
06676             NS_ASSERTION(currentPostData == aPostData,
06677                          "Different POST data for entries for the same page?");
06678         }
06679 #endif
06680     }
06681     
06682     if ((aLoadType == LOAD_NORMAL ||
06683          aLoadType == LOAD_STOP_CONTENT ||
06684          LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
06685          aLoadType == LOAD_HISTORY ||
06686          aLoadType == LOAD_LINK) && allowScroll) {
06687         PRBool wasAnchor = PR_FALSE;
06688         nscoord cx, cy;
06689         NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType, &cx, &cy), NS_ERROR_FAILURE);
06690         if (wasAnchor) {
06691             mLoadType = aLoadType;
06692             mURIResultedInDocument = PR_TRUE;
06693 
06694             /* we need to assign mLSHE to aSHEntry right here, so that on History loads, 
06695              * SetCurrentURI() called from OnNewURI() will send proper 
06696              * onLocationChange() notifications to the browser to update
06697              * back/forward buttons. 
06698              */
06699             SetHistoryEntry(&mLSHE, aSHEntry);
06700 
06701             /* This is a anchor traversal with in the same page.
06702              * call OnNewURI() so that, this traversal will be 
06703              * recorded in session and global history.
06704              */
06705             OnNewURI(aURI, nsnull, mLoadType, PR_TRUE);
06706             nsCOMPtr<nsIInputStream> postData;
06707             PRUint32 pageIdent = PR_UINT32_MAX;
06708             
06709             if (mOSHE) {
06710                 /* save current position of scroller(s) (bug 59774) */
06711                 mOSHE->SetScrollPosition(cx, cy);
06712                 // Get the postdata and page ident from the current page, if
06713                 // the new load is being done via normal means.  Note that
06714                 // "normal means" can be checked for just by checking for
06715                 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
06716                 // above -- it filters out some LOAD_CMD_NORMAL cases that we
06717                 // wouldn't want here.
06718                 if (aLoadType & LOAD_CMD_NORMAL) {
06719                     mOSHE->GetPostData(getter_AddRefs(postData));
06720                     mOSHE->GetPageIdentifier(&pageIdent);
06721                 }
06722             }
06723             
06724             /* Assign mOSHE to mLSHE. This will either be a new entry created
06725              * by OnNewURI() for normal loads or aSHEntry for history loads.
06726              */
06727             if (mLSHE) {
06728                 SetHistoryEntry(&mOSHE, mLSHE);
06729                 // Save the postData obtained from the previous page
06730                 // in to the session history entry created for the 
06731                 // anchor page, so that any history load of the anchor
06732                 // page will restore the appropriate postData.
06733                 if (postData)
06734                     mOSHE->SetPostData(postData);
06735                 
06736                 // Propagate our page ident to the new mOSHE so that
06737                 // we'll know it just differed by a scroll on the page.
06738                 if (pageIdent != PR_UINT32_MAX)
06739                     mOSHE->SetPageIdentifier(pageIdent);
06740             }
06741 
06742             /* restore previous position of scroller(s), if we're moving
06743              * back in history (bug 59774)
06744              */
06745             if (mOSHE && (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL))
06746             {
06747                 nscoord bx, by;
06748                 mOSHE->GetScrollPosition(&bx, &by);
06749                 SetCurScrollPosEx(bx, by);
06750             }
06751 
06752             /* Clear out mLSHE so that further anchor visits get
06753              * recorded in SH and SH won't misbehave. 
06754              */
06755             SetHistoryEntry(&mLSHE, nsnull);
06756             /* Set the title for the SH entry for this target url. so that
06757              * SH menus in go/back/forward buttons won't be empty for this.
06758              */
06759             if (mSessionHistory) {
06760                 PRInt32 index = -1;
06761                 mSessionHistory->GetIndex(&index);
06762                 nsCOMPtr<nsIHistoryEntry> hEntry;
06763                 mSessionHistory->GetEntryAtIndex(index, PR_FALSE,
06764                                                  getter_AddRefs(hEntry));
06765                 NS_ENSURE_TRUE(hEntry, NS_ERROR_FAILURE);
06766                 nsCOMPtr<nsISHEntry> shEntry(do_QueryInterface(hEntry));
06767                 if (shEntry)
06768                     shEntry->SetTitle(mTitle);
06769             }
06770 
06771             return NS_OK;
06772         }
06773     }
06774     
06775     // mContentViewer->PermitUnload can destroy |this| docShell, which
06776     // causes the next call of CanSavePresentation to crash. 
06777     // Hold onto |this| until we return, to prevent a crash from happening. 
06778     // (bug#331040)
06779     nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
06780 
06781     // Check if the page doesn't want to be unloaded. The javascript:
06782     // protocol handler deals with this for javascript: URLs.
06783     if (!bIsJavascript && mContentViewer) {
06784         PRBool okToUnload;
06785         rv = mContentViewer->PermitUnload(&okToUnload);
06786 
06787         if (NS_SUCCEEDED(rv) && !okToUnload) {
06788             // The user chose not to unload the page, interrupt the
06789             // load.
06790             return NS_OK;
06791         }
06792     }
06793 
06794     // Check for saving the presentation here, before calling Stop().
06795     // This is necessary so that we can catch any pending requests.
06796     // Since the new request has not been created yet, we pass null for the
06797     // new request parameter.
06798     // Also pass nsnull for the document, since it doesn't affect the return
06799     // value for our purposes here.
06800     PRBool savePresentation = CanSavePresentation(aLoadType, nsnull, nsnull);
06801 
06802     // Don't stop current network activity for javascript: URL's since
06803     // they might not result in any data, and thus nothing should be
06804     // stopped in those cases. In the case where they do result in
06805     // data, the javascript: URL channel takes care of stopping
06806     // current network activity.
06807     if (!bIsJavascript) {
06808         // Stop any current network activity.
06809         // Also stop content if this is a zombie doc. otherwise 
06810         // the onload will be delayed by other loads initiated in the 
06811         // background by the first document that
06812         // didn't fully load before the next load was initiated.
06813         // If not a zombie, don't stop content until data 
06814         // starts arriving from the new URI...
06815 
06816         nsCOMPtr<nsIContentViewer> zombieViewer;
06817         if (mContentViewer) {
06818             mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
06819         }
06820 
06821         if (zombieViewer ||
06822             LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
06823             rv = Stop(nsIWebNavigation::STOP_ALL);
06824         } else {
06825             rv = Stop(nsIWebNavigation::STOP_NETWORK);
06826         }
06827 
06828         if (NS_FAILED(rv)) 
06829             return rv;
06830     }
06831 
06832     mLoadType = aLoadType;
06833     
06834     // mLSHE should be assigned to aSHEntry, only after Stop() has
06835     // been called. But when loading an error page, do not clear the
06836     // mLSHE for the real page.
06837     if (mLoadType != LOAD_ERROR_PAGE)
06838         SetHistoryEntry(&mLSHE, aSHEntry);
06839 
06840     mSavingOldViewer = savePresentation;
06841 
06842     // If we have a saved content viewer in history, restore and show it now.
06843     if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
06844         // It's possible that the previous viewer of mContentViewer is the
06845         // viewer that will end up in aSHEntry when it gets closed.  If that's
06846         // the case, we need to go ahead and force it into its shentry so we
06847         // can restore it.
06848         if (mContentViewer) {
06849             nsCOMPtr<nsIContentViewer> prevViewer;
06850             mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
06851             if (prevViewer) {
06852 #ifdef DEBUG
06853                 nsCOMPtr<nsIContentViewer> prevPrevViewer;
06854                 prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
06855                 NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
06856 #endif
06857                 nsCOMPtr<nsISHEntry> viewerEntry;
06858                 nsCOMPtr<nsIContentViewer_MOZILLA_1_8_BRANCH2>
06859                     prevViewerBranch(do_QueryInterface(prevViewer));
06860                 if (prevViewerBranch) {
06861                     prevViewerBranch->
06862                         GetHistoryEntry(getter_AddRefs(viewerEntry));
06863                 }
06864                 if (viewerEntry == aSHEntry) {
06865                     // Make sure this viewer ends up in the right place
06866                     mContentViewer->SetPreviousViewer(nsnull);
06867                     prevViewer->Destroy();
06868                 }
06869             }
06870         }
06871         nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
06872         PRBool restoring;
06873         rv = RestorePresentation(aSHEntry, &restoring);
06874         if (restoring)
06875             return rv;
06876 
06877         // We failed to restore the presentation, so clean up.
06878         // Both the old and new history entries could potentially be in
06879         // an inconsistent state.
06880         if (NS_FAILED(rv)) {
06881             if (oldEntry)
06882                 oldEntry->SyncPresentationState();
06883 
06884             aSHEntry->SyncPresentationState();
06885         }
06886     }
06887 
06888     nsCOMPtr<nsIRequest> req;
06889     rv = DoURILoad(aURI, aReferrer,
06890                    !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
06891                    owner, aTypeHint, aPostData, aHeadersData, aFirstParty,
06892                    aDocShell, getter_AddRefs(req),
06893                    (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0);
06894     if (req && aRequest)
06895         NS_ADDREF(*aRequest = req);
06896 
06897     if (NS_FAILED(rv)) {
06898         nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
06899         DisplayLoadError(rv, aURI, nsnull, chan);
06900     }
06901     
06902     return rv;
06903 }
06904 
06905 nsIPrincipal*
06906 nsDocShell::GetInheritedPrincipal(PRBool aConsiderCurrentDocument)
06907 {
06908     nsCOMPtr<nsIDocument> document;
06909 
06910     if (aConsiderCurrentDocument && mContentViewer) {
06911         nsCOMPtr<nsIDocumentViewer>
06912             docViewer(do_QueryInterface(mContentViewer));
06913         if (!docViewer)
06914             return nsnull;
06915         docViewer->GetDocument(getter_AddRefs(document));
06916     }
06917 
06918     if (!document) {
06919         nsCOMPtr<nsIDocShellTreeItem> parentItem;
06920         GetSameTypeParent(getter_AddRefs(parentItem));
06921         if (parentItem) {
06922             nsCOMPtr<nsIDOMDocument> parentDomDoc(do_GetInterface(parentItem));
06923             document = do_QueryInterface(parentDomDoc);
06924         }
06925     }
06926 
06927     if (!document) {
06928         if (!aConsiderCurrentDocument) {
06929             return nsnull;
06930         }
06931 
06932         // Make sure we end up with _something_ as the principal no matter
06933         // what.
06934         EnsureContentViewer();  // If this fails, we'll just get a null
06935                                 // docViewer and bail.
06936 
06937         nsCOMPtr<nsIDocumentViewer>
06938             docViewer(do_QueryInterface(mContentViewer));
06939         if (!docViewer)
06940             return nsnull;
06941         docViewer->GetDocument(getter_AddRefs(document));
06942     }
06943 
06944     //-- Get the document's principal
06945     if (document) {
06946         return document->GetPrincipal();
06947     }
06948 
06949     return nsnull;
06950 }
06951 
06952 nsresult
06953 nsDocShell::DoURILoad(nsIURI * aURI,
06954                       nsIURI * aReferrerURI,
06955                       PRBool aSendReferrer,
06956                       nsISupports * aOwner,
06957                       const char * aTypeHint,
06958                       nsIInputStream * aPostData,
06959                       nsIInputStream * aHeadersData,
06960                       PRBool aFirstParty,
06961                       nsIDocShell ** aDocShell,
06962                       nsIRequest ** aRequest,
06963                       PRBool aIsNewWindowTarget)
06964 {
06965     nsresult rv;
06966     nsCOMPtr<nsIURILoader> uriLoader;
06967 
06968     uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
06969     if (NS_FAILED(rv)) return rv;
06970 
06971     nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
06972     if (aFirstParty) {
06973         // tag first party URL loads
06974         loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
06975     }
06976 
06977     if (mLoadType == LOAD_ERROR_PAGE) {
06978         // Error pages are LOAD_BACKGROUND
06979         loadFlags |= nsIChannel::LOAD_BACKGROUND;
06980     }
06981 
06982     // open a channel for the url
06983     nsCOMPtr<nsIChannel> channel;
06984 
06985     rv = NS_NewChannel(getter_AddRefs(channel),
06986                        aURI,
06987                        nsnull,
06988                        nsnull,
06989                        NS_STATIC_CAST(nsIInterfaceRequestor *, this),
06990                        loadFlags);
06991     if (NS_FAILED(rv)) {
06992         if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
06993             // This is a uri with a protocol scheme we don't know how
06994             // to handle.  Embedders might still be interested in
06995             // handling the load, though, so we fire a notification
06996             // before throwing the load away.
06997             PRBool abort = PR_FALSE;
06998             nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
06999             if (NS_SUCCEEDED(rv2) && abort) {
07000                 // Hey, they're handling the load for us!  How convenient!
07001                 return NS_OK;
07002             }
07003         }
07004             
07005         return rv;
07006     }
07007 
07008     // Make sure to give the caller a channel if we managed to create one
07009     // This is important for correct error page/session history interaction
07010     if (aRequest)
07011         NS_ADDREF(*aRequest = channel);
07012 
07013     channel->SetOriginalURI(aURI);
07014     if (aTypeHint && *aTypeHint) {
07015         channel->SetContentType(nsDependentCString(aTypeHint));
07016         mContentTypeHint = aTypeHint;
07017     }
07018     else {
07019         mContentTypeHint.Truncate();
07020     }
07021     
07022     //hack
07023     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
07024     nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
07025     if (httpChannelInternal) {
07026       if (aFirstParty) {
07027         httpChannelInternal->SetDocumentURI(aURI);
07028       } else {
07029         httpChannelInternal->SetDocumentURI(aReferrerURI);
07030       }
07031     }
07032 
07033     nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
07034     if (props)
07035     {
07036       // save true referrer for those who need it (e.g. xpinstall whitelisting)
07037       // Currently only http and ftp channels support this.
07038       props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
07039                                     aReferrerURI);
07040     }
07041 
07042     //
07043     // If this is a HTTP channel, then set up the HTTP specific information
07044     // (ie. POST data, referrer, ...)
07045     //
07046     if (httpChannel) {
07047         nsCOMPtr<nsICachingChannel>  cacheChannel(do_QueryInterface(httpChannel));
07048         /* Get the cache Key from SH */
07049         nsCOMPtr<nsISupports> cacheKey;
07050         if (mLSHE) {
07051             mLSHE->GetCacheKey(getter_AddRefs(cacheKey));
07052         }
07053         else if (mOSHE)          // for reload cases
07054             mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
07055 
07056         // figure out if we need to set the post data stream on the channel...
07057         // right now, this is only done for http channels.....
07058         if (aPostData) {
07059             // XXX it's a bit of a hack to rewind the postdata stream here but
07060             // it has to be done in case the post data is being reused multiple
07061             // times.
07062             nsCOMPtr<nsISeekableStream>
07063                 postDataSeekable(do_QueryInterface(aPostData));
07064             if (postDataSeekable) {
07065                 rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
07066                 NS_ENSURE_SUCCESS(rv, rv);
07067             }
07068 
07069             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
07070             NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
07071 
07072             // we really need to have a content type associated with this stream!!
07073             uploadChannel->SetUploadStream(aPostData, EmptyCString(), -1);
07074             /* If there is a valid postdata *and* it is a History Load,
07075              * set up the cache key on the channel, to retrieve the
07076              * data *only* from the cache. If it is a normal reload, the 
07077              * cache is free to go to the server for updated postdata. 
07078              */
07079             if (cacheChannel && cacheKey) {
07080                 if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
07081                     cacheChannel->SetCacheKey(cacheKey);
07082                     PRUint32 loadFlags;
07083                     if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags)))
07084                         channel->SetLoadFlags(loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE);
07085                 }
07086                 else if (mLoadType == LOAD_RELOAD_NORMAL)
07087                     cacheChannel->SetCacheKey(cacheKey);
07088             }         
07089         }
07090         else {
07091             /* If there is no postdata, set the cache key on the channel, and
07092              * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
07093              * will be free to get it from net if it is not found in cache.
07094              * New cache may use it creatively on CGI pages with GET
07095              * method and even on those that say "no-cache"
07096              */
07097             if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_NORMAL 
07098                 || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
07099                 if (cacheChannel && cacheKey)
07100                     cacheChannel->SetCacheKey(cacheKey);
07101             }
07102         }
07103         if (aHeadersData) {
07104             rv = AddHeadersToChannel(aHeadersData, httpChannel);
07105         }
07106         // Set the referrer explicitly
07107         if (aReferrerURI && aSendReferrer) {
07108             // Referrer is currenly only set for link clicks here.
07109             httpChannel->SetReferrer(aReferrerURI);
07110         }
07111     }
07112     //
07113     // Set the owner of the channel - only for javascript and data channels.
07114     //
07115     // XXX: Is seems wrong that the owner is ignored - even if one is
07116     //      supplied) unless the URI is javascript or data or about:blank.
07117     // XXX: If this is ever changed, check all callers for what owners they're
07118     //      passing in.  In particular, see the code and comments in LoadURI
07119     //      where we fall back on inheriting the owner if called
07120     //      from chrome.  That would be very wrong if this code changed
07121     //      anything but channels that can't provide their own security context!
07122     //
07123     //      (Currently chrome URIs set the owner when they are created!
07124     //      So setting a NULL owner would be bad!)
07125     //
07126     PRBool isJSOrData = PR_FALSE;
07127     aURI->SchemeIs("javascript", &isJSOrData);
07128     if (!isJSOrData) {
07129       aURI->SchemeIs("data", &isJSOrData);
07130     }
07131     if (isJSOrData || IsAboutBlank(aURI)) {
07132         channel->SetOwner(aOwner);
07133     }
07134 
07135     if (aIsNewWindowTarget) {
07136         nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
07137         if (props) {
07138             props->SetPropertyAsBool(
07139                 NS_LITERAL_STRING("docshell.newWindowTarget"),
07140                 PR_TRUE);
07141         }
07142     }
07143 
07144     rv = DoChannelLoad(channel, uriLoader);
07145     
07146     //
07147     // If the channel load failed, we failed and nsIWebProgress just ain't
07148     // gonna happen.
07149     //
07150     if (NS_SUCCEEDED(rv)) {
07151         if (aDocShell) {
07152           *aDocShell = this;
07153           NS_ADDREF(*aDocShell);
07154         }
07155     }
07156 
07157     return rv;
07158 }
07159 
07160 static NS_METHOD
07161 AppendSegmentToString(nsIInputStream *in,
07162                       void *closure,
07163                       const char *fromRawSegment,
07164                       PRUint32 toOffset,
07165                       PRUint32 count,
07166                       PRUint32 *writeCount)
07167 {
07168     // aFromSegment now contains aCount bytes of data.
07169 
07170     nsCAutoString *buf = NS_STATIC_CAST(nsCAutoString *, closure);
07171     buf->Append(fromRawSegment, count);
07172 
07173     // Indicate that we have consumed all of aFromSegment
07174     *writeCount = count;
07175     return NS_OK;
07176 }
07177 
07178 NS_IMETHODIMP
07179 nsDocShell::AddHeadersToChannel(nsIInputStream *aHeadersData,
07180                                 nsIChannel *aGenericChannel)
07181 {
07182     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
07183     NS_ENSURE_STATE(httpChannel);
07184 
07185     PRUint32 numRead;
07186     nsCAutoString headersString;
07187     nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString,
07188                                              &headersString,
07189                                              PR_UINT32_MAX,
07190                                              &numRead);
07191     NS_ENSURE_SUCCESS(rv, rv);
07192 
07193     // used during the manipulation of the String from the InputStream
07194     nsCAutoString headerName;
07195     nsCAutoString headerValue;
07196     PRInt32 crlf;
07197     PRInt32 colon;
07198 
07199     //
07200     // Iterate over the headersString: for each "\r\n" delimited chunk,
07201     // add the value as a header to the nsIHttpChannel
07202     //
07203 
07204     static const char kWhitespace[] = "\b\t\r\n ";
07205     while (PR_TRUE) {
07206         crlf = headersString.Find("\r\n");
07207         if (crlf == kNotFound)
07208             return NS_OK;
07209 
07210         const nsCSubstring &oneHeader = StringHead(headersString, crlf);
07211 
07212         colon = oneHeader.FindChar(':');
07213         if (colon == kNotFound)
07214             return NS_ERROR_UNEXPECTED;
07215 
07216         headerName = StringHead(oneHeader, colon);
07217         headerValue = Substring(oneHeader, colon + 1);
07218 
07219         headerName.Trim(kWhitespace);
07220         headerValue.Trim(kWhitespace);
07221 
07222         headersString.Cut(0, crlf + 2);
07223 
07224         //
07225         // FINALLY: we can set the header!
07226         // 
07227 
07228         rv = httpChannel->SetRequestHeader(headerName, headerValue, PR_TRUE);
07229         NS_ENSURE_SUCCESS(rv, rv);
07230     }
07231 
07232     NS_NOTREACHED("oops");
07233     return NS_ERROR_UNEXPECTED;
07234 }
07235 
07236 nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel,
07237                                    nsIURILoader * aURILoader)
07238 {
07239     nsresult rv;
07240     // Mark the channel as being a document URI and allow content sniffing...
07241     nsLoadFlags loadFlags = 0;
07242     (void) aChannel->GetLoadFlags(&loadFlags);
07243     loadFlags |= nsIChannel::LOAD_DOCUMENT_URI |
07244                  nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
07245 
07246     // Load attributes depend on load type...
07247     switch (mLoadType) {
07248     case LOAD_HISTORY:
07249         loadFlags |= nsIRequest::VALIDATE_NEVER;
07250         break;
07251 
07252     case LOAD_RELOAD_CHARSET_CHANGE:
07253         loadFlags |= nsIRequest::LOAD_FROM_CACHE;
07254         break;
07255     
07256     case LOAD_RELOAD_NORMAL:
07257     case LOAD_REFRESH:
07258         loadFlags |= nsIRequest::VALIDATE_ALWAYS;
07259         break;
07260 
07261     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
07262         loadFlags |= nsIRequest::LOAD_BYPASS_CACHE;
07263         break;
07264 
07265     case LOAD_NORMAL:
07266     case LOAD_LINK:
07267         // Set cache checking flags
07268         PRInt32 prefSetting;
07269         if (NS_SUCCEEDED
07270             (mPrefs->
07271              GetIntPref("browser.cache.check_doc_frequency",
07272                         &prefSetting))) {
07273             switch (prefSetting) {
07274             case 0:
07275                 loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
07276                 break;
07277             case 1:
07278                 loadFlags |= nsIRequest::VALIDATE_ALWAYS;
07279                 break;
07280             case 2:
07281                 loadFlags |= nsIRequest::VALIDATE_NEVER;
07282                 break;
07283             }
07284         }
07285         break;
07286     }
07287 
07288     (void) aChannel->SetLoadFlags(loadFlags);
07289 
07290     rv = aURILoader->OpenURI(aChannel,
07291                              (mLoadType == LOAD_LINK),
07292                              this);
07293     
07294     return rv;
07295 }
07296 
07297 NS_IMETHODIMP
07298 nsDocShell::ScrollIfAnchor(nsIURI * aURI, PRBool * aWasAnchor,
07299                            PRUint32 aLoadType, nscoord *cx, nscoord *cy)
07300 {
07301     NS_ASSERTION(aURI, "null uri arg");
07302     NS_ASSERTION(aWasAnchor, "null anchor arg");
07303 
07304     if (aURI == nsnull || aWasAnchor == nsnull) {
07305         return NS_ERROR_FAILURE;
07306     }
07307 
07308     *aWasAnchor = PR_FALSE;
07309 
07310     if (!mCurrentURI) {
07311         return NS_OK;
07312     }
07313 
07314     nsCOMPtr<nsIPresShell> shell;
07315     nsresult rv = GetPresShell(getter_AddRefs(shell));
07316     if (NS_FAILED(rv) || !shell) {
07317         // If we failed to get the shell, or if there is no shell,
07318         // nothing left to do here.
07319         
07320         return rv;
07321     }
07322 
07323     // NOTE: we assume URIs are absolute for comparison purposes
07324 
07325     nsCAutoString currentSpec;
07326     NS_ENSURE_SUCCESS(mCurrentURI->GetSpec(currentSpec),
07327                       NS_ERROR_FAILURE);
07328 
07329     nsCAutoString newSpec;
07330     NS_ENSURE_SUCCESS(aURI->GetSpec(newSpec), NS_ERROR_FAILURE);
07331 
07332     // Search for hash marks in the current URI and the new URI and
07333     // take a copy of everything to the left of the hash for
07334     // comparison.
07335 
07336     const char kHash = '#';
07337 
07338     // Split the new URI into a left and right part
07339     // (assume we're parsing it out right
07340     nsACString::const_iterator urlStart, urlEnd, refStart, refEnd;
07341     newSpec.BeginReading(urlStart);
07342     newSpec.EndReading(refEnd);
07343     
07344     PRInt32 hashNew = newSpec.FindChar(kHash);
07345     if (hashNew == 0) {
07346         return NS_OK;           // Strange URI
07347     }
07348 
07349     if (hashNew > 0) {
07350         // found it
07351         urlEnd = urlStart;
07352         urlEnd.advance(hashNew);
07353         
07354         refStart = urlEnd;
07355         ++refStart;             // advanced past '#'
07356         
07357     }
07358     else {
07359         // no hash at all
07360         urlEnd = refStart = refEnd;
07361     }
07362     const nsACString& sNewLeft = Substring(urlStart, urlEnd);
07363     const nsACString& sNewRef =  Substring(refStart, refEnd);
07364                                           
07365     // Split the current URI in a left and right part
07366     nsACString::const_iterator currentLeftStart, currentLeftEnd;
07367     currentSpec.BeginReading(currentLeftStart);
07368 
07369     PRInt32 hashCurrent = currentSpec.FindChar(kHash);
07370     if (hashCurrent == 0) {
07371         return NS_OK;           // Strange URI 
07372     }
07373 
07374     if (hashCurrent > 0) {
07375         currentLeftEnd = currentLeftStart;
07376         currentLeftEnd.advance(hashCurrent);
07377     }
07378     else {
07379         currentSpec.EndReading(currentLeftEnd);
07380     }
07381 
07382     // If we have no new anchor, we do not want to scroll, unless there is a
07383     // current anchor and we are doing a history load.  So return if we have no
07384     // new anchor, and there is no current anchor or the load is not a history
07385     // load.
07386     NS_ASSERTION(hashNew != 0 && hashCurrent != 0,
07387                  "What happened to the early returns above?");
07388     if (hashNew == kNotFound &&
07389         (hashCurrent == kNotFound || aLoadType != LOAD_HISTORY)) {
07390         return NS_OK;
07391     }
07392 
07393     // Compare the URIs.
07394     //
07395     // NOTE: this is a case sensitive comparison because some parts of the
07396     // URI are case sensitive, and some are not. i.e. the domain name
07397     // is case insensitive but the the paths are not.
07398     //
07399     // This means that comparing "http://www.ABC.com/" to "http://www.abc.com/"
07400     // will fail this test.
07401 
07402     if (!Substring(currentLeftStart, currentLeftEnd).Equals(sNewLeft)) {
07403         return NS_OK;           // URIs not the same
07404     }
07405 
07406     // Now we know we are dealing with an anchor
07407     *aWasAnchor = PR_TRUE;
07408 
07409     // Both the new and current URIs refer to the same page. We can now
07410     // browse to the hash stored in the new URI.
07411     //
07412     // But first let's capture positions of scroller(s) that can
07413     // (and usually will) be modified by GoToAnchor() call.
07414 
07415     GetCurScrollPos(ScrollOrientation_X, cx);
07416     GetCurScrollPos(ScrollOrientation_Y, cy);
07417 
07418     if (!sNewRef.IsEmpty()) {
07419         // anchor is there, but if it's a load from history,
07420         // we don't have any anchor jumping to do
07421         PRBool scroll = aLoadType != LOAD_HISTORY &&
07422                         aLoadType != LOAD_RELOAD_NORMAL;
07423 
07424         char *str = ToNewCString(sNewRef);
07425         if (!str) {
07426             return NS_ERROR_OUT_OF_MEMORY;
07427         }
07428 
07429         // nsUnescape modifies the string that is passed into it.
07430         nsUnescape(str);
07431 
07432         // We assume that the bytes are in UTF-8, as it says in the
07433         // spec:
07434         // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
07435 
07436         // We try the UTF-8 string first, and then try the document's
07437         // charset (see below).  If the string is not UTF-8,
07438         // conversion will fail and give us an empty Unicode string.
07439         // In that case, we should just fall through to using the
07440         // page's charset.
07441         rv = NS_ERROR_FAILURE;
07442         NS_ConvertUTF8toUCS2 uStr(str);
07443         if (!uStr.IsEmpty()) {
07444             rv = shell->GoToAnchor(NS_ConvertUTF8toUCS2(str), scroll);
07445         }
07446         nsMemory::Free(str);
07447 
07448         // Above will fail if the anchor name is not UTF-8.  Need to
07449         // convert from document charset to unicode.
07450         if (NS_FAILED(rv)) {
07451                 
07452             // Get a document charset
07453             NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
07454             nsCOMPtr<nsIDocumentViewer>
07455                 docv(do_QueryInterface(mContentViewer));
07456             NS_ENSURE_TRUE(docv, NS_ERROR_FAILURE);
07457             nsCOMPtr<nsIDocument> doc;
07458             rv = docv->GetDocument(getter_AddRefs(doc));
07459             NS_ENSURE_SUCCESS(rv, rv);
07460             const nsACString &aCharset = doc->GetDocumentCharacterSet();
07461 
07462             nsCOMPtr<nsITextToSubURI> textToSubURI =
07463                 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
07464             NS_ENSURE_SUCCESS(rv, rv);
07465 
07466             // Unescape and convert to unicode
07467             nsXPIDLString uStr;
07468 
07469             rv = textToSubURI->UnEscapeAndConvert(PromiseFlatCString(aCharset).get(),
07470                                                   PromiseFlatCString(sNewRef).get(),
07471                                                   getter_Copies(uStr));
07472             NS_ENSURE_SUCCESS(rv, rv);
07473 
07474             // Ignore return value of GoToAnchor, since it will return an error
07475             // if there is no such anchor in the document, which is actually a
07476             // success condition for us (we want to update the session history
07477             // with the new URI no matter whether we actually scrolled
07478             // somewhere).
07479             shell->GoToAnchor(uStr, scroll);
07480         }
07481     }
07482     else {
07483 
07484         // Tell the shell it's at an anchor, without scrolling.
07485         shell->GoToAnchor(EmptyString(), PR_FALSE);
07486         
07487         // An empty anchor was found, but if it's a load from history,
07488         // we don't have to jump to the top of the page. Scrollbar 
07489         // position will be restored by the caller, based on positions
07490         // stored in session history.
07491         if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL)
07492             return rv;
07493         //An empty anchor. Scroll to the top of the page.
07494         rv = SetCurScrollPosEx(0, 0);
07495     }
07496 
07497     return rv;
07498 }
07499 
07500 void
07501 nsDocShell::SetupReferrerFromChannel(nsIChannel * aChannel)
07502 {
07503     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
07504     if (httpChannel) {
07505         nsCOMPtr<nsIURI> referrer;
07506         nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
07507         if (NS_SUCCEEDED(rv)) {
07508             SetReferrerURI(referrer);
07509         }
07510     }
07511 }
07512 
07513 PRBool
07514 nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel,
07515                      PRUint32 aLoadType, PRBool aFireOnLocationChange,
07516                      PRBool aAddToGlobalHistory)
07517 {
07518     NS_ASSERTION(aURI, "uri is null");
07519 #if defined(PR_LOGGING) && defined(DEBUG)
07520     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
07521         nsCAutoString spec;
07522         aURI->GetSpec(spec);
07523 
07524         nsCAutoString chanName;
07525         if (aChannel)
07526             aChannel->GetName(chanName);
07527         else
07528             chanName.AssignLiteral("<no channel>");
07529 
07530         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
07531                ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(),
07532                 chanName.get(), aLoadType));
07533     }
07534 #endif
07535 
07536     PRBool updateHistory = PR_TRUE;
07537     PRBool equalUri = PR_FALSE;
07538     PRBool shAvailable = PR_TRUE;  
07539 
07540     // Get the post data from the channel
07541     nsCOMPtr<nsIInputStream> inputStream;
07542     if (aChannel) {
07543         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
07544         
07545         // Check if the HTTPChannel is hiding under a multiPartChannel
07546         if (!httpChannel)  {
07547             GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
07548         }
07549 
07550         if (httpChannel) {
07551             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
07552             if (uploadChannel) {
07553                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
07554             }
07555         }
07556     }
07557     /* Create SH Entry (mLSHE) only if there is a  SessionHistory object (mSessionHistory) in
07558      * the current frame or in the root docshell
07559      */
07560     nsCOMPtr<nsISHistory> rootSH = mSessionHistory;
07561     if (!rootSH) {
07562         // Get the handle to SH from the root docshell          
07563         GetRootSessionHistory(getter_AddRefs(rootSH));
07564         if (!rootSH)
07565             shAvailable = PR_FALSE;
07566     }  // rootSH
07567 
07568 
07569     // Determine if this type of load should update history.
07570     if (aLoadType == LOAD_BYPASS_HISTORY ||
07571         aLoadType == LOAD_ERROR_PAGE ||
07572         aLoadType & LOAD_CMD_HISTORY ||
07573         aLoadType & LOAD_CMD_RELOAD)
07574         updateHistory = PR_FALSE;
07575 
07576     // Check if the url to be loaded is the same as the one already loaded. 
07577     if (mCurrentURI)
07578         aURI->Equals(mCurrentURI, &equalUri);
07579 
07580 #ifdef DEBUG
07581     PR_LOG(gDocShellLog, PR_LOG_DEBUG,
07582            ("  shAvailable=%i updateHistory=%i equalURI=%i\n",
07583             shAvailable, updateHistory, equalUri));
07584 #endif
07585 
07586     /* If the url to be loaded is the same as the one already there,
07587      * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
07588      * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
07589      * AddToSessionHistory() won't mess with the current SHEntry and
07590      * if this page has any frame children, it also will be handled
07591      * properly. see bug 83684
07592      *
07593      * XXX Hopefully changing the loadType at this time will not hurt  
07594      *  anywhere. The other way to take care of sequentially repeating
07595      *  frameset pages is to add new methods to nsIDocShellTreeItem.
07596      * Hopefully I don't have to do that. 
07597      */
07598     if (equalUri &&
07599         (mLoadType == LOAD_NORMAL ||
07600          mLoadType == LOAD_LINK ||
07601          mLoadType == LOAD_STOP_CONTENT) &&
07602         !inputStream)
07603     {
07604         mLoadType = LOAD_NORMAL_REPLACE;
07605     }
07606 
07607     // If this is a refresh to the currently loaded url, we don't
07608     // have to update session or global history.
07609     if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
07610         SetHistoryEntry(&mLSHE, mOSHE);
07611     }
07612 
07613 
07614     /* If the user pressed shift-reload, cache will create a new cache key
07615      * for the page. Save the new cacheKey in Session History. 
07616      * see bug 90098
07617      */
07618     if (aChannel && aLoadType == LOAD_RELOAD_BYPASS_CACHE ||
07619         aLoadType == LOAD_RELOAD_BYPASS_PROXY ||
07620         aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE) {                 
07621         NS_ASSERTION(!updateHistory,
07622                      "We shouldn't be updating history for forced reloads!");
07623         
07624         nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel));
07625         nsCOMPtr<nsISupports>  cacheKey;
07626         // Get the Cache Key  and store it in SH.         
07627         if (cacheChannel) 
07628             cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
07629         // If we already have a loading history entry, store the new cache key
07630         // in it.  Otherwise, since we're doing a reload and won't be updating
07631         // our history entry, store the cache key in our current history entry.
07632         if (mLSHE)
07633             mLSHE->SetCacheKey(cacheKey);
07634         else if (mOSHE)
07635             mOSHE->SetCacheKey(cacheKey);
07636     }
07637 
07638     if (updateHistory && shAvailable) { 
07639         // Update session history if necessary...
07640         if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
07641             /* This is  a fresh page getting loaded for the first time
07642              *.Create a Entry for it and add it to SH, if this is the
07643              * rootDocShell
07644              */
07645             (void) AddToSessionHistory(aURI, aChannel, getter_AddRefs(mLSHE));
07646         }
07647 
07648         // Update Global history
07649         if (aAddToGlobalHistory) {
07650             // Get the referrer uri from the channel
07651             AddToGlobalHistory(aURI, PR_FALSE, aChannel);
07652         }
07653     }
07654 
07655     // If this was a history load, update the index in 
07656     // SH. 
07657     if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) {
07658         nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
07659         if (shInternal) {
07660             rootSH->GetIndex(&mPreviousTransIndex);
07661             shInternal->UpdateIndex();
07662             rootSH->GetIndex(&mLoadedTransIndex);
07663 #ifdef DEBUG_PAGE_CACHE
07664             printf("Previous index: %d, Loaded index: %d\n\n",
07665                    mPreviousTransIndex, mLoadedTransIndex);
07666 #endif
07667         }
07668     }
07669     PRBool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
07670                                                   aFireOnLocationChange);
07671     // Make sure to store the referrer from the channel, if any
07672     SetupReferrerFromChannel(aChannel);
07673     return onLocationChangeNeeded;
07674 }
07675 
07676 PRBool
07677 nsDocShell::OnLoadingSite(nsIChannel * aChannel, PRBool aFireOnLocationChange,
07678                           PRBool aAddToGlobalHistory)
07679 {
07680     nsCOMPtr<nsIURI> uri;
07681     // If this a redirect, use the final url (uri)
07682     // else use the original url
07683     //
07684     // Note that this should match what documents do (see nsDocument::Reset).
07685     nsLoadFlags loadFlags = 0;
07686     aChannel->GetLoadFlags(&loadFlags);
07687     if (loadFlags & nsIChannel::LOAD_REPLACE)
07688         aChannel->GetURI(getter_AddRefs(uri));
07689     else
07690         aChannel->GetOriginalURI(getter_AddRefs(uri));
07691     NS_ENSURE_TRUE(uri, PR_FALSE);
07692 
07693     return OnNewURI(uri, aChannel, mLoadType, aFireOnLocationChange,
07694                     aAddToGlobalHistory);
07695 
07696 }
07697 
07698 void
07699 nsDocShell::SetReferrerURI(nsIURI * aURI)
07700 {
07701     mReferrerURI = aURI;        // This assigment addrefs
07702 }
07703 
07704 //*****************************************************************************
07705 // nsDocShell: Session History
07706 //*****************************************************************************   
07707 PRBool
07708 nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
07709 {
07710     // I believe none of the about: urls should go in the history. But then
07711     // that could just be me... If the intent is only deny about:blank then we
07712     // should just do a spec compare, rather than two gets of the scheme and
07713     // then the path.  -Gagan
07714     nsresult rv;
07715     nsCAutoString buf;
07716 
07717     rv = aURI->GetScheme(buf);
07718     if (NS_FAILED(rv))
07719         return PR_FALSE;
07720 
07721     if (buf.Equals("about")) {
07722         rv = aURI->GetPath(buf);
07723         if (NS_FAILED(rv))
07724             return PR_FALSE;
07725 
07726         if (buf.Equals("blank")) {
07727             return PR_FALSE;
07728         }
07729     }
07730     return PR_TRUE;
07731 }
07732 
07733 nsresult
07734 nsDocShell::AddToSessionHistory(nsIURI * aURI,
07735                                 nsIChannel * aChannel, nsISHEntry ** aNewEntry)
07736 {
07737 #if defined(PR_LOGGING) && defined(DEBUG)
07738     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
07739         nsCAutoString spec;
07740         aURI->GetSpec(spec);
07741 
07742         nsCAutoString chanName;
07743         if (aChannel)
07744             aChannel->GetName(chanName);
07745         else
07746             chanName.AssignLiteral("<no channel>");
07747 
07748         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
07749                ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec.get(),
07750                 chanName.get()));
07751     }
07752 #endif
07753 
07754     nsresult rv = NS_OK;
07755     nsCOMPtr<nsISHEntry_MOZILLA_1_8_BRANCH> entry;
07756     PRBool shouldPersist;
07757 
07758     shouldPersist = ShouldAddToSessionHistory(aURI);
07759 
07760     // Get a handle to the root docshell 
07761     nsCOMPtr<nsIDocShellTreeItem> root;
07762     GetSameTypeRootTreeItem(getter_AddRefs(root));     
07763     /*
07764      * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
07765      * the existing SH entry in the page and replace the url and
07766      * other vitalities.
07767      */
07768     if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) &&
07769         root != NS_STATIC_CAST(nsIDocShellTreeItem *, this)) {
07770         // This is a subframe 
07771         entry = do_QueryInterface(mOSHE);
07772         nsCOMPtr<nsISHContainer> shContainer(do_QueryInterface(entry));
07773         if (shContainer) {
07774             PRInt32 childCount = 0;
07775             shContainer->GetChildCount(&childCount);
07776             // Remove all children of this entry 
07777             for (PRInt32 i = childCount - 1; i >= 0; i--) {
07778                 nsCOMPtr<nsISHEntry> child;
07779                 shContainer->GetChildAt(i, getter_AddRefs(child));
07780                 shContainer->RemoveChild(child);
07781             }  // for
07782         }  // shContainer
07783     }
07784 
07785     // Create a new entry if necessary.
07786     if (!entry) {
07787         entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);
07788 
07789         if (!entry) {
07790             return NS_ERROR_OUT_OF_MEMORY;
07791         }
07792     }
07793 
07794     // Get the post data & referrer
07795     nsCOMPtr<nsIInputStream> inputStream;
07796     nsCOMPtr<nsIURI> referrerURI;
07797     nsCOMPtr<nsISupports> cacheKey;
07798     nsCOMPtr<nsISupports> cacheToken;
07799     nsCOMPtr<nsISupports> owner;
07800     PRBool expired = PR_FALSE;
07801     PRBool discardLayoutState = PR_FALSE;
07802     if (aChannel) {
07803         nsCOMPtr<nsICachingChannel>
07804             cacheChannel(do_QueryInterface(aChannel));
07805         /* If there is a caching channel, get the Cache Key  and store it 
07806          * in SH.
07807          */
07808         if (cacheChannel) {
07809             cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
07810             cacheChannel->GetCacheToken(getter_AddRefs(cacheToken));
07811         }
07812         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
07813         
07814         // Check if the httpChannel is hiding under a multipartChannel
07815         if (!httpChannel) {
07816             GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
07817         }
07818         if (httpChannel) {
07819             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
07820             if (uploadChannel) {
07821                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
07822             }
07823             httpChannel->GetReferrer(getter_AddRefs(referrerURI));
07824 
07825             discardLayoutState = ShouldDiscardLayoutState(httpChannel);
07826         }
07827         aChannel->GetOwner(getter_AddRefs(owner));
07828     }
07829 
07830     //Title is set in nsDocShell::SetTitle()
07831     entry->Create_MOZILLA_1_8_BRANCH(aURI,              // uri
07832                                      EmptyString(),     // Title
07833                                      inputStream,       // Post data stream
07834                                      nsnull,            // LayoutHistory state
07835                                      cacheKey,          // CacheKey
07836                                      mContentTypeHint,  // Content-type
07837                                      owner);            // Channel owner
07838     entry->SetReferrerURI(referrerURI);
07839     /* If cache got a 'no-store', ask SH not to store
07840      * HistoryLayoutState. By default, SH will set this
07841      * flag to PR_TRUE and save HistoryLayoutState.
07842      */    
07843     if (discardLayoutState) {
07844         entry->SetSaveLayoutStateFlag(PR_FALSE);
07845     }
07846     if (cacheToken) {
07847         // Check if the page has expired from cache 
07848         nsCOMPtr<nsICacheEntryInfo> cacheEntryInfo(do_QueryInterface(cacheToken));
07849         if (cacheEntryInfo) {        
07850             PRUint32 expTime;         
07851             cacheEntryInfo->GetExpirationTime(&expTime);         
07852             PRUint32 now = PRTimeToSeconds(PR_Now());                  
07853             if (expTime <=  now)            
07854                 expired = PR_TRUE;         
07855          
07856         }
07857     }
07858     if (expired == PR_TRUE)
07859         entry->SetExpirationStatus(PR_TRUE);
07860 
07861 
07862     if (root == NS_STATIC_CAST(nsIDocShellTreeItem *, this) && mSessionHistory) {
07863         // This is the root docshell
07864         if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {            
07865             // Replace current entry in session history.
07866             PRInt32  index = 0;   
07867             mSessionHistory->GetIndex(&index);
07868             nsCOMPtr<nsISHistoryInternal>   shPrivate(do_QueryInterface(mSessionHistory));
07869             // Replace the current entry with the new entry
07870             if (shPrivate)
07871                 rv = shPrivate->ReplaceEntry(index, entry);          
07872         }
07873         else {
07874             // Add to session history
07875             nsCOMPtr<nsISHistoryInternal>
07876                 shPrivate(do_QueryInterface(mSessionHistory));
07877             NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
07878             mSessionHistory->GetIndex(&mPreviousTransIndex);
07879             rv = shPrivate->AddEntry(entry, shouldPersist);
07880             mSessionHistory->GetIndex(&mLoadedTransIndex);
07881 #ifdef DEBUG_PAGE_CACHE
07882             printf("Previous index: %d, Loaded index: %d\n\n",
07883                    mPreviousTransIndex, mLoadedTransIndex);
07884 #endif
07885         }
07886     }
07887     else {  
07888         // This is a subframe.
07889         if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType,
07890                                            LOAD_FLAGS_REPLACE_HISTORY))
07891             rv = DoAddChildSHEntry(entry, mChildOffset);
07892     }
07893 
07894     // Return the new SH entry...
07895     if (aNewEntry) {
07896         *aNewEntry = nsnull;
07897         if (NS_SUCCEEDED(rv)) {
07898             *aNewEntry = entry;
07899             NS_ADDREF(*aNewEntry);
07900         }
07901     }
07902 
07903     return rv;
07904 }
07905 
07906 
07907 NS_IMETHODIMP
07908 nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, PRUint32 aLoadType)
07909 {
07910     nsresult rv;
07911     nsCOMPtr<nsIURI> uri;
07912     nsCOMPtr<nsIInputStream> postData;
07913     nsCOMPtr<nsIURI> referrerURI;
07914     nsCAutoString contentType;
07915     nsCOMPtr<nsISupports> owner;
07916 
07917     NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
07918 
07919     NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
07920     NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
07921                       NS_ERROR_FAILURE);
07922     NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
07923                       NS_ERROR_FAILURE);
07924     NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
07925 
07926     nsCOMPtr<nsISHEntry_MOZILLA_1_8_BRANCH> branchEntry =
07927         do_QueryInterface(aEntry);
07928     NS_ENSURE_TRUE(branchEntry, NS_ERROR_UNEXPECTED);
07929     NS_ENSURE_SUCCESS(branchEntry->GetOwner(getter_AddRefs(owner)),
07930                       NS_ERROR_FAILURE);
07931     
07932 
07933     PRBool isJavaScript, isViewSource, isData;
07934     // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
07935     // that's the only thing holding a ref to aEntry that will cause aEntry to
07936     // die while we're loading it.  So hold a strong ref to aEntry here, just
07937     // in case.
07938     nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
07939     if ((NS_SUCCEEDED(uri->SchemeIs("javascript", &isJavaScript)) &&
07940          isJavaScript) ||
07941         (NS_SUCCEEDED(uri->SchemeIs("view-source", &isViewSource)) &&
07942          isViewSource) ||
07943         (NS_SUCCEEDED(uri->SchemeIs("data", &isData)) && isData)) {
07944         // We're loading a javascript: or data: URL from session
07945         // history. Replace the current document with about:blank to
07946         // prevent anything from the current document from leaking
07947         // into any JavaScript code in the URL.
07948         rv = CreateAboutBlankContentViewer();
07949 
07950         if (NS_FAILED(rv)) {
07951             // The creation of the intermittent about:blank content
07952             // viewer failed for some reason (potentially because the
07953             // user prevented it). Interrupt the history load.
07954             return NS_OK;
07955         }
07956 
07957         if (!owner) {
07958             // Ensure that we have an owner, just to make sure that nothing
07959             // reuses the principal of the about:blank page that just got
07960             // created.
07961             nsCOMPtr<nsIScriptSecurityManager> secMan = 
07962                 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
07963             NS_ENSURE_SUCCESS(rv, rv);
07964 
07965             nsCOMPtr<nsIPrincipal> prin;
07966             secMan->GetCodebasePrincipal(uri, getter_AddRefs(prin));
07967             owner = prin;
07968             NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY);
07969         }
07970     }
07971 
07972     /* If there is a valid postdata *and* the user pressed
07973      * reload or shift-reload, take user's permission before we  
07974      * repost the data to the server.
07975      */
07976     if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
07977 
07978       nsCOMPtr<nsIPrompt> prompter;
07979       PRBool repost;
07980       nsCOMPtr<nsIStringBundle> stringBundle;
07981       GetPromptAndStringBundle(getter_AddRefs(prompter), 
07982                                 getter_AddRefs(stringBundle));
07983  
07984       if (stringBundle && prompter) {
07985         nsXPIDLString messageStr;
07986         nsresult rv = stringBundle->GetStringFromName(NS_LITERAL_STRING("repostConfirm").get(), 
07987                                                       getter_Copies(messageStr));
07988           
07989         if (NS_SUCCEEDED(rv) && messageStr) {
07990           prompter->Confirm(nsnull, messageStr, &repost);
07991           /* If the user pressed cancel in the dialog, return.  We're
07992            * done here.
07993            */
07994           if (!repost)
07995             return NS_BINDING_ABORTED;  
07996         }
07997       }
07998     }
07999 
08000     rv = InternalLoad(uri,
08001                       referrerURI,
08002                       owner,
08003                       INTERNAL_LOAD_FLAGS_NONE, // Do not inherit owner from document (security-critical!)
08004                       nsnull,            // No window target
08005                       contentType.get(), // Type hint
08006                       postData,          // Post data stream
08007                       nsnull,            // No headers stream
08008                       aLoadType,         // Load type
08009                       aEntry,            // SHEntry
08010                       PR_TRUE,
08011                       nsnull,            // No nsIDocShell
08012                       nsnull);           // No nsIRequest
08013     return rv;
08014 }
08015 
08016 NS_IMETHODIMP nsDocShell::GetShouldSaveLayoutState(PRBool* aShould)
08017 {
08018     *aShould = PR_FALSE;
08019     if (mOSHE) {
08020         // Don't capture historystate and save it in history
08021         // if the page asked not to do so.
08022         mOSHE->GetSaveLayoutStateFlag(aShould);
08023     }
08024 
08025     return NS_OK;
08026 }
08027 
08028 NS_IMETHODIMP nsDocShell::PersistLayoutHistoryState()
08029 {
08030     nsresult  rv = NS_OK;
08031     
08032     if (mOSHE) {
08033         PRBool shouldSave;
08034         GetShouldSaveLayoutState(&shouldSave);
08035         if (!shouldSave)
08036             return NS_OK;
08037 
08038         nsCOMPtr<nsIPresShell> shell;
08039         rv = GetPresShell(getter_AddRefs(shell));
08040         if (NS_SUCCEEDED(rv) && shell) {
08041             nsCOMPtr<nsILayoutHistoryState> layoutState;
08042             rv = shell->CaptureHistoryState(getter_AddRefs(layoutState),
08043                                             PR_TRUE);
08044         }
08045     }
08046 
08047     return rv;
08048 }
08049 
08050 /* static */ nsresult
08051 nsDocShell::WalkHistoryEntries(nsISHEntry *aRootEntry,
08052                                nsDocShell *aRootShell,
08053                                WalkHistoryEntriesFunc aCallback,
08054                                void *aData)
08055 {
08056     NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE);
08057 
08058     nsCOMPtr<nsISHContainer> container(do_QueryInterface(aRootEntry));
08059     if (!container)
08060         return NS_ERROR_FAILURE;
08061 
08062     PRInt32 childCount;
08063     container->GetChildCount(&childCount);
08064     for (PRInt32 i = 0; i < childCount; i++) {
08065         nsCOMPtr<nsISHEntry> childEntry;
08066         container->GetChildAt(i, getter_AddRefs(childEntry));
08067         if (!childEntry) {
08068             // childEntry can be null for valid reasons, for example if the
08069             // docshell at index i never loaded anything useful.
08070             continue;
08071         }
08072 
08073         nsDocShell *childShell = nsnull;
08074         if (aRootShell) {
08075             // Walk the children of aRootShell and see if one of them
08076             // has srcChild as a SHEntry.
08077 
08078             PRInt32 childCount = aRootShell->mChildList.Count();
08079             for (PRInt32 j = 0; j < childCount; ++j) {
08080                 nsDocShell *child =
08081                     NS_STATIC_CAST(nsDocShell*, aRootShell->ChildAt(j));
08082 
08083                 if (child->HasHistoryEntry(childEntry)) {
08084                     childShell = child;
08085                     break;
08086                 }
08087             }
08088         }
08089         nsresult rv = aCallback(childEntry, childShell, i, aData);
08090         NS_ENSURE_SUCCESS(rv, rv);
08091     }
08092 
08093     return NS_OK;
08094 }
08095 
08096 // callback data for WalkHistoryEntries
08097 struct CloneAndReplaceData
08098 {
08099     CloneAndReplaceData(PRUint32 aCloneID, nsISHEntry *aReplaceEntry,
08100                         nsISHEntry *aDestTreeParent)
08101         : cloneID(aCloneID),
08102           replaceEntry(aReplaceEntry),
08103           destTreeParent(aDestTreeParent) { }
08104 
08105     PRUint32              cloneID;
08106     nsISHEntry           *replaceEntry;
08107     nsISHEntry           *destTreeParent;
08108     nsCOMPtr<nsISHEntry>  resultEntry;
08109 };
08110 
08111 /* static */ nsresult
08112 nsDocShell::CloneAndReplaceChild(nsISHEntry *aEntry, nsDocShell *aShell,
08113                                  PRInt32 aEntryIndex, void *aData)
08114 {
08115     nsresult result = NS_OK;
08116     nsCOMPtr<nsISHEntry> dest;
08117 
08118     CloneAndReplaceData *data = NS_STATIC_CAST(CloneAndReplaceData*, aData);
08119     PRUint32 cloneID = data->cloneID;
08120     nsISHEntry *replaceEntry = data->replaceEntry;
08121 
08122     PRUint32 srcID;
08123     aEntry->GetID(&srcID);
08124 
08125     if (srcID == cloneID) {
08126         // Just replace the entry, and don't walk the children.
08127         dest = replaceEntry;
08128         dest->SetIsSubFrame(PR_TRUE);
08129     } else {
08130         // Clone the SHEntry...
08131         result = aEntry->Clone(getter_AddRefs(dest));
08132         if (NS_FAILED(result))
08133             return result;
08134 
08135         // This entry is for a subframe navigation
08136         dest->SetIsSubFrame(PR_TRUE);
08137 
08138         // Walk the children
08139         CloneAndReplaceData childData(cloneID, replaceEntry, dest);
08140         result = WalkHistoryEntries(aEntry, aShell,
08141                                     CloneAndReplaceChild, &childData);
08142         if (NS_FAILED(result))
08143             return result;
08144 
08145         if (aShell)
08146             aShell->SwapHistoryEntries(aEntry, dest);
08147     }
08148 
08149     nsCOMPtr<nsISHContainer> container =
08150         do_QueryInterface(data->destTreeParent);
08151     if (container)
08152         container->AddChild(dest, aEntryIndex);
08153 
08154     data->resultEntry = dest;
08155     return result;
08156 }
08157 
08158 /* static */ nsresult
08159 nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry,
08160                                    nsDocShell *aSrcShell,
08161                                    PRUint32 aCloneID,
08162                                    nsISHEntry *aReplaceEntry,
08163                                    nsISHEntry **aResultEntry)
08164 {
08165     NS_ENSURE_ARG_POINTER(aResultEntry);
08166     NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE);
08167 
08168     CloneAndReplaceData data(aCloneID, aReplaceEntry, nsnull);
08169     nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
08170 
08171     data.resultEntry.swap(*aResultEntry);
08172     return rv;
08173 }
08174 
08175 
08176 void
08177 nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
08178 {
08179     if (aOldEntry == mOSHE)
08180         mOSHE = aNewEntry;
08181 
08182     if (aOldEntry == mLSHE)
08183         mLSHE = aNewEntry;
08184 }
08185 
08186 
08187 struct SwapEntriesData
08188 {
08189     nsDocShell *ignoreShell;     // constant; the shell to ignore
08190     nsISHEntry *destTreeRoot;    // constant; the root of the dest tree
08191     nsISHEntry *destTreeParent;  // constant; the node under destTreeRoot
08192                                  // whose children will correspond to aEntry
08193 };
08194 
08195 
08196 nsresult
08197 nsDocShell::SetChildHistoryEntry(nsISHEntry *aEntry, nsDocShell *aShell,
08198                                  PRInt32 aEntryIndex, void *aData)
08199 {
08200     SwapEntriesData *data = NS_STATIC_CAST(SwapEntriesData*, aData);
08201     nsDocShell *ignoreShell = data->ignoreShell;
08202 
08203     if (!aShell || aShell == ignoreShell)
08204         return NS_OK;
08205 
08206     nsISHEntry *destTreeRoot = data->destTreeRoot;
08207 
08208     nsCOMPtr<nsISHEntry> destEntry;
08209     nsCOMPtr<nsISHContainer> container =
08210         do_QueryInterface(data->destTreeParent);
08211 
08212     if (container) {
08213         // aEntry is a clone of some child of destTreeParent, but since the
08214         // trees aren't necessarily in sync, we'll have to locate it.
08215         // Note that we could set aShell's entry to null if we don't find a
08216         // corresponding entry under destTreeParent.
08217 
08218         PRUint32 targetID, id;
08219         aEntry->GetID(&targetID);
08220 
08221         // First look at the given index, since this is the common case.
08222         nsCOMPtr<nsISHEntry> entry;
08223         container->GetChildAt(aEntryIndex, getter_AddRefs(entry));
08224         if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) {
08225             destEntry.swap(entry);
08226         } else {
08227             PRInt32 childCount;
08228             container->GetChildCount(&childCount);
08229             for (PRInt32 i = 0; i < childCount; ++i) {
08230                 container->GetChildAt(i, getter_AddRefs(entry));
08231                 if (!entry)
08232                     continue;
08233 
08234                 entry->GetID(&id);
08235                 if (id == targetID) {
08236                     destEntry.swap(entry);
08237                     break;
08238                 }
08239             }
08240         }
08241     } else {
08242         destEntry = destTreeRoot;
08243     }
08244 
08245     aShell->SwapHistoryEntries(aEntry, destEntry);
08246 
08247     // Now handle the children of aEntry.
08248     SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry };
08249     return WalkHistoryEntries(aEntry, aShell,
08250                               SetChildHistoryEntry, &childData);
08251 }
08252 
08253 
08254 static nsISHEntry*
08255 GetRootSHEntry(nsISHEntry *aEntry)
08256 {
08257     nsCOMPtr<nsISHEntry> rootEntry = aEntry;
08258     nsISHEntry *result = nsnull;
08259     while (rootEntry) {
08260         result = rootEntry;
08261         result->GetParent(getter_AddRefs(rootEntry));
08262     }
08263 
08264     return result;
08265 }
08266 
08267 
08268 void
08269 nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry> *aPtr, nsISHEntry *aEntry)
08270 {
08271     // We need to sync up the docshell and session history trees for
08272     // subframe navigation.  If the load was in a subframe, we forward up to
08273     // the root docshell, which will then recursively sync up all docshells
08274     // to their corresponding entries in the new session history tree.
08275     // If we don't do this, then we can cache a content viewer on the wrong
08276     // cloned entry, and subsequently restore it at the wrong time.
08277 
08278     nsISHEntry *newRootEntry = GetRootSHEntry(aEntry);
08279     if (newRootEntry) {
08280         // newRootEntry is now the new root entry.
08281         // Find the old root entry as well.
08282 
08283         // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
08284         // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
08285         nsCOMPtr<nsISHEntry> oldRootEntry = GetRootSHEntry(*aPtr);
08286         if (oldRootEntry) {
08287             nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
08288             GetSameTypeParent(getter_AddRefs(parentAsItem));
08289             nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(parentAsItem);
08290             if (rootShell) { // if we're the root just set it, nothing to swap
08291                 SwapEntriesData data = { this, newRootEntry };
08292                 nsIDocShell *rootIDocShell =
08293                     NS_STATIC_CAST(nsIDocShell*, rootShell);
08294                 nsDocShell *rootDocShell = NS_STATIC_CAST(nsDocShell*,
08295                                                           rootIDocShell);
08296 
08297                 nsresult rv = SetChildHistoryEntry(oldRootEntry, rootDocShell,
08298                                                    0, &data);
08299                 NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
08300             }
08301         }
08302     }
08303 
08304     *aPtr = aEntry;
08305 }
08306 
08307 
08308 nsresult
08309 nsDocShell::GetRootSessionHistory(nsISHistory ** aReturn)
08310 {
08311     nsresult rv;
08312 
08313     nsCOMPtr<nsIDocShellTreeItem> root;
08314     //Get the root docshell
08315     rv = GetSameTypeRootTreeItem(getter_AddRefs(root));
08316     // QI to nsIWebNavigation
08317     nsCOMPtr<nsIWebNavigation> rootAsWebnav(do_QueryInterface(root));
08318     if (rootAsWebnav) {
08319         // Get the handle to SH from the root docshell
08320         rv = rootAsWebnav->GetSessionHistory(aReturn);
08321     }
08322     return rv;
08323 }
08324 
08325 nsresult
08326 nsDocShell::GetHttpChannel(nsIChannel * aChannel, nsIHttpChannel ** aReturn)
08327 {
08328     NS_ENSURE_ARG_POINTER(aReturn);
08329     if (!aChannel)
08330         return NS_ERROR_FAILURE;
08331 
08332     nsCOMPtr<nsIMultiPartChannel>  multiPartChannel(do_QueryInterface(aChannel));
08333     if (multiPartChannel) {
08334         nsCOMPtr<nsIChannel> baseChannel;
08335         multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
08336         nsCOMPtr<nsIHttpChannel>  httpChannel(do_QueryInterface(baseChannel));
08337         *aReturn = httpChannel;
08338         NS_IF_ADDREF(*aReturn);
08339     }
08340     return NS_OK;
08341 }
08342 
08343 PRBool 
08344 nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel * aChannel)
08345 {    
08346     // By default layout State will be saved. 
08347     if (!aChannel)
08348         return PR_FALSE;
08349 
08350     // figure out if SH should be saving layout state 
08351     nsCOMPtr<nsISupports> securityInfo;
08352     PRBool noStore = PR_FALSE, noCache = PR_FALSE;
08353     aChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
08354     aChannel->IsNoStoreResponse(&noStore);
08355     aChannel->IsNoCacheResponse(&noCache);
08356 
08357     return (noStore || (noCache && securityInfo));
08358 }
08359 
08360 //*****************************************************************************
08361 // nsDocShell: nsIEditorDocShell
08362 //*****************************************************************************   
08363 
08364 NS_IMETHODIMP nsDocShell::GetEditor(nsIEditor * *aEditor)
08365 {
08366   NS_ENSURE_ARG_POINTER(aEditor);
08367   nsresult rv = EnsureEditorData();
08368   if (NS_FAILED(rv)) return rv;
08369   
08370   return mEditorData->GetEditor(aEditor);
08371 }
08372 
08373 NS_IMETHODIMP nsDocShell::SetEditor(nsIEditor * aEditor)
08374 {
08375   nsresult rv = EnsureEditorData();
08376   if (NS_FAILED(rv)) return rv;
08377 
08378   return mEditorData->SetEditor(aEditor);
08379 }
08380 
08381 
08382 NS_IMETHODIMP nsDocShell::GetEditable(PRBool *aEditable)
08383 {
08384   NS_ENSURE_ARG_POINTER(aEditable);
08385   *aEditable = mEditorData && mEditorData->GetEditable();
08386   return NS_OK;
08387 }
08388 
08389 
08390 NS_IMETHODIMP nsDocShell::GetHasEditingSession(PRBool *aHasEditingSession)
08391 {
08392   NS_ENSURE_ARG_POINTER(aHasEditingSession);
08393   
08394   if (mEditorData)
08395   {
08396     nsCOMPtr<nsIEditingSession> editingSession;
08397     mEditorData->GetEditingSession(getter_AddRefs(editingSession));
08398     *aHasEditingSession = (editingSession.get() != nsnull);
08399   }
08400   else
08401   {
08402     *aHasEditingSession = PR_FALSE;
08403   }
08404 
08405   return NS_OK;
08406 }
08407 
08408 NS_IMETHODIMP nsDocShell::MakeEditable(PRBool inWaitForUriLoad)
08409 {
08410   nsresult rv = EnsureEditorData();
08411   if (NS_FAILED(rv)) return rv;
08412 
08413   return mEditorData->MakeEditable(inWaitForUriLoad);
08414 }
08415 
08416