Back to index

lightning-sunbird  0.9+nobinonly
nsGlobalWindow.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim: set sw=2 ts=2 et tw=80: */
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 mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Travis Bogard <travis@netscape.com>
00025  *   Brendan Eich <brendan@mozilla.org>
00026  *   David Hyatt (hyatt@netscape.com)
00027  *   Dan Rosen <dr@netscape.com>
00028  *   Vidur Apparao <vidur@netscape.com>
00029  *   Johnny Stenback <jst@netscape.com>
00030  *
00031  * Alternatively, the contents of this file may be used under the terms of
00032  * either of the GNU General Public License Version 2 or later (the "GPL"),
00033  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00034  * in which case the provisions of the GPL or the LGPL are applicable instead
00035  * of those above. If you wish to allow use of your version of this file only
00036  * under the terms of either the GPL or the LGPL, and not to allow others to
00037  * use your version of this file under the terms of the MPL, indicate your
00038  * decision by deleting the provisions above and replace them with the notice
00039  * and other provisions required by the GPL or the LGPL. If you do not delete
00040  * the provisions above, a recipient may use your version of this file under
00041  * the terms of any one of the MPL, the GPL or the LGPL.
00042  *
00043  * ***** END LICENSE BLOCK ***** */
00044 
00045 // Local Includes
00046 #include "nsGlobalWindow.h"
00047 #include "nsScreen.h"
00048 #include "nsHistory.h"
00049 #include "nsBarProps.h"
00050 #include "nsDOMStorage.h"
00051 
00052 // Helper Classes
00053 #include "nsXPIDLString.h"
00054 #include "nsJSUtils.h"
00055 #include "prmem.h"
00056 #include "jsdbgapi.h"           // for JS_ClearWatchPointsForObject
00057 #include "nsReadableUtils.h"
00058 #include "nsDOMClassInfo.h"
00059 #include "nsBuildID.h"
00060 
00061 // Other Classes
00062 #include "nsIEventListenerManager.h"
00063 #include "nsEscape.h"
00064 #include "nsStyleCoord.h"
00065 #include "nsMimeTypeArray.h"
00066 #include "nsNetUtil.h"
00067 #include "nsPluginArray.h"
00068 #include "nsIPluginHost.h"
00069 #ifdef OJI
00070 #include "nsIJVMManager.h"
00071 #endif
00072 #include "nsContentCID.h"
00073 #include "nsLayoutStatics.h"
00074 
00075 // Interfaces Needed
00076 #include "nsIWidget.h"
00077 #include "nsIBaseWindow.h"
00078 #include "nsICharsetConverterManager.h"
00079 #include "nsIContent.h"
00080 #include "nsIWebBrowserPrint.h"
00081 #include "nsIContentViewerEdit.h"
00082 #include "nsIDocShell.h"
00083 #include "nsIDocShellLoadInfo.h"
00084 #include "nsIDocShellTreeItem.h"
00085 #include "nsIDocShellTreeNode.h"
00086 #include "nsIDocCharset.h"
00087 #include "nsIDocument.h"
00088 #include "nsIHTMLDocument.h"
00089 #include "nsIDOMHTMLDocument.h"
00090 #include "nsIDOMHTMLElement.h"
00091 #include "nsIDOMCrypto.h"
00092 #include "nsIDOMDocument.h"
00093 #include "nsIDOMNSDocument.h"
00094 #include "nsIDOMDocumentView.h"
00095 #include "nsIDOMElement.h"
00096 #include "nsIDOMDocumentEvent.h"
00097 #include "nsIDOMEvent.h"
00098 #include "nsIDOMKeyEvent.h"
00099 #include "nsIDOMPopupBlockedEvent.h"
00100 #include "nsIDOMPkcs11.h"
00101 #include "nsDOMString.h"
00102 #include "nsIEmbeddingSiteWindow2.h"
00103 #include "nsIEventQueueService.h"
00104 #include "nsIEventStateManager.h"
00105 #include "nsIHttpProtocolHandler.h"
00106 #include "nsIJSContextStack.h"
00107 #include "nsIJSRuntimeService.h"
00108 #include "nsIMarkupDocumentViewer.h"
00109 #include "nsIPrefBranch.h"
00110 #include "nsIPresShell.h"
00111 #include "nsIPrivateDOMEvent.h"
00112 #include "nsIProgrammingLanguage.h"
00113 #include "nsIAuthPrompt.h"
00114 #include "nsIServiceManager.h"
00115 #include "nsIScriptGlobalObjectOwner.h"
00116 #include "nsIScriptSecurityManager.h"
00117 #include "nsIScrollableView.h"
00118 #include "nsISelectionController.h"
00119 #include "nsISelection.h"
00120 #include "nsIFrameSelection.h"
00121 #include "nsIPrompt.h"
00122 #include "nsIWebNavigation.h"
00123 #include "nsIWebBrowser.h"
00124 #include "nsIWebBrowserChrome.h"
00125 #include "nsIWebBrowserFind.h"  // For window.find()
00126 #include "nsIWindowMediator.h"  // For window.find()
00127 #include "nsIWebContentHandlerRegistrar.h"
00128 #include "nsIComputedDOMStyle.h"
00129 #include "nsIEntropyCollector.h"
00130 #include "nsDOMCID.h"
00131 #include "nsDOMError.h"
00132 #include "nsDOMWindowUtils.h"
00133 #include "nsIWindowWatcher.h"
00134 #include "nsPIWindowWatcher.h"
00135 #include "nsIContentViewer.h"
00136 #include "nsISupportsPrimitives.h"
00137 #include "nsDOMClassInfo.h"
00138 #include "nsIJSNativeInitializer.h"
00139 #include "nsIFullScreen.h"
00140 #include "nsIStringBundle.h"
00141 #include "nsIScriptEventManager.h" // For GetInterface()
00142 #include "nsIConsoleService.h"
00143 #include "nsIControllerContext.h"
00144 #include "nsGlobalWindowCommands.h"
00145 #include "nsAutoPtr.h"
00146 #include "nsContentUtils.h"
00147 #include "nsCSSProps.h"
00148 #include "nsIURIFixup.h"
00149 #include "nsCDefaultURIFixup.h"
00150 #include "nsIScriptError.h"
00151 #include "plbase64.h"
00152 #include "nsIObserverService.h"
00153 #include "nsIDragService.h"
00154 #include "nsIPrintSettings.h"
00155 #include "nsIPrintSettingsService.h"
00156 
00157 #include "nsWindowRoot.h"
00158 #include "nsNetCID.h"
00159 
00160 // XXX An unfortunate dependency exists here (two XUL files).
00161 #include "nsIDOMXULDocument.h"
00162 #include "nsIDOMXULCommandDispatcher.h"
00163 
00164 #include "nsIBindingManager.h"
00165 #include "nsIXBLService.h"
00166 
00167 // used for popup blocking, needs to be converted to something
00168 // belonging to the back-end like nsIContentPolicy
00169 #include "nsIPopupWindowManager.h"
00170 
00171 #ifdef MOZ_LOGGING
00172 // so we can get logging even in release builds
00173 #define FORCE_PR_LOG 1
00174 #endif
00175 #include "prlog.h"
00176 
00177 #ifdef PR_LOGGING
00178 static PRLogModuleInfo* gDOMLeakPRLog;
00179 #endif
00180 
00181 nsIScriptSecurityManager *nsGlobalWindow::sSecMan      = nsnull;
00182 nsIFactory *nsGlobalWindow::sComputedDOMStyleFactory   = nsnull;
00183 
00184 static nsIEntropyCollector *gEntropyCollector          = nsnull;
00185 static PRInt32              gRefCnt                    = 0;
00186 static PRInt32              gOpenPopupSpamCount        = 0;
00187 static PopupControlState    gPopupControlState         = openAbused;
00188 static PRInt32              gRunningTimeoutDepth       = 0;
00189 static PRBool               gMouseDown                 = PR_FALSE;
00190 static PRBool               gDragServiceDisabled       = PR_FALSE;
00191 
00192 #ifdef DEBUG_jst
00193 PRInt32 gTimeoutCnt                                    = 0;
00194 #endif
00195 
00196 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
00197 #define DEBUG_PAGE_CACHE
00198 #endif
00199 
00200 // The shortest interval/timeout we permit
00201 #define DOM_MIN_TIMEOUT_VALUE 10 // 10ms
00202 
00203 // The longest interval (as PRIntervalTime) we permit, or that our
00204 // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
00205 // nsTimerImpl.h for details.
00206 #define DOM_MAX_TIMEOUT_VALUE    PR_BIT(8 * sizeof(PRIntervalTime) - 1)
00207 
00208 #define FORWARD_TO_OUTER(method, args, err_rval)                              \
00209   PR_BEGIN_MACRO                                                              \
00210   if (IsInnerWindow()) {                                                      \
00211     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
00212     if (!outer) {                                                             \
00213       NS_WARNING("No outer window available!");                               \
00214       return err_rval;                                                        \
00215     }                                                                         \
00216     return outer->method args;                                                \
00217   }                                                                           \
00218   PR_END_MACRO
00219 
00220 #define FORWARD_TO_OUTER_VOID(method, args)                                   \
00221   PR_BEGIN_MACRO                                                              \
00222   if (IsInnerWindow()) {                                                      \
00223     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
00224     if (!outer) {                                                             \
00225       NS_WARNING("No outer window available!");                               \
00226       return;                                                                 \
00227     }                                                                         \
00228     outer->method args;                                                       \
00229     return;                                                                   \
00230   }                                                                           \
00231   PR_END_MACRO
00232 
00233 #define FORWARD_TO_OUTER_CHROME(method, args, err_rval)                       \
00234   PR_BEGIN_MACRO                                                              \
00235   if (IsInnerWindow()) {                                                      \
00236     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
00237     if (!outer) {                                                             \
00238       NS_WARNING("No outer window available!");                               \
00239       return err_rval;                                                        \
00240     }                                                                         \
00241     return ((nsGlobalChromeWindow *)outer)->method args;                      \
00242   }                                                                           \
00243   PR_END_MACRO
00244 
00245 #define FORWARD_TO_INNER(method, args, err_rval)                              \
00246   PR_BEGIN_MACRO                                                              \
00247   if (IsOuterWindow()) {                                                      \
00248     if (!mInnerWindow) {                                                      \
00249       NS_WARNING("No inner window available!");                               \
00250       return err_rval;                                                        \
00251     }                                                                         \
00252     return GetCurrentInnerWindowInternal()->method args;                      \
00253   }                                                                           \
00254   PR_END_MACRO
00255 
00256 #define FORWARD_TO_INNER_VOID(method, args)                                   \
00257   PR_BEGIN_MACRO                                                              \
00258   if (IsOuterWindow()) {                                                      \
00259     if (!mInnerWindow) {                                                      \
00260       NS_WARNING("No inner window available!");                               \
00261       return;                                                                 \
00262     }                                                                         \
00263     GetCurrentInnerWindowInternal()->method args;                             \
00264     return;                                                                   \
00265   }                                                                           \
00266   PR_END_MACRO
00267 
00268 // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
00269 // inner doesn't already exists.
00270 #define FORWARD_TO_INNER_CREATE(method, args)                                 \
00271   PR_BEGIN_MACRO                                                              \
00272   if (IsOuterWindow()) {                                                      \
00273     if (!mInnerWindow) {                                                      \
00274       if (mIsClosed) {                                                        \
00275         return NS_ERROR_NOT_AVAILABLE;                                        \
00276       }                                                                       \
00277       nsCOMPtr<nsIDOMDocument> doc;                                           \
00278       nsresult fwdic_nr = GetDocument(getter_AddRefs(doc));                   \
00279       NS_ENSURE_SUCCESS(fwdic_nr, fwdic_nr);                                  \
00280       if (!mInnerWindow) {                                                    \
00281         return NS_ERROR_NOT_AVAILABLE;                                        \
00282       }                                                                       \
00283     }                                                                         \
00284     return GetCurrentInnerWindowInternal()->method args;                      \
00285   }                                                                           \
00286   PR_END_MACRO
00287 
00288 // CIDs
00289 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00290 #ifdef OJI
00291 static NS_DEFINE_CID(kJVMServiceCID, NS_JVMMANAGER_CID);
00292 #endif
00293 static NS_DEFINE_CID(kHTTPHandlerCID, NS_HTTPPROTOCOLHANDLER_CID);
00294 static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
00295 static NS_DEFINE_CID(kCharsetConverterManagerCID,
00296                      NS_ICHARSETCONVERTERMANAGER_CID);
00297 static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID); // For window.find()
00298 static NS_DEFINE_CID(kCStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
00299 
00300 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
00301 
00302 static const char kDOMBundleURL[] = "chrome://global/locale/commonDialogs.properties";
00303 static const char kDOMSecurityWarningsBundleURL[] = "chrome://global/locale/dom/dom.properties";
00304 
00305 static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
00306 static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
00307 
00308 static PRBool
00309 IsAboutBlank(nsIURI* aURI)
00310 {
00311   NS_PRECONDITION(aURI, "Must have URI");
00312     
00313   // GetSpec can be expensive for some URIs, so check the scheme first.
00314   PRBool isAbout = PR_FALSE;
00315   if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
00316     return PR_FALSE;
00317   }
00318     
00319   nsCAutoString str;
00320   aURI->GetSpec(str);
00321   return str.EqualsLiteral("about:blank");  
00322 }
00323 
00324 //*****************************************************************************
00325 //***    nsGlobalWindow: Object Management
00326 //*****************************************************************************
00327 
00328 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
00329   : nsPIDOMWindow_MOZILLA_1_8_BRANCH2(aOuterWindow),
00330     mIsFrozen(PR_FALSE),
00331     mFullScreen(PR_FALSE),
00332     mIsClosed(PR_FALSE), 
00333     mInClose(PR_FALSE), 
00334     mHavePendingClose(PR_FALSE),
00335     mHadOriginalOpener(PR_FALSE),
00336     mIsPopupSpam(PR_FALSE),
00337     mCreatingInnerWindow(PR_FALSE),
00338     mModalStateDepth(0),
00339     mArguments(nsnull),
00340     mGlobalObjectOwner(nsnull),
00341     mDocShell(nsnull),
00342     mTimeouts(nsnull),
00343     mTimeoutInsertionPoint(&mTimeouts),
00344     mTimeoutPublicIdCounter(1),
00345     mTimeoutFiringDepth(0),
00346     mJSObject(nsnull),
00347     mPendingStorageEvents(nsnull)
00348 #ifdef DEBUG
00349     , mSetOpenerWindowCalled(PR_FALSE)
00350 #endif
00351 {
00352   nsLayoutStatics::AddRef();
00353 
00354   // Initialize the PRCList (this).
00355   PR_INIT_CLIST(this);
00356 
00357   if (aOuterWindow) {
00358     // |this| is an inner window, add this inner window to the outer
00359     // window list of inners.
00360     PR_INSERT_AFTER(this, aOuterWindow);
00361   } else {
00362     // |this| is an outer window. Outer windows start out frozen and
00363     // remain frozen until they get an inner window, so freeze this
00364     // outer window here.
00365     Freeze();
00366   }
00367 
00368   // We could have failed the first time through trying
00369   // to create the entropy collector, so we should
00370   // try to get one until we succeed.
00371   if (gRefCnt++ == 0 || !gEntropyCollector) {
00372     CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
00373   }
00374 #ifdef DEBUG
00375   printf("++DOMWINDOW == %d\n", gRefCnt);
00376 #endif
00377 
00378 #ifdef PR_LOGGING
00379   if (!gDOMLeakPRLog)
00380     gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
00381 
00382   if (gDOMLeakPRLog)
00383     PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
00384            ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
00385 #endif
00386 
00387   if (!sSecMan) {
00388     CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &sSecMan);
00389   }
00390 }
00391 
00392 nsGlobalWindow::~nsGlobalWindow()
00393 {
00394   if (!--gRefCnt) {
00395     NS_IF_RELEASE(gEntropyCollector);
00396   }
00397 #ifdef DEBUG
00398   printf("--DOMWINDOW == %d\n", gRefCnt);
00399 #endif
00400 
00401 #ifdef PR_LOGGING
00402   if (gDOMLeakPRLog)
00403     PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
00404            ("DOMWINDOW %p destroyed", this));
00405 #endif
00406 
00407   if (IsOuterWindow()) {
00408     // An outer window is destroyed with inner windows still possibly
00409     // alive, iterate through the inner windows and null out their
00410     // back pointer to this outer, and pull them out of the list of
00411     // inner windows.
00412 
00413     nsGlobalWindow *w;
00414     while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
00415       NS_ASSERTION(w->mOuterWindow == this, "Uh, bad outer window pointer?");
00416 
00417       w->mOuterWindow = nsnull;
00418 
00419       PR_REMOVE_AND_INIT_LINK(w);
00420     }
00421   } else {
00422     if (mListenerManager) {
00423       mListenerManager->Disconnect();
00424       mListenerManager = nsnull;
00425     }
00426 
00427     // An inner window is destroyed, pull it out of the outer window's
00428     // list if inner windows.
00429 
00430     PR_REMOVE_LINK(this);
00431 
00432     // If our outer window's inner window is this window, null out the
00433     // outer window's reference to this window that's being deleted.
00434     nsGlobalWindow *outer = GetOuterWindowInternal();
00435     if (outer && outer->mInnerWindow == this) {
00436       outer->mInnerWindow = nsnull;
00437     }
00438 
00439     nsCOMPtr<nsIObserverService> observerService =
00440       do_GetService("@mozilla.org/observer-service;1");
00441 
00442     if (observerService) {
00443       observerService->RemoveObserver(this, "dom-storage-changed");
00444     }
00445   }
00446 
00447   mDocument = nsnull;           // Forces Release
00448 
00449   NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!");
00450 
00451   CleanUp();
00452 
00453   delete mPendingStorageEvents;
00454 
00455   nsLayoutStatics::Release();
00456 }
00457 
00458 // static
00459 void
00460 nsGlobalWindow::ShutDown()
00461 {
00462   NS_IF_RELEASE(sSecMan);
00463   NS_IF_RELEASE(sComputedDOMStyleFactory);
00464 }
00465 
00466 void
00467 nsGlobalWindow::CleanUp()
00468 {
00469   mNavigator = nsnull;
00470   mScreen = nsnull;
00471   mHistory = nsnull;
00472   mMenubar = nsnull;
00473   mToolbar = nsnull;
00474   mLocationbar = nsnull;
00475   mPersonalbar = nsnull;
00476   mStatusbar = nsnull;
00477   mScrollbars = nsnull;
00478   mLocation = nsnull;
00479   mFrames = nsnull;
00480 
00481   ClearControllers();
00482 
00483   mOpener = nsnull;             // Forces Release
00484   if (mContext) {
00485     mContext->SetOwner(nsnull);
00486     mContext = nsnull;            // Forces Release
00487   }
00488   mChromeEventHandler = nsnull; // Forces Release
00489 
00490   if (IsOuterWindow() && IsPopupSpamWindow()) {
00491     SetPopupSpamWindow(PR_FALSE);
00492     --gOpenPopupSpamCount;
00493   }
00494 
00495   nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
00496 
00497   if (inner) {
00498     inner->CleanUp();
00499   }
00500 
00501   mInnerWindowHolder = nsnull;
00502 }
00503 
00504 void
00505 nsGlobalWindow::ClearControllers()
00506 {
00507   if (mControllers) {
00508     PRUint32 count;
00509     mControllers->GetControllerCount(&count);
00510 
00511     while (count--) {
00512       nsCOMPtr<nsIController> controller;
00513       mControllers->GetControllerAt(count, getter_AddRefs(controller));
00514 
00515       nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
00516       if (context)
00517         context->SetCommandContext(nsnull);
00518     }
00519 
00520     mControllers = nsnull;
00521   }
00522 }
00523 
00524 void
00525 nsGlobalWindow::FreeInnerObjects(JSContext *cx)
00526 {
00527   NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
00528 
00529   ClearAllTimeouts();
00530 
00531   mChromeEventHandler = nsnull;
00532 
00533   if (mListenerManager) {
00534     mListenerManager->Disconnect();
00535     mListenerManager = nsnull;
00536   }
00537 
00538   if (mDocument) {
00539     nsCOMPtr<nsIDocument> doc =
00540       do_QueryInterface(mDocument);
00541 
00542     // Remember the document's principal.
00543     mDocumentPrincipal = doc->GetPrincipal();
00544   }
00545 
00546   // Remove our reference to the document and the document principal.
00547   mDocument = nsnull;
00548 
00549   if (mJSObject && cx) {
00550     // Clear mJSObject and its prototype chain, but not Object.prototype.
00551     ::JS_ClearScope(cx, mJSObject);
00552     for (JSObject *o = ::JS_GetPrototype(cx, mJSObject), *next;
00553          o && (next = ::JS_GetPrototype(cx, o)); o = next)
00554       ::JS_ClearScope(cx, o);
00555     ::JS_ClearWatchPointsForObject(cx, mJSObject);
00556 
00557     nsWindowSH::InvalidateGlobalScopePolluter(cx, mJSObject);
00558   }
00559 }
00560 
00561 //*****************************************************************************
00562 // nsGlobalWindow::nsISupports
00563 //*****************************************************************************
00564 
00565 
00566 // QueryInterface implementation for nsGlobalWindow
00567 NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
00568   // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
00569   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
00570   NS_INTERFACE_MAP_ENTRY(nsIDOMWindowInternal)
00571   NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
00572   NS_INTERFACE_MAP_ENTRY(nsIDOMWindow2)
00573   NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
00574   NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
00575   NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
00576   NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
00577   NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
00578   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
00579   NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
00580   NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
00581   NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
00582   NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow_MOZILLA_1_8_BRANCH)
00583   NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow_MOZILLA_1_8_BRANCH2)
00584   NS_INTERFACE_MAP_ENTRY(nsIDOMViewCSS)
00585   NS_INTERFACE_MAP_ENTRY(nsIDOMAbstractView)
00586   NS_INTERFACE_MAP_ENTRY(nsIDOMStorageWindow)
00587   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00588   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
00589   NS_INTERFACE_MAP_ENTRY(nsIObserver)
00590   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
00591 NS_INTERFACE_MAP_END
00592 
00593 
00594 NS_IMPL_ADDREF(nsGlobalWindow)
00595 NS_IMPL_RELEASE(nsGlobalWindow)
00596 
00597 
00598 //*****************************************************************************
00599 // nsGlobalWindow::nsIScriptGlobalObject
00600 //*****************************************************************************
00601 
00602 void
00603 nsGlobalWindow::SetContext(nsIScriptContext* aContext)
00604 {
00605   NS_ASSERTION(IsOuterWindow(), "Uh, SetContext() called on inner window!");
00606   NS_ASSERTION(!aContext || !mContext, "Bad call to SetContext()!");
00607 
00608   // if setting the context to null, then we won't get to clean up the
00609   // named reference, so do it now
00610   if (!aContext) {
00611     NS_WARNING("Possibly early removal of script object, see bug #41608");
00612   } else {
00613     JSContext *cx = (JSContext *)aContext->GetNativeContext();
00614 
00615     mJSObject = ::JS_GetGlobalObject(cx);
00616   }
00617 
00618   if (mContext) {
00619     mContext->SetOwner(nsnull);
00620   }
00621 
00622   mContext = aContext;
00623 
00624   if (mContext) {
00625     if (IsFrame()) {
00626       // This window is a [i]frame, don't bother GC'ing when the
00627       // frame's context is destroyed since a GC will happen when the
00628       // frameset or host document is destroyed anyway.
00629 
00630       mContext->SetGCOnDestruction(PR_FALSE);
00631     }
00632   }
00633 }
00634 
00635 nsIScriptContext *
00636 nsGlobalWindow::GetContext()
00637 {
00638   FORWARD_TO_OUTER(GetContext, (), nsnull);
00639 
00640   return mContext;
00641 }
00642 
00643 PRBool
00644 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
00645 {
00646   // We reuse the inner window when:
00647   // a. We are currently at our original document.
00648   // b. At least one of the following conditions are true:
00649   // -- We are not currently a content window (i.e., we're currently a chrome
00650   //    window).
00651   // -- The new document is the same as the old document. This means that we're
00652   //    getting called from document.open().
00653   // -- The new document has the same origin as what we have loaded right now.
00654 
00655   nsCOMPtr<nsIDocument> curDoc(do_QueryInterface(mDocument));
00656   nsCOMPtr<nsIDocument_MOZILLA_1_8_BRANCH2> curDoc_MOZILLA_1_8_BRANCH2 =
00657     do_QueryInterface(mDocument);
00658   if (!curDoc || !curDoc_MOZILLA_1_8_BRANCH2 || !aNewDocument) {
00659     return PR_FALSE;
00660   }
00661 
00662   nsIPrincipal* newPrincipal = aNewDocument->GetPrincipal();
00663   if (!newPrincipal) {
00664     // Play it safe
00665     return PR_FALSE;
00666   }
00667     
00668   if (!curDoc_MOZILLA_1_8_BRANCH2->IsInitialDocument()) {
00669     return PR_FALSE;
00670   }
00671   
00672   NS_ASSERTION(IsAboutBlank(curDoc->GetDocumentURI()),
00673                "How'd this happen?");
00674   
00675   // Great, we're the original document, check for one of the other
00676   if (curDoc == aNewDocument) {
00677     // aClearScopeHint is false.
00678     return PR_TRUE;
00679   }
00680 
00681   nsIPrincipal* curPrincipal = curDoc->GetPrincipal();
00682   if (!curPrincipal) {
00683     // Play it safe
00684     return PR_FALSE;
00685   }
00686  
00687   if (nsContentUtils::GetSecurityManager() &&
00688       NS_SUCCEEDED(nsContentUtils::GetSecurityManager()->
00689         CheckSameOriginPrincipal(curPrincipal, newPrincipal))) {
00690     // The origin is the same.
00691     return PR_TRUE;
00692   }
00693 
00694   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
00695 
00696   if (treeItem) {
00697     PRInt32 itemType = nsIDocShellTreeItem::typeContent;
00698     treeItem->GetItemType(&itemType);
00699 
00700     // If we're a chrome window, then we want to reuse the inner window.
00701     return itemType == nsIDocShellTreeItem::typeChrome;
00702   }
00703 
00704   // No treeItem: don't reuse the current inner window.
00705   return PR_FALSE;
00706 }
00707 
00708 void
00709 nsGlobalWindow::SetOpenerScriptURL(nsIURI* aURI)
00710 {
00711 }
00712 
00713 void
00714 nsGlobalWindow::SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal)
00715 {
00716   FORWARD_TO_OUTER_VOID(SetOpenerScriptPrincipal, (aPrincipal));
00717 
00718   nsCOMPtr<nsIDocument> curDoc(do_QueryInterface(mDocument));
00719   nsCOMPtr<nsIDocument_MOZILLA_1_8_BRANCH2> curDoc_MOZILLA_1_8_BRANCH2 =
00720     do_QueryInterface(mDocument);
00721   if (curDoc && curDoc_MOZILLA_1_8_BRANCH2) {
00722     if (!curDoc_MOZILLA_1_8_BRANCH2->IsInitialDocument()) {
00723       // We have a document already, and it's not the original one.  Bail out.
00724       // Do NOT set mOpenerScriptPrincipal in this case, just to be safe.
00725       return;
00726     }
00727     
00728 #ifdef DEBUG
00729     // We better have an about:blank document loaded at this point.  Otherwise,
00730     // something is really weird.
00731     if (curDoc->GetPrincipal()) {
00732       nsCOMPtr<nsIURI> uri;
00733       curDoc->GetPrincipal()->GetURI(getter_AddRefs(uri));
00734       NS_ASSERTION(uri && IsAboutBlank(uri) &&
00735                    IsAboutBlank(curDoc->GetDocumentURI()),
00736                    "Unexpected original document");
00737     }
00738 #endif
00739     
00740     // Set the opener principal on our document; given the above check, this
00741     // is safe.
00742     curDoc->SetPrincipal(aPrincipal);
00743   }
00744 
00745   mOpenerScriptPrincipal = aPrincipal;
00746 }
00747 
00748 nsIPrincipal*
00749 nsGlobalWindow::GetOpenerScriptPrincipal()
00750 {
00751   FORWARD_TO_OUTER(GetOpenerScriptPrincipal, (), nsnull);
00752 
00753   return mOpenerScriptPrincipal;
00754 }
00755 
00756 PopupControlState
00757 PushPopupControlState(PopupControlState aState, PRBool aForce)
00758 {
00759   PopupControlState oldState = gPopupControlState;
00760 
00761   if (aState < gPopupControlState || aForce) {
00762     gPopupControlState = aState;
00763   }
00764 
00765   return oldState;
00766 }
00767 
00768 void
00769 PopPopupControlState(PopupControlState aState)
00770 {
00771   gPopupControlState = aState;
00772 }
00773 
00774 PopupControlState
00775 nsGlobalWindow::PushPopupControlState(PopupControlState aState,
00776                                       PRBool aForce) const
00777 {
00778   return ::PushPopupControlState(aState, aForce);
00779 }
00780 
00781 void
00782 nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
00783 {
00784   ::PopPopupControlState(aState);
00785 }
00786 
00787 PopupControlState
00788 nsGlobalWindow::GetPopupControlState() const
00789 {
00790   return gPopupControlState;
00791 }
00792 
00793 #define WINDOWSTATEHOLDER_IID \
00794 {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
00795 
00796 class WindowStateHolder : public nsISupports
00797 {
00798 public:
00799   NS_DEFINE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
00800   NS_DECL_ISUPPORTS
00801 
00802   WindowStateHolder(nsGlobalWindow *aWindow,
00803                     nsIXPConnectJSObjectHolder *aHolder,
00804                     nsNavigator *aNavigator,
00805                     nsLocation *aLocation,
00806                     nsIXPConnectJSObjectHolder *aOuterProto);
00807 
00808   // Get the contents of focus memory when the state was saved
00809   // (if the focus was inside of this window).
00810   nsIDOMElement* GetFocusedElement() { return mFocusedElement; }
00811   nsIDOMWindowInternal* GetFocusedWindow() { return mFocusedWindow; }
00812 
00813   nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
00814   nsIXPConnectJSObjectHolder* GetInnerWindowHolder()
00815   { return mInnerWindowHolder; }
00816 
00817   nsNavigator* GetNavigator() { return mNavigator; }
00818   nsLocation* GetLocation() { return mLocation; }
00819   nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
00820 
00821   void DidRestoreWindow()
00822   {
00823     mInnerWindow = nsnull;
00824     mInnerWindowHolder = nsnull;
00825     mNavigator = nsnull;
00826     mLocation = nsnull;
00827     mOuterProto = nsnull;
00828   }
00829 
00830 protected:
00831   ~WindowStateHolder();
00832 
00833   nsGlobalWindow *mInnerWindow;
00834   // We hold onto this to make sure the inner window doesn't go away. The outer
00835   // window ends up recalculating it anyway.
00836   nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
00837   nsRefPtr<nsNavigator> mNavigator;
00838   nsRefPtr<nsLocation> mLocation;
00839   nsCOMPtr<nsIDOMElement> mFocusedElement;
00840   nsCOMPtr<nsIDOMWindowInternal> mFocusedWindow;
00841   nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
00842 };
00843 
00844 WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
00845                                      nsIXPConnectJSObjectHolder *aHolder,
00846                                      nsNavigator *aNavigator,
00847                                      nsLocation *aLocation,
00848                                      nsIXPConnectJSObjectHolder *aOuterProto)
00849   : mInnerWindow(aWindow),
00850     mInnerWindowHolder(aHolder),
00851     mNavigator(aNavigator),
00852     mLocation(aLocation),
00853     mOuterProto(aOuterProto)
00854 {
00855   NS_PRECONDITION(aWindow, "null window");
00856   NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
00857 
00858   nsIFocusController *fc = aWindow->GetRootFocusController();
00859   NS_ASSERTION(fc, "null focus controller");
00860 
00861   // We want to save the focused element/window only if they are inside of
00862   // this window.
00863 
00864   nsCOMPtr<nsIDOMWindowInternal> focusWinInternal;
00865   fc->GetFocusedWindow(getter_AddRefs(focusWinInternal));
00866 
00867   nsCOMPtr<nsPIDOMWindow> focusedWindow = do_QueryInterface(focusWinInternal);
00868 
00869   // The outer window is used for focus purposes, so make sure that's what
00870   // we're looking for.
00871   nsPIDOMWindow *targetWindow = aWindow->GetOuterWindow();
00872 
00873   while (focusedWindow) {
00874     if (focusedWindow == targetWindow) {
00875       fc->GetFocusedWindow(getter_AddRefs(mFocusedWindow));
00876       fc->GetFocusedElement(getter_AddRefs(mFocusedElement));
00877       break;
00878     }
00879 
00880     focusedWindow =
00881       NS_STATIC_CAST(nsGlobalWindow*,
00882                      NS_STATIC_CAST(nsPIDOMWindow*,
00883                                     focusedWindow))->GetPrivateParent();
00884   }
00885 
00886   aWindow->SuspendTimeouts();
00887 }
00888 
00889 WindowStateHolder::~WindowStateHolder()
00890 {
00891   if (mInnerWindow) {
00892     // This window was left in the bfcache and is now going away. We need to
00893     // free it up.
00894     nsCOMPtr<nsIThreadJSContextStack> stack(do_GetService(sJSStackContractID));
00895     JSContext *cx = nsnull;
00896 
00897     if (stack)
00898       stack->GetSafeJSContext(&cx);
00899 
00900     if (!cx) {
00901       NS_WARNING("Trusting GC to finish cleaning up this inner window");
00902       return;
00903     }
00904 
00905     mInnerWindow->FreeInnerObjects(cx);
00906   }
00907 }
00908 
00909 NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder)
00910 
00911 nsresult
00912 nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
00913                                nsISupports* aState,
00914                                PRBool aRemoveEventListeners,
00915                                PRBool aClearScopeHint)
00916 {
00917   return SetNewDocument(aDocument, aState, aRemoveEventListeners,
00918                         aClearScopeHint, PR_FALSE);
00919 }
00920 
00921 nsresult
00922 nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
00923                                nsISupports* aState,
00924                                PRBool aRemoveEventListeners,
00925                                PRBool aClearScopeHint,
00926                                PRBool aIsInternalCall)
00927 {
00928   NS_WARN_IF_FALSE(mDocumentPrincipal == nsnull,
00929                    "mDocumentPrincipal prematurely set!");
00930 #ifdef PR_LOGGING
00931   if (IsInnerWindow() && aDocument && gDOMLeakPRLog &&
00932       PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
00933     nsCOMPtr<nsIDocument> newDoc(do_QueryInterface(aDocument));
00934     nsIURI *uri = nsnull;
00935     if (newDoc)
00936       uri = newDoc->GetDocumentURI();
00937     nsCAutoString spec;
00938     if (uri)
00939       uri->GetSpec(spec);
00940     PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
00941   }
00942 #endif
00943 
00944   if (IsOuterWindow() && IsFrozen()) {
00945     // This outer is now getting its first inner, thaw the outer now
00946     // that it's ready and is getting an inner window.
00947 
00948     Thaw();
00949   }
00950 
00951   if (!aIsInternalCall && IsInnerWindow()) {
00952     if (!mOuterWindow) {
00953       return NS_ERROR_NOT_INITIALIZED;
00954     }
00955 
00956     return GetOuterWindowInternal()->SetNewDocument(aDocument,
00957                                                     aState,
00958                                                     aRemoveEventListeners,
00959                                                     aClearScopeHint, PR_TRUE);
00960   }
00961 
00962   if (!aDocument) {
00963     NS_ERROR("SetNewDocument(null) called!");
00964 
00965     return NS_ERROR_INVALID_ARG;
00966   }
00967 
00968   NS_ASSERTION(!GetCurrentInnerWindow() ||
00969                GetCurrentInnerWindow()->GetExtantDocument() == mDocument,
00970                "Uh, mDocument doesn't match the current inner window "
00971                "document!");
00972 
00973   nsCOMPtr<nsIDocument> newDoc(do_QueryInterface(aDocument));
00974   NS_ENSURE_TRUE(newDoc, NS_ERROR_FAILURE);
00975 
00976   nsresult rv = NS_OK;
00977 
00978   nsCOMPtr<nsIDocument> oldDoc(do_QueryInterface(mDocument));
00979 
00980   // Always clear watchpoints, to deal with two cases:
00981   // 1.  The first document for this window is loading, and a miscreant has
00982   //     preset watchpoints on the window object in order to attack the new
00983   //     document's privileged information.
00984   // 2.  A document loaded and used watchpoints on its own window, leaving
00985   //     them set until the next document loads. We must clean up window
00986   //     watchpoints here.
00987   // Watchpoints set on document and subordinate objects are all cleared
00988   // when those sub-window objects are finalized, after JS_ClearScope and
00989   // a GC run that finds them to be garbage.
00990 
00991   // XXXjst: Update above comment.
00992   nsIScriptContext *scx = GetContextInternal();
00993   NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
00994 
00995   JSContext *cx = (JSContext *)scx->GetNativeContext();
00996 
00997   // clear smartcard events, our document has gone away.
00998   if (mCrypto) {
00999     mCrypto->SetEnableSmartCardEvents(PR_FALSE);
01000   }
01001 
01002   if (!mDocument) {
01003     // First document load.
01004 
01005     // Get our private root. If it is equal to us, then we need to
01006     // attach our global key bindings that handle browser scrolling
01007     // and other browser commands.
01008     nsIDOMWindowInternal *internal = nsGlobalWindow::GetPrivateRoot();
01009 
01010     if (internal == NS_STATIC_CAST(nsIDOMWindowInternal *, this)) {
01011       nsCOMPtr<nsIXBLService> xblService = do_GetService("@mozilla.org/xbl;1");
01012       if (xblService) {
01013         nsCOMPtr<nsIDOMEventReceiver> rec =
01014           do_QueryInterface(mChromeEventHandler);
01015         xblService->AttachGlobalKeyHandler(rec);
01016 
01017         // for now, the only way to get drag/drop is to use the XUL
01018         // wrapper. There are just too many things that need to be
01019         // added to hookup DnD with XBL (pinkerton)
01020         //xblService->AttachGlobalDragHandler(rec);
01021       }
01022     }
01023   }
01024 
01025   /* No mDocShell means we're either an inner window or we're already
01026      been partially closed down.  When that happens, setting status
01027      isn't a big requirement, so don't. (Doesn't happen under normal
01028      circumstances, but bug 49615 describes a case.) */
01029 
01030   SetStatus(EmptyString());
01031   SetDefaultStatus(EmptyString());
01032 
01033   // This code should not be called during shutdown any more (now that
01034   // we don't ever call SetNewDocument(nsnull), so no need to null
01035   // check xpc here.
01036   nsIXPConnect *xpc = nsContentUtils::XPConnect();
01037 
01038   PRBool reUseInnerWindow = WouldReuseInnerWindow(newDoc);
01039 
01040   // XXX We used to share event listeners between inner windows in special
01041   // circumstances (that were remarkably close to the conditions that we set
01042   // reUseInnerWindow in) but that left dangling pointers to the old (destroyed)
01043   // inner window (bug 303765). Setting this here should be a no-op.
01044   aRemoveEventListeners = !reUseInnerWindow;
01045 
01046   // Remember the old document's principal.
01047   nsIPrincipal *oldPrincipal = nsnull;
01048 
01049   if (oldDoc) {
01050     oldPrincipal = oldDoc->GetPrincipal();
01051   }
01052 
01053   // Drop our reference to the navigator object unless we're reusing
01054   // the existing inner window or the new document is from the same
01055   // origin as the old document.
01056   if (!reUseInnerWindow && mNavigator && oldPrincipal) {
01057     nsIPrincipal *newPrincipal = newDoc->GetPrincipal();
01058     rv = NS_ERROR_FAILURE;
01059 
01060     if (newPrincipal) {
01061       rv = sSecMan->CheckSameOriginPrincipal(oldPrincipal, newPrincipal);
01062     }
01063 
01064     if (NS_FAILED(rv)) {
01065       // Different origins.  Release the navigator object so it gets
01066       // recreated for the new document.  The plugins or mime types
01067       // arrays may have changed. See bug 150087.
01068       mNavigator->SetDocShell(nsnull);
01069 
01070       mNavigator = nsnull;
01071     }
01072   }
01073 
01074   if (mNavigator && newDoc != oldDoc) {
01075     // We didn't drop our reference to our old navigator object and
01076     // we're loading a new document. Notify the navigator object about
01077     // the new document load so that it can make sure it is ready for
01078     // the new document.
01079 
01080     mNavigator->LoadingNewDocument();
01081   }
01082 
01083   // Set mDocument even if this is an outer window to avoid
01084   // having to *always* reach into the inner window to find the
01085   // document.
01086 
01087   mDocument = aDocument;
01088 
01089   if (IsOuterWindow()) {
01090     scx->WillInitializeContext();
01091 
01092     nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
01093 
01094     if (currentInner && !currentInner->IsFrozen()) {
01095       if (!reUseInnerWindow) {
01096         currentInner->ClearAllTimeouts();
01097 
01098         currentInner->mChromeEventHandler = nsnull;
01099       }
01100 
01101       if (aRemoveEventListeners && currentInner->mListenerManager) {
01102         currentInner->mListenerManager->Disconnect();
01103         currentInner->mListenerManager = nsnull;
01104       }
01105 
01106       if (!reUseInnerWindow || newDoc != oldDoc) {
01107         nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
01108       }
01109     }
01110 
01111     nsRefPtr<nsGlobalWindow> newInnerWindow;
01112 
01113     nsCOMPtr<nsIDOMChromeWindow> thisChrome =
01114       do_QueryInterface(NS_STATIC_CAST(nsIDOMWindow *, this));
01115     nsCOMPtr<nsIXPConnectJSObjectHolder> navigatorHolder;
01116 
01117     PRUint32 flags = 0;
01118 
01119     // Make sure to clear scope on the outer window *before* we
01120     // initialize the new inner window. If we don't, things
01121     // (Object.prototype etc) could leak from the old outer to the new
01122     // inner scope.
01123     ::JS_ClearScope(cx, mJSObject);
01124     ::JS_ClearWatchPointsForObject(cx, mJSObject);
01125 
01126     // Clear the regexp statics for the new page unconditionally.
01127     // XXX They don't get restored on the inner window when we go back.
01128     ::JS_ClearRegExpStatics(cx);
01129 
01130     if (reUseInnerWindow) {
01131       // We're reusing the current inner window.
01132       NS_ASSERTION(!currentInner->IsFrozen(),
01133                    "We should never be reusing a shared inner window");
01134       newInnerWindow = currentInner;
01135     } else {
01136       if (aState) {
01137         nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
01138         NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
01139 
01140         newInnerWindow = wsh->GetInnerWindow();
01141         mInnerWindowHolder = wsh->GetInnerWindowHolder();
01142 
01143         // These assignments addref.
01144         mNavigator = wsh->GetNavigator();
01145         mLocation = wsh->GetLocation();
01146 
01147         if (mNavigator) {
01148           // Update mNavigator's docshell pointer now.
01149           mNavigator->SetDocShell(mDocShell);
01150           mNavigator->LoadingNewDocument();
01151         }
01152       } else {
01153         if (thisChrome) {
01154           newInnerWindow = new nsGlobalChromeWindow(this);
01155 
01156           flags = nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT;
01157         } else {
01158           newInnerWindow = new nsGlobalWindow(this);
01159         }
01160 
01161         if (newInnerWindow) {
01162           nsCOMPtr<nsIObserverService> observerService =
01163             do_GetService("@mozilla.org/observer-service;1", &rv);
01164           NS_ENSURE_SUCCESS(rv, rv);
01165 
01166           observerService->AddObserver(newInnerWindow, "dom-storage-changed",
01167                                        PR_TRUE);
01168         }
01169 
01170         mLocation = nsnull;
01171       }
01172 
01173       if (!newInnerWindow) {
01174         return NS_ERROR_OUT_OF_MEMORY;
01175       }
01176 
01177       if (!aState) {
01178         // This is redundant if we're restoring from a previous inner window.
01179         nsIScriptGlobalObject *sgo =
01180           (nsIScriptGlobalObject *)newInnerWindow.get();
01181 
01182         // Freeze the outer window and null out the inner window so
01183         // that initializing classes on the new inner doesn't end up
01184         // reaching into the old inner window for classes etc.
01185         //
01186         // [This happens with Object.prototype when XPConnect creates
01187         // a temporary global while initializing classes; the reason
01188         // being that xpconnect creates the temp global w/o a parent
01189         // and proto, which makes the JS engine look up classes in
01190         // cx->globalObject, i.e. this outer window].
01191 
01192         mInnerWindow = nsnull;
01193 
01194         Freeze();
01195         mCreatingInnerWindow = PR_TRUE;
01196         rv = xpc->
01197           InitClassesWithNewWrappedGlobal(cx, sgo, NS_GET_IID(nsISupports),
01198                                           flags,
01199                                           getter_AddRefs(mInnerWindowHolder));
01200         mCreatingInnerWindow = PR_FALSE;
01201         Thaw();
01202 
01203         NS_ENSURE_SUCCESS(rv, rv);
01204 
01205         mInnerWindowHolder->GetJSObject(&newInnerWindow->mJSObject);
01206       }
01207 
01208       if (currentInner && currentInner->mJSObject) {
01209         if (mNavigator && !aState) {
01210           // Hold on to the navigator wrapper so that we can set
01211           // window.navigator in the new window to point to the same
01212           // object (assuming we didn't change origins etc). See bug
01213           // 163645 for more on why we need this.
01214 
01215           nsIDOMNavigator* navigator =
01216             NS_STATIC_CAST(nsIDOMNavigator*, mNavigator.get());
01217           xpc->WrapNative(cx, currentInner->mJSObject, navigator,
01218                           NS_GET_IID(nsIDOMNavigator),
01219                           getter_AddRefs(navigatorHolder));
01220         }
01221 
01222         PRBool termFuncSet = PR_FALSE;
01223 
01224         if (oldDoc == newDoc) {
01225           nsCOMPtr<nsIJSContextStack> stack =
01226             do_GetService(sJSStackContractID);
01227 
01228           JSContext *cx = nsnull;
01229 
01230           if (stack) {
01231             stack->Peek(&cx);
01232           }
01233 
01234           nsIScriptContext *callerScx;
01235           if (cx && (callerScx = GetScriptContextFromJSContext(cx))) {
01236             // We're called from document.open() (and document.open() is
01237             // called from JS), clear the scope etc in a termination
01238             // function on the calling context to prevent clearing the
01239             // calling scope.
01240             NS_ASSERTION(!currentInner->IsFrozen(),
01241                 "How does this opened window get into session history");
01242             callerScx->SetTerminationFunction(ClearWindowScope,
01243                                               NS_STATIC_CAST(nsIDOMWindow *,
01244                                                              currentInner));
01245 
01246             termFuncSet = PR_TRUE;
01247           }
01248         }
01249 
01250         // Don't clear scope on our current inner window if it's going to be
01251         // held in the bfcache.
01252         if (!currentInner->IsFrozen()) {
01253           if (!termFuncSet) {
01254             // Clear currentInner->mJSObject and its prototype chain,
01255             // but not Object.prototype.
01256             ::JS_ClearScope(cx, currentInner->mJSObject);
01257             for (JSObject *o = ::JS_GetPrototype(cx, currentInner->mJSObject), *next;
01258                  o && (next = ::JS_GetPrototype(cx, o)); o = next)
01259               ::JS_ClearScope(cx, o);
01260             ::JS_ClearWatchPointsForObject(cx, currentInner->mJSObject);
01261           }
01262 
01263           // Make the current inner window release its strong references
01264           // to the document to prevent it from keeping everything
01265           // around. But remember the document's principal.
01266           currentInner->mDocument = nsnull;
01267           currentInner->mDocumentPrincipal = oldPrincipal;
01268         }
01269       }
01270 
01271       mInnerWindow = newInnerWindow;
01272     }
01273 
01274     if (!aState && !reUseInnerWindow) {
01275       // Loading a new page and creating a new inner window, *not*
01276       // restoring from session history.
01277 
01278       // InitClassesWithNewWrappedGlobal() for the new inner window
01279       // sets the global object in cx to be the new wrapped global. We
01280       // don't want that, but re-initializing the outer window will
01281       // fix that for us. And perhaps more importantly, this will
01282       // ensure that the outer window gets a new prototype so we don't
01283       // leak prototype properties from the old inner window to the
01284       // new one.
01285 
01286       scx->InitContext(this);
01287 
01288       // *Don't* call JS_ClearScope here since it's unnecessary
01289       // and it confuses the JS engine as to which Function is
01290       // on which window. See bug 343966.
01291 
01292       // Make the inner and outer window both share the same
01293       // prototype. The prototype we share is the outer window's
01294       // prototype, this way XPConnect can still find the wrapper to
01295       // use when making a call like alert() (w/o qualifying it with
01296       // "window."). XPConnect looks up the wrapper based on the
01297       // function object's parent, which is the object the function
01298       // was called on, and when calling alert() we'll be calling the
01299       // alert() function from the outer window's prototype off of the
01300       // inner window. In this case XPConnect is able to find the
01301       // outer (through the JSExtendedClass hook outerObject), so this
01302       // prototype sharing works.
01303 
01304       // We do *not* want to use anything else out of the outer
01305       // object's prototype chain than the first prototype, which is
01306       // the XPConnect prototype. The rest we want from the inner
01307       // window's prototype, i.e. the global scope polluter and
01308       // Object.prototype. This way the outer also gets the benefits
01309       // of the global scope polluter, and the inner window's
01310       // Object.prototype.
01311       JSObject *proto = ::JS_GetPrototype(cx, mJSObject);
01312       JSObject *innerProto = ::JS_GetPrototype(cx, newInnerWindow->mJSObject);
01313       JSObject *innerProtoProto = ::JS_GetPrototype(cx, innerProto);
01314 
01315       ::JS_SetPrototype(cx, newInnerWindow->mJSObject, proto);
01316       ::JS_SetPrototype(cx, proto, innerProtoProto);
01317     }
01318 
01319     // Now that the prototype is all set up, install the global scope
01320     // polluter. This must happen after the above prototype fixup. If
01321     // the GSP was to be installed on the inner window's real
01322     // prototype (as it would be if this was done before the prototype
01323     // fixup above) we would end up holding the GSP alive (through
01324     // XPConnect's internal marking of wrapper prototypes) as long as
01325     // the inner window was around, and if the GSP had properties on
01326     // it that held an element alive we'd hold the document alive,
01327     // which could hold event handlers alive, which hold the context
01328     // alive etc.
01329 
01330     if ((!reUseInnerWindow || newDoc != oldDoc) && !aState) {
01331       nsCOMPtr<nsIHTMLDocument> html_doc(do_QueryInterface(mDocument));
01332       nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject,
01333                                              html_doc);
01334     }
01335 
01336     if (aState) {
01337       // Restoring from session history.
01338 
01339       nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
01340       NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
01341 
01342       // Restore the prototype for the Window/ChromeWindow class in
01343       // the outer window scope.
01344       nsCOMPtr<nsIClassInfo> ci =
01345         do_QueryInterface((nsIScriptGlobalObject *)this);
01346 
01347       rv = xpc->RestoreWrappedNativePrototype(cx, mJSObject, ci,
01348                                               wsh->GetOuterProto());
01349       NS_ENSURE_SUCCESS(rv, rv);
01350 
01351       // Refresh the outer window's prototype to what it was when the
01352       // window state was saved. This will make the outer window
01353       // object (and wrapper) pick up the prototype it had when the
01354       // window state was saved. This means Object.prototype etc from
01355       // the old inner will again be on the outer window's prototype
01356       // chain.
01357 
01358       nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
01359       rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
01360                                            getter_AddRefs(wrapper));
01361       NS_ENSURE_SUCCESS(rv, rv);
01362 
01363       rv = wrapper->RefreshPrototype();
01364       NS_ENSURE_SUCCESS(rv, rv);
01365     }
01366 
01367     if (newDoc) {
01368       newDoc->SetScriptGlobalObject(newInnerWindow);
01369     }
01370 
01371     if (!aState) {
01372       if (reUseInnerWindow) {
01373         if (newInnerWindow->mDocument != aDocument) {
01374           newInnerWindow->mDocument = aDocument;
01375 
01376           // We're reusing the inner window for a new document. In this
01377           // case we don't clear the inner window's scope, but we must
01378           // make sure the cached document property gets updated.
01379 
01380           ::JS_DeleteProperty(cx, currentInner->mJSObject, "document");
01381         }
01382       } else {
01383         rv = newInnerWindow->SetNewDocument(aDocument, nsnull,
01384                                             aRemoveEventListeners,
01385                                             aClearScopeHint, PR_TRUE);
01386         NS_ENSURE_SUCCESS(rv, rv);
01387 
01388         // Initialize DOM classes etc on the inner window.
01389         rv = scx->InitClasses(newInnerWindow->mJSObject);
01390         NS_ENSURE_SUCCESS(rv, rv);
01391 
01392         if (navigatorHolder) {
01393           // Restore window.navigator onto the new inner window.
01394           JSObject *nav;
01395           navigatorHolder->GetJSObject(&nav);
01396 
01397           ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator",
01398                               OBJECT_TO_JSVAL(nav), nsnull, nsnull,
01399                               JSPROP_ENUMERATE);
01400         }
01401       }
01402 
01403       if (mArguments) {
01404         jsval args = OBJECT_TO_JSVAL(mArguments);
01405 
01406         ::JS_SetProperty(cx, newInnerWindow->mJSObject, "arguments",
01407                          &args);
01408 
01409         ::JS_UnlockGCThing(cx, mArguments);
01410         mArguments = nsnull;
01411       }
01412 
01413       // Give the new inner window our chrome event handler (since it
01414       // doesn't have one).
01415       newInnerWindow->mChromeEventHandler = mChromeEventHandler;
01416     }
01417 
01418     // Add an extra ref in case we release mContext during GC.
01419     nsCOMPtr<nsIScriptContext> kungFuDeathGrip = scx;
01420     scx->GC();
01421 
01422     scx->DidInitializeContext();
01423   }
01424 
01425   // Clear our mutation bitfield.
01426   mMutationBits = 0;
01427 
01428   return NS_OK;
01429 }
01430 
01431 void
01432 nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
01433 {
01434   NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
01435 
01436   if (aDocShell == mDocShell)
01437     return;
01438 
01439   // SetDocShell(nsnull) means the window is being torn down. Drop our
01440   // reference to the script context, allowing it to be deleted
01441   // later. Meanwhile, keep our weak reference to the script object
01442   // (mJSObject) so that it can be retrieved later (until it is
01443   // finalized by the JS GC).
01444 
01445   if (!aDocShell && mContext) {
01446     NS_ASSERTION(!mTimeouts, "Uh, outer window holds timeouts!");
01447 
01448     JSContext *cx = (JSContext *)mContext->GetNativeContext();
01449     // Call FreeInnerObjects on all inner windows, not just the current
01450     // one, since some could be held by WindowStateHolder objects that
01451     // are GC-owned.
01452     for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
01453          inner != this;
01454          inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
01455       NS_ASSERTION(inner->mOuterWindow == this, "bad outer window pointer");
01456       inner->FreeInnerObjects(cx);
01457     }
01458 
01459     nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
01460 
01461     if (currentInner) {
01462       nsCOMPtr<nsIDocument> doc =
01463         do_QueryInterface(mDocument);
01464 
01465       // Remember the document's principal.
01466       mDocumentPrincipal = doc->GetPrincipal();
01467 
01468       // Release our document reference
01469       mDocument = nsnull;
01470 
01471       if (mJSObject) {
01472         // Clear mJSObject and its prototype chain, but not Object.prototype.
01473         ::JS_ClearScope(cx, mJSObject);
01474         for (JSObject *o = ::JS_GetPrototype(cx, mJSObject), *next;
01475              o && (next = ::JS_GetPrototype(cx, o)); o = next)
01476           ::JS_ClearScope(cx, o);
01477         ::JS_ClearWatchPointsForObject(cx, mJSObject);
01478 
01479         // An outer window shouldn't have a global scope polluter, but
01480         // in case code on a webpage took one and put it in an outer
01481         // object's prototype, we need to invalidate it nonetheless.
01482         nsWindowSH::InvalidateGlobalScopePolluter(cx, mJSObject);
01483       }
01484 
01485       ::JS_ClearRegExpStatics(cx);
01486     }
01487 
01488     // if we are closing the window while in full screen mode, be sure
01489     // to restore os chrome
01490     if (mFullScreen) {
01491       nsIFocusController *focusController =
01492         nsGlobalWindow::GetRootFocusController();
01493       PRBool isActive = PR_FALSE;
01494       if (focusController)
01495         focusController->GetActive(&isActive);
01496       // only restore OS chrome if the closing window was active
01497 
01498       if (isActive) {
01499         nsCOMPtr<nsIFullScreen> fullScreen =
01500           do_GetService("@mozilla.org/browser/fullscreen;1");
01501 
01502         if (fullScreen)
01503           fullScreen->ShowAllOSChrome();
01504       }
01505     }
01506 
01507     ClearControllers();
01508 
01509     mChromeEventHandler = nsnull; // force release now
01510 
01511     if (mArguments) { 
01512       // We got no new document after someone called
01513       // SetNewArguments(), drop our reference to the arguments.
01514       ::JS_UnlockGCThing(cx, mArguments);
01515       mArguments = nsnull;
01516     }
01517 
01518     mInnerWindowHolder = nsnull;
01519 
01520     mContext->GC();
01521 
01522     if (mContext) {
01523       mContext->SetOwner(nsnull);
01524       mContext = nsnull;          // force release now
01525     }
01526   }
01527 
01528   mDocShell = aDocShell;        // Weak Reference
01529 
01530   if (mNavigator)
01531     mNavigator->SetDocShell(aDocShell);
01532   if (mLocation)
01533     mLocation->SetDocShell(aDocShell);
01534   if (mHistory)
01535     mHistory->SetDocShell(aDocShell);
01536   if (mFrames)
01537     mFrames->SetDocShell(aDocShell);
01538   if (mScreen)
01539     mScreen->SetDocShell(aDocShell);
01540 
01541   if (mDocShell) {
01542     // tell our member elements about the new browserwindow
01543     if (mMenubar) {
01544       nsCOMPtr<nsIWebBrowserChrome> browserChrome;
01545       GetWebBrowserChrome(getter_AddRefs(browserChrome));
01546       mMenubar->SetWebBrowserChrome(browserChrome);
01547     }
01548 
01549     // Get our enclosing chrome shell and retrieve its global window impl, so
01550     // that we can do some forwarding to the chrome document.
01551     mDocShell->GetChromeEventHandler(getter_AddRefs(mChromeEventHandler));
01552     if (!mChromeEventHandler) {
01553       // We have no chrome event handler. If we have a parent,
01554       // get our chrome event handler from the parent. If
01555       // we don't have a parent, then we need to make a new
01556       // window root object that will function as a chrome event
01557       // handler and receive all events that occur anywhere inside
01558       // our window.
01559       nsCOMPtr<nsIDOMWindow> parentWindow;
01560       GetParent(getter_AddRefs(parentWindow));
01561       if (parentWindow.get() != NS_STATIC_CAST(nsIDOMWindow*,this)) {
01562         nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
01563         mChromeEventHandler = piWindow->GetChromeEventHandler();
01564       }
01565       else NS_NewWindowRoot(this, getter_AddRefs(mChromeEventHandler));
01566     }
01567   }
01568 }
01569 
01570 nsIDocShell *
01571 nsGlobalWindow::GetDocShell()
01572 {
01573   return GetDocShellInternal();
01574 }
01575 
01576 void
01577 nsGlobalWindow::SetOpenerWindow(nsIDOMWindowInternal* aOpener)
01578 {
01579   SetOpenerWindow(aOpener, PR_TRUE);
01580 }
01581 
01582 void
01583 nsGlobalWindow::SetOpenerWindow(nsIDOMWindowInternal* aOpener,
01584                                 PRBool aOriginalOpener)
01585 {
01586   FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
01587 
01588   NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
01589                "aOriginalOpener is true, but not first call to "
01590                "SetOpenerWindow!");
01591  
01592   mOpener = aOpener;
01593   if (aOriginalOpener) {
01594     mHadOriginalOpener = PR_TRUE;
01595   }
01596 
01597 #ifdef DEBUG
01598   mSetOpenerWindowCalled = PR_TRUE;
01599 #endif
01600 }
01601 
01602 void
01603 nsGlobalWindow::SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner)
01604 {
01605   FORWARD_TO_OUTER_VOID(SetGlobalObjectOwner, (aOwner));
01606 
01607   mGlobalObjectOwner = aOwner;  // Note this is supposed to be a weak ref.
01608 }
01609 
01610 nsIScriptGlobalObjectOwner *
01611 nsGlobalWindow::GetGlobalObjectOwner()
01612 {
01613   FORWARD_TO_OUTER(GetGlobalObjectOwner, (), nsnull);
01614 
01615   return mGlobalObjectOwner;
01616 }
01617 
01618 nsresult
01619 nsGlobalWindow::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent,
01620                                nsIDOMEvent** aDOMEvent, PRUint32 aFlags,
01621                                nsEventStatus* aEventStatus)
01622 {
01623   FORWARD_TO_INNER(HandleDOMEvent,
01624                    (aPresContext, aEvent, aDOMEvent, aFlags, aEventStatus),
01625                    NS_OK);
01626 
01627   nsGlobalWindow *outer = GetOuterWindowInternal();
01628 
01629   // Make sure to tell the event that dispatch has started.
01630   NS_MARK_EVENT_DISPATCH_STARTED(aEvent);
01631 
01632   nsresult ret = NS_OK;
01633   PRBool externalDOMEvent = PR_FALSE;
01634   nsIDOMEvent *domEvent = nsnull;
01635   static PRUint32 count = 0;
01636 
01637   /* mChromeEventHandler and mContext go dangling in the middle of this
01638      function under some circumstances (events that destroy the window)
01639      without this addref. */
01640   nsCOMPtr<nsIChromeEventHandler> kungFuDeathGrip1(mChromeEventHandler);
01641   nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
01642 
01643   /* If this is a mouse event, use the struct to provide entropy for
01644    * the system.
01645    */
01646   if (gEntropyCollector &&
01647       (NS_EVENT_FLAG_CAPTURE & aFlags) &&
01648       (aEvent->message == NS_MOUSE_MOVE)) {
01649     //I'd like to not come in here if there is a mChromeEventHandler
01650     //present, but there is always one when the message is
01651     //NS_MOUSE_MOVE.
01652     //
01653     //Chances are this counter will overflow during the life of the
01654     //process, but that's OK for our case. Means we get a little
01655     //more entropy.
01656     if (count++ % 100 == 0) {
01657       //Since the high bits seem to be zero's most of the time,
01658       //let's only take the lowest half of the point structure.
01659       PRInt16 myCoord[4];
01660 
01661       myCoord[0] = aEvent->point.x;
01662       myCoord[1] = aEvent->point.y;
01663       myCoord[2] = aEvent->refPoint.x;
01664       myCoord[3] = aEvent->refPoint.y;
01665       gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
01666       gEntropyCollector->RandomUpdate((void*)&aEvent->time, sizeof(PRUint32));
01667     }
01668   }
01669 
01670   if (NS_IS_TRUSTED_EVENT(aEvent)) {
01671     if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) {
01672       gMouseDown = PR_TRUE;
01673     } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) {
01674       gMouseDown = PR_FALSE;
01675       if (gDragServiceDisabled) {
01676         nsCOMPtr<nsIDragService_1_8_BRANCH> ds18 =
01677           do_GetService("@mozilla.org/widget/dragservice;1");
01678         NS_WARN_IF_FALSE(ds18, "No drag service?");
01679         if (ds18) {
01680           gDragServiceDisabled = PR_FALSE;
01681           ds18->Unsuppress();
01682         }
01683       }
01684     }
01685   }
01686 
01687   // if the window is deactivated while in full screen mode,
01688   // restore OS chrome, and hide it again upon re-activation
01689   if (outer && outer->mFullScreen && (NS_EVENT_FLAG_BUBBLE & aFlags)) {
01690     if (aEvent->message == NS_DEACTIVATE || aEvent->message == NS_ACTIVATE) {
01691       nsCOMPtr<nsIFullScreen> fullScreen =
01692         do_GetService("@mozilla.org/browser/fullscreen;1");
01693       if (fullScreen) {
01694         if (aEvent->message == NS_DEACTIVATE)
01695           fullScreen->ShowAllOSChrome();
01696         else
01697           fullScreen->HideAllOSChrome();
01698       }
01699     }
01700   }
01701 
01702   if (NS_EVENT_FLAG_INIT & aFlags) {
01703     if (aDOMEvent) {
01704       if (*aDOMEvent) {
01705         externalDOMEvent = PR_TRUE;
01706       }
01707     }
01708     else {
01709       aDOMEvent = &domEvent;
01710     }
01711     aEvent->flags |= aFlags;
01712     aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL);
01713     aFlags |= NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_CAPTURE;
01714 
01715     // Execute bindingdetached handlers before we tear ourselves
01716     // down.
01717     if (aEvent->message == NS_PAGE_UNLOAD && mDocument &&
01718         !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT)) {
01719       nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
01720       doc->BindingManager()->ExecuteDetachedHandlers();
01721     }
01722   }
01723 
01724   if (aEvent->message == NS_PAGE_UNLOAD) {
01725     mIsDocumentLoaded = PR_FALSE;
01726   }
01727 
01728   // Capturing stage
01729   if ((NS_EVENT_FLAG_CAPTURE & aFlags) && mChromeEventHandler) {
01730     // Check chrome document capture here.
01731     // XXX The chrome can not handle this, see bug 51211
01732     if (aEvent->message != NS_IMAGE_LOAD) {
01733       mChromeEventHandler->HandleChromeEvent(aPresContext, aEvent, aDOMEvent,
01734                                              aFlags & NS_EVENT_CAPTURE_MASK,
01735                                              aEventStatus);
01736     }
01737   }
01738 
01739   if (aEvent->message == NS_RESIZE_EVENT) {
01740     mIsHandlingResizeEvent = PR_TRUE;
01741   }
01742 
01743   // Local handling stage
01744   if (outer && (aEvent->message != NS_BLUR_CONTENT || !GetBlurSuppression()) &&
01745       mListenerManager &&
01746       !((NS_EVENT_FLAG_CANT_BUBBLE & aEvent->flags) &&
01747         (NS_EVENT_FLAG_BUBBLE & aFlags) &&
01748         !(NS_EVENT_FLAG_INIT & aFlags))) {
01749     aEvent->flags |= aFlags;
01750     mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent,
01751                                   outer, aFlags, aEventStatus);
01752     aEvent->flags &= ~aFlags;
01753   }
01754 
01755   if (aEvent->message == NS_RESIZE_EVENT) {
01756     mIsHandlingResizeEvent = PR_FALSE;
01757   }
01758 
01759   if (aEvent->message == NS_PAGE_LOAD) {
01760     mIsDocumentLoaded = PR_TRUE;
01761   }
01762 
01763   // Bubbling stage
01764   if ((NS_EVENT_FLAG_BUBBLE & aFlags) && mChromeEventHandler) {
01765     // Bubble to a chrome document if it exists
01766     // XXX Need a way to know if an event should really bubble or not.
01767     // For now filter out load and unload, since they cause problems.
01768     if ((aEvent->message != NS_PAGE_LOAD) &&
01769         (aEvent->message != NS_PAGE_UNLOAD) &&
01770         (aEvent->message != NS_IMAGE_LOAD) &&
01771         (aEvent->message != NS_FOCUS_CONTENT) &&
01772         (aEvent->message != NS_BLUR_CONTENT)) {
01773       mChromeEventHandler->HandleChromeEvent(aPresContext, aEvent,
01774                                              aDOMEvent,
01775                                              aFlags & NS_EVENT_BUBBLE_MASK,
01776                                              aEventStatus);
01777     }
01778   }
01779 
01780   if (aEvent->message == NS_PAGE_LOAD) {
01781     nsCOMPtr<nsIContent> content(do_QueryInterface(GetFrameElementInternal()));
01782 
01783     nsCOMPtr<nsIDocShellTreeItem> treeItem =
01784       do_QueryInterface(GetDocShellInternal());
01785 
01786     PRInt32 itemType = nsIDocShellTreeItem::typeChrome;
01787 
01788     if (treeItem) {
01789       treeItem->GetItemType(&itemType);
01790     }
01791 
01792     if (content && GetParentInternal() &&
01793         itemType != nsIDocShellTreeItem::typeChrome) {
01794       // If we're not in chrome, or at a chrome boundary, fire the
01795       // onload event for the frame element.
01796 
01797       nsEventStatus status = nsEventStatus_eIgnore;
01798       nsEvent event(NS_IS_TRUSTED_EVENT(aEvent), NS_PAGE_LOAD);
01799 
01800       // Most of the time we could get a pres context to pass in here,
01801       // but not always (i.e. if this window is not shown there won't
01802       // be a pres context available). Since we're not firing a GUI
01803       // event we don't need a pres context anyway so we just pass
01804       // null as the pres context all the time here.
01805 
01806       ret = content->HandleDOMEvent(nsnull, &event, nsnull,
01807                                     NS_EVENT_FLAG_INIT, &status);
01808     }
01809   }
01810 
01811   if (NS_EVENT_FLAG_INIT & aFlags) {
01812     // We're leaving the DOM event loop so if we created an event,
01813     // release here.
01814     if (*aDOMEvent && !externalDOMEvent) {
01815       nsrefcnt rc;
01816       NS_RELEASE2(*aDOMEvent, rc);
01817       if (rc) {
01818         // Okay, so someone in the DOM loop (a listener, JS object) still has
01819         // a ref to the DOM Event but the internal data hasn't been malloc'd.
01820         // Force a copy of the data here so the DOM Event is still valid.
01821         nsCOMPtr<nsIPrivateDOMEvent>
01822           privateEvent(do_QueryInterface(*aDOMEvent));
01823         if (privateEvent)
01824           privateEvent->DuplicatePrivateData();
01825       }
01826       aDOMEvent = nsnull;
01827     }
01828 
01829     // Now that we're done with this event, remove the flag that says
01830     // we're in the process of dispatching this event.
01831     NS_MARK_EVENT_DISPATCH_DONE(aEvent);
01832   }
01833 
01834   return ret;
01835 }
01836 
01837 JSObject *
01838 nsGlobalWindow::GetGlobalJSObject()
01839 {
01840   return mJSObject;
01841 }
01842 
01843 void
01844 nsGlobalWindow::OnFinalize(JSObject *aJSObject)
01845 {
01846   if (aJSObject == mJSObject) {
01847     mJSObject = nsnull;
01848   } else if (mJSObject) {
01849     NS_ERROR("Huh? XPConnect created more than one wrapper for this global!");
01850   } else {
01851     NS_WARNING("Weird, we're finalized with a null mJSObject?");
01852   }
01853 }
01854 
01855 void
01856 nsGlobalWindow::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
01857 {
01858   FORWARD_TO_INNER_VOID(SetScriptsEnabled, (aEnabled, aFireTimeouts));
01859 
01860   if (aEnabled && aFireTimeouts) {
01861     // Scripts are enabled (again?) on this context, run timeouts that
01862     // fired on this context while scripts were disabled.
01863 
01864     RunTimeout(nsnull);
01865   }
01866 }
01867 
01868 nsresult
01869 nsGlobalWindow::SetNewArguments(PRUint32 aArgc, void* aArgv)
01870 {
01871   FORWARD_TO_OUTER(SetNewArguments, (aArgc, aArgv), NS_ERROR_NOT_INITIALIZED);
01872 
01873   JSContext *cx;
01874   NS_ENSURE_TRUE(mContext &&
01875                  (cx = (JSContext *)mContext->GetNativeContext()),
01876                  NS_ERROR_NOT_INITIALIZED);
01877 
01878   if (mArguments) {
01879     ::JS_UnlockGCThing(cx, mArguments);
01880     mArguments = nsnull;
01881   }
01882   
01883   if (aArgc == 0) {
01884     return NS_OK;
01885   }
01886 
01887   jsval* argv = NS_STATIC_CAST(jsval*, aArgv);
01888 
01889   NS_ASSERTION(argv, "Must have argv!");
01890 
01891   JSObject *argArray = ::JS_NewArrayObject(cx, aArgc, argv);
01892 
01893   NS_ENSURE_TRUE(argArray, NS_ERROR_OUT_OF_MEMORY);
01894   
01895   // Note that currentInner may be non-null if someone's doing a
01896   // window.open with an existing window name.
01897   nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
01898   
01899   jsval args = OBJECT_TO_JSVAL(argArray);
01900 
01901   // The object newborn keeps argArray alive across this set.
01902   if (currentInner && currentInner->mJSObject) {
01903     if (!::JS_SetProperty(cx, currentInner->mJSObject, "arguments", &args)) {
01904       return NS_ERROR_FAILURE;
01905     }
01906   }
01907 
01908   // Hold on to the arguments so that we can re-set them once the next
01909   // document is loaded.
01910   mArguments = argArray;
01911   ::JS_LockGCThing(cx, mArguments);
01912 
01913   return NS_OK;
01914 }
01915 
01916 //*****************************************************************************
01917 // nsGlobalWindow::nsIScriptObjectPrincipal
01918 //*****************************************************************************
01919 
01920 nsIPrincipal*
01921 nsGlobalWindow::GetPrincipal()
01922 {
01923   if (mDocument) {
01924     // If we have a document, get the principal from the document
01925     nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
01926     NS_ENSURE_TRUE(doc, nsnull);
01927 
01928     return doc->GetPrincipal();
01929   }
01930 
01931   if (mDocumentPrincipal) {
01932     return mDocumentPrincipal;
01933   }
01934 
01935   // If we don't have a principal and we don't have a document we
01936   // ask the parent window for the principal. This can happen when
01937   // loading a frameset that has a <frame src="javascript:xxx">, in
01938   // that case the global window is used in JS before we've loaded
01939   // a document into the window.
01940 
01941   nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
01942     do_QueryInterface(GetParentInternal());
01943 
01944   if (objPrincipal) {
01945     return objPrincipal->GetPrincipal();
01946   }
01947 
01948   return nsnull;
01949 }
01950 
01951 //*****************************************************************************
01952 // nsGlobalWindow::nsIDOMWindow
01953 //*****************************************************************************
01954 
01955 NS_IMETHODIMP
01956 nsGlobalWindow::GetDocument(nsIDOMDocument** aDocument)
01957 {
01958   // This method *should* forward calls to the outer window, but since
01959   // there's nothing here that *depends* on anything in the outer
01960   // (GetDocShellInternal() eliminates that dependency), we won't do
01961   // that to avoid the extra virtual function call.
01962 
01963   // lazily instantiate an about:blank document if necessary, and if
01964   // we have what it takes to do so. Note that domdoc here is the same
01965   // thing as our mDocument, but we don't have to explicitly set the
01966   // member variable because the docshell has already called
01967   // SetNewDocument().
01968   nsIDocShell *docShell;
01969   if (!mDocument && (docShell = GetDocShellInternal()))
01970     nsCOMPtr<nsIDOMDocument> domdoc(do_GetInterface(docShell));
01971 
01972   NS_IF_ADDREF(*aDocument = mDocument);
01973 
01974   return NS_OK;
01975 }
01976 
01977 //*****************************************************************************
01978 // nsGlobalWindow::nsIDOMWindowInternal
01979 //*****************************************************************************
01980 
01981 NS_IMETHODIMP
01982 nsGlobalWindow::GetWindow(nsIDOMWindowInternal** aWindow)
01983 {
01984   FORWARD_TO_OUTER(GetWindow, (aWindow), NS_ERROR_NOT_INITIALIZED);
01985 
01986   *aWindow = NS_STATIC_CAST(nsIDOMWindowInternal *, this);
01987   NS_ADDREF(*aWindow);
01988   return NS_OK;
01989 }
01990 
01991 NS_IMETHODIMP
01992 nsGlobalWindow::GetSelf(nsIDOMWindowInternal** aWindow)
01993 {
01994   FORWARD_TO_OUTER(GetSelf, (aWindow), NS_ERROR_NOT_INITIALIZED);
01995 
01996   *aWindow = NS_STATIC_CAST(nsIDOMWindowInternal *, this);
01997   NS_ADDREF(*aWindow);
01998   return NS_OK;
01999 }
02000 
02001 NS_IMETHODIMP
02002 nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
02003 {
02004   FORWARD_TO_OUTER(GetNavigator, (aNavigator), NS_ERROR_NOT_INITIALIZED);
02005 
02006   *aNavigator = nsnull;
02007 
02008   if (!mNavigator) {
02009     mNavigator = new nsNavigator(mDocShell);
02010     if (!mNavigator) {
02011       return NS_ERROR_OUT_OF_MEMORY;
02012     }
02013   }
02014 
02015   NS_ADDREF(*aNavigator = mNavigator);
02016 
02017   return NS_OK;
02018 }
02019 
02020 NS_IMETHODIMP
02021 nsGlobalWindow::GetScreen(nsIDOMScreen** aScreen)
02022 {
02023   FORWARD_TO_OUTER(GetScreen, (aScreen), NS_ERROR_NOT_INITIALIZED);
02024 
02025   *aScreen = nsnull;
02026 
02027   if (!mScreen && mDocShell) {
02028     mScreen = new nsScreen(mDocShell);
02029     if (!mScreen) {
02030       return NS_ERROR_OUT_OF_MEMORY;
02031     }
02032   }
02033 
02034   NS_IF_ADDREF(*aScreen = mScreen);
02035 
02036   return NS_OK;
02037 }
02038 
02039 NS_IMETHODIMP
02040 nsGlobalWindow::GetHistory(nsIDOMHistory** aHistory)
02041 {
02042   FORWARD_TO_OUTER(GetHistory, (aHistory), NS_ERROR_NOT_INITIALIZED);
02043 
02044   *aHistory = nsnull;
02045 
02046   if (!mHistory && mDocShell) {
02047     mHistory = new nsHistory(mDocShell);
02048     if (!mHistory) {
02049       return NS_ERROR_OUT_OF_MEMORY;
02050     }
02051   }
02052 
02053   NS_IF_ADDREF(*aHistory = mHistory);
02054   return NS_OK;
02055 }
02056 
02057 NS_IMETHODIMP
02058 nsGlobalWindow::GetParent(nsIDOMWindow** aParent)
02059 {
02060   FORWARD_TO_OUTER(GetParent, (aParent), NS_ERROR_NOT_INITIALIZED);
02061 
02062   *aParent = nsnull;
02063   if (!mDocShell)
02064     return NS_OK;
02065 
02066   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
02067   NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
02068 
02069   nsCOMPtr<nsIDocShellTreeItem> parent;
02070   docShellAsItem->GetSameTypeParent(getter_AddRefs(parent));
02071 
02072   if (parent) {
02073     nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(parent));
02074     NS_ENSURE_SUCCESS(CallQueryInterface(globalObject.get(), aParent),
02075                       NS_ERROR_FAILURE);
02076   }
02077   else {
02078     *aParent = NS_STATIC_CAST(nsIDOMWindowInternal *, this);
02079     NS_ADDREF(*aParent);
02080   }
02081   return NS_OK;
02082 }
02083 
02084 NS_IMETHODIMP
02085 nsGlobalWindow::GetTop(nsIDOMWindow** aTop)
02086 {
02087   FORWARD_TO_OUTER(GetTop, (aTop), NS_ERROR_NOT_INITIALIZED);
02088 
02089   nsresult ret = NS_OK;
02090 
02091   *aTop = nsnull;
02092   if (mDocShell) {
02093     nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
02094     nsCOMPtr<nsIDocShellTreeItem> root;
02095     docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
02096 
02097     if (root) {
02098       nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(root));
02099       CallQueryInterface(globalObject.get(), aTop);
02100     }
02101   }
02102 
02103   return ret;
02104 }
02105 
02106 NS_IMETHODIMP
02107 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
02108 {
02109   FORWARD_TO_OUTER(GetContent, (aContent), NS_ERROR_NOT_INITIALIZED);
02110 
02111   *aContent = nsnull;
02112 
02113   nsCOMPtr<nsIDocShellTreeItem> primaryContent;
02114 
02115   if (!IsCallerChrome()) {
02116     // If we're called by non-chrome code, make sure we don't return
02117     // the primary content window if the calling tab is hidden. In
02118     // such a case we return the same-type root in the hidden tab,
02119     // which is "good enough", for now.
02120     nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
02121 
02122     if (baseWin) {
02123       PRBool visible = PR_FALSE;
02124       baseWin->GetVisibility(&visible);
02125 
02126       if (!visible) {
02127         nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
02128 
02129         treeItem->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
02130       }
02131     }
02132   }
02133 
02134   if (!primaryContent) {
02135     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
02136     GetTreeOwner(getter_AddRefs(treeOwner));
02137     NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
02138 
02139     treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
02140   }
02141 
02142   nsCOMPtr<nsIDOMWindowInternal> domWindow(do_GetInterface(primaryContent));
02143   NS_IF_ADDREF(*aContent = domWindow);
02144 
02145   return NS_OK;
02146 }
02147 
02148 NS_IMETHODIMP
02149 nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
02150 {
02151   FORWARD_TO_OUTER(GetPrompter, (aPrompt), NS_ERROR_NOT_INITIALIZED);
02152 
02153   if (!mDocShell)
02154     return NS_ERROR_FAILURE;
02155 
02156   nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
02157   NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
02158 
02159   NS_ADDREF(*aPrompt = prompter);
02160   return NS_OK;
02161 }
02162 
02163 NS_IMETHODIMP
02164 nsGlobalWindow::GetMenubar(nsIDOMBarProp** aMenubar)
02165 {
02166   FORWARD_TO_OUTER(GetMenubar, (aMenubar), NS_ERROR_NOT_INITIALIZED);
02167 
02168   *aMenubar = nsnull;
02169 
02170   if (!mMenubar) {
02171     mMenubar = new nsMenubarProp();
02172     if (!mMenubar) {
02173       return NS_ERROR_OUT_OF_MEMORY;
02174     }
02175 
02176     nsCOMPtr<nsIWebBrowserChrome> browserChrome;
02177     GetWebBrowserChrome(getter_AddRefs(browserChrome));
02178 
02179     mMenubar->SetWebBrowserChrome(browserChrome);
02180   }
02181 
02182   NS_ADDREF(*aMenubar = mMenubar);
02183 
02184   return NS_OK;
02185 }
02186 
02187 NS_IMETHODIMP
02188 nsGlobalWindow::GetToolbar(nsIDOMBarProp** aToolbar)
02189 {
02190   FORWARD_TO_OUTER(GetToolbar, (aToolbar), NS_ERROR_NOT_INITIALIZED);
02191 
02192   *aToolbar = nsnull;
02193 
02194   if (!mToolbar) {
02195     mToolbar = new nsToolbarProp();
02196     if (!mToolbar) {
02197       return NS_ERROR_OUT_OF_MEMORY;
02198     }
02199 
02200     nsCOMPtr<nsIWebBrowserChrome> browserChrome;
02201     GetWebBrowserChrome(getter_AddRefs(browserChrome));
02202 
02203     mToolbar->SetWebBrowserChrome(browserChrome);
02204   }
02205 
02206   NS_ADDREF(*aToolbar = mToolbar);
02207 
02208   return NS_OK;
02209 }
02210 
02211 NS_IMETHODIMP
02212 nsGlobalWindow::GetLocationbar(nsIDOMBarProp** aLocationbar)
02213 {
02214   FORWARD_TO_OUTER(GetLocationbar, (aLocationbar), NS_ERROR_NOT_INITIALIZED);
02215 
02216   *aLocationbar = nsnull;
02217 
02218   if (!mLocationbar) {
02219     mLocationbar = new nsLocationbarProp();
02220     if (!mLocationbar) {
02221       return NS_ERROR_OUT_OF_MEMORY;
02222     }
02223 
02224     nsCOMPtr<nsIWebBrowserChrome> browserChrome;
02225     GetWebBrowserChrome(getter_AddRefs(browserChrome));
02226 
02227     mLocationbar->SetWebBrowserChrome(browserChrome);
02228   }
02229 
02230   NS_ADDREF(*aLocationbar = mLocationbar);
02231 
02232   return NS_OK;
02233 }
02234 
02235 NS_IMETHODIMP
02236 nsGlobalWindow::GetPersonalbar(nsIDOMBarProp** aPersonalbar)
02237 {
02238   FORWARD_TO_OUTER(GetPersonalbar, (aPersonalbar), NS_ERROR_NOT_INITIALIZED);
02239 
02240   *aPersonalbar = nsnull;
02241 
02242   if (!mPersonalbar) {
02243     mPersonalbar = new nsPersonalbarProp();
02244     if (!mPersonalbar) {
02245       return NS_ERROR_OUT_OF_MEMORY;
02246     }
02247 
02248     nsCOMPtr<nsIWebBrowserChrome> browserChrome;
02249     GetWebBrowserChrome(getter_AddRefs(browserChrome));
02250 
02251     mPersonalbar->SetWebBrowserChrome(browserChrome);
02252   }
02253 
02254   NS_ADDREF(*aPersonalbar = mPersonalbar);
02255 
02256   return NS_OK;
02257 }
02258 
02259 NS_IMETHODIMP
02260 nsGlobalWindow::GetStatusbar(nsIDOMBarProp** aStatusbar)
02261 {
02262   FORWARD_TO_OUTER(GetStatusbar, (aStatusbar), NS_ERROR_NOT_INITIALIZED);
02263 
02264   *aStatusbar = nsnull;
02265 
02266   if (!mStatusbar) {
02267     mStatusbar = new nsStatusbarProp();
02268     if (!mStatusbar) {
02269       return NS_ERROR_OUT_OF_MEMORY;
02270     }
02271 
02272     nsCOMPtr<nsIWebBrowserChrome> browserChrome;
02273     GetWebBrowserChrome(getter_AddRefs(browserChrome));
02274 
02275     mStatusbar->SetWebBrowserChrome(browserChrome);
02276   }
02277 
02278   NS_ADDREF(*aStatusbar = mStatusbar);
02279 
02280   return NS_OK;
02281 }
02282 
02283 NS_IMETHODIMP
02284 nsGlobalWindow::GetScrollbars(nsIDOMBarProp** aScrollbars)
02285 {
02286   FORWARD_TO_OUTER(GetScrollbars, (aScrollbars), NS_ERROR_NOT_INITIALIZED);
02287 
02288   *aScrollbars = nsnull;
02289 
02290   if (!mScrollbars) {
02291     mScrollbars = new nsScrollbarsProp(this);
02292     if (!mScrollbars) {
02293       return NS_ERROR_OUT_OF_MEMORY;
02294     }
02295 
02296     nsCOMPtr<nsIWebBrowserChrome> browserChrome;
02297     GetWebBrowserChrome(getter_AddRefs(browserChrome));
02298 
02299     mScrollbars->SetWebBrowserChrome(browserChrome);
02300   }
02301 
02302   NS_ADDREF(*aScrollbars = mScrollbars);
02303 
02304   return NS_OK;
02305 }
02306 
02307 NS_IMETHODIMP
02308 nsGlobalWindow::GetDirectories(nsIDOMBarProp** aDirectories)
02309 {
02310   return GetPersonalbar(aDirectories);
02311 }
02312 
02313 NS_IMETHODIMP
02314 nsGlobalWindow::GetClosed(PRBool* aClosed)
02315 {
02316   FORWARD_TO_OUTER(GetClosed, (aClosed), NS_ERROR_NOT_INITIALIZED);
02317 
02318   // If someone called close(), or if we don't have a docshell, we're
02319   // closed.
02320   *aClosed = mIsClosed || !mDocShell;
02321 
02322   return NS_OK;
02323 }
02324 
02325 NS_IMETHODIMP
02326 nsGlobalWindow::GetFrames(nsIDOMWindowCollection** aFrames)
02327 {
02328   FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
02329 
02330   *aFrames = nsnull;
02331 
02332   if (!mFrames && mDocShell) {
02333     mFrames = new nsDOMWindowList(mDocShell);
02334     if (!mFrames) {
02335       return NS_ERROR_OUT_OF_MEMORY;
02336     }
02337   }
02338 
02339   *aFrames = NS_STATIC_CAST(nsIDOMWindowCollection *, mFrames);
02340   NS_IF_ADDREF(*aFrames);
02341   return NS_OK;
02342 }
02343 
02344 NS_IMETHODIMP
02345 nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
02346 {
02347   FORWARD_TO_OUTER(GetCrypto, (aCrypto), NS_ERROR_NOT_INITIALIZED);
02348 
02349   if (!mCrypto) {
02350     mCrypto = do_CreateInstance(kCryptoContractID);
02351   }
02352 
02353   NS_IF_ADDREF(*aCrypto = mCrypto);
02354 
02355   return NS_OK;
02356 }
02357 
02358 NS_IMETHODIMP
02359 nsGlobalWindow::GetPkcs11(nsIDOMPkcs11** aPkcs11)
02360 {
02361   FORWARD_TO_OUTER(GetPkcs11, (aPkcs11), NS_ERROR_NOT_INITIALIZED);
02362 
02363   if (!mPkcs11) {
02364     mPkcs11 = do_CreateInstance(kPkcs11ContractID);
02365   }
02366 
02367   NS_IF_ADDREF(*aPkcs11 = mPkcs11);
02368 
02369   return NS_OK;
02370 }
02371 
02372 NS_IMETHODIMP
02373 nsGlobalWindow::GetControllers(nsIControllers** aResult)
02374 {
02375   FORWARD_TO_OUTER(GetControllers, (aResult), NS_ERROR_NOT_INITIALIZED);
02376 
02377   if (!mControllers) {
02378     nsresult rv;
02379     mControllers = do_CreateInstance(kXULControllersCID, &rv);
02380     NS_ENSURE_SUCCESS(rv, rv);
02381 
02382     // Add in the default controller
02383     nsCOMPtr<nsIController> controller = do_CreateInstance(
02384                                NS_WINDOWCONTROLLER_CONTRACTID, &rv);
02385     NS_ENSURE_SUCCESS(rv, rv);
02386     
02387     mControllers->InsertControllerAt(0, controller);
02388     nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
02389     if (!controllerContext) return NS_ERROR_FAILURE;
02390 
02391     controllerContext->SetCommandContext(NS_STATIC_CAST(nsIDOMWindow*, this));
02392   }
02393 
02394   *aResult = mControllers;
02395   NS_ADDREF(*aResult);
02396   return NS_OK;
02397 }
02398 
02399 NS_IMETHODIMP
02400 nsGlobalWindow::GetOpener(nsIDOMWindowInternal** aOpener)
02401 {
02402   FORWARD_TO_OUTER(GetOpener, (aOpener), NS_ERROR_NOT_INITIALIZED);
02403 
02404   *aOpener = nsnull;
02405   // First, check if we were called from a privileged chrome script
02406 
02407   if (IsCallerChrome()) {
02408     *aOpener = mOpener;
02409     NS_IF_ADDREF(*aOpener);
02410     return NS_OK;
02411   }
02412 
02413   // We don't want to reveal the opener if the opener is a mail window,
02414   // because opener can be used to spoof the contents of a message (bug 105050).
02415   // So, we look in the opener's root docshell to see if it's a mail window.
02416   nsCOMPtr<nsIScriptGlobalObject> openerSGO(do_QueryInterface(mOpener));
02417   if (openerSGO) {
02418     nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
02419       do_QueryInterface(openerSGO->GetDocShell());
02420 
02421     if (docShellAsItem) {
02422       nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
02423       docShellAsItem->GetRootTreeItem(getter_AddRefs(openerRootItem));
02424       nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
02425       if (openerRootDocShell) {
02426         PRUint32 appType;
02427         nsresult rv = openerRootDocShell->GetAppType(&appType);
02428         if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
02429           *aOpener = mOpener;
02430         }
02431       }
02432     }
02433   }
02434   NS_IF_ADDREF(*aOpener);
02435   return NS_OK;
02436 }
02437 
02438 NS_IMETHODIMP
02439 nsGlobalWindow::SetOpener(nsIDOMWindowInternal* aOpener)
02440 {
02441   // check if we were called from a privileged chrome script.
02442   // If not, opener is settable only to null.
02443   if (aOpener && !IsCallerChrome()) {
02444     return NS_OK;
02445   }
02446 
02447   SetOpenerWindow(aOpener, PR_FALSE);
02448 
02449   return NS_OK;
02450 }
02451 
02452 NS_IMETHODIMP
02453 nsGlobalWindow::GetStatus(nsAString& aStatus)
02454 {
02455   FORWARD_TO_OUTER(GetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
02456 
02457   aStatus = mStatus;
02458   return NS_OK;
02459 }
02460 
02461 NS_IMETHODIMP
02462 nsGlobalWindow::SetStatus(const nsAString& aStatus)
02463 {
02464   FORWARD_TO_OUTER(SetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
02465 
02466   /*
02467    * If caller is not chrome and dom.disable_window_status_change is true,
02468    * prevent setting window.status by exiting early
02469    */
02470 
02471   if (!CanSetProperty("dom.disable_window_status_change")) {
02472     return NS_OK;
02473   }
02474 
02475   mStatus = aStatus;
02476 
02477   nsCOMPtr<nsIWebBrowserChrome> browserChrome;
02478   GetWebBrowserChrome(getter_AddRefs(browserChrome));
02479   if(browserChrome) {
02480     browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
02481                              PromiseFlatString(aStatus).get());
02482   }
02483 
02484   return NS_OK;
02485 }
02486 
02487 NS_IMETHODIMP
02488 nsGlobalWindow::GetDefaultStatus(nsAString& aDefaultStatus)
02489 {
02490   FORWARD_TO_OUTER(GetDefaultStatus, (aDefaultStatus),
02491                    NS_ERROR_NOT_INITIALIZED);
02492 
02493   aDefaultStatus = mDefaultStatus;
02494   return NS_OK;
02495 }
02496 
02497 NS_IMETHODIMP
02498 nsGlobalWindow::SetDefaultStatus(const nsAString& aDefaultStatus)
02499 {
02500   FORWARD_TO_OUTER(SetDefaultStatus, (aDefaultStatus),
02501                    NS_ERROR_NOT_INITIALIZED);
02502 
02503   /*
02504    * If caller is not chrome and dom.disable_window_status_change is true,
02505    * prevent setting window.defaultStatus by exiting early
02506    */
02507 
02508   if (!CanSetProperty("dom.disable_window_status_change")) {
02509     return NS_OK;
02510   }
02511 
02512   mDefaultStatus = aDefaultStatus;
02513 
02514   nsCOMPtr<nsIWebBrowserChrome> browserChrome;
02515   GetWebBrowserChrome(getter_AddRefs(browserChrome));
02516   if (browserChrome) {
02517     browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT_DEFAULT,
02518                              PromiseFlatString(aDefaultStatus).get());
02519   }
02520 
02521   return NS_OK;
02522 }
02523 
02524 NS_IMETHODIMP
02525 nsGlobalWindow::GetName(nsAString& aName)
02526 {
02527   FORWARD_TO_OUTER(GetName, (aName), NS_ERROR_NOT_INITIALIZED);
02528 
02529   nsXPIDLString name;
02530   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
02531   if (docShellAsItem)
02532     docShellAsItem->GetName(getter_Copies(name));
02533 
02534   aName.Assign(name);
02535   return NS_OK;
02536 }
02537 
02538 NS_IMETHODIMP
02539 nsGlobalWindow::SetName(const nsAString& aName)
02540 {
02541   FORWARD_TO_OUTER(SetName, (aName), NS_ERROR_NOT_INITIALIZED);
02542 
02543   nsresult result = NS_OK;
02544   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
02545   if (docShellAsItem)
02546     result = docShellAsItem->SetName(PromiseFlatString(aName).get());
02547   return result;
02548 }
02549 
02550 
02551 void
02552 MaybeSuppressDrag() {
02553   if (gMouseDown && !gDragServiceDisabled) {
02554     nsCOMPtr<nsIDragService_1_8_BRANCH> ds18 =
02555       do_GetService("@mozilla.org/widget/dragservice;1");
02556     NS_WARN_IF_FALSE(ds18, "No drag service?");
02557     if (ds18) {
02558       gDragServiceDisabled = PR_TRUE;
02559       ds18->Suppress();
02560     }
02561   }
02562 }
02563 
02564 NS_IMETHODIMP
02565 nsGlobalWindow::GetInnerWidth(PRInt32* aInnerWidth)
02566 {
02567   FORWARD_TO_OUTER(GetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
02568 
02569   EnsureSizeUpToDate();
02570 
02571   nsCOMPtr<nsIBaseWindow> docShellWin(do_QueryInterface(mDocShell));
02572   *aInnerWidth = 0;
02573   PRInt32 notused;
02574   if (docShellWin)
02575     docShellWin->GetSize(aInnerWidth, &notused);
02576 
02577   return NS_OK;
02578 }
02579 
02580 NS_IMETHODIMP
02581 nsGlobalWindow::SetInnerWidth(PRInt32 aInnerWidth)
02582 {
02583   FORWARD_TO_OUTER(SetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
02584 
02585   /*
02586    * If caller is not chrome and dom.disable_window_move_resize is true,
02587    * prevent setting window.innerWidth by exiting early
02588    */
02589 
02590   if (!CanSetProperty("dom.disable_window_move_resize") || IsFrame()) {
02591     return NS_OK;
02592   }
02593   MaybeSuppressDrag();
02594 
02595   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
02596   NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
02597 
02598   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
02599   docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
02600   NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
02601 
02602   NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aInnerWidth, nsnull),
02603                     NS_ERROR_FAILURE);
02604 
02605   nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
02606   PRInt32 notused, cy = 0;
02607   docShellAsWin->GetSize(&notused, &cy);
02608   NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, aInnerWidth, cy),
02609                     NS_ERROR_FAILURE);
02610   return NS_OK;
02611 }
02612 
02613 NS_IMETHODIMP
02614 nsGlobalWindow::GetInnerHeight(PRInt32* aInnerHeight)
02615 {
02616   FORWARD_TO_OUTER(GetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
02617 
02618   EnsureSizeUpToDate();
02619 
02620   nsCOMPtr<nsIBaseWindow> docShellWin(do_QueryInterface(mDocShell));
02621   *aInnerHeight = 0;
02622   PRInt32 notused;
02623   if (docShellWin)
02624     docShellWin->GetSize(&notused, aInnerHeight);
02625 
02626   return NS_OK;
02627 }
02628 
02629 NS_IMETHODIMP
02630 nsGlobalWindow::SetInnerHeight(PRInt32 aInnerHeight)
02631 {
02632   FORWARD_TO_OUTER(SetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
02633 
02634   /*
02635    * If caller is not chrome and dom.disable_window_move_resize is true,
02636    * prevent setting window.innerHeight by exiting early
02637    */
02638 
02639   if (!CanSetProperty("dom.disable_window_move_resize") || IsFrame()) {
02640     return NS_OK;
02641   }
02642   MaybeSuppressDrag();
02643 
02644   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
02645   NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
02646 
02647   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
02648   docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
02649   NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
02650 
02651   NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(nsnull, &aInnerHeight),
02652                     NS_ERROR_FAILURE);
02653 
02654   nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
02655   PRInt32 cx = 0, notused;
02656   docShellAsWin->GetSize(&cx, &notused);
02657   NS_ENSURE_SUCCESS(treeOwner->
02658                     SizeShellTo(docShellAsItem, cx, aInnerHeight),
02659                     NS_ERROR_FAILURE);
02660   return NS_OK;
02661 }
02662 
02663 NS_IMETHODIMP
02664 nsGlobalWindow::GetOuterWidth(PRInt32* aOuterWidth)
02665 {
02666   FORWARD_TO_OUTER(GetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
02667 
02668   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
02669   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
02670   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
02671 
02672   nsGlobalWindow* rootWindow =
02673     NS_STATIC_CAST(nsGlobalWindow *, GetPrivateRoot());
02674   if (rootWindow) {
02675     rootWindow->FlushPendingNotifications(Flush_Layout);
02676   }
02677   PRInt32 notused;
02678   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(aOuterWidth, &notused),
02679                     NS_ERROR_FAILURE);
02680 
02681   return NS_OK;
02682 }
02683 
02684 NS_IMETHODIMP
02685 nsGlobalWindow::SetOuterWidth(PRInt32 aOuterWidth)
02686 {
02687   FORWARD_TO_OUTER(SetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
02688 
02689   /*
02690    * If caller is not chrome and dom.disable_window_move_resize is true,
02691    * prevent setting window.outerWidth by exiting early
02692    */
02693 
02694   if (!CanSetProperty("dom.disable_window_move_resize")) {
02695     return NS_OK;
02696   }
02697   MaybeSuppressDrag();
02698 
02699   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
02700   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
02701   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
02702 
02703   NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aOuterWidth, nsnull),
02704                     NS_ERROR_FAILURE);
02705 
02706   PRInt32 notused, cy;
02707   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&notused, &cy), NS_ERROR_FAILURE);
02708 
02709   NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(aOuterWidth, cy, PR_TRUE),
02710                     NS_ERROR_FAILURE);
02711 
02712   return NS_OK;
02713 }
02714 
02715 NS_IMETHODIMP
02716 nsGlobalWindow::GetOuterHeight(PRInt32* aOuterHeight)
02717 {
02718   FORWARD_TO_OUTER(GetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
02719 
02720   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
02721   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
02722   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
02723 
02724   nsGlobalWindow* rootWindow =
02725     NS_STATIC_CAST(nsGlobalWindow *, GetPrivateRoot());
02726   if (rootWindow) {
02727     rootWindow->FlushPendingNotifications(Flush_Layout);
02728   }
02729 
02730   PRInt32 notused;
02731   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&notused, aOuterHeight),
02732                     NS_ERROR_FAILURE);
02733 
02734   return NS_OK;
02735 }
02736 
02737 NS_IMETHODIMP
02738 nsGlobalWindow::SetOuterHeight(PRInt32 aOuterHeight)
02739 {
02740   FORWARD_TO_OUTER(SetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
02741 
02742   /*
02743    * If caller is not chrome and dom.disable_window_move_resize is true,
02744    * prevent setting window.outerHeight by exiting early
02745    */
02746 
02747   if (!CanSetProperty("dom.disable_window_move_resize")) {
02748     return NS_OK;
02749   }
02750   MaybeSuppressDrag();
02751 
02752   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
02753   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
02754   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
02755 
02756   NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(nsnull, &aOuterHeight),
02757                     NS_ERROR_FAILURE);
02758 
02759   PRInt32 cx, notused;
02760   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&cx, &notused), NS_ERROR_FAILURE);
02761 
02762   NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(cx, aOuterHeight, PR_TRUE),
02763                     NS_ERROR_FAILURE);
02764 
02765   return NS_OK;
02766 }
02767 
02768 NS_IMETHODIMP
02769 nsGlobalWindow::GetScreenX(PRInt32* aScreenX)
02770 {
02771   FORWARD_TO_OUTER(GetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
02772 
02773   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
02774   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
02775   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
02776 
02777   PRInt32 y;
02778 
02779   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(aScreenX, &y),
02780                     NS_ERROR_FAILURE);
02781 
02782   return NS_OK;
02783 }
02784 
02785 NS_IMETHODIMP
02786 nsGlobalWindow::SetScreenX(PRInt32 aScreenX)
02787 {
02788   FORWARD_TO_OUTER(SetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
02789 
02790   /*
02791    * If caller is not chrome and dom.disable_window_move_resize is true,
02792    * prevent setting window.screenX by exiting early
02793    */
02794 
02795   if (!CanSetProperty("dom.disable_window_move_resize")) {
02796     return NS_OK;
02797   }
02798   MaybeSuppressDrag();
02799 
02800   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
02801   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
02802   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
02803 
02804   NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aScreenX, nsnull),
02805                     NS_ERROR_FAILURE);
02806 
02807   PRInt32 x, y;
02808   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
02809                     NS_ERROR_FAILURE);
02810 
02811   NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(aScreenX, y),
02812                     NS_ERROR_FAILURE);
02813 
02814   return NS_OK;
02815 }
02816 
02817 NS_IMETHODIMP
02818 nsGlobalWindow::GetScreenY(PRInt32* aScreenY)
02819 {
02820   FORWARD_TO_OUTER(GetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
02821 
02822   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
02823   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
02824   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
02825 
02826   PRInt32 x;
02827 
02828   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, aScreenY),
02829                     NS_ERROR_FAILURE);
02830 
02831   return NS_OK;
02832 }
02833 
02834 NS_IMETHODIMP
02835 nsGlobalWindow::SetScreenY(PRInt32 aScreenY)
02836 {
02837   FORWARD_TO_OUTER(SetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
02838 
02839   /*
02840    * If caller is not chrome and dom.disable_window_move_resize is true,
02841    * prevent setting window.screenY by exiting early
02842    */
02843 
02844   if (!CanSetProperty("dom.disable_window_move_resize")) {
02845     return NS_OK;
02846   }
02847   MaybeSuppressDrag();
02848 
02849   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
02850   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
02851   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
02852 
02853   NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(nsnull, &aScreenY),
02854                     NS_ERROR_FAILURE);
02855 
02856   PRInt32 x, y;
02857   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
02858                     NS_ERROR_FAILURE);
02859 
02860   NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, aScreenY),
02861                     NS_ERROR_FAILURE);
02862 
02863   return NS_OK;
02864 }
02865 
02866 nsresult
02867 nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight)
02868 {
02869   if (!nsContentUtils::IsCallerTrustedForWrite()) {
02870     // if attempting to resize the window, hide any open popups
02871     nsCOMPtr<nsIPresShell> presShell;
02872     mDocShell->GetPresShell(getter_AddRefs(presShell));
02873 
02874     nsCOMPtr<nsIPresShell_MOZILLA_1_8_BRANCH> presShell18 = do_QueryInterface(presShell);
02875     if (presShell18)
02876       presShell18->HidePopups();
02877   }
02878 
02879   // This one is easy. Just ensure the variable is greater than 100;
02880   if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
02881     // Check security state for use in determing window dimensions
02882 
02883     NS_ENSURE_TRUE(sSecMan, NS_ERROR_FAILURE);
02884 
02885     PRBool enabled;
02886     nsresult res = sSecMan->IsCapabilityEnabled("UniversalBrowserWrite",
02887                                                 &enabled);
02888 
02889     if (NS_FAILED(res) || !enabled) {
02890       //sec check failed
02891       if (aWidth && *aWidth < 100) {
02892         *aWidth = 100;
02893       }
02894       if (aHeight && *aHeight < 100) {
02895         *aHeight = 100;
02896       }
02897     }
02898   }
02899 
02900   return NS_OK;
02901 }
02902 
02903 nsresult
02904 nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop)
02905 {
02906   // This one is harder. We have to get the screen size and window dimensions.
02907 
02908   // Check security state for use in determing window dimensions
02909 
02910   NS_ENSURE_TRUE(sSecMan, NS_ERROR_FAILURE);
02911 
02912   PRBool enabled;
02913   nsresult res = sSecMan->IsCapabilityEnabled("UniversalBrowserWrite",
02914                                               &enabled);
02915   if (NS_FAILED(res)) {
02916     enabled = PR_FALSE;
02917   }
02918 
02919   if (!enabled) {
02920     // if attempting to move the window, hide any open popups
02921     nsCOMPtr<nsIPresShell> presShell;
02922     mDocShell->GetPresShell(getter_AddRefs(presShell));
02923     nsCOMPtr<nsIPresShell_MOZILLA_1_8_BRANCH> presShell18 = do_QueryInterface(presShell);
02924     if (presShell18)
02925       presShell18->HidePopups();
02926 
02927     PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
02928     PRInt32 winLeft, winTop, winWidth, winHeight;
02929 
02930     nsGlobalWindow* rootWindow =
02931       NS_STATIC_CAST(nsGlobalWindow*, GetPrivateRoot());
02932     if (rootWindow) {
02933       rootWindow->FlushPendingNotifications(Flush_Layout);
02934     }
02935 
02936     // Get the window size
02937     nsCOMPtr<nsIBaseWindow> treeOwner;
02938     GetTreeOwner(getter_AddRefs(treeOwner));
02939     if (treeOwner)
02940       treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
02941 
02942     // Get the screen dimensions
02943     // XXX This should use nsIScreenManager once it's fully fleshed out.
02944     nsCOMPtr<nsIDOMScreen> screen;
02945     GetScreen(getter_AddRefs(screen));
02946     if (screen) {
02947       screen->GetAvailLeft(&screenLeft);
02948       screen->GetAvailWidth(&screenWidth);
02949       screen->GetAvailHeight(&screenHeight);
02950 #if defined(XP_MAC) || defined(XP_MACOSX)
02951       /* The mac's coordinate system is different from the assumed Windows'
02952          system. It offsets by the height of the menubar so that a window
02953          placed at (0,0) will be entirely visible. Unfortunately that
02954          correction is made elsewhere (in Widget) and the meaning of
02955          the Avail... coordinates is overloaded. Here we allow a window
02956          to be placed at (0,0) because it does make sense to do so.
02957       */
02958       screen->GetTop(&screenTop);
02959 #else
02960       screen->GetAvailTop(&screenTop);
02961 #endif
02962     }
02963 
02964     if (screen && treeOwner) {
02965       if (aLeft) {
02966         if (screenLeft+screenWidth < *aLeft+winWidth)
02967           *aLeft = screenLeft+screenWidth - winWidth;
02968         if (screenLeft > *aLeft)
02969           *aLeft = screenLeft;
02970       }
02971       if (aTop) {
02972         if (screenTop+screenHeight < *aTop+winHeight)
02973           *aTop = screenTop+screenHeight - winHeight;
02974         if (screenTop > *aTop)
02975           *aTop = screenTop;
02976       }
02977     } else {
02978       if (aLeft)
02979         *aLeft = 0;
02980       if (aTop)
02981         *aTop = 0;
02982     }
02983   }
02984 
02985   return NS_OK;
02986 }
02987 
02988 NS_IMETHODIMP
02989 nsGlobalWindow::GetPageXOffset(PRInt32* aPageXOffset)
02990 {
02991   return GetScrollX(aPageXOffset);
02992 }
02993 
02994 NS_IMETHODIMP
02995 nsGlobalWindow::GetPageYOffset(PRInt32* aPageYOffset)
02996 {
02997   return GetScrollY(aPageYOffset);
02998 }
02999 
03000 nsresult
03001 nsGlobalWindow::GetScrollMaxXY(PRInt32* aScrollMaxX, PRInt32* aScrollMaxY)
03002 {
03003   FORWARD_TO_OUTER(GetScrollMaxXY, (aScrollMaxX, aScrollMaxY),
03004                    NS_ERROR_NOT_INITIALIZED);
03005 
03006   nsresult rv;
03007   nsIScrollableView *view = nsnull;      // no addref/release for views
03008   float p2t, t2p;
03009 
03010   FlushPendingNotifications(Flush_Layout);
03011   GetScrollInfo(&view, &p2t, &t2p);
03012   if (!view)
03013     return NS_OK;      // bug 230965 changed from NS_ERROR_FAILURE
03014 
03015   nsSize scrolledSize;
03016   rv = view->GetContainerSize(&scrolledSize.width, &scrolledSize.height);
03017   NS_ENSURE_SUCCESS(rv, rv);
03018 
03019   nsRect portRect = view->View()->GetBounds();
03020 
03021   if (aScrollMaxX)
03022     *aScrollMaxX = PR_MAX(0,
03023       (PRInt32)floor(t2p*(scrolledSize.width - portRect.width)));
03024   if (aScrollMaxY)
03025     *aScrollMaxY = PR_MAX(0,
03026       (PRInt32)floor(t2p*(scrolledSize.height - portRect.height)));
03027 
03028   return NS_OK;
03029 }
03030 
03031 NS_IMETHODIMP
03032 nsGlobalWindow::GetScrollMaxX(PRInt32* aScrollMaxX)
03033 {
03034   NS_ENSURE_ARG_POINTER(aScrollMaxX);
03035   *aScrollMaxX = 0;
03036   return GetScrollMaxXY(aScrollMaxX, nsnull);
03037 }
03038 
03039 NS_IMETHODIMP
03040 nsGlobalWindow::GetScrollMaxY(PRInt32* aScrollMaxY)
03041 {
03042   NS_ENSURE_ARG_POINTER(aScrollMaxY);
03043   *aScrollMaxY = 0;
03044   return GetScrollMaxXY(nsnull, aScrollMaxY);
03045 }
03046 
03047 nsresult
03048 nsGlobalWindow::GetScrollXY(PRInt32* aScrollX, PRInt32* aScrollY,
03049                             PRBool aDoFlush)
03050 {
03051   FORWARD_TO_OUTER(GetScrollXY, (aScrollX, aScrollY, aDoFlush),
03052                    NS_ERROR_NOT_INITIALIZED);
03053 
03054   nsresult rv;
03055   nsIScrollableView *view = nsnull;      // no addref/release for views
03056   float p2t, t2p;
03057 
03058   if (aDoFlush) {
03059     FlushPendingNotifications(Flush_Layout);
03060   } else {
03061     EnsureSizeUpToDate();
03062   }
03063   
03064   GetScrollInfo(&view, &p2t, &t2p);
03065   if (!view)
03066     return NS_OK;      // bug 202206 changed from NS_ERROR_FAILURE
03067 
03068   nscoord xPos, yPos;
03069   rv = view->GetScrollPosition(xPos, yPos);
03070   NS_ENSURE_SUCCESS(rv, rv);
03071 
03072   if ((xPos != 0 || yPos != 0) && !aDoFlush) {
03073     // Oh, well.  This is the expensive case -- the window is scrolled and we
03074     // didn't actually flush yet.  Repeat, but with a flush, since the content
03075     // may get shorter and hence our scroll position may decrease.
03076     return GetScrollXY(aScrollX, aScrollY, PR_TRUE);
03077   }
03078   
03079   if (aScrollX)
03080     *aScrollX = NSTwipsToIntPixels(xPos, t2p);
03081   if (aScrollY)
03082     *aScrollY = NSTwipsToIntPixels(yPos, t2p);
03083 
03084   return NS_OK;
03085 }
03086 
03087 NS_IMETHODIMP
03088 nsGlobalWindow::GetScrollX(PRInt32* aScrollX)
03089 {
03090   NS_ENSURE_ARG_POINTER(aScrollX);
03091   *aScrollX = 0;
03092   return GetScrollXY(aScrollX, nsnull, PR_FALSE);
03093 }
03094 
03095 NS_IMETHODIMP
03096 nsGlobalWindow::GetScrollY(PRInt32* aScrollY)
03097 {
03098   NS_ENSURE_ARG_POINTER(aScrollY);
03099   *aScrollY = 0;
03100   return GetScrollXY(nsnull, aScrollY, PR_FALSE);
03101 }
03102 
03103 NS_IMETHODIMP
03104 nsGlobalWindow::GetLength(PRUint32* aLength)
03105 {
03106   nsCOMPtr<nsIDOMWindowCollection> frames;
03107   if (NS_SUCCEEDED(GetFrames(getter_AddRefs(frames))) && frames) {
03108     return frames->GetLength(aLength);
03109   }
03110   return NS_ERROR_FAILURE;
03111 }
03112 
03113 PRBool
03114 nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
03115 {
03116   nsCOMPtr<nsIDOMDocumentEvent> doc(do_QueryInterface(mDocument));
03117   nsCOMPtr<nsIDOMEvent> event;
03118 
03119   PRBool defaultActionEnabled = PR_TRUE;
03120 
03121   if (doc) {
03122     doc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
03123 
03124     nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
03125     if (privateEvent) {
03126       event->InitEvent(NS_ConvertASCIItoUTF16(aEventName), PR_TRUE, PR_TRUE);
03127 
03128       privateEvent->SetTrusted(PR_TRUE);
03129 
03130       DispatchEvent(event, &defaultActionEnabled);
03131     }
03132   }
03133 
03134   return defaultActionEnabled;
03135 }
03136 
03137 static already_AddRefed<nsIDocShellTreeItem>
03138 GetCallerDocShellTreeItem()
03139 {
03140   nsCOMPtr<nsIJSContextStack> stack =
03141     do_GetService(sJSStackContractID);
03142 
03143   JSContext *cx = nsnull;
03144 
03145   if (stack) {
03146     stack->Peek(&cx);
03147   }
03148 
03149   nsIDocShellTreeItem *callerItem = nsnull;
03150 
03151   if (cx) {
03152     nsCOMPtr<nsIWebNavigation> callerWebNav =
03153       do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
03154 
03155     if (callerWebNav) {
03156       CallQueryInterface(callerWebNav, &callerItem);
03157     }
03158   }
03159 
03160   return callerItem;
03161 }
03162 
03163 PRBool
03164 nsGlobalWindow::WindowExists(const nsAString& aName,
03165                              PRBool aLookForCallerOnJSStack)
03166 {
03167   NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
03168   NS_PRECONDITION(mDocShell, "Must have docshell");
03169 
03170   nsCOMPtr<nsIDocShellTreeItem> caller;
03171   if (aLookForCallerOnJSStack) {
03172     caller = GetCallerDocShellTreeItem();
03173   }
03174 
03175   nsCOMPtr<nsIDocShellTreeItem> docShell = do_QueryInterface(mDocShell);
03176   NS_ASSERTION(docShell,
03177                "Docshell doesn't implement nsIDocShellTreeItem?");
03178 
03179   if (!caller) {
03180     caller = docShell;
03181   }
03182 
03183   nsCOMPtr<nsIDocShellTreeItem> namedItem;
03184   docShell->FindItemWithName(PromiseFlatString(aName).get(), nsnull, caller,
03185                              getter_AddRefs(namedItem));
03186   return namedItem != nsnull;
03187 }
03188 
03189 already_AddRefed<nsIWidget>
03190 nsGlobalWindow::GetMainWidget()
03191 {
03192   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
03193   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
03194 
03195   nsIWidget *widget = nsnull;
03196 
03197   if (treeOwnerAsWin) {
03198     treeOwnerAsWin->GetMainWidget(&widget);
03199   }
03200 
03201   return widget;
03202 }
03203 
03204 NS_IMETHODIMP
03205 nsGlobalWindow::SetFullScreen(PRBool aFullScreen)
03206 {
03207   FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
03208 
03209   // Only chrome can change our fullScreen mode.
03210   if (aFullScreen == mFullScreen || !IsCallerChrome()) {
03211     return NS_OK;
03212   }
03213 
03214   // SetFullScreen needs to be called on the root window, so get that
03215   // via the DocShell tree, and if we are not already the root,
03216   // call SetFullScreen on that window instead.
03217   nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
03218   nsCOMPtr<nsIDocShellTreeItem> rootItem;
03219   treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
03220   nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(rootItem);
03221   if (!window)
03222     return NS_ERROR_FAILURE;
03223   if (rootItem != treeItem)
03224     return window->SetFullScreen(aFullScreen);
03225 
03226   // make sure we don't try to set full screen on a non-chrome window,
03227   // which might happen in embedding world
03228   PRInt32 itemType;
03229   treeItem->GetItemType(&itemType);
03230   if (itemType != nsIDocShellTreeItem::typeChrome)
03231     return NS_ERROR_FAILURE;
03232 
03233   // dispatch a "fullscreen" DOM event so that XUL apps can
03234   // respond visually if we are kicked into full screen mode
03235   if (!DispatchCustomEvent("fullscreen")) {
03236     // event handlers can prevent us from going into full-screen mode
03237 
03238     return NS_OK;
03239   }
03240 
03241   nsCOMPtr<nsIWidget> widget = GetMainWidget();
03242   if (widget)
03243     widget->MakeFullScreen(aFullScreen);
03244 
03245   mFullScreen = aFullScreen;
03246 
03247   return NS_OK;
03248 }
03249 
03250 NS_IMETHODIMP
03251 nsGlobalWindow::GetFullScreen(PRBool* aFullScreen)
03252 {
03253   FORWARD_TO_OUTER(GetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
03254 
03255   *aFullScreen = mFullScreen;
03256   return NS_OK;
03257 }
03258 
03259 NS_IMETHODIMP
03260 nsGlobalWindow::Dump(const nsAString& aStr)
03261 {
03262 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
03263   {
03264     // In optimized builds we check a pref that controls if we should
03265     // enable output from dump() or not, in debug builds it's always
03266     // enabled.
03267 
03268     // if pref doesn't exist, disable dump output.
03269     PRBool enable_dump =
03270       nsContentUtils::GetBoolPref("browser.dom.window.dump.enabled");
03271 
03272     if (!enable_dump) {
03273       return NS_OK;
03274     }
03275   }
03276 #endif
03277 
03278   char *cstr = ToNewUTF8String(aStr);
03279 
03280 #if defined(XP_MAC) || defined(XP_MACOSX)
03281   // have to convert \r to \n so that printing to the console works
03282   char *c = cstr, *cEnd = cstr + aStr.Length();
03283   while (c < cEnd) {
03284     if (*c == '\r')
03285       *c = '\n';
03286     c++;
03287   }
03288 #endif
03289 
03290   if (cstr) {
03291     printf("%s", cstr);
03292     nsMemory::Free(cstr);
03293   }
03294 
03295   return NS_OK;
03296 }
03297 
03298 void
03299 nsGlobalWindow::EnsureReflowFlushAndPaint()
03300 {
03301   NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
03302                "docshell!");
03303 
03304   nsCOMPtr<nsIPresShell> presShell;
03305   mDocShell->GetPresShell(getter_AddRefs(presShell));
03306 
03307   if (!presShell)
03308     return;
03309 
03310   // Flush pending reflows.
03311   nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
03312 
03313   if (doc) {
03314     doc->FlushPendingNotifications(Flush_Layout);
03315   }
03316 
03317   // Unsuppress painting.
03318   presShell->UnsuppressPainting();
03319 }
03320 
03321 NS_IMETHODIMP
03322 nsGlobalWindow::GetTextZoom(float *aZoom)
03323 {
03324   FORWARD_TO_OUTER(GetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
03325 
03326   if (mDocShell) {
03327     nsCOMPtr<nsIContentViewer> contentViewer;
03328     mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
03329     nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
03330 
03331     if (markupViewer) {
03332       return markupViewer->GetTextZoom(aZoom);
03333     }
03334   }
03335   return NS_ERROR_FAILURE;
03336 }
03337 
03338 NS_IMETHODIMP
03339 nsGlobalWindow::SetTextZoom(float aZoom)
03340 {
03341   FORWARD_TO_OUTER(SetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
03342 
03343   if (mDocShell) {
03344     nsCOMPtr<nsIContentViewer> contentViewer;
03345     mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
03346     nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
03347 
03348     if (markupViewer)
03349       return markupViewer->SetTextZoom(aZoom);
03350   }
03351   return NS_ERROR_FAILURE;
03352 }
03353 
03354 // static
03355 PRBool
03356 nsGlobalWindow::IsCallerChrome()
03357 {
03358   NS_ENSURE_TRUE(sSecMan, PR_FALSE);
03359 
03360   PRBool isChrome = PR_FALSE;
03361   nsresult rv = sSecMan->SubjectPrincipalIsSystem(&isChrome);
03362 
03363   return NS_SUCCEEDED(rv) ? isChrome : PR_FALSE;
03364 }
03365 
03366 // static
03367 void
03368 nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
03369 {
03370   aOutTitle.Truncate();
03371 
03372   // Try to get a host from the running principal -- this will do the
03373   // right thing for javascript: and data: documents.
03374 
03375   nsresult rv = NS_OK;
03376   NS_WARN_IF_FALSE(sSecMan, "Global Window has no security manager!");
03377   
03378   nsCOMPtr<nsIStringBundleService> stringBundleService =
03379     do_GetService(kCStringBundleServiceCID);
03380   
03381   if (sSecMan && stringBundleService) {
03382     nsCOMPtr<nsIPrincipal> principal;
03383     rv = sSecMan->GetSubjectPrincipal(getter_AddRefs(principal));
03384 
03385     if (NS_SUCCEEDED(rv) && principal) {
03386       nsCOMPtr<nsIURI> uri;
03387       rv = principal->GetURI(getter_AddRefs(uri));
03388 
03389       if (NS_SUCCEEDED(rv) && uri) {
03390         // remove user:pass for privacy and spoof prevention
03391 
03392         nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
03393         if (fixup) {
03394           nsCOMPtr<nsIURI> fixedURI;
03395           rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
03396           if (NS_SUCCEEDED(rv) && fixedURI) {
03397             nsCAutoString host;
03398             fixedURI->GetHost(host);
03399 
03400             if (!host.IsEmpty()) {
03401               // if this URI has a host we'll show it. For other
03402               // schemes (e.g. file:) we fall back to the localized
03403               // generic string
03404 
03405               nsCAutoString prepath;
03406               fixedURI->GetPrePath(prepath);
03407 
03408               nsCOMPtr<nsIStringBundle> stringBundle;
03409               stringBundleService->CreateBundle(kDOMBundleURL,
03410                                                 getter_AddRefs(stringBundle));
03411               if (stringBundle) {
03412                 nsXPIDLString tempString;
03413                 const PRUnichar *formatStrings[1];
03414                 NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
03415                 formatStrings[0] = ucsPrePath.get();
03416                 stringBundle->FormatStringFromName(NS_LITERAL_STRING("ScriptDlgHeading").get(),
03417                                                    formatStrings, 1, getter_Copies(tempString));
03418                 if (tempString) {
03419                   aOutTitle = tempString.get();
03420                 }
03421               }
03422             }
03423           }
03424         }
03425       }
03426     }
03427     else { // failed to get subject principal
03428       NS_WARNING("No script principal? Who is calling alert/confirm/prompt?!");
03429     }
03430   }
03431 
03432   if (aOutTitle.IsEmpty() && stringBundleService) {
03433     // We didn't find a host so use the generic heading
03434     nsCOMPtr<nsIStringBundle> stringBundle;
03435     stringBundleService->CreateBundle(kDOMBundleURL,
03436                                       getter_AddRefs(stringBundle));
03437     if (stringBundle) {
03438       nsXPIDLString tempString;
03439       stringBundle->GetStringFromName(NS_LITERAL_STRING("ScriptDlgGenericHeading").get(),
03440                                       getter_Copies(tempString));
03441       if (tempString)
03442         aOutTitle = tempString.get();
03443     }
03444   }
03445 
03446   // Just in case
03447   if (aOutTitle.IsEmpty()) {
03448     NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
03449     aOutTitle.AssignLiteral("[Script]");
03450   }
03451 }
03452 
03453 NS_IMETHODIMP
03454 nsGlobalWindow::Alert(const nsAString& aString)
03455 {
03456   FORWARD_TO_OUTER(Alert, (aString), NS_ERROR_NOT_INITIALIZED);
03457 
03458   nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
03459   NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
03460 
03461   // Reset popup state while opening a modal dialog, and firing events
03462   // about the dialog, to prevent the current state from being active
03463   // the whole time a modal dialog is open.
03464   nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
03465 
03466   // Special handling for alert(null) in JS for backwards
03467   // compatibility.
03468 
03469   NS_NAMED_LITERAL_STRING(null_str, "null");
03470 
03471   const nsAString *str = DOMStringIsNull(aString) ? &null_str : &aString;
03472 
03473   // Test whether title needs to prefixed with [script]
03474   nsAutoString newTitle;
03475   const PRUnichar *title = nsnull;
03476   if (!IsCallerChrome()) {
03477       MakeScriptDialogTitle(newTitle);
03478       title = newTitle.get();
03479   }
03480   else {
03481       NS_WARNING("chrome shouldn't be calling alert(), use the prompt "
03482                  "service");
03483   }
03484 
03485   // Before bringing up the window, unsuppress painting and flush
03486   // pending reflows.
03487   EnsureReflowFlushAndPaint();
03488 
03489   return prompter->Alert(title, PromiseFlatString(*str).get());
03490 }
03491 
03492 NS_IMETHODIMP
03493 nsGlobalWindow::Confirm(const nsAString& aString, PRBool* aReturn)
03494 {
03495   FORWARD_TO_OUTER(Confirm, (aString, aReturn), NS_ERROR_NOT_INITIALIZED);
03496 
03497   nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
03498   NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
03499 
03500   // Reset popup state while opening a modal dialog, and firing events
03501   // about the dialog, to prevent the current state from being active
03502   // the whole time a modal dialog is open.
03503   nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
03504 
03505   *aReturn = PR_FALSE;
03506 
03507   // Test whether title needs to prefixed with [script]
03508   nsAutoString newTitle;
03509   const PRUnichar *title = nsnull;
03510   if (!IsCallerChrome()) {
03511       MakeScriptDialogTitle(newTitle);
03512       title = newTitle.get();
03513   }
03514   else {
03515       NS_WARNING("chrome shouldn't be calling confirm(), use the prompt "
03516                  "service");
03517   }
03518 
03519   // Before bringing up the window, unsuppress painting and flush
03520   // pending reflows.
03521   EnsureReflowFlushAndPaint();
03522 
03523   return prompter->Confirm(title, PromiseFlatString(aString).get(), aReturn);
03524 }
03525 
03526 NS_IMETHODIMP
03527 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
03528                        const nsAString& aTitle, PRUint32 aSavePassword,
03529                        nsAString& aReturn)
03530 {
03531   SetDOMStringToNull(aReturn);
03532 
03533   nsresult rv;
03534   nsCOMPtr<nsIWindowWatcher> wwatch =
03535     do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
03536   NS_ENSURE_SUCCESS(rv, rv);
03537 
03538   nsCOMPtr<nsIAuthPrompt> prompter;
03539   wwatch->GetNewAuthPrompter(this, getter_AddRefs(prompter));
03540   NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
03541 
03542   // Reset popup state while opening a modal dialog, and firing events
03543   // about the dialog, to prevent the current state from being active
03544   // the whole time a modal dialog is open.
03545   nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
03546 
03547   PRBool b;
03548   nsXPIDLString uniResult;
03549 
03550   // Before bringing up the window, unsuppress painting and flush
03551   // pending reflows.
03552   EnsureReflowFlushAndPaint();
03553 
03554   // Test whether title needs to prefixed with [script]
03555   nsAutoString title;
03556   if (!IsCallerChrome()) {
03557     MakeScriptDialogTitle(title);
03558   } else {
03559     NS_WARNING("chrome shouldn't be calling prompt(), use the prompt "
03560                "service");
03561     title.Assign(aTitle);
03562   }
03563 
03564   rv = prompter->Prompt(title.get(), PromiseFlatString(aMessage).get(), nsnull,
03565                         aSavePassword, PromiseFlatString(aInitial).get(),
03566                         getter_Copies(uniResult), &b);
03567   NS_ENSURE_SUCCESS(rv, rv);
03568 
03569   if (uniResult && b) {
03570     aReturn.Assign(uniResult);
03571   }
03572 
03573   return rv;
03574 }
03575 
03576 NS_IMETHODIMP
03577 nsGlobalWindow::Prompt(nsAString& aReturn)
03578 {
03579   FORWARD_TO_OUTER(Prompt, (aReturn), NS_ERROR_NOT_INITIALIZED);
03580 
03581   NS_ENSURE_STATE(mDocShell);
03582 
03583   nsresult rv = NS_OK;
03584   nsCOMPtr<nsIXPCNativeCallContext> ncc;
03585 
03586   rv = nsContentUtils::XPConnect()->
03587     GetCurrentNativeCallContext(getter_AddRefs(ncc));
03588   NS_ENSURE_SUCCESS(rv, rv);
03589 
03590   if (!ncc)
03591     return NS_ERROR_NOT_AVAILABLE;
03592 
03593   JSContext *cx = nsnull;
03594 
03595   rv = ncc->GetJSContext(&cx);
03596   NS_ENSURE_SUCCESS(rv, rv);
03597 
03598   nsAutoString message, initial, title;
03599 
03600   PRUint32 argc;
03601   jsval *argv = nsnull;
03602 
03603   ncc->GetArgc(&argc);
03604   ncc->GetArgvPtr(&argv);
03605 
03606   PRUint32 savePassword = nsIAuthPrompt::SAVE_PASSWORD_NEVER;
03607 
03608   if (argc > 0) {
03609     nsJSUtils::ConvertJSValToString(message, cx, argv[0]);
03610 
03611     if (argc > 1) {
03612       nsJSUtils::ConvertJSValToString(initial, cx, argv[1]);
03613 
03614       if (argc > 2) {
03615         nsJSUtils::ConvertJSValToString(title, cx, argv[2]);
03616 
03617         if (argc > 3) {
03618           nsJSUtils::ConvertJSValToUint32(&savePassword, cx, argv[3]);
03619         }
03620       }
03621     }
03622   }
03623 
03624   return Prompt(message, initial, title, savePassword, aReturn);
03625 }
03626 
03627 NS_IMETHODIMP
03628 nsGlobalWindow::Focus()
03629 {
03630   FORWARD_TO_OUTER(Focus, (), NS_ERROR_NOT_INITIALIZED);
03631 
03632   nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
03633 
03634   PRBool isVisible = PR_FALSE;
03635   if (baseWin) {
03636     baseWin->GetVisibility(&isVisible);
03637   }
03638 
03639   if (!isVisible) {
03640     // A hidden tab is being focused, ignore this call.
03641     return NS_OK;
03642   }
03643 
03644   /*
03645    * If caller is not chrome and dom.disable_window_flip is true,
03646    * prevent bringing a window to the front if the window is not the
03647    * currently active window, but do change the currently focused
03648    * window in the focus controller so that focus is in the right
03649    * place when the window is activated again.
03650    */
03651 
03652   PRBool canFocus =
03653     CanSetProperty("dom.disable_window_flip") ||
03654     CheckOpenAllow(CheckForAbusePoint()) == allowNoAbuse;
03655 
03656   PRBool isActive = PR_FALSE;
03657   nsIFocusController *focusController =
03658     nsGlobalWindow::GetRootFocusController();
03659   if (focusController) {
03660     focusController->GetActive(&isActive);
03661   }
03662 
03663   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
03664   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
03665   if (treeOwnerAsWin && (canFocus || isActive)) {
03666     PRBool isEnabled = PR_TRUE;
03667     if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
03668       NS_WARNING( "Should not try to set the focus on a disabled window" );
03669       return NS_ERROR_FAILURE;
03670     }
03671 
03672     treeOwnerAsWin->SetVisibility(PR_TRUE);
03673     nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
03674     if (embeddingWin)
03675       embeddingWin->SetFocus();
03676   }
03677 
03678   nsCOMPtr<nsIPresShell> presShell;
03679   if (mDocShell) {
03680     // Don't look for a presshell if we're a root chrome window that's got
03681     // about:blank loaded.  We don't want to focus our widget in that case.
03682     // XXXbz should we really be checking for IsInitialDocument() instead?
03683     PRBool lookForPresShell = PR_TRUE;
03684     PRInt32 itemType = nsIDocShellTreeItem::typeContent;
03685     nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
03686     NS_ASSERTION(treeItem, "What happened?");
03687     treeItem->GetItemType(&itemType);
03688     if (itemType == nsIDocShellTreeItem::typeChrome &&
03689         GetPrivateRoot() == NS_STATIC_CAST(nsIDOMWindowInternal*, this) &&
03690         mDocument) {
03691       nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
03692       NS_ASSERTION(doc, "Bogus doc?");
03693       nsIURI* ourURI = doc->GetDocumentURI();
03694       if (ourURI) {
03695         lookForPresShell = !IsAboutBlank(ourURI);
03696       }
03697     }
03698       
03699     if (lookForPresShell) {
03700       mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
03701     }
03702   }
03703 
03704   nsresult result = NS_OK;
03705   if (presShell && (canFocus || isActive)) {
03706     nsIViewManager* vm = presShell->GetViewManager();
03707     if (vm) {
03708       nsCOMPtr<nsIWidget> widget;
03709       vm->GetWidget(getter_AddRefs(widget));
03710       if (widget)
03711         // raise the window since this was a focus call on the window.
03712         result = widget->SetFocus(PR_TRUE);
03713     }
03714   }
03715   else {
03716     if (focusController) {
03717       focusController->SetFocusedWindow(this);
03718     }
03719   }
03720 
03721   return result;
03722 }
03723 
03724 NS_IMETHODIMP
03725 nsGlobalWindow::Blur()
03726 {
03727   FORWARD_TO_OUTER(Blur, (), NS_ERROR_NOT_INITIALIZED);
03728 
03729   nsresult rv = NS_ERROR_FAILURE;
03730 
03731   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
03732   GetTreeOwner(getter_AddRefs(treeOwner));
03733   nsCOMPtr<nsIEmbeddingSiteWindow2> siteWindow(do_GetInterface(treeOwner));
03734   if (siteWindow)
03735     // This method call may cause mDocShell to become nsnull.
03736     rv = siteWindow->Blur();
03737 
03738   if (NS_SUCCEEDED(rv) && mDocShell)
03739     mDocShell->SetHasFocus(PR_FALSE);
03740 
03741   return rv;
03742 }
03743 
03744 NS_IMETHODIMP
03745 nsGlobalWindow::Back()
03746 {
03747   FORWARD_TO_OUTER(Back, (), NS_ERROR_NOT_INITIALIZED);
03748 
03749   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
03750   NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
03751 
03752   return webNav->GoBack();
03753 }
03754 
03755 NS_IMETHODIMP
03756 nsGlobalWindow::Forward()
03757 {
03758   FORWARD_TO_OUTER(Forward, (), NS_ERROR_NOT_INITIALIZED);
03759 
03760   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
03761   NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
03762 
03763   return webNav->GoForward();
03764 }
03765 
03766 NS_IMETHODIMP
03767 nsGlobalWindow::Home()
03768 {
03769   FORWARD_TO_OUTER(Home, (), NS_ERROR_NOT_INITIALIZED);
03770 
03771   if (!mDocShell)
03772     return NS_OK;
03773 
03774   nsAdoptingString homeURL =
03775     nsContentUtils::GetLocalizedStringPref(PREF_BROWSER_STARTUP_HOMEPAGE);
03776 
03777   if (homeURL.IsEmpty()) {
03778     // if all else fails, use this
03779 #ifdef DEBUG_seth
03780     printf("all else failed.  using %s as the home page\n", DEFAULT_HOME_PAGE);
03781 #endif
03782     CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
03783   }
03784 
03785 #ifdef MOZ_PHOENIX
03786   {
03787     // Firefox lets the user specify multiple home pages to open in
03788     // individual tabs by separating them with '|'. Since we don't
03789     // have the machinery in place to easily open new tabs from here,
03790     // simply truncate the homeURL at the first '|' character to
03791     // prevent any possibilities of leaking the users list of home
03792     // pages to the first home page.
03793     //
03794     // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
03795     // fixed we can revisit this.
03796     PRInt32 firstPipe = homeURL.FindChar('|');
03797 
03798     if (firstPipe > 0) {
03799       homeURL.Truncate(firstPipe);
03800     }
03801   }
03802 #endif
03803 
03804   nsresult rv;
03805   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
03806   NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
03807   rv = webNav->LoadURI(homeURL.get(),
03808                        nsIWebNavigation::LOAD_FLAGS_NONE,
03809                        nsnull,
03810                        nsnull,
03811                        nsnull);
03812   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
03813   return NS_OK;
03814 }
03815 
03816 NS_IMETHODIMP
03817 nsGlobalWindow::Stop()
03818 {
03819   FORWARD_TO_OUTER(Stop, (), NS_ERROR_NOT_INITIALIZED);
03820 
03821   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
03822   if (!webNav)
03823     return NS_OK;
03824 
03825   return webNav->Stop(nsIWebNavigation::STOP_ALL);
03826 }
03827 
03828 NS_IMETHODIMP
03829 nsGlobalWindow::Print()
03830 {
03831   FORWARD_TO_OUTER(Print, (), NS_ERROR_NOT_INITIALIZED);
03832 
03833   nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
03834   if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
03835                                 getter_AddRefs(webBrowserPrint)))) {
03836 
03837     nsCOMPtr<nsIPrintSettingsService> printSettingsService = 
03838       do_GetService("@mozilla.org/gfx/printsettings-service;1");
03839 
03840     nsCOMPtr<nsIPrintSettings> printSettings;
03841     if (printSettingsService) {
03842       PRBool printSettingsAreGlobal =
03843         nsContentUtils::GetBoolPref("print.use_global_printsettings", PR_FALSE);
03844 
03845       if (printSettingsAreGlobal) {
03846         printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
03847 
03848         nsXPIDLString printerName;
03849         printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
03850         if (printerName)
03851           printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
03852         printSettingsService->InitPrintSettingsFromPrefs(printSettings, 
03853                                                          PR_TRUE, 
03854                                                          nsIPrintSettings::kInitSaveAll);
03855       } else {
03856         printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
03857       }
03858 
03859       webBrowserPrint->Print(printSettings, nsnull);
03860 
03861       PRBool savePrintSettings =
03862         nsContentUtils::GetBoolPref("print.save_print_settings", PR_FALSE);
03863       if (printSettingsAreGlobal && savePrintSettings) {
03864         printSettingsService->
03865           SavePrintSettingsToPrefs(printSettings,
03866                                    PR_TRUE,
03867                                    nsIPrintSettings::kInitSaveAll);
03868         printSettingsService->
03869           SavePrintSettingsToPrefs(printSettings,
03870                                    PR_FALSE,
03871                                    nsIPrintSettings::kInitSavePrinterName);
03872       }
03873     } else {
03874       webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
03875       webBrowserPrint->Print(printSettings, nsnull);
03876     }
03877   } 
03878 
03879   return NS_OK;
03880 }
03881 
03882 NS_IMETHODIMP
03883 nsGlobalWindow::MoveTo(PRInt32 aXPos, PRInt32 aYPos)
03884 {
03885   FORWARD_TO_OUTER(MoveTo, (aXPos, aYPos), NS_ERROR_NOT_INITIALIZED);
03886 
03887   /*
03888    * If caller is not chrome and dom.disable_window_move_resize is true,
03889    * prevent window.moveTo() by exiting early
03890    */
03891 
03892   if (!CanSetProperty("dom.disable_window_move_resize") || IsFrame()) {
03893     return NS_OK;
03894   }
03895   MaybeSuppressDrag();
03896 
03897   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
03898   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
03899   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
03900 
03901   NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aXPos, &aYPos),
03902                     NS_ERROR_FAILURE);
03903 
03904   NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(aXPos, aYPos),
03905                     NS_ERROR_FAILURE);
03906 
03907   return NS_OK;
03908 }
03909 
03910 NS_IMETHODIMP
03911 nsGlobalWindow::MoveBy(PRInt32 aXDif, PRInt32 aYDif)
03912 {
03913   FORWARD_TO_OUTER(MoveBy, (aXDif, aYDif), NS_ERROR_NOT_INITIALIZED);
03914 
03915   /*
03916    * If caller is not chrome and dom.disable_window_move_resize is true,
03917    * prevent window.moveBy() by exiting early
03918    */
03919 
03920   if (!CanSetProperty("dom.disable_window_move_resize") || IsFrame()) {
03921     return NS_OK;
03922   }
03923   MaybeSuppressDrag();
03924 
03925   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
03926   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
03927   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
03928 
03929   PRInt32 x, y;
03930   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y), NS_ERROR_FAILURE);
03931 
03932   PRInt32 newX = x + aXDif;
03933   PRInt32 newY = y + aYDif;
03934   NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&newX, &newY), NS_ERROR_FAILURE);
03935 
03936   NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(newX, newY),
03937                     NS_ERROR_FAILURE);
03938 
03939   return NS_OK;
03940 }
03941 
03942 NS_IMETHODIMP
03943 nsGlobalWindow::ResizeTo(PRInt32 aWidth, PRInt32 aHeight)
03944 {
03945   FORWARD_TO_OUTER(ResizeTo, (aWidth, aHeight), NS_ERROR_NOT_INITIALIZED);
03946 
03947   /*
03948    * If caller is not chrome and dom.disable_window_move_resize is true,
03949    * prevent window.resizeTo() by exiting early
03950    */
03951 
03952   if (!CanSetProperty("dom.disable_window_move_resize") || IsFrame()) {
03953     return NS_OK;
03954   }
03955   MaybeSuppressDrag();
03956 
03957   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
03958   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
03959   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
03960 
03961   NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aWidth, &aHeight),
03962                     NS_ERROR_FAILURE);
03963 
03964   NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(aWidth, aHeight, PR_TRUE),
03965                     NS_ERROR_FAILURE);
03966 
03967   return NS_OK;
03968 }
03969 
03970 NS_IMETHODIMP
03971 nsGlobalWindow::ResizeBy(PRInt32 aWidthDif, PRInt32 aHeightDif)
03972 {
03973   FORWARD_TO_OUTER(ResizeBy, (aWidthDif, aHeightDif), NS_ERROR_NOT_INITIALIZED);
03974 
03975   /*
03976    * If caller is not chrome and dom.disable_window_move_resize is true,
03977    * prevent window.resizeBy() by exiting early
03978    */
03979 
03980   if (!CanSetProperty("dom.disable_window_move_resize") || IsFrame()) {
03981     return NS_OK;
03982   }
03983   MaybeSuppressDrag();
03984 
03985   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
03986   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
03987   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
03988 
03989   PRInt32 cx, cy;
03990   NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&cx, &cy), NS_ERROR_FAILURE);
03991 
03992   PRInt32 newCX = cx + aWidthDif;
03993   PRInt32 newCY = cy + aHeightDif;
03994   NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&newCX, &newCY),
03995                     NS_ERROR_FAILURE);
03996 
03997   NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(newCX, newCY,
03998                                             PR_TRUE), NS_ERROR_FAILURE);
03999 
04000   return NS_OK;
04001 }
04002 
04003 NS_IMETHODIMP
04004 nsGlobalWindow::SizeToContent()
04005 {
04006   FORWARD_TO_OUTER(SizeToContent, (), NS_ERROR_NOT_INITIALIZED);
04007 
04008   if (!mDocShell) {
04009     return NS_OK;
04010   }
04011 
04012   /*
04013    * If caller is not chrome and dom.disable_window_move_resize is true,
04014    * block window.SizeToContent() by exiting
04015    */
04016 
04017   if (!CanSetProperty("dom.disable_window_move_resize") || IsFrame()) {
04018     return NS_OK;
04019   }
04020   MaybeSuppressDrag();
04021 
04022   // The content viewer does a check to make sure that it's a content
04023   // viewer for a toplevel docshell.
04024   
04025   nsCOMPtr<nsIContentViewer> cv;
04026   mDocShell->GetContentViewer(getter_AddRefs(cv));
04027   nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
04028   NS_ENSURE_TRUE(markupViewer, NS_ERROR_FAILURE);
04029   NS_ENSURE_SUCCESS(markupViewer->SizeToContent(), NS_ERROR_FAILURE);
04030 
04031   return NS_OK;
04032 }
04033 
04034 NS_IMETHODIMP
04035 nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
04036 {
04037   *aWindowRoot = nsnull;
04038 
04039   nsIDOMWindowInternal *rootWindow = nsGlobalWindow::GetPrivateRoot();
04040   nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
04041   if (!piWin) {
04042     return NS_OK;
04043   }
04044 
04045   nsIChromeEventHandler *chromeHandler = piWin->GetChromeEventHandler();
04046   if (!chromeHandler) {
04047     return NS_OK;
04048   }
04049 
04050   return CallQueryInterface(chromeHandler, aWindowRoot);
04051 }
04052 
04053 NS_IMETHODIMP
04054 nsGlobalWindow::Scroll(PRInt32 aXScroll, PRInt32 aYScroll)
04055 {
04056   return ScrollTo(aXScroll, aYScroll);
04057 }
04058 
04059 NS_IMETHODIMP
04060 nsGlobalWindow::ScrollTo(PRInt32 aXScroll, PRInt32 aYScroll)
04061 {
04062   nsresult result;
04063   nsIScrollableView *view = nsnull;      // no addref/release for views
04064   float p2t, t2p;
04065 
04066   FlushPendingNotifications(Flush_Layout);
04067   result = GetScrollInfo(&view, &p2t, &t2p);
04068 
04069   if (view) {
04070     // Here we calculate what the max pixel value is that we can
04071     // scroll to, we do this by dividing maxint with the pixel to
04072     // twips conversion factor, and substracting 4, the 4 comes from
04073     // experimenting with this value, anything less makes the view
04074     // code not scroll correctly, I have no idea why. -- jst
04075     const PRInt32 maxpx = (PRInt32)((float)0x7fffffff / p2t) - 4;
04076 
04077     if (aXScroll > maxpx) {
04078       aXScroll = maxpx;
04079     }
04080 
04081     if (aYScroll > maxpx) {
04082       aYScroll = maxpx;
04083     }
04084 
04085     result = view->ScrollTo(NSIntPixelsToTwips(aXScroll, p2t),
04086                             NSIntPixelsToTwips(aYScroll, p2t),
04087                             NS_VMREFRESH_IMMEDIATE);
04088   }
04089 
04090   return result;
04091 }
04092 
04093 NS_IMETHODIMP
04094 nsGlobalWindow::ScrollBy(PRInt32 aXScrollDif, PRInt32 aYScrollDif)
04095 {
04096   nsresult result;
04097   nsIScrollableView *view = nsnull;      // no addref/release for views
04098   float p2t, t2p;
04099 
04100   FlushPendingNotifications(Flush_Layout);
04101   result = GetScrollInfo(&view, &p2t, &t2p);
04102 
04103   if (view) {
04104     nscoord xPos, yPos;
04105     result = view->GetScrollPosition(xPos, yPos);
04106     if (NS_SUCCEEDED(result)) {
04107       result = ScrollTo(NSTwipsToIntPixels(xPos, t2p) + aXScrollDif,
04108                         NSTwipsToIntPixels(yPos, t2p) + aYScrollDif);
04109     }
04110   }
04111 
04112   return result;
04113 }
04114 
04115 NS_IMETHODIMP
04116 nsGlobalWindow::ScrollByLines(PRInt32 numLines)
04117 {
04118   nsresult result;
04119   nsIScrollableView *view = nsnull;   // no addref/release for views
04120   float p2t, t2p;
04121 
04122   FlushPendingNotifications(Flush_Layout);
04123   result = GetScrollInfo(&view, &p2t, &t2p);
04124   if (view) {
04125     result = view->ScrollByLines(0, numLines);
04126   }
04127 
04128   return result;
04129 }
04130 
04131 NS_IMETHODIMP
04132 nsGlobalWindow::ScrollByPages(PRInt32 numPages)
04133 {
04134   nsresult result;
04135   nsIScrollableView *view = nsnull;   // no addref/release for views
04136   float p2t, t2p;
04137 
04138   FlushPendingNotifications(Flush_Layout);
04139   result = GetScrollInfo(&view, &p2t, &t2p);
04140   if (view) {
04141     result = view->ScrollByPages(0, numPages);
04142   }
04143 
04144   return result;
04145 }
04146 
04147 NS_IMETHODIMP
04148 nsGlobalWindow::ClearTimeout()
04149 {
04150   return ClearTimeoutOrInterval();
04151 }
04152 
04153 NS_IMETHODIMP
04154 nsGlobalWindow::ClearInterval()
04155 {
04156   return ClearTimeoutOrInterval();
04157 }
04158 
04159 NS_IMETHODIMP
04160 nsGlobalWindow::SetTimeout(PRBool *_retval)
04161 {
04162   return SetTimeoutOrInterval(PR_FALSE, _retval);
04163 }
04164 
04165 NS_IMETHODIMP
04166 nsGlobalWindow::SetInterval(PRBool *_retval)
04167 {
04168   return SetTimeoutOrInterval(PR_TRUE, _retval);
04169 }
04170 
04171 NS_IMETHODIMP
04172 nsGlobalWindow::SetResizable(PRBool aResizable)
04173 {
04174   // nop
04175 
04176   return NS_OK;
04177 }
04178 
04179 static void
04180 ReportUseOfDeprecatedMethod(nsGlobalWindow* aWindow, const char* aWarning)
04181 {
04182   nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
04183   nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
04184                                   aWarning,
04185                                   nsnull, 0,
04186                                   doc ? doc->GetDocumentURI() : nsnull,
04187                                   EmptyString(), 0, 0,
04188                                   nsIScriptError::warningFlag,
04189                                   "DOM Events");
04190 }
04191 
04192 NS_IMETHODIMP
04193 nsGlobalWindow::CaptureEvents(PRInt32 aEventFlags)
04194 {
04195   ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
04196 
04197   nsCOMPtr<nsIEventListenerManager> manager;
04198 
04199   if (NS_SUCCEEDED(GetListenerManager(getter_AddRefs(manager)))) {
04200     manager->CaptureEvent(aEventFlags);
04201     return NS_OK;
04202   }
04203 
04204   return NS_ERROR_FAILURE;
04205 }
04206 
04207 NS_IMETHODIMP
04208 nsGlobalWindow::ReleaseEvents(PRInt32 aEventFlags)
04209 {
04210   ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
04211 
04212   nsCOMPtr<nsIEventListenerManager> manager;
04213 
04214   if (NS_SUCCEEDED(GetListenerManager(getter_AddRefs(manager)))) {
04215     manager->ReleaseEvent(aEventFlags);
04216     return NS_OK;
04217   }
04218 
04219   return NS_ERROR_FAILURE;
04220 }
04221 
04222 NS_IMETHODIMP
04223 nsGlobalWindow::RouteEvent(nsIDOMEvent* aEvt)
04224 {
04225   ReportUseOfDeprecatedMethod(this, "UseOfRouteEventWarning");
04226   return NS_OK;
04227 }
04228 
04229 NS_IMETHODIMP
04230 nsGlobalWindow::EnableExternalCapture()
04231 {
04232   return NS_ERROR_FAILURE;
04233 }
04234 
04235 NS_IMETHODIMP
04236 nsGlobalWindow::DisableExternalCapture()
04237 {
04238   return NS_ERROR_FAILURE;
04239 }
04240 
04241 static
04242 PRBool IsPopupBlocked(nsIDOMDocument* aDoc)
04243 {
04244   nsCOMPtr<nsIPopupWindowManager> pm =
04245     do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
04246 
04247   if (!pm) {
04248     return PR_FALSE;
04249   }
04250 
04251   PRBool blocked = PR_TRUE;
04252   nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
04253 
04254   if (doc) {
04255     PRUint32 permission = nsIPopupWindowManager::ALLOW_POPUP;
04256     pm->TestPermission(doc->GetDocumentURI(), &permission);
04257     blocked = (permission == nsIPopupWindowManager::DENY_POPUP);
04258   }
04259   return blocked;
04260 }
04261 
04262 static
04263 void FirePopupBlockedEvent(nsIDOMDocument* aDoc,
04264                            nsIDOMWindow *aRequestingWindow, nsIURI *aPopupURI,
04265                            const nsAString &aPopupWindowFeatures)
04266 {
04267   if (aDoc) {
04268     // Fire a "DOMPopupBlocked" event so that the UI can hear about
04269     // blocked popups.
04270     nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(aDoc));
04271     nsCOMPtr<nsIDOMEvent> event;
04272     docEvent->CreateEvent(NS_LITERAL_STRING("PopupBlockedEvents"),
04273                           getter_AddRefs(event));
04274     nsCOMPtr<nsIDOMPopupBlockedEvent_MOZILLA_1_8_BRANCH> pbev = 
04275       do_QueryInterface(event);
04276     if (pbev) {
04277       pbev->InitPopupBlockedEvent(NS_LITERAL_STRING("DOMPopupBlocked"),
04278                                   PR_TRUE, PR_TRUE, aRequestingWindow,
04279                                   aPopupURI, aPopupWindowFeatures);
04280       nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
04281       privateEvent->SetTrusted(PR_TRUE);
04282 
04283       nsCOMPtr<nsIDOMEventTarget> targ(do_QueryInterface(aDoc));
04284       PRBool defaultActionEnabled;
04285       targ->DispatchEvent(event, &defaultActionEnabled);
04286     }
04287   }
04288 }
04289 
04290 void FirePopupWindowEvent(nsIDOMDocument* aDoc)
04291 {
04292   if (aDoc) {
04293     // Fire a "PopupWindow" event
04294     nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(aDoc));
04295     nsCOMPtr<nsIDOMEvent> event;
04296     docEvent->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
04297     if (event) {
04298       event->InitEvent(NS_LITERAL_STRING("PopupWindow"), PR_TRUE, PR_TRUE);
04299 
04300       nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
04301       privateEvent->SetTrusted(PR_TRUE);
04302 
04303       PRBool defaultActionEnabled;
04304       nsCOMPtr<nsIDOMEventTarget> targ(do_QueryInterface(aDoc));
04305       targ->DispatchEvent(event, &defaultActionEnabled);
04306     }
04307   }
04308 }
04309 
04310 // static
04311 PRBool
04312 nsGlobalWindow::CanSetProperty(const char *aPrefName)
04313 {
04314   // Chrome can set any property.
04315   if (IsCallerChrome()) {
04316     return PR_TRUE;
04317   }
04318 
04319   // If the pref is set to true, we can not set the property
04320   // and vice versa.
04321   return !nsContentUtils::GetBoolPref(aPrefName, PR_TRUE);
04322 }
04323 
04324 
04325 /*
04326  * Examine the current document state to see if we're in a way that is
04327  * typically abused by web designers. The window.open code uses this
04328  * routine to determine whether to allow the new window.
04329  * Returns a value from the CheckForAbusePoint enum.
04330  */
04331 PopupControlState
04332 nsGlobalWindow::CheckForAbusePoint()
04333 {
04334   FORWARD_TO_OUTER(CheckForAbusePoint, (), openAbused);
04335 
04336   NS_ASSERTION(mDocShell, "Must have docshell");
04337   
04338   nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(mDocShell));
04339 
04340   NS_ASSERTION(item, "Docshell doesn't implenent nsIDocShellTreeItem?");
04341 
04342   PRInt32 type = nsIDocShellTreeItem::typeChrome;
04343   item->GetItemType(&type);
04344   if (type != nsIDocShellTreeItem::typeContent)
04345     return openAllowed;
04346 
04347   // level of abuse we've detected, initialized to the current popup
04348   // state
04349   PopupControlState abuse = gPopupControlState;
04350 
04351   // limit the number of simultaneously open popups
04352   if (abuse == openAbused || abuse == openControlled) {
04353     PRInt32 popupMax = nsContentUtils::GetIntPref("dom.popup_maximum", -1);
04354     if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
04355       abuse = openOverridden;
04356   }
04357 
04358   return abuse;
04359 }
04360 
04361 /* Allow or deny a window open based on whether popups are suppressed.
04362    A popup generally will be allowed if it's from a white-listed domain.
04363    Returns a value from the CheckOpenAllow enum. */
04364 OpenAllowValue
04365 nsGlobalWindow::CheckOpenAllow(PopupControlState aAbuseLevel)
04366 {
04367   NS_PRECONDITION(GetDocShell(), "Must have docshell");
04368 
04369   OpenAllowValue allowWindow = allowNoAbuse; // (also used for openControlled)
04370   
04371   if (aAbuseLevel >= openAbused) {
04372     allowWindow = allowNot;
04373 
04374     // However it might still not be blocked. For now we use both our
04375     // location and the top window's location when determining whether
04376     // a popup open request is whitelisted or not. This isn't ideal
04377     // when dealing with iframe/frame documents, but it'll do for
04378     // now. Getting the iframe/frame case right would require some
04379     // changes to the frontend's handling of popup events etc.
04380     if (aAbuseLevel == openAbused) {
04381       nsCOMPtr<nsIDOMWindow> topWindow;
04382       GetTop(getter_AddRefs(topWindow));
04383 
04384       nsCOMPtr<nsPIDOMWindow> topPIWin(do_QueryInterface(topWindow));
04385 
04386       if (topPIWin && (!IsPopupBlocked(topPIWin->GetExtantDocument()) ||
04387                        !IsPopupBlocked(mDocument))) {
04388         allowWindow = allowWhitelisted;
04389       }
04390     }
04391   }
04392 
04393   return allowWindow;
04394 }
04395 
04396 OpenAllowValue
04397 nsGlobalWindow::GetOpenAllow(const nsAString &aName)
04398 {
04399   NS_ENSURE_TRUE(GetDocShell(), allowNot);
04400   return CheckOpenAllow(CheckForAbusePoint());
04401 }
04402 
04403 /* If a window open is blocked, fire the appropriate DOM events.
04404    aBlocked signifies we just blocked a popup.
04405    aWindow signifies we just opened what is probably a popup.
04406 */
04407 void
04408 nsGlobalWindow::FireAbuseEvents(PRBool aBlocked, PRBool aWindow,
04409                                 const nsAString &aPopupURL,
04410                                 const nsAString &aPopupWindowFeatures)
04411 {
04412   // fetch the URI of the window requesting the opened window
04413 
04414   nsCOMPtr<nsIDOMWindow> topWindow;
04415   GetTop(getter_AddRefs(topWindow));
04416   if (!topWindow)
04417     return;
04418 
04419   nsCOMPtr<nsIDOMDocument> topDoc;
04420   topWindow->GetDocument(getter_AddRefs(topDoc));
04421 
04422   nsCOMPtr<nsIURI> popupURI;
04423 
04424   // build the URI of the would-have-been popup window
04425   // (see nsWindowWatcher::URIfromURL)
04426 
04427   // first, fetch the opener's base URI
04428 
04429   nsIURI *baseURL = 0;
04430 
04431   nsCOMPtr<nsIJSContextStack> stack = do_GetService(sJSStackContractID);
04432   nsCOMPtr<nsIDOMWindow> contextWindow;
04433   if (stack) {
04434     JSContext *cx = nsnull;
04435     stack->Peek(&cx);
04436     if (cx) {
04437       nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
04438       if (currentCX) {
04439         contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
04440       }
04441     }
04442   }
04443   if (!contextWindow)
04444     contextWindow = NS_STATIC_CAST(nsIDOMWindow*,this);
04445 
04446   nsCOMPtr<nsIDOMDocument> domdoc;
04447   contextWindow->GetDocument(getter_AddRefs(domdoc));
04448   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domdoc));
04449   if (doc)
04450     baseURL = doc->GetBaseURI();
04451 
04452   // use the base URI to build what would have been the popup's URI
04453   nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
04454   if (ios)
04455     ios->NewURI(NS_ConvertUCS2toUTF8(aPopupURL), 0, baseURL,
04456                 getter_AddRefs(popupURI));
04457 
04458   // fire an event chock full of informative URIs
04459   if (aBlocked)
04460     FirePopupBlockedEvent(topDoc, this, popupURI, aPopupWindowFeatures);
04461   if (aWindow)
04462     FirePopupWindowEvent(topDoc);
04463 }
04464 
04465 NS_IMETHODIMP
04466 nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
04467                      const nsAString& aOptions, nsIDOMWindow **_retval)
04468 {
04469   return OpenInternal(aUrl, aName, aOptions,
04470                       PR_FALSE,          // aDialog
04471                       PR_TRUE,           // aCalledNoScript
04472                       PR_FALSE,          // aDoJSFixups
04473                       nsnull, 0, nsnull, // No args
04474                       GetPrincipal(),    // aCalleePrincipal
04475                       _retval);
04476 }
04477 
04478 NS_IMETHODIMP
04479 nsGlobalWindow::Open(nsIDOMWindow **_retval)
04480 {
04481   *_retval = nsnull;
04482 
04483   nsCOMPtr<nsIXPCNativeCallContext> ncc;
04484 
04485   nsresult rv = nsContentUtils::XPConnect()->
04486     GetCurrentNativeCallContext(getter_AddRefs(ncc));
04487   NS_ENSURE_SUCCESS(rv, rv);
04488 
04489   if (!ncc)
04490     return NS_ERROR_NOT_AVAILABLE;
04491 
04492   JSContext *cx = nsnull;
04493 
04494   rv = ncc->GetJSContext(&cx);
04495   NS_ENSURE_SUCCESS(rv, rv);
04496 
04497   nsAutoString url, name, options;
04498 
04499   PRUint32 argc;
04500   jsval *argv = nsnull;
04501 
04502   ncc->GetArgc(&argc);
04503   ncc->GetArgvPtr(&argv);
04504 
04505   if (argc > 0) {
04506     nsJSUtils::ConvertJSValToString(url, cx, argv[0]);
04507 
04508     if (argc > 1) {
04509       nsJSUtils::ConvertJSValToString(name, cx, argv[1]);
04510 
04511       if (argc > 2) {
04512         nsJSUtils::ConvertJSValToString(options, cx, argv[2]);
04513       }
04514     }
04515   }
04516 
04517   return OpenInternal(url, name, options,
04518                       PR_FALSE,          // aDialog
04519                       PR_FALSE,          // aCalledNoScript
04520                       PR_TRUE,           // aDoJSFixups
04521                       nsnull, 0, nsnull, // No args
04522                       GetPrincipal(),    // aCalleePrincipal
04523                       _retval);
04524 }
04525 
04526 // like Open, but attaches to the new window any extra parameters past
04527 // [features] as a JS property named "arguments"
04528 NS_IMETHODIMP
04529 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
04530                            const nsAString& aOptions,
04531                            nsISupports* aExtraArgument, nsIDOMWindow** _retval)
04532 {
04533   return OpenInternal(aUrl, aName, aOptions,
04534                       PR_TRUE,                    // aDialog
04535                       PR_TRUE,                    // aCalledNoScript
04536                       PR_FALSE,                   // aDoJSFixups
04537                       nsnull, 0, aExtraArgument,  // Arguments
04538                       GetPrincipal(),             // aCalleePrincipal
04539                       _retval);
04540 }
04541 
04542 NS_IMETHODIMP
04543 nsGlobalWindow::OpenDialog(nsIDOMWindow** _retval)
04544 {
04545   if (!IsCallerChrome()) {
04546     return NS_ERROR_DOM_SECURITY_ERR;
04547   }
04548 
04549   nsCOMPtr<nsIXPCNativeCallContext> ncc;
04550   nsresult rv = nsContentUtils::XPConnect()->
04551     GetCurrentNativeCallContext(getter_AddRefs(ncc));
04552   NS_ENSURE_SUCCESS(rv, rv);
04553 
04554   if (!ncc)
04555     return NS_ERROR_NOT_AVAILABLE;
04556 
04557   JSContext *cx = nsnull;
04558 
04559   rv = ncc->GetJSContext(&cx);
04560   NS_ENSURE_SUCCESS(rv, rv);
04561 
04562   nsAutoString url, name, options;
04563 
04564   PRUint32 argc;
04565   jsval *argv = nsnull;
04566 
04567   ncc->GetArgc(&argc);
04568   ncc->GetArgvPtr(&argv);
04569 
04570   if (argc > 0) {
04571     nsJSUtils::ConvertJSValToString(url, cx, argv[0]);
04572 
04573     if (argc > 1) {
04574       nsJSUtils::ConvertJSValToString(name, cx, argv[1]);
04575 
04576       if (argc > 2) {
04577         nsJSUtils::ConvertJSValToString(options, cx, argv[2]);
04578       }
04579     }
04580   }
04581 
04582   return OpenInternal(url, name, options,
04583                       PR_TRUE,             // aDialog
04584                       PR_FALSE,            // aCalledNoScript
04585                       PR_FALSE,            // aDoJSFixups
04586                       argv, argc, nsnull,  // Arguments
04587                       GetPrincipal(),      // aCalleePrincipal
04588                       _retval);
04589 }
04590 
04591 NS_IMETHODIMP
04592 nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
04593 {
04594   FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
04595 
04596   *aFrames = this;
04597   NS_ADDREF(*aFrames);
04598 
04599   FlushPendingNotifications(Flush_ContentAndNotify);
04600 
04601   return NS_OK;
04602 }
04603 
04604 struct nsCloseEvent : public PLEvent {
04605   nsCloseEvent (nsGlobalWindow *aWindow)
04606     : mWindow(aWindow)
04607   {
04608   }
04609  
04610   void HandleEvent() {
04611     if (mWindow)
04612       mWindow->ReallyCloseWindow();
04613   }
04614 
04615   nsresult PostCloseEvent();
04616 
04617   nsRefPtr<nsGlobalWindow> mWindow;
04618 };
04619 
04620 static void PR_CALLBACK HandleCloseEvent(nsCloseEvent* aEvent)
04621 {
04622   aEvent->HandleEvent();
04623 }
04624 static void PR_CALLBACK DestroyCloseEvent(nsCloseEvent* aEvent)
04625 {
04626   delete aEvent;
04627 }
04628 
04629 nsresult
04630 nsCloseEvent::PostCloseEvent()
04631 {
04632   nsCOMPtr<nsIEventQueueService> eventService(do_GetService(kEventQueueServiceCID));
04633   if (eventService) {
04634     nsCOMPtr<nsIEventQueue> eventQueue;  
04635     eventService->GetThreadEventQueue(PR_GetCurrentThread(), getter_AddRefs(eventQueue));
04636     if (eventQueue) {
04637 
04638       PL_InitEvent(this, nsnull, (PLHandleEventProc) ::HandleCloseEvent, (PLDestroyEventProc) ::DestroyCloseEvent);
04639       return eventQueue->PostEvent(this);
04640     }
04641   }
04642 
04643   return NS_ERROR_FAILURE;
04644 }
04645 
04646 NS_IMETHODIMP
04647 nsGlobalWindow::Close()
04648 {
04649   FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
04650 
04651   if (IsFrame() || !mDocShell || IsInModalState()) {
04652     // window.close() is called on a frame in a frameset, on a window
04653     // that's already closed, or on a window for which there's
04654     // currently a modal dialog open. Ignore such calls.
04655 
04656     return NS_OK;
04657   }
04658 
04659   if (mHavePendingClose) {
04660     // We're going to be closed anyway; do nothing since we don't want
04661     // to double-close
04662     return NS_OK;
04663   }
04664 
04665   // Don't allow scripts from content to close windows
04666   // that were not opened by script
04667   nsresult rv = NS_OK;
04668   if (!mHadOriginalOpener) {
04669     PRBool allowClose = PR_FALSE;
04670 
04671     // UniversalBrowserWrite will be enabled if it's been explicitly
04672     // enabled, or if we're called from chrome.
04673     rv = sSecMan->IsCapabilityEnabled("UniversalBrowserWrite",
04674                                       &allowClose);
04675 
04676     if (NS_SUCCEEDED(rv) && !allowClose) {
04677       allowClose =
04678         nsContentUtils::GetBoolPref("dom.allow_scripts_to_close_windows",
04679                                     PR_TRUE);
04680       if (!allowClose) {
04681         // We're blocking the close operation
04682         // report localized error msg in JS console
04683         nsCOMPtr<nsIStringBundleService> stringBundleService =
04684           do_GetService(kCStringBundleServiceCID);
04685         if (stringBundleService) {
04686           nsCOMPtr<nsIStringBundle> stringBundle;
04687           stringBundleService->CreateBundle(kDOMSecurityWarningsBundleURL,
04688                                             getter_AddRefs(stringBundle));
04689           if (stringBundle) {
04690             nsXPIDLString errorMsg;
04691             rv = stringBundle->GetStringFromName(
04692                    NS_LITERAL_STRING("WindowCloseBlockedWarning").get(),
04693                    getter_Copies(errorMsg));
04694             if (NS_SUCCEEDED(rv)) {
04695               nsCOMPtr<nsIConsoleService> console =
04696                 do_GetService("@mozilla.org/consoleservice;1");
04697               if (console)
04698                 console->LogStringMessage(errorMsg.get());
04699             }
04700           }
04701         }
04702 
04703         return NS_OK;
04704       }
04705     }
04706   }
04707 
04708   // Ask the content viewer whether the toplevel window can close.
04709   // If the content viewer returns false, it is responsible for calling
04710   // Close() as soon as it is possible for the window to close.
04711   // This allows us to not close the window while printing is happening.
04712 
04713   nsCOMPtr<nsIContentViewer> cv;
04714   mDocShell->GetContentViewer(getter_AddRefs(cv));
04715   if (!mInClose && !mIsClosed && cv) {
04716     PRBool canClose;
04717 
04718     rv = cv->PermitUnload(&canClose);
04719     if (NS_SUCCEEDED(rv) && !canClose)
04720       return NS_OK;
04721 
04722     rv = cv->RequestWindowClose(&canClose);
04723     if (NS_SUCCEEDED(rv) && !canClose)
04724       return NS_OK;
04725   }
04726 
04727   // Fire a DOM event notifying listeners that this window is about to
04728   // be closed. The tab UI code may choose to cancel the default
04729   // action for this event, if so, we won't actually close the window
04730   // (since the tab UI code will close the tab in stead). Sure, this
04731   // could be abused by content code, but do we care? I don't think
04732   // so...
04733 
04734   PRBool wasInClose = mInClose;
04735   mInClose = PR_TRUE;
04736 
04737   if (!DispatchCustomEvent("DOMWindowClose")) {
04738     // Someone chose to prevent the default action for this event, if
04739     // so, let's not close this window after all...
04740 
04741     mInClose = wasInClose;
04742     return NS_OK;
04743   }
04744 
04745   // Flag that we were closed.
04746   mIsClosed = PR_TRUE;
04747 
04748   nsCOMPtr<nsIJSContextStack> stack =
04749     do_GetService(sJSStackContractID);
04750 
04751   JSContext *cx = nsnull;
04752 
04753   if (stack) {
04754     stack->Peek(&cx);
04755   }
04756 
04757   if (cx) {
04758     nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
04759 
04760     if (currentCX && currentCX == mContext) {
04761       // We ignore the return value here.  If setting the termination function
04762       // fails, it's better to fail to close the window than it is to crash
04763       // (which is what would tend to happen if we did this synchronously
04764       // here).
04765       rv = currentCX->SetTerminationFunction(CloseWindow,
04766                                              NS_STATIC_CAST(nsIDOMWindow *,
04767                                                             this));
04768       if (NS_SUCCEEDED(rv)) {
04769         mHavePendingClose = PR_TRUE;
04770       }
04771       return NS_OK;
04772     }
04773   }
04774 
04775   
04776   // We may have plugins on the page that have issued this close from their
04777   // event loop and because we currently destroy the plugin window with
04778   // frames, we crash. So, if we are called from Javascript, post an event
04779   // to really close the window.
04780   rv = NS_ERROR_FAILURE;
04781   if (!IsCallerChrome()) {
04782     nsCloseEvent *ev = new nsCloseEvent(this);
04783 
04784     if (ev) {
04785       rv = ev->PostCloseEvent();
04786 
04787       if (NS_FAILED(rv)) {
04788         PL_DestroyEvent(ev);
04789       }
04790     } else rv = NS_ERROR_OUT_OF_MEMORY;
04791   }
04792   
04793   if (NS_FAILED(rv)) {
04794     ReallyCloseWindow();
04795     rv = NS_OK;
04796   } else {
04797     mHavePendingClose = PR_TRUE;
04798   }
04799   
04800   return rv;
04801 }
04802 
04803 
04804 void
04805 nsGlobalWindow::ReallyCloseWindow()
04806 {
04807   FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
04808 
04809   // Make sure we never reenter this method.
04810   mHavePendingClose = PR_TRUE;
04811 
04812   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
04813   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
04814 
04815   // If there's no treeOwnerAsWin, this window must already be closed.
04816 
04817   if (treeOwnerAsWin) {
04818 
04819     // but if we're a browser window we could be in some nasty
04820     // self-destroying cascade that we should mostly ignore
04821 
04822     nsCOMPtr<nsIDocShellTreeItem> docItem(do_QueryInterface(mDocShell));
04823     if (docItem) {
04824       nsCOMPtr<nsIBrowserDOMWindow> bwin;
04825       nsCOMPtr<nsIDocShellTreeItem> rootItem;
04826       docItem->GetRootTreeItem(getter_AddRefs(rootItem));
04827       nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
04828       nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
04829       if (chromeWin)
04830         chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
04831 
04832       if (rootWin) {
04833         /* Normally we destroy the entire window, but not if
04834            this DOM window belongs to a tabbed browser and doesn't
04835            correspond to a tab. This allows a well-behaved tab
04836            to destroy the container as it should but is a final measure
04837            to prevent an errant tab from doing so when it shouldn't.
04838            This works because we reach this code when we shouldn't only
04839            in the particular circumstance that we belong to a tab
04840            that has just been closed (and is therefore already missing
04841            from the list of browsers) (and has an unload handler
04842            that closes the window). */
04843         // XXXbz now that we have mHavePendingClose, is this needed?
04844         PRBool isTab = PR_FALSE;
04845         if (rootWin == this ||
04846             !bwin || (bwin->IsTabContentWindow(GetOuterWindowInternal(),
04847                                                &isTab), isTab))
04848           treeOwnerAsWin->Destroy();
04849       }
04850     }
04851 
04852     CleanUp();
04853   }
04854 }
04855 
04856 void
04857 nsGlobalWindow::EnterModalState()
04858 {
04859   nsCOMPtr<nsIDOMWindow> top;
04860   GetTop(getter_AddRefs(top));
04861 
04862   if (!top) {
04863     NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
04864 
04865     return;
04866   }
04867 
04868   NS_STATIC_CAST(nsGlobalWindow *,
04869                  NS_STATIC_CAST(nsIDOMWindow *,
04870                                 top.get()))->mModalStateDepth++;
04871 }
04872 
04873 void
04874 nsGlobalWindow::LeaveModalState()
04875 {
04876   nsCOMPtr<nsIDOMWindow> top;
04877   GetTop(getter_AddRefs(top));
04878 
04879   if (!top) {
04880     NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
04881 
04882     return;
04883   }
04884 
04885   NS_STATIC_CAST(nsGlobalWindow *,
04886                  NS_STATIC_CAST(nsIDOMWindow *,
04887                                 top.get()))->mModalStateDepth--;
04888 }
04889 
04890 PRBool
04891 nsGlobalWindow::IsInModalState()
04892 {
04893   nsCOMPtr<nsIDOMWindow> top;
04894   GetTop(getter_AddRefs(top));
04895 
04896   if (!top) {
04897     NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
04898 
04899     return PR_FALSE;
04900   }
04901 
04902   return NS_STATIC_CAST(nsGlobalWindow *,
04903                         NS_STATIC_CAST(nsIDOMWindow *,
04904                                        top.get()))->mModalStateDepth != 0;
04905 }
04906 
04907 NS_IMETHODIMP
04908 nsGlobalWindow::GetFrameElement(nsIDOMElement** aFrameElement)
04909 {
04910   FORWARD_TO_OUTER(GetFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
04911 
04912   *aFrameElement = nsnull;
04913 
04914   nsCOMPtr<nsIDocShellTreeItem> docShellTI(do_QueryInterface(mDocShell));
04915 
04916   if (!docShellTI) {
04917     return NS_OK;
04918   }
04919 
04920   nsCOMPtr<nsIDocShellTreeItem> parent;
04921   docShellTI->GetSameTypeParent(getter_AddRefs(parent));
04922 
04923   if (!parent || parent == docShellTI) {
04924     // We're at a chrome boundary, don't expose the chrome iframe
04925     // element to content code.
04926 
04927     return NS_OK;
04928   }
04929 
04930   *aFrameElement = mFrameElement;
04931   NS_IF_ADDREF(*aFrameElement);
04932 
04933   return NS_OK;
04934 }
04935 
04936 NS_IMETHODIMP
04937 nsGlobalWindow::UpdateCommands(const nsAString& anAction)
04938 {
04939   nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
04940   if (!rootWindow)
04941     return NS_OK;
04942 
04943   nsCOMPtr<nsIDOMXULDocument> xulDoc =
04944     do_QueryInterface(rootWindow->GetExtantDocument());
04945   // See if we contain a XUL document.
04946   if (xulDoc) {
04947     // Retrieve the command dispatcher and call updateCommands on it.
04948     nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
04949     xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
04950     xulCommandDispatcher->UpdateCommands(anAction);
04951   }
04952 
04953   return NS_OK;
04954 }
04955 
04956 nsresult
04957 nsGlobalWindow::ConvertCharset(const nsAString& aStr, char** aDest)
04958 {
04959   nsresult result = NS_OK;
04960   nsCOMPtr<nsIUnicodeEncoder> encoder;
04961 
04962   nsCOMPtr<nsICharsetConverterManager>
04963     ccm(do_GetService(kCharsetConverterManagerCID));
04964   NS_ENSURE_TRUE(ccm, NS_ERROR_FAILURE);
04965 
04966   // Get the document character set
04967   nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
04968   if (mDocument) {
04969     nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
04970 
04971     if (doc)
04972       charset = doc->GetDocumentCharacterSet();
04973   }
04974 
04975   // Get an encoder for the character set
04976   result = ccm->GetUnicodeEncoderRaw(charset.get(),
04977                                      getter_AddRefs(encoder));
04978   if (NS_FAILED(result))
04979     return result;
04980 
04981   result = encoder->Reset();
04982   if (NS_FAILED(result))
04983     return result;
04984 
04985   PRInt32 maxByteLen, srcLen;
04986   srcLen = aStr.Length();
04987 
04988   const nsPromiseFlatString& flatSrc = PromiseFlatString(aStr);
04989   const PRUnichar* src = flatSrc.get();
04990 
04991   // Get the expected length of result string
04992   result = encoder->GetMaxLength(src, srcLen, &maxByteLen);
04993   if (NS_FAILED(result))
04994     return result;
04995 
04996   // Allocate a buffer of the maximum length
04997   *aDest = (char *) nsMemory::Alloc(maxByteLen + 1);
04998   PRInt32 destLen2, destLen = maxByteLen;
04999   if (!*aDest)
05000     return NS_ERROR_OUT_OF_MEMORY;
05001 
05002   // Convert from unicode to the character set
05003   result = encoder->Convert(src, &srcLen, *aDest, &destLen);
05004   if (NS_FAILED(result)) {    
05005     nsMemory::Free(*aDest);
05006     *aDest = nsnull;
05007     return result;
05008   }
05009 
05010   // Allow the encoder to finish the conversion
05011   destLen2 = maxByteLen - destLen;
05012   encoder->Finish(*aDest + destLen, &destLen2);
05013   (*aDest)[destLen + destLen2] = '\0';
05014 
05015   return result;
05016 }
05017 
05018 PRBool
05019 nsGlobalWindow::GetBlurSuppression()
05020 {
05021   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
05022   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
05023   PRBool suppress = PR_FALSE;
05024   if (treeOwnerAsWin)
05025     treeOwnerAsWin->GetBlurSuppression(&suppress);
05026   return suppress;
05027 }
05028 
05029 NS_IMETHODIMP
05030 nsGlobalWindow::GetSelection(nsISelection** aSelection)
05031 {
05032   FORWARD_TO_OUTER(GetSelection, (aSelection), NS_ERROR_NOT_INITIALIZED);
05033 
05034   NS_ENSURE_ARG_POINTER(aSelection);
05035   *aSelection = nsnull;
05036 
05037   if (!mDocShell)
05038     return NS_OK;
05039 
05040   nsCOMPtr<nsIPresShell> presShell;
05041   mDocShell->GetPresShell(getter_AddRefs(presShell));
05042 
05043   if (!presShell)
05044     return NS_OK;
05045 
05046   return presShell->FrameSelection()->
05047     GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection);
05048 }
05049 
05050 // Non-scriptable version of window.find(), part of nsIDOMWindowInternal
05051 NS_IMETHODIMP
05052 nsGlobalWindow::Find(const nsAString& aStr, PRBool aCaseSensitive,
05053                      PRBool aBackwards, PRBool aWrapAround, PRBool aWholeWord,
05054                      PRBool aSearchInFrames, PRBool aShowDialog,
05055                      PRBool *aDidFind)
05056 {
05057   return FindInternal(aStr, aCaseSensitive, aBackwards, aWrapAround,
05058                       aWholeWord, aSearchInFrames, aShowDialog, aDidFind);
05059 }
05060 
05061 // Scriptable version of window.find() which takes a variable number of
05062 // arguments, part of nsIDOMJSWindow.
05063 NS_IMETHODIMP
05064 nsGlobalWindow::Find(PRBool *aDidFind)
05065 {
05066   nsresult rv = NS_OK;
05067 
05068   // We get the arguments passed to the function using the XPConnect native
05069   // call context.
05070   nsCOMPtr<nsIXPCNativeCallContext> ncc;
05071 
05072   rv = nsContentUtils::XPConnect()->
05073     GetCurrentNativeCallContext(getter_AddRefs(ncc));
05074   NS_ENSURE_SUCCESS(rv, rv);
05075 
05076   NS_ASSERTION(ncc, "No Native Call Context."
05077                     "Please don't call this method from C++.");
05078   if (!ncc) {
05079     return NS_ERROR_NOT_AVAILABLE;
05080   }
05081 
05082   JSContext *cx = nsnull;
05083 
05084   rv = ncc->GetJSContext(&cx);
05085   NS_ENSURE_SUCCESS(rv, rv);
05086 
05087   PRUint32 argc;
05088   jsval *argv = nsnull;
05089 
05090   ncc->GetArgc(&argc);
05091   ncc->GetArgvPtr(&argv);
05092 
05093   // Parse the arguments passed to the function
05094   nsAutoString searchStr;
05095   PRBool caseSensitive  = PR_FALSE;
05096   PRBool backwards      = PR_FALSE;
05097   PRBool wrapAround     = PR_FALSE;
05098   PRBool showDialog     = PR_FALSE;
05099   PRBool wholeWord      = PR_FALSE;
05100   PRBool searchInFrames = PR_FALSE;
05101 
05102   if (argc > 0) {
05103     // First arg is the search pattern
05104     nsJSUtils::ConvertJSValToString(searchStr, cx, argv[0]);
05105   }
05106 
05107   if (argc > 1 && !JS_ValueToBoolean(cx, argv[1], &caseSensitive)) {
05108     // Second arg is the case sensitivity
05109     caseSensitive = PR_FALSE;
05110   }
05111 
05112   if (argc > 2 && !JS_ValueToBoolean(cx, argv[2], &backwards)) {
05113     // Third arg specifies whether to search backwards
05114     backwards = PR_FALSE;
05115   }
05116 
05117   if (argc > 3 && !JS_ValueToBoolean(cx, argv[3], &wrapAround)) {
05118     // Fourth arg specifies whether we should wrap the search
05119     wrapAround = PR_FALSE;
05120   }
05121 
05122   if (argc > 4 && !JS_ValueToBoolean(cx, argv[4], &wholeWord)) {
05123     // Fifth arg specifies whether we should show the Find dialog
05124     wholeWord = PR_FALSE;
05125   }
05126 
05127   if (argc > 5 && !JS_ValueToBoolean(cx, argv[5], &searchInFrames)) {
05128     // Sixth arg specifies whether we should search only for whole words
05129     searchInFrames = PR_FALSE;
05130   }
05131 
05132   if (argc > 6 && !JS_ValueToBoolean(cx, argv[6], &showDialog)) {
05133     // Seventh arg specifies whether we should search in all frames
05134     showDialog = PR_FALSE;
05135   }
05136 
05137   return FindInternal(searchStr, caseSensitive, backwards, wrapAround,
05138                       wholeWord, searchInFrames, showDialog, aDidFind);
05139 }
05140 
05141 nsresult
05142 nsGlobalWindow::FindInternal(const nsAString& aStr, PRBool caseSensitive,
05143                              PRBool backwards, PRBool wrapAround,
05144                              PRBool wholeWord, PRBool searchInFrames,
05145                              PRBool showDialog, PRBool *aDidFind)
05146 {
05147   FORWARD_TO_OUTER(FindInternal, (aStr, caseSensitive, backwards, wrapAround,
05148                                   wholeWord, searchInFrames, showDialog,
05149                                   aDidFind), NS_ERROR_NOT_INITIALIZED);
05150 
05151   NS_ENSURE_ARG_POINTER(aDidFind);
05152   nsresult rv = NS_OK;
05153   *aDidFind = PR_FALSE;
05154 
05155   nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
05156 
05157   // Set the options of the search
05158   rv = finder->SetSearchString(PromiseFlatString(aStr).get());
05159   NS_ENSURE_SUCCESS(rv, rv);
05160   finder->SetMatchCase(caseSensitive);
05161   finder->SetFindBackwards(backwards);
05162   finder->SetWrapFind(wrapAround);
05163   finder->SetEntireWord(wholeWord);
05164   finder->SetSearchFrames(searchInFrames);
05165 
05166   // the nsIWebBrowserFind is initialized to use this window
05167   // as the search root, but uses focus to set the current search
05168   // frame. If we're being called from JS (as here), this window
05169   // should be the current search frame.
05170   nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
05171   if (framesFinder) {
05172     framesFinder->SetRootSearchFrame(this);   // paranoia
05173     framesFinder->SetCurrentSearchFrame(this);
05174   }
05175   
05176   // The Find API does not accept empty strings. Launch the Find Dialog.
05177   if (aStr.IsEmpty() || showDialog) {
05178     // See if the find dialog is already up using nsIWindowMediator
05179     nsCOMPtr<nsIWindowMediator> windowMediator =
05180       do_GetService(kWindowMediatorCID);
05181 
05182     nsCOMPtr<nsIDOMWindowInternal> findDialog;
05183 
05184     if (windowMediator) {
05185       windowMediator->GetMostRecentWindow(NS_LITERAL_STRING("findInPage").get(),
05186                                           getter_AddRefs(findDialog));
05187     }
05188 
05189     if (findDialog) {
05190       // The Find dialog is already open, bring it to the top.
05191       rv = findDialog->Focus();
05192     } else { // Open a Find dialog
05193       if (finder) {
05194         nsCOMPtr<nsIDOMWindow> dialog;
05195         rv = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
05196                         NS_LITERAL_STRING("_blank"),
05197                         NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
05198                         finder, getter_AddRefs(dialog));
05199       }
05200     }
05201   } else {
05202     // Launch the search with the passed in search string
05203     rv = finder->FindNext(aDidFind);
05204     NS_ENSURE_SUCCESS(rv, rv);
05205   }
05206 
05207   return rv;
05208 }
05209 
05210 static PRBool
05211 Is8bit(const nsAString& aString)
05212 {
05213   static const PRUnichar EIGHT_BIT = PRUnichar(~0x00FF);
05214 
05215   nsAString::const_iterator done_reading;
05216   aString.EndReading(done_reading);
05217 
05218   // for each chunk of |aString|...
05219   PRUint32 fragmentLength = 0;
05220   nsAString::const_iterator iter;
05221   for (aString.BeginReading(iter); iter != done_reading;
05222        iter.advance(PRInt32(fragmentLength))) {
05223     fragmentLength = PRUint32(iter.size_forward());
05224     const PRUnichar* c = iter.get();
05225     const PRUnichar* fragmentEnd = c + fragmentLength;
05226 
05227     // for each character in this chunk...
05228     while (c < fragmentEnd)
05229       if (*c++ & EIGHT_BIT)
05230         return PR_FALSE;
05231   }
05232 
05233   return PR_TRUE;
05234 }
05235 
05236 NS_IMETHODIMP
05237 nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
05238                      nsAString& aBinaryData)
05239 {
05240   aBinaryData.Truncate();
05241 
05242   if (!Is8bit(aAsciiBase64String)) {
05243     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
05244   }
05245 
05246   char *base64 = ToNewCString(aAsciiBase64String);
05247   if (!base64) {
05248     return NS_ERROR_OUT_OF_MEMORY;
05249   }
05250 
05251   PRUint32 dataLen = aAsciiBase64String.Length();
05252 
05253   PRInt32 resultLen = dataLen;
05254   if (!aAsciiBase64String.IsEmpty() && base64[dataLen - 1] == '=') {
05255     if (aAsciiBase64String.Length() > 1 && base64[dataLen - 2] == '=') {
05256       resultLen = dataLen - 2;
05257     } else {
05258       resultLen = dataLen - 1;
05259     }
05260   }
05261 
05262   resultLen = ((resultLen * 3) / 4);
05263 
05264   char *bin_data = PL_Base64Decode(base64, dataLen,
05265                                    nsnull);
05266   if (!bin_data) {
05267     nsMemory::Free(base64);
05268 
05269     return NS_ERROR_OUT_OF_MEMORY;
05270   }
05271 
05272   CopyASCIItoUCS2(Substring(bin_data, bin_data + resultLen), aBinaryData);
05273 
05274   nsMemory::Free(base64);
05275   PR_Free(bin_data);
05276 
05277   return NS_OK;
05278 }
05279 
05280 NS_IMETHODIMP
05281 nsGlobalWindow::Btoa(const nsAString& aBinaryData,
05282                      nsAString& aAsciiBase64String)
05283 {
05284   aAsciiBase64String.Truncate();
05285 
05286   if (!Is8bit(aBinaryData)) {
05287     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
05288   }
05289 
05290   char *bin_data = ToNewCString(aBinaryData);
05291   if (!bin_data) {
05292     return NS_ERROR_OUT_OF_MEMORY;
05293   }
05294 
05295   PRInt32 resultLen = ((aBinaryData.Length() + 2) / 3) * 4;
05296 
05297   char *base64 = PL_Base64Encode(bin_data, aBinaryData.Length(), nsnull);
05298   if (!base64) {
05299     nsMemory::Free(bin_data);
05300 
05301     return NS_ERROR_OUT_OF_MEMORY;
05302   }
05303 
05304   CopyASCIItoUCS2(nsDependentCString(base64, resultLen), aAsciiBase64String);
05305 
05306   PR_Free(base64);
05307   nsMemory::Free(bin_data);
05308 
05309   return NS_OK;
05310 }
05311 
05312 //*****************************************************************************
05313 // nsGlobalWindow::nsIDOMEventTarget
05314 //*****************************************************************************
05315 
05316 NS_IMETHODIMP
05317 nsGlobalWindow::AddEventListener(const nsAString& aType,
05318                                  nsIDOMEventListener* aListener,
05319                                  PRBool aUseCapture)
05320 {
05321   FORWARD_TO_INNER_CREATE(AddEventListener, (aType, aListener, aUseCapture));
05322 
05323   nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
05324 
05325   return AddEventListener(aType, aListener, aUseCapture,
05326                           !nsContentUtils::IsChromeDoc(doc));
05327 }
05328 
05329 NS_IMETHODIMP
05330 nsGlobalWindow::RemoveEventListener(const nsAString& aType,
05331                                     nsIDOMEventListener* aListener,
05332                                     PRBool aUseCapture)
05333 {
05334   return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
05335 }
05336 
05337 NS_IMETHODIMP
05338 nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, PRBool* _retval)
05339 {
05340   FORWARD_TO_INNER(DispatchEvent, (aEvent, _retval), NS_OK);
05341 
05342   nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
05343   if (!doc) {
05344     return NS_ERROR_FAILURE;
05345   }
05346 
05347   // Obtain a presentation shell
05348   nsIPresShell *shell = doc->GetShellAt(0);
05349   if (!shell) {
05350     return NS_OK;
05351   }
05352 
05353   // Retrieve the context
05354   nsCOMPtr<nsPresContext> presContext = shell->GetPresContext();
05355   return presContext->EventStateManager()->
05356     DispatchNewEvent(GetOuterWindow(), aEvent, _retval);
05357 }
05358 
05359 //*****************************************************************************
05360 // nsGlobalWindow::nsIDOM3EventTarget
05361 //*****************************************************************************
05362 
05363 NS_IMETHODIMP
05364 nsGlobalWindow::AddGroupedEventListener(const nsAString & aType,
05365                                         nsIDOMEventListener *aListener,
05366                                         PRBool aUseCapture,
05367                                         nsIDOMEventGroup *aEvtGrp)
05368 {
05369   FORWARD_TO_INNER_CREATE(AddGroupedEventListener,
05370                           (aType, aListener, aUseCapture, aEvtGrp));
05371 
05372   nsCOMPtr<nsIEventListenerManager> manager;
05373 
05374   if (NS_SUCCEEDED(GetListenerManager(getter_AddRefs(manager)))) {
05375     PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
05376 
05377     manager->AddEventListenerByType(aListener, aType, flags, aEvtGrp);
05378     return NS_OK;
05379   }
05380   return NS_ERROR_FAILURE;
05381 }
05382 
05383 NS_IMETHODIMP
05384 nsGlobalWindow::RemoveGroupedEventListener(const nsAString & aType,
05385                                            nsIDOMEventListener *aListener,
05386                                            PRBool aUseCapture,
05387                                            nsIDOMEventGroup *aEvtGrp)
05388 {
05389   FORWARD_TO_INNER(RemoveGroupedEventListener,
05390                    (aType, aListener, aUseCapture, aEvtGrp),
05391                    NS_ERROR_NOT_INITIALIZED);
05392 
05393   if (mListenerManager) {
05394     PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
05395 
05396     mListenerManager->RemoveEventListenerByType(aListener, aType, flags,
05397                                                 aEvtGrp);
05398     return NS_OK;
05399   }
05400   return NS_ERROR_FAILURE;
05401 }
05402 
05403 NS_IMETHODIMP
05404 nsGlobalWindow::CanTrigger(const nsAString & type, PRBool *_retval)
05405 {
05406   return NS_ERROR_NOT_IMPLEMENTED;
05407 }
05408 
05409 NS_IMETHODIMP
05410 nsGlobalWindow::IsRegisteredHere(const nsAString & type, PRBool *_retval)
05411 {
05412   return NS_ERROR_NOT_IMPLEMENTED;
05413 }
05414 
05415 NS_IMETHODIMP
05416 nsGlobalWindow::AddEventListener(const nsAString& aType,
05417                                  nsIDOMEventListener *aListener,
05418                                  PRBool aUseCapture, PRBool aWantsUntrusted)
05419 {
05420   nsCOMPtr<nsIEventListenerManager> manager;
05421   nsresult rv = GetListenerManager(getter_AddRefs(manager));
05422   NS_ENSURE_SUCCESS(rv, rv);
05423 
05424   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
05425 
05426   if (aWantsUntrusted) {
05427     flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
05428   }
05429 
05430   return manager->AddEventListenerByType(aListener, aType, flags, nsnull);
05431 }
05432 
05433 
05434 //*****************************************************************************
05435 // nsGlobalWindow::nsIDOMEventReceiver
05436 //*****************************************************************************
05437 
05438 NS_IMETHODIMP
05439 nsGlobalWindow::AddEventListenerByIID(nsIDOMEventListener* aListener,
05440                                       const nsIID& aIID)
05441 {
05442   nsCOMPtr<nsIEventListenerManager> manager;
05443 
05444   if (NS_SUCCEEDED (GetListenerManager(getter_AddRefs(manager)))) {
05445     manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
05446     return NS_OK;
05447   }
05448   return NS_ERROR_FAILURE;
05449 }
05450 
05451 NS_IMETHODIMP
05452 nsGlobalWindow::RemoveEventListenerByIID(nsIDOMEventListener* aListener,
05453                                          const nsIID& aIID)
05454 {
05455   FORWARD_TO_INNER(RemoveEventListenerByIID, (aListener, aIID),
05456                    NS_ERROR_NOT_INITIALIZED);
05457 
05458   if (mListenerManager) {
05459     mListenerManager->RemoveEventListenerByIID(aListener, aIID,
05460                                                NS_EVENT_FLAG_BUBBLE);
05461     return NS_OK;
05462   }
05463   return NS_ERROR_FAILURE;
05464 }
05465 
05466 NS_IMETHODIMP
05467 nsGlobalWindow::GetListenerManager(nsIEventListenerManager **aResult)
05468 {
05469   FORWARD_TO_INNER_CREATE(GetListenerManager, (aResult));
05470 
05471   if (!mListenerManager) {
05472     static NS_DEFINE_CID(kEventListenerManagerCID,
05473                          NS_EVENTLISTENERMANAGER_CID);
05474     nsresult rv;
05475 
05476     mListenerManager = do_CreateInstance(kEventListenerManagerCID, &rv);
05477     NS_ENSURE_SUCCESS(rv, rv);
05478     mListenerManager->SetListenerTarget(
05479       NS_STATIC_CAST(nsIDOMEventReceiver*, this));
05480   }
05481 
05482   NS_ADDREF(*aResult = mListenerManager);
05483 
05484   return NS_OK;
05485 }
05486 
05487 NS_IMETHODIMP
05488 nsGlobalWindow::HandleEvent(nsIDOMEvent *aEvent)
05489 {
05490   PRBool defaultActionEnabled;
05491   return DispatchEvent(aEvent, &defaultActionEnabled);
05492 }
05493 
05494 NS_IMETHODIMP
05495 nsGlobalWindow::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
05496 {
05497   nsCOMPtr<nsIEventListenerManager> manager;
05498   if (NS_SUCCEEDED(GetListenerManager(getter_AddRefs(manager))) && manager) {
05499     return manager->GetSystemEventGroupLM(aGroup);
05500   }
05501   return NS_ERROR_FAILURE;
05502 }
05503 
05504 //*****************************************************************************
05505 // nsGlobalWindow::nsIDOMGCParticipant
05506 //*****************************************************************************
05507 
05508 nsIDOMGCParticipant*
05509 nsGlobalWindow::GetSCCIndex()
05510 {
05511   return this;
05512 }
05513 
05514 static void AppendToReachableList(nsISupports *aObject,
05515                                   nsCOMArray<nsIDOMGCParticipant>& aArray)
05516 {
05517   nsCOMPtr<nsIDOMGCParticipant> p = do_QueryInterface(aObject);
05518   if (p)
05519     aArray.AppendObject(p);
05520 }
05521 
05522 void
05523 nsGlobalWindow::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
05524 {
05525   AppendToReachableList(mChromeEventHandler, aArray);
05526   AppendToReachableList(mDocument, aArray);
05527   // XXXldb Do we want this to go both ways?
05528   if (IsOuterWindow()) {
05529     AppendToReachableList(mInnerWindow, aArray);
05530   } else {
05531     AppendToReachableList(mOuterWindow, aArray);
05532   }
05533 }
05534 
05535 //*****************************************************************************
05536 // nsGlobalWindow::nsPIDOMWindow
05537 //*****************************************************************************
05538 
05539 nsPIDOMWindow*
05540 nsGlobalWindow::GetPrivateParent()
05541 {
05542   FORWARD_TO_OUTER(GetPrivateParent, (), nsnull);
05543 
05544   nsCOMPtr<nsIDOMWindow> parent;
05545   GetParent(getter_AddRefs(parent));
05546 
05547   if (NS_STATIC_CAST(nsIDOMWindow *, this) == parent.get()) {
05548     nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
05549     if (!chromeElement)
05550       return nsnull;             // This is ok, just means a null parent.
05551 
05552     nsIDocument* doc = chromeElement->GetDocument();
05553     if (!doc)
05554       return nsnull;             // This is ok, just means a null parent.
05555 
05556     nsIScriptGlobalObject *globalObject = doc->GetScriptGlobalObject();
05557     if (!globalObject)
05558       return nsnull;             // This is ok, just means a null parent.
05559 
05560     parent = do_QueryInterface(globalObject);
05561   }
05562 
05563   if (parent) {
05564     return NS_STATIC_CAST(nsGlobalWindow *,
05565                           NS_STATIC_CAST(nsIDOMWindow*, parent.get()));
05566   }
05567 
05568   return nsnull;
05569 }
05570 
05571 nsPIDOMWindow*
05572 nsGlobalWindow::GetPrivateRoot()
05573 {
05574   FORWARD_TO_OUTER(GetPrivateRoot, (), nsnull);
05575 
05576   nsCOMPtr<nsIDOMWindow> parent;
05577   GetTop(getter_AddRefs(parent));
05578 
05579   nsCOMPtr<nsIScriptGlobalObject> parentTop = do_QueryInterface(parent);
05580   NS_ASSERTION(parentTop, "cannot get parentTop");
05581   if (!parentTop)
05582     return nsnull;
05583 
05584   nsIDocShell *docShell = parentTop->GetDocShell();
05585 
05586   // Get the chrome event handler from the doc shell, since we only
05587   // want to deal with XUL chrome handlers and not the new kind of
05588   // window root handler.
05589   nsCOMPtr<nsIChromeEventHandler> chromeEventHandler;
05590   docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
05591 
05592   nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
05593   if (chromeElement) {
05594     nsIDocument* doc = chromeElement->GetDocument();
05595     if (doc) {
05596       parent = do_QueryInterface(doc->GetScriptGlobalObject());
05597       if (parent) {
05598         nsCOMPtr<nsIDOMWindow> tempParent;
05599         parent->GetTop(getter_AddRefs(tempParent));
05600         tempParent.swap(parent);
05601       }
05602     }
05603   }
05604 
05605   return NS_STATIC_CAST(nsGlobalWindow *,
05606                         NS_STATIC_CAST(nsIDOMWindow *, parent));
05607 }
05608 
05609 
05610 NS_IMETHODIMP
05611 nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
05612 {
05613   FORWARD_TO_OUTER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
05614 
05615   *aLocation = nsnull;
05616 
05617   if (!mLocation && mDocShell) {
05618     mLocation = new nsLocation(mDocShell);
05619     if (!mLocation) {
05620       return NS_ERROR_OUT_OF_MEMORY;
05621     }
05622   }
05623 
05624   NS_IF_ADDREF(*aLocation = mLocation);
05625 
05626   return NS_OK;
05627 }
05628 
05629 nsresult
05630 nsGlobalWindow::GetObjectProperty(const PRUnichar *aProperty,
05631                                   nsISupports ** aObject)
05632 {
05633   FORWARD_TO_INNER(GetObjectProperty, (aProperty, aObject),
05634                    NS_ERROR_NOT_INITIALIZED);
05635 
05636   NS_ENSURE_TRUE(mJSObject, NS_ERROR_NOT_AVAILABLE);
05637 
05638   // Get JSContext from stack.
05639   nsCOMPtr<nsIThreadJSContextStack> stack(do_GetService(sJSStackContractID));
05640   NS_ENSURE_TRUE(stack, NS_ERROR_FAILURE);
05641 
05642   JSContext *cx;
05643   NS_ENSURE_SUCCESS(stack->Peek(&cx), NS_ERROR_FAILURE);
05644 
05645   if (!cx) {
05646     stack->GetSafeJSContext(&cx);
05647     NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
05648   }
05649 
05650   jsval propertyVal;
05651 
05652   if (!::JS_LookupUCProperty(cx, mJSObject,
05653                              NS_REINTERPRET_CAST(const jschar *, aProperty),
05654                              nsCRT::strlen(aProperty), &propertyVal)) {
05655     return NS_ERROR_FAILURE;
05656   }
05657 
05658   if (!nsJSUtils::ConvertJSValToXPCObject(aObject, NS_GET_IID(nsISupports),
05659                                           cx, propertyVal)) {
05660     return NS_ERROR_FAILURE;
05661   }
05662 
05663   return NS_OK;
05664 }
05665 
05666 nsresult
05667 nsGlobalWindow::Activate()
05668 {
05669   FORWARD_TO_OUTER(Activate, (), NS_ERROR_NOT_INITIALIZED);
05670 
05671 /*
05672    nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
05673    GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
05674    if(treeOwnerAsWin)
05675       treeOwnerAsWin->SetVisibility(PR_TRUE);
05676 
05677    nsCOMPtr<nsIPresShell> presShell;
05678    mDocShell->GetPresShell(getter_AddRefs(presShell));
05679    NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
05680 
05681    nsIViewManager* vm = presShell->GetViewManager();
05682    NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
05683 
05684    nsIView* rootView;
05685    vm->GetRootView(rootView);
05686    NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
05687 
05688    nsIWidget* widget = rootView->GetWidget();
05689    NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
05690 
05691    return widget->SetFocus();
05692  */
05693 
05694   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
05695   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
05696   if (treeOwnerAsWin) {
05697     PRBool isEnabled = PR_TRUE;
05698     if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
05699       NS_WARNING( "Should not try to activate a disabled window" );
05700       return NS_ERROR_FAILURE;
05701     }
05702 
05703     treeOwnerAsWin->SetVisibility(PR_TRUE);
05704   }
05705 
05706   nsCOMPtr<nsIPresShell> presShell;
05707   mDocShell->GetPresShell(getter_AddRefs(presShell));
05708   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
05709 
05710   nsIViewManager* vm = presShell->GetViewManager();
05711   NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
05712 
05713   nsIView *rootView;
05714   vm->GetRootView(rootView);
05715   NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
05716 
05717   // We're holding a STRONG REF to the widget to ensure it doesn't go away
05718   // during event processing
05719   nsCOMPtr<nsIWidget> widget = rootView->GetWidget();
05720   NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
05721 
05722   nsEventStatus status;
05723 
05724   nsGUIEvent guiEvent(PR_TRUE, NS_ACTIVATE, widget);
05725   guiEvent.time = PR_IntervalNow();
05726 
05727   vm->DispatchEvent(&guiEvent, &status);
05728 
05729   return NS_OK;
05730 }
05731 
05732 nsresult
05733 nsGlobalWindow::Deactivate()
05734 {
05735   FORWARD_TO_OUTER(Deactivate, (), NS_ERROR_NOT_INITIALIZED);
05736 
05737   nsCOMPtr<nsIPresShell> presShell;
05738   mDocShell->GetPresShell(getter_AddRefs(presShell));
05739   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
05740 
05741   nsIViewManager* vm = presShell->GetViewManager();
05742   NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
05743 
05744   nsIView *rootView;
05745   vm->GetRootView(rootView);
05746   NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
05747 
05748   // Hold a STRONG REF to keep the widget around during event processing
05749   nsCOMPtr<nsIWidget> widget = rootView->GetWidget();
05750   NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
05751 
05752   nsEventStatus status;
05753 
05754   nsGUIEvent guiEvent(PR_TRUE, NS_DEACTIVATE, widget);
05755   guiEvent.time = PR_IntervalNow();
05756 
05757   vm->DispatchEvent(&guiEvent, &status);
05758 
05759   return NS_OK;
05760 }
05761 
05762 nsIFocusController*
05763 nsGlobalWindow::GetRootFocusController()
05764 {
05765   nsIDOMWindowInternal *rootWindow = nsGlobalWindow::GetPrivateRoot();
05766   if (rootWindow) {
05767     // Obtain the chrome event handler.
05768     nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
05769     nsIChromeEventHandler *chromeHandler = piWin->GetChromeEventHandler();
05770     if (chromeHandler) {
05771       nsCOMPtr<nsPIWindowRoot> windowRoot(do_QueryInterface(chromeHandler));
05772       if (windowRoot) {
05773         nsCOMPtr<nsIFocusController> fc;
05774         windowRoot->GetFocusController(getter_AddRefs(fc));
05775         return fc;  // this reference is going away, but the root holds onto it
05776       }
05777     }
05778   }
05779   return nsnull;
05780 }
05781 
05782 //*****************************************************************************
05783 // nsGlobalWindow::nsIDOMViewCSS
05784 //*****************************************************************************
05785 
05786 NS_IMETHODIMP
05787 nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
05788                                  const nsAString& aPseudoElt,
05789                                  nsIDOMCSSStyleDeclaration** aReturn)
05790 {
05791   FORWARD_TO_OUTER(GetComputedStyle, (aElt, aPseudoElt, aReturn),
05792                    NS_ERROR_NOT_INITIALIZED);
05793 
05794   NS_ENSURE_ARG_POINTER(aReturn);
05795   *aReturn = nsnull;
05796 
05797   if (!aElt) {
05798     NS_ERROR("Don't call getComputedStyle with a null DOMElement reference!");
05799     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
05800   }
05801 
05802   if (!mDocShell) {
05803     return NS_OK;
05804   }
05805 
05806   nsCOMPtr<nsIPresShell> presShell;
05807   mDocShell->GetPresShell(getter_AddRefs(presShell));
05808 
05809   if (!presShell) {
05810     return NS_OK;
05811   }
05812 
05813   nsresult rv = NS_OK;
05814   nsCOMPtr<nsIComputedDOMStyle> compStyle;
05815 
05816   if (!sComputedDOMStyleFactory) {
05817     rv = CallGetClassObject("@mozilla.org/DOM/Level2/CSS/computedStyleDeclaration;1",
05818                             &sComputedDOMStyleFactory);
05819     NS_ENSURE_SUCCESS(rv, rv);
05820   }
05821 
05822   rv =
05823     sComputedDOMStyleFactory->CreateInstance(nsnull,
05824                                              NS_GET_IID(nsIComputedDOMStyle),
05825                                              getter_AddRefs(compStyle));
05826 
05827   NS_ENSURE_SUCCESS(rv, rv);
05828 
05829   rv = compStyle->Init(aElt, aPseudoElt, presShell);
05830   NS_ENSURE_SUCCESS(rv, rv);
05831 
05832   return compStyle->QueryInterface(NS_GET_IID(nsIDOMCSSStyleDeclaration),
05833                                    (void **) aReturn);
05834 }
05835 
05836 //*****************************************************************************
05837 // nsGlobalWindow::nsIDOMAbstractView
05838 //*****************************************************************************
05839 
05840 NS_IMETHODIMP
05841 nsGlobalWindow::GetDocument(nsIDOMDocumentView ** aDocumentView)
05842 {
05843   NS_ENSURE_ARG_POINTER(aDocumentView);
05844 
05845   nsresult rv = NS_OK;
05846 
05847   if (mDocument) {
05848     rv = mDocument->QueryInterface(NS_GET_IID(nsIDOMDocumentView),
05849                                    (void **) aDocumentView);
05850   }
05851   else {
05852     *aDocumentView = nsnull;
05853   }
05854 
05855   return rv;
05856 }
05857 
05858 //*****************************************************************************
05859 // nsGlobalWindow::nsIDOMStorageWindow
05860 //*****************************************************************************
05861 
05862 NS_IMETHODIMP
05863 nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
05864 {
05865   *aSessionStorage = nsnull;
05866 
05867   FORWARD_TO_INNER(GetSessionStorage, (aSessionStorage), NS_ERROR_UNEXPECTED);
05868 
05869   nsIPrincipal *principal = GetPrincipal();
05870   nsIDocShell *docShell = GetDocShell();
05871 
05872   if (!principal || !docShell) {
05873     return NS_OK;
05874   }
05875 
05876   nsCOMPtr<nsIURI> codebase;
05877   nsresult rv = principal->GetURI(getter_AddRefs(codebase));
05878 
05879   if (NS_FAILED(rv) || !codebase) {
05880     return NS_FAILED(rv) ? rv : NS_ERROR_DOM_NOT_SUPPORTED_ERR;
05881   }
05882 
05883   nsCOMPtr<nsIDocShell_MOZILLA_1_8_BRANCH> ds(do_QueryInterface(docShell));
05884   NS_ENSURE_TRUE(ds, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
05885 
05886   return ds->GetSessionStorageForURI(codebase, aSessionStorage);
05887 }
05888 
05889 NS_IMETHODIMP
05890 nsGlobalWindow::GetGlobalStorage(nsIDOMStorageList ** aGlobalStorage)
05891 {
05892   NS_ENSURE_ARG_POINTER(aGlobalStorage);
05893 
05894 #ifdef MOZ_STORAGE
05895   if (!gGlobalStorageList) {
05896     nsresult rv = NS_NewDOMStorageList(getter_AddRefs(gGlobalStorageList));
05897     NS_ENSURE_SUCCESS(rv, rv);
05898   }
05899 
05900   *aGlobalStorage = gGlobalStorageList;
05901   NS_IF_ADDREF(*aGlobalStorage);
05902 
05903   return NS_OK;
05904 #else
05905   return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
05906 #endif
05907 }
05908 
05909 //*****************************************************************************
05910 // nsGlobalWindow::nsIInterfaceRequestor
05911 //*****************************************************************************
05912 
05913 NS_IMETHODIMP
05914 nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
05915 {
05916   NS_ENSURE_ARG_POINTER(aSink);
05917   *aSink = nsnull;
05918 
05919   if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
05920     FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
05921 
05922     if (mDocShell) {
05923       nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(mDocShell));
05924       if (docCharset) {
05925         *aSink = docCharset;
05926         NS_ADDREF(((nsISupports *) *aSink));
05927       }
05928     }
05929   }
05930   else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
05931     FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
05932 
05933     if (mDocShell) {
05934       nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
05935       if (webNav) {
05936         *aSink = webNav;
05937         NS_ADDREF(((nsISupports *) *aSink));
05938       }
05939     }
05940   }
05941   else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
05942     FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
05943 
05944     if (mDocShell) {
05945       nsCOMPtr<nsIContentViewer> viewer;
05946       mDocShell->GetContentViewer(getter_AddRefs(viewer));
05947       if (viewer) {
05948         nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
05949         if (webBrowserPrint) {
05950           *aSink = webBrowserPrint;
05951           NS_ADDREF(((nsISupports *) *aSink));
05952         }
05953       }
05954     }
05955   }
05956   else if (aIID.Equals(NS_GET_IID(nsIScriptEventManager))) {
05957     nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
05958     if (doc) {
05959       nsIScriptEventManager* mgr = doc->GetScriptEventManager();
05960       if (mgr) {
05961         *aSink = mgr;
05962         NS_ADDREF(((nsISupports *) *aSink));
05963       }
05964     }
05965   }
05966   else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
05967     FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
05968 
05969     nsCOMPtr<nsISupports> utils(do_QueryReferent(mWindowUtils));
05970     if (utils) {
05971       *aSink = utils;
05972       NS_ADDREF(((nsISupports *) *aSink));
05973     } else {
05974       nsDOMWindowUtils *utilObj = new nsDOMWindowUtils(this);
05975       nsCOMPtr<nsISupports> utilsIfc =
05976                               NS_ISUPPORTS_CAST(nsIDOMWindowUtils *, utilObj);
05977       if (utilsIfc) {
05978         mWindowUtils = do_GetWeakReference(utilsIfc);
05979         *aSink = utilsIfc;
05980         NS_ADDREF(((nsISupports *) *aSink));
05981       }
05982     }
05983   }
05984   else {
05985     return QueryInterface(aIID, aSink);
05986   }
05987 
05988   return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
05989 }
05990 
05991 //*****************************************************************************
05992 // nsGlobalWindow::nsIObserver
05993 //*****************************************************************************
05994 
05995 NS_IMETHODIMP
05996 nsGlobalWindow::Observe(nsISupports *aSubject, const char *aTopic,
05997                         const PRUnichar *someData)
05998 {
05999   if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage-changed")) {
06000     nsIPrincipal *principal;
06001     nsresult rv;
06002 
06003     nsCOMPtr<nsIDocument> curDoc(do_QueryInterface(mDocument)); 
06004     if (!someData) {
06005       nsCOMPtr<nsIDOMStorage> storage;
06006       GetSessionStorage(getter_AddRefs(storage));
06007 
06008       if (storage != aSubject && !someData) {
06009         // A sessionStorage object changed, but not our session storage
06010         // object.
06011         return NS_OK;
06012       }
06013     } else if ((principal = GetPrincipal())) {
06014       // A global storage object changed, check to see if it's one
06015       // this window can access.
06016 
06017       nsCOMPtr<nsIURI> codebase;
06018       principal->GetURI(getter_AddRefs(codebase));
06019 
06020       if (!codebase) {
06021         return NS_OK;
06022       }
06023 
06024       nsCAutoString currentDomain;
06025       rv = codebase->GetAsciiHost(currentDomain);
06026       if (NS_FAILED(rv)) {
06027         return NS_OK;
06028       }
06029 
06030       if (!nsDOMStorageList::CanAccessDomain(nsDependentString(someData),
06031                                              NS_ConvertASCIItoUTF16(currentDomain))) {
06032         // This window can't reach the global storage object for the
06033         // domain for which the change happened, so don't fire any
06034         // events in this window.
06035 
06036         return NS_OK;
06037       }
06038     }
06039 
06040     nsAutoString domain(someData);
06041 
06042     if (IsFrozen()) {
06043       // This window is frozen, rather than firing the events here,
06044       // store the domain in which the change happened and fire the
06045       // events if we're ever thawed.
06046 
06047       if (!mPendingStorageEvents) {
06048         mPendingStorageEvents = new nsDataHashtable<nsStringHashKey, PRBool>;
06049         NS_ENSURE_TRUE(mPendingStorageEvents, NS_ERROR_OUT_OF_MEMORY);
06050 
06051         rv = mPendingStorageEvents->Init();
06052         NS_ENSURE_SUCCESS(rv, rv);
06053       }
06054 
06055       mPendingStorageEvents->Put(domain, PR_TRUE);
06056 
06057       return NS_OK;
06058     }
06059 
06060     nsRefPtr<nsDOMStorageEvent> event = new nsDOMStorageEvent(domain);
06061     NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
06062 
06063     rv = event->Init();
06064     NS_ENSURE_SUCCESS(rv, rv);
06065 
06066     nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
06067 
06068     nsCOMPtr<nsIDOMEventTarget> target;
06069 
06070     if (htmlDoc) {
06071       nsCOMPtr<nsIDOMHTMLElement> body;
06072       htmlDoc->GetBody(getter_AddRefs(body));
06073 
06074       target = do_QueryInterface(body);
06075     }
06076 
06077     if (!target) {
06078       target = this;
06079     }
06080 
06081     PRBool defaultActionEnabled;
06082     target->DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
06083   }
06084 
06085   return NS_OK;
06086 }
06087 
06088 PR_STATIC_CALLBACK(PLDHashOperator)
06089 FirePendingStorageEvents(const nsAString& aKey, PRBool aData, void *userArg)
06090 {
06091   nsGlobalWindow *win = NS_STATIC_CAST(nsGlobalWindow *, userArg);
06092 
06093   nsCOMPtr<nsIDOMStorage> storage;
06094   win->GetSessionStorage(getter_AddRefs(storage));
06095 
06096   if (storage) {
06097     win->Observe(storage, "dom-storage-changed",
06098                  aKey.IsEmpty() ? nsnull : PromiseFlatString(aKey).get());
06099   }
06100 
06101   return PL_DHASH_NEXT;
06102 }
06103 
06104 nsresult
06105 nsGlobalWindow::FireDelayedDOMEvents()
06106 {
06107   FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
06108 
06109   if (mPendingStorageEvents) {
06110     // Fire pending storage events.
06111     mPendingStorageEvents->EnumerateRead(FirePendingStorageEvents, this);
06112 
06113     delete mPendingStorageEvents;
06114     mPendingStorageEvents = nsnull;
06115   }
06116 
06117   nsCOMPtr<nsIDocShellTreeNode> node =
06118     do_QueryInterface(GetDocShell());
06119   if (node) {
06120     PRInt32 childCount = 0;
06121     node->GetChildCount(&childCount);
06122 
06123     for (PRInt32 i = 0; i < childCount; ++i) {
06124       nsCOMPtr<nsIDocShellTreeItem> childShell;
06125       node->GetChildAt(i, getter_AddRefs(childShell));
06126       NS_ASSERTION(childShell, "null child shell");
06127 
06128       nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
06129       if (pWin) {
06130         nsGlobalWindow *win =
06131           NS_STATIC_CAST(nsGlobalWindow*,
06132                          NS_STATIC_CAST(nsPIDOMWindow*, pWin));
06133         win->FireDelayedDOMEvents();
06134       }
06135     }
06136   }
06137 
06138   return NS_OK;
06139 }
06140 
06141 //*****************************************************************************
06142 // nsGlobalWindow: Window Control Functions
06143 //*****************************************************************************
06144 
06145 nsIDOMWindowInternal *
06146 nsGlobalWindow::GetParentInternal()
06147 {
06148   FORWARD_TO_OUTER(GetParentInternal, (), nsnull);
06149 
06150   nsIDOMWindowInternal *parentInternal = nsnull;
06151 
06152   nsCOMPtr<nsIDOMWindow> parent;
06153   GetParent(getter_AddRefs(parent));
06154 
06155   if (parent && parent != NS_STATIC_CAST(nsIDOMWindow *, this)) {
06156     nsCOMPtr<nsIDOMWindowInternal> tmp(do_QueryInterface(parent));
06157     NS_ASSERTION(parent, "Huh, parent not an nsIDOMWindowInternal?");
06158 
06159     parentInternal = tmp;
06160   }
06161 
06162   return parentInternal;
06163 }
06164 
06165 nsresult
06166 nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
06167                              const nsAString& aOptions, PRBool aDialog,
06168                              PRBool aCalledNoScript, PRBool aDoJSFixups,
06169                              jsval *argv, PRUint32 argc,
06170                              nsISupports *aExtraArgument,
06171                              nsIPrincipal *aCalleePrincipal,
06172                              nsIDOMWindow **aReturn)
06173 {
06174   FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
06175                                   aCalledNoScript, aDoJSFixups,
06176                                   argv, argc, aExtraArgument, aCalleePrincipal,
06177                                   aReturn),
06178                    NS_ERROR_NOT_INITIALIZED);
06179 
06180   NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
06181                   "Can't pass in arguments both ways");
06182   NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
06183                   "Can't pass JS args when called via the noscript methods");
06184   NS_PRECONDITION(!aDoJSFixups || !aCalledNoScript,
06185                   "JS fixups should not be done when called noscript");
06186 
06187   *aReturn = nsnull;
06188   
06189   nsCOMPtr<nsIWebBrowserChrome> chrome;
06190   GetWebBrowserChrome(getter_AddRefs(chrome));
06191   if (!chrome) {
06192     // No chrome means we don't want to go through with this open call
06193     // -- see nsIWindowWatcher.idl
06194     return NS_ERROR_NOT_AVAILABLE;
06195   }
06196 
06197   NS_ASSERTION(mDocShell, "Must have docshell here");
06198 
06199   const PRBool checkForPopup =
06200     !aDialog && !WindowExists(aName, !aCalledNoScript);
06201 
06202   nsCOMPtr<nsIURI> currentCodebase;
06203 
06204   if (aCalleePrincipal) {
06205     aCalleePrincipal->GetURI(getter_AddRefs(currentCodebase));
06206   }
06207 
06208   // Note: it's very important that this be an nsXPIDLCString, since we want
06209   // .get() on it to return nsnull until we write stuff to it.  The window
06210   // watcher expects a null URL string if there is no URL to load.
06211   nsXPIDLCString url;
06212   nsresult rv = NS_OK;
06213 
06214   // It's important to do this security check before determining whether this
06215   // window opening should be blocked, to ensure that we don't FireAbuseEvents
06216   // for a window opening that wouldn't have succeeded in the first place.
06217   if (!aUrl.IsEmpty()) {
06218     AppendUTF16toUTF8(aUrl, url);
06219 
06220     /* Check whether the URI is allowed, but not for dialogs --
06221        see bug 56851. The security of this function depends on
06222        window.openDialog being inaccessible from web scripts */
06223     if (url.get() && !aDialog)
06224       rv = SecurityCheckURL(url.get());
06225   }
06226 
06227   if (NS_FAILED(rv))
06228     return rv;
06229 
06230   // These next two variables are only accessed when checkForPopup is true
06231   PopupControlState abuseLevel;
06232   OpenAllowValue allowReason;
06233   if (checkForPopup) {
06234     abuseLevel = CheckForAbusePoint();
06235     allowReason = CheckOpenAllow(abuseLevel);
06236     if (allowReason == allowNot) {
06237       FireAbuseEvents(PR_TRUE, PR_FALSE, aUrl, aOptions);
06238       return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
06239     }
06240   }    
06241 
06242   nsCOMPtr<nsIDOMWindow> domReturn;
06243 
06244   nsCOMPtr<nsIWindowWatcher> wwatch =
06245     do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
06246   NS_ENSURE_TRUE(wwatch, rv);
06247 
06248   NS_ConvertUTF16toUTF8 options(aOptions);
06249   NS_ConvertUTF16toUTF8 name(aName);
06250 
06251   const char *options_ptr = aOptions.IsEmpty() ? nsnull : options.get();
06252   const char *name_ptr = aName.IsEmpty() ? nsnull : name.get();
06253 
06254   {
06255     // Reset popup state while opening a window to prevent the
06256     // current state from being active the whole time a modal
06257     // dialog is open.
06258     nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
06259 
06260     if (!aCalledNoScript) {
06261       nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
06262       NS_ASSERTION(pwwatch,
06263                    "Unable to open windows from JS because window watcher "
06264                    "is broken");
06265       NS_ENSURE_TRUE(pwwatch, NS_ERROR_UNEXPECTED);
06266         
06267       PRUint32 extraArgc = argc >= 3 ? argc - 3 : 0;
06268       rv = pwwatch->OpenWindowJS(this, url.get(), name_ptr, options_ptr,
06269                                  aDialog, extraArgc, argv + 3,
06270                                  getter_AddRefs(domReturn));
06271     } else {
06272       // Push a null JSContext here so that the window watcher won't screw us
06273       // up.  We do NOT want this case looking at the JS context on the stack
06274       // when searching.  Compare comments on
06275       // nsIDOMWindowInternal::OpenWindow and nsIWindowWatcher::OpenWindow.
06276       nsCOMPtr<nsIJSContextStack> stack =
06277         do_GetService(sJSStackContractID);
06278 
06279       if (stack) {
06280         rv = stack->Push(nsnull);
06281         NS_ENSURE_SUCCESS(rv, rv);
06282       }
06283         
06284       rv = wwatch->OpenWindow(this, url.get(), name_ptr, options_ptr,
06285                               aExtraArgument, getter_AddRefs(domReturn));
06286 
06287       if (stack) {
06288         JSContext* cx;
06289         stack->Pop(&cx);
06290         NS_ASSERTION(!cx, "Unexpected JSContext popped!");
06291       }
06292     }
06293   }
06294 
06295   NS_ENSURE_SUCCESS(rv, rv);
06296 
06297   // success!
06298 
06299   domReturn.swap(*aReturn);
06300 
06301   if (aDoJSFixups) {      
06302     nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
06303     if (!chrome_win) {
06304       // A new non-chrome window was created from a call to
06305       // window.open() from JavaScript, make sure there's a document in
06306       // the new window. We do this by simply asking the new window for
06307       // its document, this will synchronously create an empty document
06308       // if there is no document in the window.
06309 #ifdef DEBUG_jst
06310       {
06311         nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
06312 
06313         nsIDOMDocument *temp = pidomwin->GetExtantDocument();
06314 
06315         NS_ASSERTION(temp, "No document in new window!!!");
06316       }
06317 #endif
06318 
06319       nsCOMPtr<nsIDOMDocument> doc;
06320       (*aReturn)->GetDocument(getter_AddRefs(doc));
06321     }
06322   }
06323     
06324   if (checkForPopup) {
06325     if (abuseLevel >= openControlled) {
06326       nsGlobalWindow *opened = NS_STATIC_CAST(nsGlobalWindow *, *aReturn);
06327       if (!opened->IsPopupSpamWindow()) {
06328         opened->SetPopupSpamWindow(PR_TRUE);
06329         ++gOpenPopupSpamCount;
06330       }
06331     }
06332     if (abuseLevel >= openAbused)
06333       FireAbuseEvents(PR_FALSE, PR_TRUE, aUrl, aOptions);
06334   }
06335 
06336   // copy the session storage data over to the new window if
06337   // necessary.  If the new window has the same domain as this window
06338   // did at the beginning of this function, the session storage data
06339   // for that domain, and only that domain, is copied over.
06340   nsGlobalWindow *opened = NS_STATIC_CAST(nsGlobalWindow *, *aReturn);
06341   nsCOMPtr<nsIDocShell_MOZILLA_1_8_BRANCH> newDocShell =
06342     do_QueryInterface(opened->GetDocShell());
06343 
06344   if (currentCodebase && newDocShell && mDocShell && url.get()) {
06345     nsCOMPtr<nsIURI> newURI;
06346 
06347     JSContext       *cx;
06348     PRBool           freePass;
06349     BuildURIfromBase(url, getter_AddRefs(newURI), &freePass, &cx);
06350 
06351     if (newURI) {
06352       nsCAutoString thisDomain, newDomain;
06353       nsresult gethostrv = currentCodebase->GetAsciiHost(thisDomain);
06354       gethostrv |= newURI->GetAsciiHost(newDomain);
06355 
06356       if (NS_SUCCEEDED(gethostrv) && thisDomain.Equals(newDomain)) {
06357         nsCOMPtr<nsIDOMStorage> storage;
06358         newDocShell->GetSessionStorageForURI(currentCodebase,
06359                                              getter_AddRefs(storage));
06360         nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(storage);
06361         if (piStorage) {
06362           nsCOMPtr<nsIDOMStorage> newstorage = piStorage->Clone(newURI);
06363           newDocShell->AddSessionStorage(thisDomain, newstorage);
06364         }
06365       }
06366     }
06367   }
06368 
06369   return rv;
06370 }
06371 
06372 // static
06373 void
06374 nsGlobalWindow::CloseWindow(nsISupports *aWindow)
06375 {
06376   nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
06377 
06378   nsGlobalWindow* globalWin =
06379     NS_STATIC_CAST(nsGlobalWindow *,
06380                    NS_STATIC_CAST(nsPIDOMWindow*, win));
06381 
06382   // Need to post an event for closing, otherwise window and 
06383   // presshell etc. may get destroyed while creating frames, bug 338897.
06384   nsCloseEvent* ev = new nsCloseEvent(globalWin);
06385   if (ev) {
06386     if (NS_FAILED(ev->PostCloseEvent())) {
06387       PL_DestroyEvent(ev);
06388     }
06389   }
06390   // else if OOM, better not to close. That might cause a crash.
06391 }
06392 
06393 // static
06394 void
06395 nsGlobalWindow::ClearWindowScope(nsISupports *aWindow)
06396 {
06397   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aWindow));
06398 
06399   nsIScriptContext *scx = sgo->GetContext();
06400 
06401   if (scx) {
06402     JSContext *cx = (JSContext *)scx->GetNativeContext();
06403     JSObject *global = sgo->GetGlobalJSObject();
06404 
06405     if (global) {
06406       // Clear global and its prototype chain, but not Object.prototype.
06407       ::JS_ClearScope(cx, global);
06408       for (JSObject *o = ::JS_GetPrototype(cx, global), *next;
06409            o && (next = ::JS_GetPrototype(cx, o)); o = next)
06410         ::JS_ClearScope(cx, o);
06411       ::JS_ClearWatchPointsForObject(cx, global);
06412     }
06413 
06414     ::JS_ClearRegExpStatics(cx);
06415   }
06416 }
06417 
06418 //*****************************************************************************
06419 // nsGlobalWindow: Timeout Functions
06420 //*****************************************************************************
06421 
06422 static const char kSetIntervalStr[] = "setInterval";
06423 static const char kSetTimeoutStr[] = "setTimeout";
06424 
06425 nsresult
06426 nsGlobalWindow::SetTimeoutOrInterval(PRBool aIsInterval, PRInt32 *aReturn)
06427 {
06428   FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
06429                    NS_ERROR_NOT_INITIALIZED);
06430 
06431   nsIScriptContext *scx = GetContextInternal();
06432 
06433   if (!scx) {
06434     // This window was already closed, or never properly initialized,
06435     // don't let a timer be scheduled on such a window.
06436 
06437     return NS_ERROR_NOT_INITIALIZED;
06438   }
06439 
06440   nsCOMPtr<nsIXPCNativeCallContext> ncc;
06441   nsresult rv = nsContentUtils::XPConnect()->
06442     GetCurrentNativeCallContext(getter_AddRefs(ncc));
06443   NS_ENSURE_SUCCESS(rv, rv);
06444 
06445   if (!ncc)
06446     return NS_ERROR_NOT_AVAILABLE;
06447 
06448   JSContext *cx = nsnull;
06449 
06450   rv = ncc->GetJSContext(&cx);
06451   NS_ENSURE_SUCCESS(rv, rv);
06452 
06453   PRUint32 argc;
06454   jsval *argv = nsnull;
06455 
06456   ncc->GetArgc(&argc);
06457   ncc->GetArgvPtr(&argv);
06458 
06459   JSString *expr = nsnull;
06460   JSObject *funobj = nsnull;
06461   nsTimeout *timeout;
06462   jsdouble interval = 0.0;
06463 
06464   if (argc < 1) {
06465     ::JS_ReportError(cx, "Function %s requires at least 1 parameter",
06466                      aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
06467 
06468     return ncc->SetExceptionWasThrown(PR_TRUE);
06469   }
06470 
06471   if (argc > 1 && !::JS_ValueToNumber(cx, argv[1], &interval)) {
06472     ::JS_ReportError(cx,
06473                      "Second argument to %s must be a millisecond interval",
06474                      aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
06475 
06476     return ncc->SetExceptionWasThrown(PR_TRUE);
06477   }
06478 
06479   switch (::JS_TypeOfValue(cx, argv[0])) {
06480   case JSTYPE_FUNCTION:
06481     funobj = JSVAL_TO_OBJECT(argv[0]);
06482     break;
06483 
06484   case JSTYPE_STRING:
06485   case JSTYPE_OBJECT:
06486     expr = ::JS_ValueToString(cx, argv[0]);
06487     if (!expr)
06488       return NS_ERROR_OUT_OF_MEMORY;
06489     argv[0] = STRING_TO_JSVAL(expr);
06490     break;
06491 
06492   default:
06493     ::JS_ReportError(cx, "useless %s call (missing quotes around argument?)",
06494                      aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
06495 
06496     return ncc->SetExceptionWasThrown(PR_TRUE);
06497   }
06498 
06499   // If we don't have a document (we could have been unloaded since
06500   // the call to setTimeout was made), do nothing.
06501   if (!mDocument) {
06502     return NS_OK;
06503   }
06504 
06505   if (interval < DOM_MIN_TIMEOUT_VALUE) {
06506     // Don't allow timeouts less than DOM_MIN_TIMEOUT_VALUE from
06507     // now...
06508 
06509     interval = DOM_MIN_TIMEOUT_VALUE;
06510   }
06511 
06512   // Make sure we don't proceed with a interval larger than our timer
06513   // code can handle.
06514   if (interval > PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE)) {
06515     interval = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
06516   }
06517 
06518   timeout = new nsTimeout();
06519   if (!timeout)
06520     return NS_ERROR_OUT_OF_MEMORY;
06521 
06522   // Increment the timeout's reference count to represent this function's hold
06523   // on the timeout.
06524   timeout->AddRef();
06525 
06526   if (aIsInterval) {
06527     timeout->mInterval = (PRInt32)interval;
06528   }
06529 
06530   if (expr) {
06531     if (!::JS_AddNamedRoot(cx, &timeout->mExpr, "timeout.mExpr")) {
06532       timeout->Release(scx);
06533 
06534       return NS_ERROR_OUT_OF_MEMORY;
06535     }
06536 
06537     timeout->mExpr = expr;
06538   } else if (funobj) {
06539     // Leave an extra slot for a secret final argument that
06540     // indicates to the called function how "late" the timeout is.
06541     timeout->mArgv =
06542       (jsval *) PR_MALLOC(((argc > 1) ? argc - 1 : 1) * sizeof(jsval));
06543 
06544     if (!timeout->mArgv) {
06545       timeout->Release(scx);
06546 
06547       return NS_ERROR_OUT_OF_MEMORY;
06548     }
06549 
06550     if (!::JS_AddNamedRoot(cx, &timeout->mFunObj, "timeout.mFunObj")) {
06551       timeout->Release(scx);
06552 
06553       return NS_ERROR_FAILURE;
06554     }
06555 
06556     timeout->mFunObj = funobj;
06557     timeout->mArgc = 0;
06558 
06559     for (PRInt32 i = 2; (PRUint32)i < argc; ++i) {
06560       timeout->mArgv[i - 2] = argv[i];
06561 
06562       if (!::JS_AddNamedRoot(cx, &timeout->mArgv[i - 2], "timeout.mArgv[i]")) {
06563         timeout->Release(scx);
06564 
06565         return NS_ERROR_FAILURE;
06566       }
06567 
06568       timeout->mArgc++;
06569     }
06570   }
06571 
06572   nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
06573 
06574   const char *filename;
06575   if (nsJSUtils::GetCallingLocation(cx, &filename, &timeout->mLineNo,
06576                                     ourPrincipal)) {
06577     timeout->mFileName = PL_strdup(filename);
06578 
06579     if (!timeout->mFileName) {
06580       timeout->Release(scx);
06581 
06582       return NS_ERROR_OUT_OF_MEMORY;
06583     }
06584   }
06585 
06586   timeout->mVersion = ::JS_VersionToString(::JS_GetVersion(cx));
06587 
06588   // Get principal of currently executing code, save for execution of timeout.
06589   // If either our principals subsume the subject principal, or we're from the
06590   // same origin, then use the subject principal. Otherwise, use our principal
06591   // to avoid running script in elevated principals.
06592 
06593   nsCOMPtr<nsIPrincipal> subjectPrincipal;
06594   rv = sSecMan->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
06595   if (NS_FAILED(rv)) {
06596     timeout->Release(scx);
06597 
06598     return NS_ERROR_FAILURE;
06599   }
06600 
06601   PRBool subsumes = PR_FALSE;
06602 
06603   // Note the direction of this test: We don't allow chrome setTimeouts on
06604   // content windows, but we do allow content setTimeouts on chrome windows.
06605   rv = ourPrincipal->Subsumes(subjectPrincipal, &subsumes);
06606   if (NS_FAILED(rv)) {
06607     timeout->Release(scx);
06608 
06609     return NS_ERROR_FAILURE;
06610   }
06611 
06612   if (subsumes) {
06613     timeout->mPrincipal = subjectPrincipal;
06614   } else {
06615     // Subsumes does a very strict equality test. Allow sites of the same origin
06616     // to set timeouts on each other.
06617 
06618     rv = sSecMan->CheckSameOriginPrincipal(subjectPrincipal, ourPrincipal);
06619     timeout->mPrincipal = NS_SUCCEEDED(rv) ? subjectPrincipal : ourPrincipal;
06620     rv = NS_OK;
06621   }
06622 
06623   PRTime delta = (PRTime)interval * PR_USEC_PER_MSEC;
06624 
06625   if (!IsFrozen()) {
06626     // If we're not currently frozen, then we set timeout->mWhen to be the
06627     // actual firing time of the timer (i.e., now + delta). We also actually
06628     // create a timer and fire it off.
06629 
06630     timeout->mWhen = PR_Now() + delta;
06631 
06632     timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
06633     if (NS_FAILED(rv)) {
06634       timeout->Release(scx);
06635 
06636       return rv;
06637     }
06638 
06639     rv = timeout->mTimer->InitWithFuncCallback(TimerCallback, timeout,
06640                                                (PRInt32)interval,
06641                                                nsITimer::TYPE_ONE_SHOT);
06642     if (NS_FAILED(rv)) {
06643       timeout->Release(scx);
06644 
06645       return rv;
06646     }
06647 
06648     // The timeout is now also held in the timer's closure.
06649     timeout->AddRef();
06650   } else {
06651     // If we are frozen, however, then we instead simply set timeout->mWhen to
06652     // be the "time remaining" in the timeout (i.e., the interval itself). We
06653     // don't create a timer for it, since that will happen when we are thawed
06654     // and the timeout will then get a timer and run to completion.
06655 
06656     timeout->mWhen = delta;
06657   }
06658 
06659   timeout->mWindow = this;
06660   NS_ADDREF(timeout->mWindow);
06661 
06662   // No popups from timeouts by default
06663   timeout->mPopupState = openAbused;
06664 
06665   if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
06666     // This timeout is *not* set from another timeout and it's set
06667     // while popups are enabled. Propagate the state to the timeout if
06668     // its delay (interval) is equal to or less than what
06669     // "dom.disable_open_click_delay" is set to (in ms).
06670 
06671     PRInt32 delay =
06672       nsContentUtils::GetIntPref("dom.disable_open_click_delay");
06673 
06674     if (interval <= delay) {
06675       timeout->mPopupState = gPopupControlState;
06676     }
06677   }
06678 
06679   InsertTimeoutIntoList(mTimeoutInsertionPoint, timeout);
06680 
06681   timeout->mPublicId = ++mTimeoutPublicIdCounter;
06682   *aReturn = timeout->mPublicId;
06683 
06684   // Our hold on the timeout is expiring. Note that this should not actually
06685   // free the timeout (since the list should have taken ownership as well).
06686   timeout->Release(scx);
06687 
06688   return NS_OK;
06689 }
06690 
06691 // static
06692 void
06693 nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
06694 {
06695   NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
06696   NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
06697 
06698   // Make sure that the script context doesn't go away as a result of
06699   // running timeouts
06700   nsCOMPtr<nsIScriptContext> scx = GetContextInternal();
06701 
06702   if (!scx) {
06703     // No context means this window was closed or never properly
06704     // initialized.
06705 
06706     return;
06707   }
06708 
06709   if (!scx->GetScriptsEnabled()) {
06710     // Scripts were enabled once in this window (unless aTimeout ==
06711     // nsnull) but now scripts are disabled (we might be in
06712     // print-preview, for instance), this means we shouldn't run any
06713     // timeouts at this point.
06714     //
06715     // If scripts are enabled in this window again we'll fire the
06716     // timeouts that are due at that point.
06717 
06718     return;
06719   }
06720 
06721   nsTimeout *next, *prev, *timeout;
06722   nsTimeout *last_expired_timeout, **last_insertion_point;
06723   nsTimeout dummy_timeout;
06724   JSContext *cx;
06725   PRUint32 firingDepth = mTimeoutFiringDepth + 1;
06726 
06727   // Make sure that the window and the script context don't go away as
06728   // a result of running timeouts
06729   nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
06730 
06731   cx = (JSContext *)scx->GetNativeContext();
06732 
06733   // A native timer has gone off. See which of our timeouts need
06734   // servicing
06735   PRTime now = PR_Now();
06736   PRTime deadline;
06737 
06738   if (aTimeout && aTimeout->mWhen > now) {
06739     // The OS timer fired early (yikes!), and possibly out of order
06740     // too. Set |deadline| to be the time when the OS timer *should*
06741     // have fired so that any timers that *should* have fired before
06742     // aTimeout *will* be fired now. This happens most of the time on
06743     // Win2k.
06744 
06745     deadline = aTimeout->mWhen;
06746   } else {
06747     deadline = now;
06748   }
06749 
06750   // The timeout list is kept in deadline order. Discover the latest
06751   // timeout whose deadline has expired. On some platforms, native
06752   // timeout events fire "early", so we need to test the timer as well
06753   // as the deadline.
06754   last_expired_timeout = nsnull;
06755   for (timeout = mTimeouts; timeout; timeout = timeout->mNext) {
06756     if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
06757         (timeout->mFiringDepth == 0)) {
06758       // Mark any timeouts that are on the list to be fired with the
06759       // firing depth so that we can reentrantly run timeouts
06760       timeout->mFiringDepth = firingDepth;
06761       last_expired_timeout = timeout;
06762     }
06763   }
06764 
06765   // Maybe the timeout that the event was fired for has been deleted
06766   // and there are no others timeouts with deadlines that make them
06767   // eligible for execution yet. Go away.
06768   if (!last_expired_timeout) {
06769     return;
06770   }
06771 
06772   // Insert a dummy timeout into the list of timeouts between the
06773   // portion of the list that we are about to process now and those
06774   // timeouts that will be processed in a future call to
06775   // win_run_timeout(). This dummy timeout serves as the head of the
06776   // list for any timeouts inserted as a result of running a timeout.
06777   dummy_timeout.mFiringDepth = firingDepth;
06778   dummy_timeout.mNext = last_expired_timeout->mNext;
06779   last_expired_timeout->mNext = &dummy_timeout;
06780 
06781   // Don't let ClearWindowTimeouts throw away our stack-allocated
06782   // dummy timeout.
06783   dummy_timeout.AddRef();
06784   dummy_timeout.AddRef();
06785 
06786   last_insertion_point = mTimeoutInsertionPoint;
06787   mTimeoutInsertionPoint = &dummy_timeout.mNext;
06788 
06789   prev = nsnull;
06790   for (timeout = mTimeouts; timeout != &dummy_timeout && !IsFrozen(); timeout = next) {
06791     next = timeout->mNext;
06792 
06793     if (timeout->mFiringDepth != firingDepth) {
06794       // We skip the timeout since it's on the list to run at another
06795       // depth.
06796 
06797       prev = timeout;
06798 
06799       continue;
06800     }
06801 
06802     // The timeout is on the list to run at this depth, go ahead and
06803     // process it.
06804 
06805     nsTimeout *last_running_timeout = mRunningTimeout;
06806     mRunningTimeout = timeout;
06807     timeout->mRunning = PR_TRUE;
06808 
06809     // Push this timeout's popup control state, which should only be
06810     // eabled the first time a timeout fires that was created while
06811     // popups were enabled and with a delay less than
06812     // "dom.disable_open_click_delay".
06813     nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
06814 
06815     // Clear the timeout's popup state, if any, to prevent interval
06816     // timeouts from repeatedly opening poups.
06817     timeout->mPopupState = openAbused;
06818 
06819     // Hold on to the timeout in case mExpr or mFunObj releases its
06820     // doc.
06821     timeout->AddRef();
06822 
06823     ++gRunningTimeoutDepth;
06824     ++mTimeoutFiringDepth;
06825 
06826     if (timeout->mExpr) {
06827       // Evaluate the timeout expression.
06828       const PRUnichar *script =
06829         NS_REINTERPRET_CAST(const PRUnichar *,
06830                             ::JS_GetStringChars(timeout->mExpr));
06831 
06832       PRBool is_undefined;
06833       scx->EvaluateString(nsDependentString(script), mJSObject,
06834                           timeout->mPrincipal, timeout->mFileName,
06835                           timeout->mLineNo, timeout->mVersion, nsnull,
06836                           &is_undefined);
06837     } else {
06838       // Add a "secret" final argument that indicates timeout lateness
06839       // in milliseconds
06840       PRTime lateness = now - timeout->mWhen;
06841 
06842       // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
06843       // PRTime to make the division do the right thing on 64-bit
06844       // platforms whether lateness is positive or negative.
06845       timeout->mArgv[timeout->mArgc] =
06846         INT_TO_JSVAL((jsint)(lateness / (PRTime)PR_USEC_PER_MSEC));
06847 
06848       jsval dummy;
06849       scx->CallEventHandler(mJSObject, timeout->mFunObj, timeout->mArgc + 1,
06850                             timeout->mArgv, &dummy);
06851     }
06852 
06853     --mTimeoutFiringDepth;
06854     --gRunningTimeoutDepth;
06855 
06856     mRunningTimeout = last_running_timeout;
06857     timeout->mRunning = PR_FALSE;
06858 
06859     // We ignore any failures from calling EvaluateString() or
06860     // CallEventHandler() on the context here since we're in a loop
06861     // where we're likely to be running timeouts whose OS timers
06862     // didn't fire in time and we don't want to not fire those timers
06863     // now just because execution of one timer failed. We can't
06864     // propagate the error to anyone who cares about it from this
06865     // point anyway so we just drop it.
06866 
06867     // If all timeouts were cleared and |timeout != aTimeout| then
06868     // |timeout| may be the last reference to the timeout so check if
06869     // it was cleared before releasing it.
06870     PRBool timeout_was_cleared = timeout->mCleared;
06871 
06872     timeout->Release(scx);
06873 
06874     if (timeout_was_cleared) {
06875       // The running timeout's window was cleared, this means that
06876       // ClearAllTimeouts() was called from a *nested* call, possibly
06877       // through a timeout that fired while a modal (to this window)
06878       // dialog was open or through other non-obvious paths.
06879 
06880       mTimeoutInsertionPoint = last_insertion_point;
06881 
06882       return;
06883     }
06884 
06885     PRBool isInterval = PR_FALSE;
06886 
06887     // If we have a regular interval timer, we re-schedule the
06888     // timeout, accounting for clock drift.
06889     if (timeout->mInterval) {
06890       // Compute time to next timeout for interval timer.
06891       // Also check if the next interval timeout is overdue. If so,
06892       // then restart the interval from now.
06893       PRTime nextInterval = (PRTime)timeout->mInterval * PR_USEC_PER_MSEC;
06894       if (nextInterval + timeout->mWhen <= now)
06895         nextInterval += now;
06896       else
06897         nextInterval += timeout->mWhen;
06898 
06899       PRTime delay = nextInterval - PR_Now();
06900 
06901       // Make sure the delay is at least DOM_MIN_TIMEOUT_VALUE.
06902       // Note: We must cast the rhs expression to PRTime to work
06903       // around what looks like a compiler bug on x86_64.
06904       if (delay < (PRTime)(DOM_MIN_TIMEOUT_VALUE * PR_USEC_PER_MSEC)) {
06905         delay = DOM_MIN_TIMEOUT_VALUE * PR_USEC_PER_MSEC;
06906       }
06907 
06908       if (timeout->mTimer) {
06909         timeout->mWhen = nextInterval;
06910 
06911         // Reschedule the OS timer. Don't bother returning any error
06912         // codes if this fails since the callers of this method
06913         // doesn't care about them nobody who cares about them
06914         // anyways.
06915 
06916         // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
06917         // PRTime to make the division do the right thing on 64-bit
06918         // platforms whether delay is positive or negative (which we
06919         // know is always positive here, but cast anyways for
06920         // consistency).
06921         nsresult rv = timeout->mTimer->
06922           InitWithFuncCallback(TimerCallback, timeout,
06923                                (PRInt32)(delay / (PRTime)PR_USEC_PER_MSEC),
06924                                nsITimer::TYPE_ONE_SHOT);
06925 
06926         if (NS_FAILED(rv)) {
06927           NS_ERROR("Error initializing timer for DOM timeout!");
06928 
06929           // We failed to initialize the new OS timer, this timer does
06930           // us no good here so we just cancel it (just in case) and
06931           // null out the pointer to the OS timer, this will release the
06932           // OS timer. As we continue executing the code below we'll end
06933           // up deleting the timeout since it's not an interval timeout
06934           // any more (since timeout->mTimer == nsnull).
06935           timeout->mTimer->Cancel();
06936           timeout->mTimer = nsnull;
06937 
06938           // Now that the OS timer no longer has a reference to the
06939           // timeout we need to drop that reference.
06940           timeout->Release(scx);
06941         }
06942       } else {
06943         NS_ASSERTION(IsFrozen(), "How'd our timer end up null if we're not frozen?");
06944 
06945         timeout->mWhen = delay;
06946         isInterval = PR_TRUE;
06947       }
06948     }
06949 
06950     if (timeout->mTimer) {
06951       if (timeout->mInterval) {
06952         isInterval = PR_TRUE;
06953       } else {
06954         // The timeout still has an OS timer, and it's not an
06955         // interval, that means that the OS timer could still fire (if
06956         // it didn't already, i.e. aTimeout == timeout), cancel the OS
06957         // timer and release it's reference to the timeout.
06958         timeout->mTimer->Cancel();
06959         timeout->mTimer = nsnull;
06960 
06961         timeout->Release(scx);
06962       }
06963     }
06964 
06965     // Running a timeout can cause another timeout to be deleted, so
06966     // we need to reset the pointer to the following timeout.
06967     next = timeout->mNext;
06968 
06969     if (!prev) {
06970       mTimeouts = next;
06971     } else {
06972       prev->mNext = next;
06973     }
06974 
06975     // Release the timeout struct since it's out of the list
06976     timeout->Release(scx);
06977 
06978     if (isInterval) {
06979       // Reschedule an interval timeout. Insert interval timeout
06980       // onto list sorted in deadline order.
06981 
06982       InsertTimeoutIntoList(mTimeoutInsertionPoint, timeout);
06983     }
06984   }
06985 
06986   // Take the dummy timeout off the head of the list
06987   if (!prev) {
06988     mTimeouts = dummy_timeout.mNext;
06989   } else {
06990     prev->mNext = dummy_timeout.mNext;
06991   }
06992 
06993   mTimeoutInsertionPoint = last_insertion_point;
06994 }
06995 
06996 void
06997 nsTimeout::Release(nsIScriptContext *aContext)
06998 {
06999   if (--mRefCnt > 0)
07000     return;
07001 
07002   if (mExpr || mFunObj) {
07003     nsIScriptContext *scx = aContext;
07004     JSRuntime *rt = nsnull;
07005 
07006     if (!scx && mWindow) {
07007       scx = mWindow->GetContext();
07008     }
07009 
07010     if (scx) {
07011       JSContext *cx;
07012       cx = (JSContext *)scx->GetNativeContext();
07013       rt = ::JS_GetRuntime(cx);
07014     } else {
07015       // XXX The timeout *must* be unrooted, even if !scx. This can be
07016       // done without a JS context using the JSRuntime. This is safe
07017       // enough, but it would be better to drop all a window's
07018       // timeouts before its context is cleared. Bug 50705 describes a
07019       // situation where we're not. In that case, at the time the
07020       // context is cleared, a timeout (actually an Interval) is still
07021       // active, but temporarily removed from the window's list of
07022       // timers (placed instead on the timer manager's list). This
07023       // makes the nearly handy ClearAllTimeouts routine useless, so
07024       // we settled on using the JSRuntime rather than relying on the
07025       // window having a context. It would be good to remedy this
07026       // workable but clumsy situation someday.
07027 
07028       nsCOMPtr<nsIJSRuntimeService> rtsvc =
07029         do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
07030 
07031       if (rtsvc)
07032         rtsvc->GetRuntime(&rt);
07033     }
07034 
07035     if (!rt) {
07036       // most unexpected. not much choice but to bail.
07037 
07038       NS_ERROR("nsTimeout::Release() with no JSRuntime. eek!");
07039 
07040       return;
07041     }
07042 
07043     if (mExpr) {
07044       ::JS_RemoveRootRT(rt, &mExpr);
07045     } else {
07046       ::JS_RemoveRootRT(rt, &mFunObj);
07047 
07048       if (mArgv) {
07049         for (PRInt32 i = 0; i < mArgc; ++i) {
07050           ::JS_RemoveRootRT(rt, &mArgv[i]);
07051         }
07052 
07053         PR_FREEIF(mArgv);
07054       }
07055     }
07056   }
07057 
07058   if (mTimer) {
07059     mTimer->Cancel();
07060     mTimer = nsnull;
07061   }
07062 
07063   if (mFileName) {
07064     PL_strfree(mFileName);
07065   }
07066 
07067   NS_IF_RELEASE(mWindow);
07068 
07069   delete this;
07070 }
07071 
07072 void
07073 nsTimeout::AddRef()
07074 {
07075   ++mRefCnt;
07076 }
07077 
07078 nsresult
07079 nsGlobalWindow::ClearTimeoutOrInterval()
07080 {
07081   FORWARD_TO_INNER(ClearTimeoutOrInterval, (), NS_ERROR_NOT_INITIALIZED);
07082 
07083   nsresult rv = NS_OK;
07084   nsCOMPtr<nsIXPCNativeCallContext> ncc;
07085 
07086   rv = nsContentUtils::XPConnect()->
07087     GetCurrentNativeCallContext(getter_AddRefs(ncc));
07088   NS_ENSURE_SUCCESS(rv, rv);
07089 
07090   if (!ncc)
07091     return NS_ERROR_NOT_AVAILABLE;
07092 
07093   JSContext *cx = nsnull;
07094 
07095   rv = ncc->GetJSContext(&cx);
07096   NS_ENSURE_SUCCESS(rv, rv);
07097 
07098   PRUint32 argc;
07099 
07100   ncc->GetArgc(&argc);
07101 
07102   if (argc < 1) {
07103     // No arguments, return early.
07104 
07105     return NS_OK;
07106   }
07107 
07108   jsval *argv = nsnull;
07109 
07110   ncc->GetArgvPtr(&argv);
07111 
07112   int32 timer_id;
07113 
07114   if (argv[0] == JSVAL_VOID || !::JS_ValueToInt32(cx, argv[0], &timer_id) ||
07115       timer_id <= 0) {
07116     // Undefined or non-positive number passed as argument, return
07117     // early.
07118 
07119     return NS_OK;
07120   }
07121 
07122   PRUint32 public_id = (PRUint32)timer_id;
07123   nsTimeout **top, *timeout;
07124   nsIScriptContext *scx = GetContextInternal();
07125 
07126   for (top = &mTimeouts; (timeout = *top) != NULL; top = &timeout->mNext) {
07127     if (timeout->mPublicId == public_id) {
07128       if (timeout->mRunning) {
07129         /* We're running from inside the timeout. Mark this
07130            timeout for deferred deletion by the code in
07131            RunTimeout() */
07132         timeout->mInterval = 0;
07133       }
07134       else {
07135         /* Delete the timeout from the pending timeout list */
07136         *top = timeout->mNext;
07137 
07138         if (timeout->mTimer) {
07139           timeout->mTimer->Cancel();
07140           timeout->mTimer = nsnull;
07141           timeout->Release(scx);
07142         }
07143         timeout->Release(scx);
07144       }
07145       break;
07146     }
07147   }
07148 
07149   return NS_OK;
07150 }
07151 
07152 void
07153 nsGlobalWindow::ClearAllTimeouts()
07154 {
07155   nsTimeout *timeout, *next;
07156   nsIScriptContext *scx = GetContextInternal();
07157 
07158   for (timeout = mTimeouts; timeout; timeout = next) {
07159     /* If RunTimeout() is higher up on the stack for this
07160        window, e.g. as a result of document.write from a timeout,
07161        then we need to reset the list insertion point for
07162        newly-created timeouts in case the user adds a timeout,
07163        before we pop the stack back to RunTimeout. */
07164     if (mRunningTimeout == timeout)
07165       mTimeoutInsertionPoint = &mTimeouts;
07166 
07167     next = timeout->mNext;
07168 
07169     if (timeout->mTimer) {
07170       timeout->mTimer->Cancel();
07171       timeout->mTimer = nsnull;
07172 
07173       // Drop the count since the timer isn't going to hold on
07174       // anymore.
07175       timeout->Release(scx);
07176     }
07177 
07178     // Set timeout->mCleared to true to indicate that the timeout was
07179     // cleared and taken out of the list of timeouts
07180     timeout->mCleared = PR_TRUE;
07181 
07182     // Drop the count since we're removing it from the list.
07183     timeout->Release(scx);
07184   }
07185 
07186   mTimeouts = NULL;
07187 }
07188 
07189 void
07190 nsGlobalWindow::InsertTimeoutIntoList(nsTimeout **aList,
07191                                       nsTimeout *aTimeout)
07192 {
07193   NS_ASSERTION(IsInnerWindow(),
07194                "InsertTimeoutIntoList() called on outer window!");
07195 
07196   nsTimeout *to;
07197 
07198   NS_ASSERTION(aList,
07199                "nsGlobalWindow::InsertTimeoutIntoList null timeoutList");
07200   while ((to = *aList) != nsnull) {
07201     if (to->mWhen > aTimeout->mWhen)
07202       break;
07203     aList = &to->mNext;
07204   }
07205   aTimeout->mFiringDepth = 0;
07206   aTimeout->mNext = to;
07207   *aList = aTimeout;
07208 
07209   // Increment the timeout's reference count since it's now held on to
07210   // by the list
07211   aTimeout->AddRef();
07212 }
07213 
07214 // static
07215 void
07216 nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
07217 {
07218   nsTimeout *timeout = (nsTimeout *)aClosure;
07219 
07220   // Hold on to the timeout to ensure it doesn't go away while it's
07221   // being handled (aka kungFuDeathGrip).
07222   timeout->AddRef();
07223 
07224   timeout->mWindow->RunTimeout(timeout);
07225 
07226   // Drop our reference to the timeout now that we're done with it.
07227   timeout->Release(nsnull);
07228 }
07229 
07230 //*****************************************************************************
07231 // nsGlobalWindow: Helper Functions
07232 //*****************************************************************************
07233 
07234 nsresult
07235 nsGlobalWindow::GetTreeOwner(nsIDocShellTreeOwner **aTreeOwner)
07236 {
07237   FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
07238 
07239   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
07240 
07241   // If there's no docShellAsItem, this window must have been closed,
07242   // in that case there is no tree owner.
07243 
07244   if (!docShellAsItem) {
07245     *aTreeOwner = nsnull;
07246 
07247     return NS_OK;
07248   }
07249 
07250   return docShellAsItem->GetTreeOwner(aTreeOwner);
07251 }
07252 
07253 nsresult
07254 nsGlobalWindow::GetTreeOwner(nsIBaseWindow **aTreeOwner)
07255 {
07256   FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
07257 
07258   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
07259   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
07260 
07261   // If there's no docShellAsItem, this window must have been closed,
07262   // in that case there is no tree owner.
07263 
07264   if (docShellAsItem) {
07265     docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
07266   }
07267 
07268   if (!treeOwner) {
07269     *aTreeOwner = nsnull;
07270     return NS_OK;
07271   }
07272 
07273   return CallQueryInterface(treeOwner, aTreeOwner);
07274 }
07275 
07276 nsresult
07277 nsGlobalWindow::GetWebBrowserChrome(nsIWebBrowserChrome **aBrowserChrome)
07278 {
07279   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
07280   GetTreeOwner(getter_AddRefs(treeOwner));
07281 
07282   nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner));
07283   NS_IF_ADDREF(*aBrowserChrome = browserChrome);
07284 
07285   return NS_OK;
07286 }
07287 
07288 nsresult
07289 nsGlobalWindow::GetScrollInfo(nsIScrollableView **aScrollableView, float *aP2T,
07290                               float *aT2P)
07291 {
07292   FORWARD_TO_OUTER(GetScrollInfo, (aScrollableView, aP2T, aT2P),
07293                    NS_ERROR_NOT_INITIALIZED);
07294 
07295   *aScrollableView = nsnull;
07296   *aP2T = 0.0f;
07297   *aT2P = 0.0f;
07298 
07299   if (!mDocShell) {
07300     return NS_OK;
07301   }
07302 
07303   nsCOMPtr<nsPresContext> presContext;
07304   mDocShell->GetPresContext(getter_AddRefs(presContext));
07305   if (presContext) {
07306     *aP2T = presContext->PixelsToTwips();
07307     *aT2P = presContext->TwipsToPixels();
07308 
07309     nsIViewManager* vm = presContext->GetViewManager();
07310     if (vm)
07311       return vm->GetRootScrollableView(aScrollableView);
07312   }
07313   return NS_OK;
07314 }
07315 
07316 nsresult
07317 nsGlobalWindow::BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
07318                                  PRBool *aFreeSecurityPass,
07319                                  JSContext **aCXused)
07320 {
07321   nsIScriptContext *scx = GetContextInternal();
07322   JSContext *cx = nsnull;
07323 
07324   *aBuiltURI = nsnull;
07325   *aFreeSecurityPass = PR_FALSE;
07326   if (aCXused)
07327     *aCXused = nsnull;
07328 
07329   // get JSContext
07330   NS_ASSERTION(scx, "opening window missing its context");
07331   NS_ASSERTION(mDocument, "opening window missing its document");
07332   if (!scx || !mDocument)
07333     return NS_ERROR_FAILURE;
07334 
07335   nsCOMPtr<nsIDOMChromeWindow> chrome_win =
07336     do_QueryInterface(NS_STATIC_CAST(nsIDOMWindow *, this));
07337 
07338   if (IsCallerChrome() && !chrome_win) {
07339     // If open() is called from chrome on a non-chrome window, we'll
07340     // use the context from the window on which open() is being called
07341     // to prevent giving chrome priveleges to new windows opened in
07342     // such a way. This also makes us get the appropriate base URI for
07343     // the below URI resolution code.
07344 
07345     cx = (JSContext *)scx->GetNativeContext();
07346   } else {
07347     // get the JSContext from the call stack
07348     nsCOMPtr<nsIThreadJSContextStack> stack(do_GetService(sJSStackContractID));
07349     if (stack)
07350       stack->Peek(&cx);
07351   }
07352 
07353   /* resolve the URI, which could be relative to the calling window
07354      (note the algorithm to get the base URI should match the one
07355      used to actually kick off the load in nsWindowWatcher.cpp). */
07356   nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
07357   nsIURI* baseURI = nsnull;
07358   nsCOMPtr<nsIURI> uriToLoad;
07359   nsCOMPtr<nsIDOMWindow> sourceWindow;
07360 
07361   if (cx) {
07362     nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
07363     if (scriptcx)
07364       sourceWindow = do_QueryInterface(scriptcx->GetGlobalObject());
07365   }
07366 
07367   if (!sourceWindow) {
07368     sourceWindow = do_QueryInterface(NS_ISUPPORTS_CAST(nsIDOMWindow *, this));
07369     *aFreeSecurityPass = PR_TRUE;
07370   }
07371 
07372   if (sourceWindow) {
07373     nsCOMPtr<nsIDOMDocument> domDoc;
07374     sourceWindow->GetDocument(getter_AddRefs(domDoc));
07375     nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
07376     if (doc) {
07377       baseURI = doc->GetBaseURI();
07378       charset = doc->GetDocumentCharacterSet();
07379     }
07380   }
07381 
07382   if (aCXused)
07383     *aCXused = cx;
07384   return NS_NewURI(aBuiltURI, nsDependentCString(aURL), charset.get(), baseURI);
07385 }
07386 
07387 nsresult
07388 nsGlobalWindow::SecurityCheckURL(const char *aURL)
07389 {
07390   JSContext       *cx;
07391   PRBool           freePass;
07392   nsCOMPtr<nsIURI> uri;
07393 
07394   if (NS_FAILED(BuildURIfromBase(aURL, getter_AddRefs(uri), &freePass, &cx)))
07395     return NS_ERROR_FAILURE;
07396 
07397   if (!freePass && NS_FAILED(sSecMan->CheckLoadURIFromScript(cx, uri)))
07398     return NS_ERROR_FAILURE;
07399 
07400   return NS_OK;
07401 }
07402 
07403 void
07404 nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
07405 {
07406   nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
07407   if (doc) {
07408     doc->FlushPendingNotifications(aType);
07409   }
07410 }
07411 
07412 void
07413 nsGlobalWindow::EnsureSizeUpToDate()
07414 {
07415   // If we're a subframe, make sure our size is up to date.  It's OK that this
07416   // crosses the content/chrome boundary, since chrome can have pending reflows
07417   // too.
07418   nsGlobalWindow *parent =
07419     NS_STATIC_CAST(nsGlobalWindow *, GetPrivateParent());
07420   if (parent) {
07421     parent->FlushPendingNotifications(Flush_Layout);
07422   }
07423 }
07424 
07425 nsresult
07426 nsGlobalWindow::SaveWindowState(nsISupports **aState)
07427 {
07428   NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
07429 
07430   *aState = nsnull;
07431 
07432   if (!mContext || !mJSObject) {
07433     // The window may be getting torn down; don't bother saving state.
07434     return NS_OK;
07435   }
07436 
07437   nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
07438   NS_ASSERTION(inner, "No inner window to save");
07439 
07440   // Don't do anything else to this inner window! After this point, all
07441   // calls to SetTimeoutOrInterval will create entries in the timeout
07442   // list that will only run after this window has come out of the bfcache.
07443   inner->Freeze();
07444 
07445   // Remember the outer window's XPConnect prototype.
07446   nsCOMPtr<nsIClassInfo> ci =
07447     do_QueryInterface((nsIScriptGlobalObject *)this);
07448   nsCOMPtr<nsIXPConnectJSObjectHolder> proto;
07449   nsresult rv = nsContentUtils::XPConnect()->
07450     GetWrappedNativePrototype((JSContext *)mContext->GetNativeContext(),
07451                               mJSObject, ci, getter_AddRefs(proto));
07452   NS_ENSURE_SUCCESS(rv, rv);
07453 
07454   nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
07455                                                       mInnerWindowHolder,
07456                                                       mNavigator,
07457                                                       mLocation,
07458                                                       proto);
07459   NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
07460 
07461 #ifdef DEBUG_PAGE_CACHE
07462   printf("saving window state, state = %p\n", (void*)state);
07463 #endif
07464 
07465   state.swap(*aState);
07466   return NS_OK;
07467 }
07468 
07469 nsresult
07470 nsGlobalWindow::RestoreWindowState(nsISupports *aState)
07471 {
07472   NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
07473 
07474   if (!mContext || !mJSObject) {
07475     // The window may be getting torn down; don't bother restoring state.
07476     return NS_OK;
07477   }
07478 
07479   nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
07480   NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
07481 
07482 #ifdef DEBUG_PAGE_CACHE
07483   printf("restoring window state, state = %p\n", (void*)holder);
07484 #endif
07485 
07486   nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
07487 
07488   nsIDOMElement *focusedElement = holder->GetFocusedElement();
07489   nsIDOMWindowInternal *focusedWindow = holder->GetFocusedWindow();
07490 
07491   // If the toplevel window isn't focused, just update the focus controller.
07492   nsIFocusController *fc = nsGlobalWindow::GetRootFocusController();
07493   NS_ENSURE_TRUE(fc, NS_ERROR_UNEXPECTED);
07494 
07495   PRBool active;
07496   fc->GetActive(&active);
07497   if (active) {
07498     PRBool didFocusContent = PR_FALSE;
07499     nsCOMPtr<nsIContent> focusedContent = do_QueryInterface(focusedElement);
07500 
07501     if (focusedContent) {
07502       // We don't bother checking whether the element or frame is focusable.
07503       // If it was focusable when we stored the presentation, it must be
07504       // focusable now.
07505       nsIDocument *doc = focusedContent->GetCurrentDoc();
07506       if (doc) {
07507         nsIPresShell *shell = doc->GetShellAt(0);
07508         if (shell) {
07509           nsPresContext *pc = shell->GetPresContext();
07510           if (pc) {
07511             pc->EventStateManager()->SetContentState(focusedContent,
07512                                                      NS_EVENT_STATE_FOCUS);
07513             didFocusContent = PR_TRUE;
07514           }
07515         }
07516       }
07517     }
07518 
07519     if (!didFocusContent && focusedWindow)
07520       focusedWindow->Focus();
07521   } else if (focusedWindow) {
07522     // Just update the saved focus memory.
07523     fc->SetFocusedWindow(focusedWindow);
07524     fc->SetFocusedElement(focusedElement);
07525   }
07526 
07527   // And we're ready to go!
07528   inner->Thaw();
07529 
07530   holder->DidRestoreWindow();
07531 
07532   return NS_OK;
07533 }
07534 
07535 void
07536 nsGlobalWindow::SuspendTimeouts()
07537 {
07538   FORWARD_TO_INNER_VOID(SuspendTimeouts, ());
07539 
07540   PRTime now = PR_Now();
07541   for (nsTimeout *t = mTimeouts; t; t = t->mNext) {
07542     // Change mWhen to be the time remaining for this timer.    
07543     if (t->mWhen > now)
07544       t->mWhen -= now;
07545     else
07546       t->mWhen = 0;
07547 
07548     // Drop the XPCOM timer; we'll reschedule when restoring the state.
07549     if (t->mTimer) {
07550       t->mTimer->Cancel();
07551       t->mTimer = nsnull;
07552 
07553       // Drop the reference that the timer's closure had on this timeout, we'll
07554       // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
07555       // passing null for the context, since this shouldn't actually release this
07556       // timeout.
07557       t->Release(nsnull);
07558     }
07559   }
07560 
07561   // Suspend our children as well.
07562   nsCOMPtr<nsIDocShellTreeNode> node =
07563     do_QueryInterface(GetDocShellInternal());
07564   if (node) {
07565     PRInt32 childCount = 0;
07566     node->GetChildCount(&childCount);
07567 
07568     for (PRInt32 i = 0; i < childCount; ++i) {
07569       nsCOMPtr<nsIDocShellTreeItem> childShell;
07570       node->GetChildAt(i, getter_AddRefs(childShell));
07571       NS_ASSERTION(childShell, "null child shell");
07572 
07573       nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
07574       if (pWin) {
07575         nsGlobalWindow *win =
07576           NS_STATIC_CAST(nsGlobalWindow*,
07577                          NS_STATIC_CAST(nsPIDOMWindow*, pWin));
07578 
07579         win->SuspendTimeouts();
07580 
07581         NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
07582         nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
07583         if (inner) {
07584           inner->Freeze();
07585         }
07586       }
07587     }
07588   }
07589 }
07590 
07591 nsresult
07592 nsGlobalWindow::ResumeTimeouts()
07593 {
07594   FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
07595 
07596   // Restore all of the timeouts, using the stored time remaining
07597   // (stored in timeout->mWhen).
07598 
07599   PRTime now = PR_Now();
07600   nsresult rv;
07601 
07602   for (nsTimeout *t = mTimeouts; t; t = t->mNext) {
07603     // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
07604     // PRTime to make the division do the right thing on 64-bit
07605     // platforms whether t->mWhen is positive or negative (which is
07606     // likely to always be positive here, but cast anyways for
07607     // consistency).
07608     PRUint32 delay =
07609       PR_MAX(((PRUint32)(t->mWhen / (PRTime)PR_USEC_PER_MSEC)),
07610               DOM_MIN_TIMEOUT_VALUE);
07611 
07612     // Set mWhen back to the time when the timer is supposed to
07613     // fire.
07614     t->mWhen += now;
07615 
07616     t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
07617     NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
07618 
07619     rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, delay,
07620                                          nsITimer::TYPE_ONE_SHOT);
07621     if (NS_FAILED(rv)) {
07622       t->mTimer = nsnull;
07623       return rv;
07624     }
07625 
07626     // Add a reference for the new timer's closure.
07627     t->AddRef();
07628   }
07629 
07630   // Resume our children as well.
07631   nsCOMPtr<nsIDocShellTreeNode> node =
07632     do_QueryInterface(GetDocShellInternal());
07633   if (node) {
07634     PRInt32 childCount = 0;
07635     node->GetChildCount(&childCount);
07636 
07637     for (PRInt32 i = 0; i < childCount; ++i) {
07638       nsCOMPtr<nsIDocShellTreeItem> childShell;
07639       node->GetChildAt(i, getter_AddRefs(childShell));
07640       NS_ASSERTION(childShell, "null child shell");
07641 
07642       nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
07643       if (pWin) {
07644         nsGlobalWindow *win =
07645           NS_STATIC_CAST(nsGlobalWindow*,
07646                          NS_STATIC_CAST(nsPIDOMWindow*, pWin));
07647 
07648         NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
07649         nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
07650         if (inner) {
07651           inner->Thaw();
07652         }
07653 
07654         rv = win->ResumeTimeouts();
07655         NS_ENSURE_SUCCESS(rv, rv);
07656       }
07657     }
07658   }
07659 
07660   return NS_OK;
07661 }
07662 
07663 // QueryInterface implementation for nsGlobalChromeWindow
07664 NS_INTERFACE_MAP_BEGIN(nsGlobalChromeWindow)
07665   NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
07666   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
07667 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
07668 
07669 NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
07670 NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
07671 
07672 // nsGlobalChromeWindow implementation
07673 
07674 static void TitleConsoleWarning()
07675 {
07676   nsCOMPtr<nsIConsoleService> console(do_GetService("@mozilla.org/consoleservice;1"));
07677   if (console)
07678     console->LogStringMessage(NS_LITERAL_STRING("Deprecated property window.title used.  Please use document.title instead.").get());
07679 }
07680 
07681 NS_IMETHODIMP
07682 nsGlobalChromeWindow::GetTitle(nsAString& aTitle)
07683 {
07684   NS_ERROR("nsIDOMChromeWindow::GetTitle is deprecated, use nsIDOMNSDocument instead");
07685   TitleConsoleWarning();
07686 
07687   nsresult rv;
07688   nsCOMPtr<nsIDOMNSDocument> nsdoc(do_QueryInterface(mDocument, &rv));
07689   NS_ENSURE_SUCCESS(rv, rv);
07690   return nsdoc->GetTitle(aTitle);
07691 }
07692 
07693 NS_IMETHODIMP
07694 nsGlobalChromeWindow::SetTitle(const nsAString& aTitle)
07695 {
07696   NS_ERROR("nsIDOMChromeWindow::SetTitle is deprecated, use nsIDOMNSDocument instead");
07697   TitleConsoleWarning();
07698 
07699   nsresult rv;
07700   nsCOMPtr<nsIDOMNSDocument> nsdoc(do_QueryInterface(mDocument, &rv));
07701   NS_ENSURE_SUCCESS(rv, rv);
07702   return nsdoc->SetTitle(aTitle);
07703 }
07704 
07705 NS_IMETHODIMP
07706 nsGlobalChromeWindow::GetWindowState(PRUint16* aWindowState)
07707 {
07708   *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
07709 
07710   nsCOMPtr<nsIWidget> widget = GetMainWidget();
07711 
07712   PRInt32 aMode = 0;
07713 
07714   if (widget) {
07715     nsresult rv = widget->GetSizeMode(&aMode);
07716     NS_ENSURE_SUCCESS(rv, rv);
07717   }
07718 
07719   switch (aMode) {
07720     case nsSizeMode_Minimized:
07721       *aWindowState = nsIDOMChromeWindow::STATE_MINIMIZED;
07722       break;
07723     case nsSizeMode_Maximized:
07724       *aWindowState = nsIDOMChromeWindow::STATE_MAXIMIZED;
07725       break;
07726     case nsSizeMode_Normal:
07727       *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
07728       break;
07729     default:
07730       NS_WARNING("Illegal window state for this chrome window");
07731       break;
07732   }
07733 
07734   return NS_OK;
07735 }
07736 
07737 NS_IMETHODIMP
07738 nsGlobalChromeWindow::Maximize()
07739 {
07740   nsCOMPtr<nsIWidget> widget = GetMainWidget();
07741   nsresult rv = NS_OK;
07742 
07743   if (widget) {
07744     rv = widget->SetSizeMode(nsSizeMode_Maximized);
07745   }
07746 
07747   return rv;
07748 }
07749 
07750 NS_IMETHODIMP
07751 nsGlobalChromeWindow::Minimize()
07752 {
07753   nsCOMPtr<nsIWidget> widget = GetMainWidget();
07754   nsresult rv = NS_OK;
07755 
07756   if (widget) {
07757     // minimize doesn't send deactivate events on windows,
07758     // so we need to forcefully restore the os chrome
07759     nsCOMPtr<nsIFullScreen> fullScreen =
07760       do_GetService("@mozilla.org/browser/fullscreen;1");
07761     if (fullScreen)
07762       fullScreen->ShowAllOSChrome();
07763 
07764     rv = widget->SetSizeMode(nsSizeMode_Minimized);
07765   }
07766 
07767   return rv;
07768 }
07769 
07770 NS_IMETHODIMP
07771 nsGlobalChromeWindow::Restore()
07772 {
07773   nsCOMPtr<nsIWidget> widget = GetMainWidget();
07774   nsresult rv = NS_OK;
07775 
07776   if (widget) {
07777     rv = widget->SetSizeMode(nsSizeMode_Normal);
07778   }
07779 
07780   return rv;
07781 }
07782 
07783 NS_IMETHODIMP
07784 nsGlobalChromeWindow::GetAttention()
07785 {
07786   return GetAttentionWithCycleCount(-1);
07787 }
07788 
07789 NS_IMETHODIMP
07790 nsGlobalChromeWindow::GetAttentionWithCycleCount(PRInt32 aCycleCount)
07791 {
07792   nsCOMPtr<nsIWidget> widget = GetMainWidget();
07793   nsresult rv = NS_OK;
07794 
07795   if (widget) {
07796     rv = widget->GetAttention(aCycleCount);
07797   }
07798 
07799   return rv;
07800 }
07801 
07802 //Note: This call will lock the cursor, it will not change as it moves.
07803 //To unlock, the cursor must be set back to CURSOR_AUTO.
07804 NS_IMETHODIMP
07805 nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
07806 {
07807   FORWARD_TO_OUTER_CHROME(SetCursor, (aCursor), NS_ERROR_NOT_INITIALIZED);
07808 
07809   nsresult rv = NS_OK;
07810   PRInt32 cursor;
07811 
07812   // use C strings to keep the code/data size down
07813   NS_ConvertUCS2toUTF8 cursorString(aCursor);
07814 
07815   if (cursorString.Equals("auto"))
07816     cursor = NS_STYLE_CURSOR_AUTO;
07817   else {
07818     nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
07819     if (eCSSKeyword_UNKNOWN == keyword ||
07820         !nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
07821       // XXX remove the following three values (leave return NS_OK) after 1.8
07822       // XXX since they should have been -moz- prefixed (covered by FindKeyword).
07823       // XXX (also remove |cursorString| at that point?).
07824       if (cursorString.Equals("grab"))
07825         cursor = NS_STYLE_CURSOR_GRAB;
07826       else if (cursorString.Equals("grabbing"))
07827         cursor = NS_STYLE_CURSOR_GRABBING;
07828       else if (cursorString.Equals("spinning"))
07829         cursor = NS_STYLE_CURSOR_SPINNING;
07830       else
07831         return NS_OK;
07832     }
07833   }
07834 
07835   nsCOMPtr<nsPresContext> presContext;
07836   if (mDocShell) {
07837     mDocShell->GetPresContext(getter_AddRefs(presContext));
07838   }
07839 
07840   if (presContext) {
07841     // Need root widget.
07842     nsCOMPtr<nsIPresShell> presShell;
07843     mDocShell->GetPresShell(getter_AddRefs(presShell));
07844     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
07845 
07846     nsIViewManager* vm = presShell->GetViewManager();
07847     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
07848 
07849     nsIView *rootView;
07850     vm->GetRootView(rootView);
07851     NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
07852 
07853     nsIWidget* widget = rootView->GetWidget();
07854     NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
07855 
07856     // Call esm and set cursor.
07857     rv = presContext->EventStateManager()->SetCursor(cursor, nsnull,
07858                                                      PR_FALSE, 0.0f, 0.0f,
07859                                                      widget, PR_TRUE);
07860   }
07861 
07862   return rv;
07863 }
07864 
07865 NS_IMETHODIMP
07866 nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
07867 {
07868   FORWARD_TO_OUTER_CHROME(GetBrowserDOMWindow, (aBrowserWindow),
07869                           NS_ERROR_NOT_INITIALIZED);
07870 
07871   NS_ENSURE_ARG_POINTER(aBrowserWindow);
07872 
07873   *aBrowserWindow = mBrowserDOMWindow;
07874   NS_IF_ADDREF(*aBrowserWindow);
07875   return NS_OK;
07876 }
07877 
07878 NS_IMETHODIMP
07879 nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
07880 {
07881   FORWARD_TO_OUTER_CHROME(SetBrowserDOMWindow, (aBrowserWindow),
07882                           NS_ERROR_NOT_INITIALIZED);
07883 
07884   mBrowserDOMWindow = aBrowserWindow;
07885   return NS_OK;
07886 }
07887 
07888 //*****************************************************************************
07889 // nsGlobalWindow: Creator Function (This should go away)
07890 //*****************************************************************************
07891 
07892 nsresult
07893 NS_NewScriptGlobalObject(PRBool aIsChrome, nsIScriptGlobalObject **aResult)
07894 {
07895   *aResult = nsnull;
07896 
07897   nsGlobalWindow *global;
07898 
07899   if (aIsChrome) {
07900     global = new nsGlobalChromeWindow(nsnull);
07901   } else {
07902     global = new nsGlobalWindow(nsnull);
07903   }
07904 
07905   NS_ENSURE_TRUE(global, NS_ERROR_OUT_OF_MEMORY);
07906 
07907   return CallQueryInterface(NS_STATIC_CAST(nsIScriptGlobalObject *, global),
07908                             aResult);
07909 }
07910 
07911 //*****************************************************************************
07912 //***    nsNavigator: Object Management
07913 //*****************************************************************************
07914 
07915 nsNavigator::nsNavigator(nsIDocShell *aDocShell)
07916   : mDocShell(aDocShell)
07917 {
07918 }
07919 
07920 nsNavigator::~nsNavigator()
07921 {
07922   sPrefInternal_id = JSVAL_VOID;
07923 }
07924 
07925 //*****************************************************************************
07926 //    nsNavigator::nsISupports
07927 //*****************************************************************************
07928 
07929 
07930 // QueryInterface implementation for nsNavigator
07931 NS_INTERFACE_MAP_BEGIN(nsNavigator)
07932   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator)
07933   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator)
07934   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator_MOZILLA_1_8_BRANCH)
07935   NS_INTERFACE_MAP_ENTRY(nsIDOMJSNavigator)
07936   NS_INTERFACE_MAP_ENTRY(nsIDOMClientInformation)
07937   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
07938 NS_INTERFACE_MAP_END
07939 
07940 
07941 NS_IMPL_ADDREF(nsNavigator)
07942 NS_IMPL_RELEASE(nsNavigator)
07943 
07944 
07945 void
07946 nsNavigator::SetDocShell(nsIDocShell *aDocShell)
07947 {
07948   mDocShell = aDocShell;
07949   if (mPlugins)
07950     mPlugins->SetDocShell(aDocShell);
07951 }
07952 
07953 //*****************************************************************************
07954 //    nsNavigator::nsIDOMNavigator
07955 //*****************************************************************************
07956 
07957 NS_IMETHODIMP
07958 nsNavigator::GetUserAgent(nsAString& aUserAgent)
07959 {
07960   nsresult rv;
07961   nsCOMPtr<nsIHttpProtocolHandler>
07962     service(do_GetService(kHTTPHandlerCID, &rv));
07963   if (NS_SUCCEEDED(rv)) {
07964     nsCAutoString ua;
07965     rv = service->GetUserAgent(ua);
07966     CopyASCIItoUCS2(ua, aUserAgent);
07967   }
07968 
07969   return rv;
07970 }
07971 
07972 NS_IMETHODIMP
07973 nsNavigator::GetAppCodeName(nsAString& aAppCodeName)
07974 {
07975   nsresult rv;
07976   nsCOMPtr<nsIHttpProtocolHandler>
07977     service(do_GetService(kHTTPHandlerCID, &rv));
07978   if (NS_SUCCEEDED(rv)) {
07979     nsCAutoString appName;
07980     rv = service->GetAppName(appName);
07981     CopyASCIItoUTF16(appName, aAppCodeName);
07982   }
07983 
07984   return rv;
07985 }
07986 
07987 NS_IMETHODIMP
07988 nsNavigator::GetAppVersion(nsAString& aAppVersion)
07989 {
07990   if (!nsGlobalWindow::IsCallerChrome()) {
07991     const nsAdoptingCString& override = 
07992       nsContentUtils::GetCharPref("general.appversion.override");
07993 
07994     if (override) {
07995       CopyUTF8toUTF16(override, aAppVersion);
07996       return NS_OK;
07997     }
07998   }
07999 
08000   nsresult rv;
08001   nsCOMPtr<nsIHttpProtocolHandler>
08002     service(do_GetService(kHTTPHandlerCID, &rv));
08003   if (NS_SUCCEEDED(rv)) {
08004     nsCAutoString str;
08005     rv = service->GetAppVersion(str);
08006     CopyASCIItoUTF16(str, aAppVersion);
08007     if (NS_FAILED(rv))
08008       return rv;
08009 
08010     aAppVersion.AppendLiteral(" (");
08011 
08012     rv = service->GetPlatform(str);
08013     if (NS_FAILED(rv))
08014       return rv;
08015 
08016     AppendASCIItoUTF16(str, aAppVersion);
08017 
08018     aAppVersion.AppendLiteral("; ");
08019 
08020     rv = service->GetLanguage(str);
08021     if (NS_FAILED(rv))
08022       return rv;
08023     AppendASCIItoUTF16(str, aAppVersion);
08024 
08025     aAppVersion.Append(PRUnichar(')'));
08026   }
08027 
08028   return rv;
08029 }
08030 
08031 NS_IMETHODIMP
08032 nsNavigator::GetAppName(nsAString& aAppName)
08033 {
08034   if (!nsGlobalWindow::IsCallerChrome()) {
08035     const nsAdoptingCString& override =
08036       nsContentUtils::GetCharPref("general.appname.override");
08037 
08038     if (override) {
08039       CopyUTF8toUTF16(override, aAppName);
08040       return NS_OK;
08041     }
08042   }
08043 
08044   aAppName.AssignLiteral("Netscape");
08045   return NS_OK;
08046 }
08047 
08048 NS_IMETHODIMP
08049 nsNavigator::GetLanguage(nsAString& aLanguage)
08050 {
08051   nsresult rv;
08052   nsCOMPtr<nsIHttpProtocolHandler>
08053     service(do_GetService(kHTTPHandlerCID, &rv));
08054   if (NS_SUCCEEDED(rv)) {
08055     nsCAutoString lang;
08056     rv = service->GetLanguage(lang);
08057     CopyASCIItoUCS2(lang, aLanguage);
08058   }
08059 
08060   return rv;
08061 }
08062 
08063 NS_IMETHODIMP
08064 nsNavigator::GetPlatform(nsAString& aPlatform)
08065 {
08066   if (!nsGlobalWindow::IsCallerChrome()) {
08067     const nsAdoptingCString& override =
08068       nsContentUtils::GetCharPref("general.platform.override");
08069 
08070     if (override) {
08071       CopyUTF8toUTF16(override, aPlatform);
08072       return NS_OK;
08073     }
08074   }
08075 
08076   nsresult rv;
08077   nsCOMPtr<nsIHttpProtocolHandler>
08078     service(do_GetService(kHTTPHandlerCID, &rv));
08079   if (NS_SUCCEEDED(rv)) {
08080     // sorry for the #if platform ugliness, but Communicator is
08081     // likewise hardcoded and we're seeking backward compatibility
08082     // here (bug 47080)
08083 #if defined(WIN32)
08084     aPlatform.AssignLiteral("Win32");
08085 #elif defined(XP_MACOSX) && defined(__ppc__)
08086     aPlatform.AssignLiteral("MacPPC");
08087 #elif defined(XP_MACOSX) && defined(__i386__)
08088     aPlatform.AssignLiteral("MacIntel");
08089 #elif defined(XP_OS2)
08090     aPlatform.AssignLiteral("OS/2");
08091 #else
08092     // XXX Communicator uses compiled-in build-time string defines
08093     // to indicate the platform it was compiled *for*, not what it is
08094     // currently running *on* which is what this does.
08095     nsCAutoString plat;
08096     rv = service->GetOscpu(plat);
08097     CopyASCIItoUTF16(plat, aPlatform);
08098 #endif
08099   }
08100 
08101   return rv;
08102 }
08103 
08104 NS_IMETHODIMP
08105 nsNavigator::GetOscpu(nsAString& aOSCPU)
08106 {
08107   if (!nsGlobalWindow::IsCallerChrome()) {
08108     const nsAdoptingCString& override =
08109       nsContentUtils::GetCharPref("general.oscpu.override");
08110 
08111     if (override) {
08112       CopyUTF8toUTF16(override, aOSCPU);
08113       return NS_OK;
08114     }
08115   }
08116 
08117   nsresult rv;
08118   nsCOMPtr<nsIHttpProtocolHandler>
08119     service(do_GetService(kHTTPHandlerCID, &rv));
08120   if (NS_SUCCEEDED(rv)) {
08121     nsCAutoString oscpu;
08122     rv = service->GetOscpu(oscpu);
08123     CopyASCIItoUCS2(oscpu, aOSCPU);
08124   }
08125 
08126   return rv;
08127 }
08128 
08129 NS_IMETHODIMP
08130 nsNavigator::GetVendor(nsAString& aVendor)
08131 {
08132   nsresult rv;
08133   nsCOMPtr<nsIHttpProtocolHandler>
08134     service(do_GetService(kHTTPHandlerCID, &rv));
08135   if (NS_SUCCEEDED(rv)) {
08136     nsCAutoString vendor;
08137     rv = service->GetVendor(vendor);
08138     CopyASCIItoUCS2(vendor, aVendor);
08139   }
08140 
08141   return rv;
08142 }
08143 
08144 
08145 NS_IMETHODIMP
08146 nsNavigator::GetVendorSub(nsAString& aVendorSub)
08147 {
08148   nsresult rv;
08149   nsCOMPtr<nsIHttpProtocolHandler>
08150     service(do_GetService(kHTTPHandlerCID, &rv));
08151   if (NS_SUCCEEDED(rv)) {
08152     nsCAutoString vendor;
08153     rv = service->GetVendorSub(vendor);
08154     CopyASCIItoUCS2(vendor, aVendorSub);
08155   }
08156 
08157   return rv;
08158 }
08159 
08160 NS_IMETHODIMP
08161 nsNavigator::GetProduct(nsAString& aProduct)
08162 {
08163   nsresult rv;
08164   nsCOMPtr<nsIHttpProtocolHandler>
08165     service(do_GetService(kHTTPHandlerCID, &rv));
08166   if (NS_SUCCEEDED(rv)) {
08167     nsCAutoString product;
08168     rv = service->GetProduct(product);
08169     CopyASCIItoUCS2(product, aProduct);
08170   }
08171 
08172   return rv;
08173 }
08174 
08175 NS_IMETHODIMP
08176 nsNavigator::GetProductSub(nsAString& aProductSub)
08177 {
08178   if (!nsGlobalWindow::IsCallerChrome()) {
08179     const nsAdoptingCString& override =
08180       nsContentUtils::GetCharPref("general.productSub.override");
08181 
08182     if (override) {
08183       CopyUTF8toUTF16(override, aProductSub);
08184       return NS_OK;
08185     }
08186   }
08187 
08188   nsresult rv;
08189   nsCOMPtr<nsIHttpProtocolHandler>
08190     service(do_GetService(kHTTPHandlerCID, &rv));
08191   if (NS_SUCCEEDED(rv)) {
08192     nsCAutoString productSub;
08193     rv = service->GetProductSub(productSub);
08194     CopyASCIItoUCS2(productSub, aProductSub);
08195   }
08196 
08197   return rv;
08198 }
08199 
08200 NS_IMETHODIMP
08201 nsNavigator::GetSecurityPolicy(nsAString& aSecurityPolicy)
08202 {
08203   return NS_OK;
08204 }
08205 
08206 NS_IMETHODIMP
08207 nsNavigator::GetMimeTypes(nsIDOMMimeTypeArray **aMimeTypes)
08208 {
08209   if (!mMimeTypes) {
08210     mMimeTypes = new nsMimeTypeArray(this);
08211     if (!mMimeTypes) {
08212       return NS_ERROR_OUT_OF_MEMORY;
08213     }
08214   }
08215 
08216   NS_ADDREF(*aMimeTypes = mMimeTypes);
08217 
08218   return NS_OK;
08219 }
08220 
08221 NS_IMETHODIMP
08222 nsNavigator::GetPlugins(nsIDOMPluginArray **aPlugins)
08223 {
08224   if (!mPlugins) {
08225     mPlugins = new nsPluginArray(this, mDocShell);
08226     if (!mPlugins) {
08227       return NS_ERROR_OUT_OF_MEMORY;
08228     }
08229   }
08230 
08231   NS_ADDREF(*aPlugins = mPlugins);
08232 
08233   return NS_OK;
08234 }
08235 
08236 // values for the network.cookie.cookieBehavior pref are documented in
08237 // nsCookieService.cpp.
08238 #define COOKIE_BEHAVIOR_REJECT 2
08239 
08240 NS_IMETHODIMP
08241 nsNavigator::GetCookieEnabled(PRBool *aCookieEnabled)
08242 {
08243   *aCookieEnabled =
08244     (nsContentUtils::GetIntPref("network.cookie.cookieBehavior",
08245                                 COOKIE_BEHAVIOR_REJECT) !=
08246      COOKIE_BEHAVIOR_REJECT);
08247 
08248   return NS_OK;
08249 }
08250 
08251 NS_IMETHODIMP
08252 nsNavigator::GetOnLine(PRBool* aOnline)
08253 {
08254   NS_PRECONDITION(aOnline, "Null out param");
08255   
08256   *aOnline = PR_FALSE;  // No ioservice would mean this is the case
08257   
08258   nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
08259   if (ios) {
08260     ios->GetOffline(aOnline);
08261     *aOnline = !*aOnline;
08262   }
08263   
08264   return NS_OK;
08265 }
08266 
08267 NS_IMETHODIMP
08268 nsNavigator::GetBuildID(nsAString & aBuildID)
08269 {
08270   if (!nsGlobalWindow::IsCallerChrome()) {
08271     const nsAdoptingCString& override =
08272       nsContentUtils::GetCharPref("general.buildID.override");
08273 
08274     if (override) {
08275       CopyUTF8toUTF16(override, aBuildID);
08276       return NS_OK;
08277     }
08278   }
08279 
08280   aBuildID = NS_LITERAL_STRING(NS_STRINGIFY(NS_BUILD_ID));
08281 
08282   return NS_OK;
08283 }
08284 
08285 NS_IMETHODIMP
08286 nsNavigator::JavaEnabled(PRBool *aReturn)
08287 {
08288   nsresult rv = NS_OK;
08289   *aReturn = PR_FALSE;
08290 
08291 #ifdef OJI
08292   // determine whether user has enabled java.
08293   // if pref doesn't exist, map result to false.
08294   *aReturn = nsContentUtils::GetBoolPref("security.enable_java");
08295 
08296   // if Java is not enabled, result is false and return reight away
08297   if (!*aReturn)
08298     return NS_OK;
08299 
08300   // Ask the nsIJVMManager if Java is enabled
08301   nsCOMPtr<nsIJVMManager> jvmService = do_GetService(kJVMServiceCID);
08302   if (jvmService) {
08303     jvmService->GetJavaEnabled(aReturn);
08304   }
08305   else {
08306     *aReturn = PR_FALSE;
08307   }
08308 #endif
08309   return rv;
08310 }
08311 
08312 NS_IMETHODIMP
08313 nsNavigator::TaintEnabled(PRBool *aReturn)
08314 {
08315   *aReturn = PR_FALSE;
08316   return NS_OK;
08317 }
08318 
08319 jsval
08320 nsNavigator::sPrefInternal_id = JSVAL_VOID;
08321 
08322 NS_IMETHODIMP
08323 nsNavigator::Preference()
08324 {
08325   nsCOMPtr<nsIXPCNativeCallContext> ncc;
08326   nsresult rv = nsContentUtils::XPConnect()->
08327     GetCurrentNativeCallContext(getter_AddRefs(ncc));
08328   NS_ENSURE_SUCCESS(rv, rv);
08329 
08330   if (!ncc)
08331     return NS_ERROR_NOT_AVAILABLE;
08332 
08333   PRUint32 argc;
08334 
08335   ncc->GetArgc(&argc);
08336 
08337   if (argc == 0) {
08338     // No arguments means there's nothing to be done here.
08339 
08340     return NS_OK;
08341   }
08342 
08343   jsval *argv = nsnull;
08344 
08345   ncc->GetArgvPtr(&argv);
08346   NS_ENSURE_TRUE(argv, NS_ERROR_UNEXPECTED);
08347 
08348   JSContext *cx = nsnull;
08349 
08350   rv = ncc->GetJSContext(&cx);
08351   NS_ENSURE_SUCCESS(rv, rv);
08352 
08353   //--Check to see if the caller is allowed to access prefs
08354   if (sPrefInternal_id == JSVAL_VOID) {
08355     sPrefInternal_id =
08356       STRING_TO_JSVAL(::JS_InternString(cx, "preferenceinternal"));
08357   }
08358 
08359   PRUint32 action;
08360   if (argc == 1) {
08361       action = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
08362   } else {
08363       action = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
08364   }
08365 
08366   nsCOMPtr<nsIScriptSecurityManager> secMan =
08367       do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
08368   NS_ENSURE_SUCCESS(rv, rv);
08369 
08370   rv = secMan->CheckPropertyAccess(cx, nsnull, "Navigator", sPrefInternal_id,
08371                                    action);
08372   if (NS_FAILED(rv)) {
08373     return NS_OK;
08374   }
08375 
08376   nsIPrefBranch *prefBranch = nsContentUtils::GetPrefBranch();
08377   NS_ENSURE_STATE(prefBranch);
08378 
08379   JSString *str = ::JS_ValueToString(cx, argv[0]);
08380   NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
08381 
08382   jsval *retval = nsnull;
08383 
08384   rv = ncc->GetRetValPtr(&retval);
08385   NS_ENSURE_SUCCESS(rv, rv);
08386 
08387   char *prefStr = ::JS_GetStringBytes(str);
08388   if (argc == 1) {
08389     PRInt32 prefType;
08390 
08391     prefBranch->GetPrefType(prefStr, &prefType);
08392 
08393     switch (prefType) {
08394     case nsIPrefBranch::PREF_STRING:
08395       {
08396