dom/base/nsGlobalWindow.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsGlobalWindow.h"
     9 #include <algorithm>
    11 #include "mozilla/MemoryReporting.h"
    13 // Local Includes
    14 #include "Navigator.h"
    15 #include "nsScreen.h"
    16 #include "nsHistory.h"
    17 #include "nsPerformance.h"
    18 #include "nsDOMNavigationTiming.h"
    19 #include "nsIDOMStorage.h"
    20 #include "nsIDOMStorageManager.h"
    21 #include "DOMStorage.h"
    22 #include "nsDOMOfflineResourceList.h"
    23 #include "nsError.h"
    24 #include "nsIIdleService.h"
    25 #include "nsISizeOfEventTarget.h"
    26 #include "nsDOMJSUtils.h"
    27 #include "nsArrayUtils.h"
    28 #include "nsIDOMWindowCollection.h"
    29 #include "nsDOMWindowList.h"
    30 #include "mozilla/dom/WakeLock.h"
    31 #include "mozilla/dom/power/PowerManagerService.h"
    32 #include "nsIDocShellTreeOwner.h"
    33 #include "nsIPermissionManager.h"
    34 #include "nsIScriptContext.h"
    35 #include "nsIScriptTimeoutHandler.h"
    36 #include "nsIController.h"
    37 #include "nsScriptNameSpaceManager.h"
    38 #include "nsWindowMemoryReporter.h"
    40 // Helper Classes
    41 #include "nsJSUtils.h"
    42 #include "jsapi.h"              // for JSAutoRequest
    43 #include "js/OldDebugAPI.h"     // for JS_ClearWatchPointsForObject
    44 #include "jswrapper.h"
    45 #include "nsReadableUtils.h"
    46 #include "nsDOMClassInfo.h"
    47 #include "nsJSEnvironment.h"
    48 #include "ScriptSettings.h"
    49 #include "mozilla/Preferences.h"
    50 #include "mozilla/Likely.h"
    51 #include "mozilla/unused.h"
    53 // Other Classes
    54 #include "mozilla/dom/BarProps.h"
    55 #include "nsContentCID.h"
    56 #include "nsLayoutStatics.h"
    57 #include "nsCCUncollectableMarker.h"
    58 #include "mozilla/dom/workers/Workers.h"
    59 #include "mozilla/dom/MessagePortList.h"
    60 #include "nsJSPrincipals.h"
    61 #include "mozilla/Attributes.h"
    62 #include "mozilla/Debug.h"
    63 #include "mozilla/EventListenerManager.h"
    64 #include "mozilla/EventStates.h"
    65 #include "mozilla/MouseEvents.h"
    66 #include "AudioChannelService.h"
    67 #include "MessageEvent.h"
    69 // Interfaces Needed
    70 #include "nsIFrame.h"
    71 #include "nsCanvasFrame.h"
    72 #include "nsIWidget.h"
    73 #include "nsIWidgetListener.h"
    74 #include "nsIBaseWindow.h"
    75 #include "nsIDeviceSensors.h"
    76 #include "nsIContent.h"
    77 #include "nsIDocShell.h"
    78 #include "nsIDocCharset.h"
    79 #include "nsIDocument.h"
    80 #include "Crypto.h"
    81 #ifndef MOZ_DISABLE_CRYPTOLEGACY
    82 #include "nsIDOMCryptoLegacy.h"
    83 #endif
    84 #include "nsIDOMDocument.h"
    85 #include "nsIDOMElement.h"
    86 #include "nsIDOMEvent.h"
    87 #include "nsIDOMPopupBlockedEvent.h"
    88 #include "nsIDOMPopStateEvent.h"
    89 #include "nsIDOMHashChangeEvent.h"
    90 #include "nsIDOMOfflineResourceList.h"
    91 #include "nsPIDOMStorage.h"
    92 #include "nsDOMString.h"
    93 #include "nsIEmbeddingSiteWindow.h"
    94 #include "nsThreadUtils.h"
    95 #include "nsILoadContext.h"
    96 #include "nsIMarkupDocumentViewer.h"
    97 #include "nsIPresShell.h"
    98 #include "nsIScriptSecurityManager.h"
    99 #include "nsIScrollableFrame.h"
   100 #include "nsView.h"
   101 #include "nsViewManager.h"
   102 #include "nsISelectionController.h"
   103 #include "nsISelection.h"
   104 #include "nsIPrompt.h"
   105 #include "nsIPromptService.h"
   106 #include "nsIPromptFactory.h"
   107 #include "nsIWritablePropertyBag2.h"
   108 #include "nsIWebNavigation.h"
   109 #include "nsIWebBrowserChrome.h"
   110 #include "nsIWebBrowserFind.h"  // For window.find()
   111 #include "nsIWindowMediator.h"  // For window.find()
   112 #include "nsComputedDOMStyle.h"
   113 #include "nsIEntropyCollector.h"
   114 #include "nsDOMCID.h"
   115 #include "nsDOMWindowUtils.h"
   116 #include "nsIWindowWatcher.h"
   117 #include "nsPIWindowWatcher.h"
   118 #include "nsIContentViewer.h"
   119 #include "nsIScriptError.h"
   120 #include "nsIControllers.h"
   121 #include "nsIControllerContext.h"
   122 #include "nsGlobalWindowCommands.h"
   123 #include "nsAutoPtr.h"
   124 #include "nsContentUtils.h"
   125 #include "nsCxPusher.h"
   126 #include "nsCSSProps.h"
   127 #include "nsIDOMFile.h"
   128 #include "nsIDOMFileList.h"
   129 #include "nsIURIFixup.h"
   130 #ifndef DEBUG
   131 #include "nsIAppStartup.h"
   132 #include "nsToolkitCompsCID.h"
   133 #endif
   134 #include "nsCDefaultURIFixup.h"
   135 #include "mozilla/EventDispatcher.h"
   136 #include "mozilla/EventStateManager.h"
   137 #include "nsIObserverService.h"
   138 #include "nsFocusManager.h"
   139 #include "nsIXULWindow.h"
   140 #include "nsITimedChannel.h"
   141 #include "nsServiceManagerUtils.h"
   142 #ifdef MOZ_XUL
   143 #include "nsIDOMXULControlElement.h"
   144 #include "nsMenuPopupFrame.h"
   145 #endif
   146 #include "nsIDOMCustomEvent.h"
   147 #include "nsIFrameRequestCallback.h"
   148 #include "nsIJARChannel.h"
   150 #include "xpcprivate.h"
   152 #ifdef NS_PRINTING
   153 #include "nsIPrintSettings.h"
   154 #include "nsIPrintSettingsService.h"
   155 #include "nsIWebBrowserPrint.h"
   156 #endif
   158 #include "nsWindowRoot.h"
   159 #include "nsNetCID.h"
   160 #include "nsIArray.h"
   162 // XXX An unfortunate dependency exists here (two XUL files).
   163 #include "nsIDOMXULDocument.h"
   164 #include "nsIDOMXULCommandDispatcher.h"
   166 #include "nsBindingManager.h"
   167 #include "nsXBLService.h"
   169 // used for popup blocking, needs to be converted to something
   170 // belonging to the back-end like nsIContentPolicy
   171 #include "nsIPopupWindowManager.h"
   173 #include "nsIDragService.h"
   174 #include "mozilla/dom/Element.h"
   175 #include "mozilla/dom/Selection.h"
   176 #include "nsFrameLoader.h"
   177 #include "nsISupportsPrimitives.h"
   178 #include "nsXPCOMCID.h"
   179 #include "GeneratedEvents.h"
   180 #include "GeneratedEventClasses.h"
   181 #include "mozIThirdPartyUtil.h"
   182 #ifdef MOZ_LOGGING
   183 // so we can get logging even in release builds
   184 #define FORCE_PR_LOG 1
   185 #endif
   186 #include "prlog.h"
   187 #include "prenv.h"
   188 #include "prprf.h"
   190 #include "mozilla/dom/MessageChannel.h"
   191 #include "mozilla/dom/MessagePort.h"
   192 #include "mozilla/dom/MessagePortBinding.h"
   193 #include "mozilla/dom/indexedDB/IDBFactory.h"
   194 #include "mozilla/dom/quota/QuotaManager.h"
   196 #include "mozilla/dom/StructuredCloneTags.h"
   198 #ifdef MOZ_GAMEPAD
   199 #include "mozilla/dom/GamepadService.h"
   200 #endif
   202 #include "nsRefreshDriver.h"
   204 #include "mozilla/Services.h"
   205 #include "mozilla/Telemetry.h"
   206 #include "nsLocation.h"
   207 #include "nsHTMLDocument.h"
   208 #include "nsWrapperCacheInlines.h"
   209 #include "mozilla/DOMEventTargetHelper.h"
   210 #include "prrng.h"
   211 #include "nsSandboxFlags.h"
   212 #include "TimeChangeObserver.h"
   213 #include "mozilla/dom/AudioContext.h"
   214 #include "mozilla/dom/BrowserElementDictionariesBinding.h"
   215 #include "mozilla/dom/Console.h"
   216 #include "mozilla/dom/FunctionBinding.h"
   217 #include "mozilla/dom/WindowBinding.h"
   218 #include "nsITabChild.h"
   219 #include "mozilla/dom/MediaQueryList.h"
   220 #include "mozilla/dom/ScriptSettings.h"
   221 #ifdef HAVE_SIDEBAR
   222 #include "mozilla/dom/ExternalBinding.h"
   223 #endif
   225 #ifdef MOZ_WEBSPEECH
   226 #include "mozilla/dom/SpeechSynthesis.h"
   227 #endif
   229 #ifdef MOZ_JSDEBUGGER
   230 #include "jsdIDebuggerService.h"
   231 #endif
   233 #ifdef MOZ_B2G
   234 #include "nsPISocketTransportService.h"
   235 #endif
   237 // Apple system headers seem to have a check() macro.  <sigh>
   238 #ifdef check
   239 class nsIScriptTimeoutHandler;
   240 #undef check
   241 #endif // check
   242 #include "AccessCheck.h"
   244 #ifdef ANDROID
   245 #include <android/log.h>
   246 #endif
   248 #ifdef PR_LOGGING
   249 static PRLogModuleInfo* gDOMLeakPRLog;
   250 #endif
   252 #ifdef XP_WIN
   253 #include <process.h>
   254 #define getpid _getpid
   255 #else
   256 #include <unistd.h> // for getpid()
   257 #endif
   259 static const char kStorageEnabled[] = "dom.storage.enabled";
   261 using namespace mozilla;
   262 using namespace mozilla::dom;
   263 using namespace mozilla::dom::ipc;
   264 using mozilla::TimeStamp;
   265 using mozilla::TimeDuration;
   267 nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sWindowsById = nullptr;
   268 bool nsGlobalWindow::sWarnedAboutWindowInternal = false;
   269 bool nsGlobalWindow::sIdleObserversAPIFuzzTimeDisabled = false;
   271 static nsIEntropyCollector *gEntropyCollector          = nullptr;
   272 static int32_t              gRefCnt                    = 0;
   273 static int32_t              gOpenPopupSpamCount        = 0;
   274 static PopupControlState    gPopupControlState         = openAbused;
   275 static int32_t              gRunningTimeoutDepth       = 0;
   276 static bool                 gMouseDown                 = false;
   277 static bool                 gDragServiceDisabled       = false;
   278 static FILE                *gDumpFile                  = nullptr;
   279 static uint64_t             gNextWindowID              = 0;
   280 static uint32_t             gSerialCounter             = 0;
   281 static uint32_t             gTimeoutsRecentlySet       = 0;
   282 static TimeStamp            gLastRecordedRecentTimeouts;
   283 #define STATISTICS_INTERVAL (30 * PR_MSEC_PER_SEC)
   285 #ifdef DEBUG_jst
   286 int32_t gTimeoutCnt                                    = 0;
   287 #endif
   289 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
   290 #define DEBUG_PAGE_CACHE
   291 #endif
   293 #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
   295 // The default shortest interval/timeout we permit
   296 #define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
   297 #define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
   298 static int32_t gMinTimeoutValue;
   299 static int32_t gMinBackgroundTimeoutValue;
   300 inline int32_t
   301 nsGlobalWindow::DOMMinTimeoutValue() const {
   302   bool isBackground = !mOuterWindow || mOuterWindow->IsBackground();
   303   return
   304     std::max(isBackground ? gMinBackgroundTimeoutValue : gMinTimeoutValue, 0);
   305 }
   307 // The number of nested timeouts before we start clamping. HTML5 says 1, WebKit
   308 // uses 5.
   309 #define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
   311 // The longest interval (as PRIntervalTime) we permit, or that our
   312 // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
   313 // nsTimerImpl.h for details.
   314 #define DOM_MAX_TIMEOUT_VALUE    DELAY_INTERVAL_LIMIT
   316 #define FORWARD_TO_OUTER(method, args, err_rval)                              \
   317   PR_BEGIN_MACRO                                                              \
   318   if (IsInnerWindow()) {                                                      \
   319     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   320     if (!HasActiveDocument()) {                                                \
   321       NS_WARNING(outer ?                                                      \
   322                  "Inner window does not have active document." :              \
   323                  "No outer window available!");                               \
   324       return err_rval;                                                        \
   325     }                                                                         \
   326     return outer->method args;                                                \
   327   }                                                                           \
   328   PR_END_MACRO
   330 #define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval)        \
   331   PR_BEGIN_MACRO                                                              \
   332   if (IsInnerWindow()) {                                                      \
   333     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   334     if (!HasActiveDocument()) {                                               \
   335       if (!outer) {                                                           \
   336         NS_WARNING("No outer window available!");                             \
   337         errorresult.Throw(NS_ERROR_NOT_INITIALIZED);                          \
   338       } else {                                                                \
   339         errorresult.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO);                \
   340       }                                                                       \
   341     } else {                                                                  \
   342       return outer->method args;                                              \
   343     }                                                                         \
   344     return err_rval;                                                          \
   345   }                                                                           \
   346   PR_END_MACRO
   348 #define FORWARD_TO_OUTER_VOID(method, args)                                   \
   349   PR_BEGIN_MACRO                                                              \
   350   if (IsInnerWindow()) {                                                      \
   351     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   352     if (!HasActiveDocument()) {                                               \
   353       NS_WARNING(outer ?                                                      \
   354                  "Inner window does not have active document." :              \
   355                  "No outer window available!");                               \
   356       return;                                                                 \
   357     }                                                                         \
   358     outer->method args;                                                       \
   359     return;                                                                   \
   360   }                                                                           \
   361   PR_END_MACRO
   363 #define FORWARD_TO_OUTER_CHROME(method, args, err_rval)                       \
   364   PR_BEGIN_MACRO                                                              \
   365   if (IsInnerWindow()) {                                                      \
   366     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   367     if (!HasActiveDocument()) {                                               \
   368       NS_WARNING(outer ?                                                      \
   369                  "Inner window does not have active document." :              \
   370                  "No outer window available!");                               \
   371       return err_rval;                                                        \
   372     }                                                                         \
   373     return ((nsGlobalChromeWindow *)outer)->method args;                      \
   374   }                                                                           \
   375   PR_END_MACRO
   377 #define FORWARD_TO_INNER_CHROME(method, args, err_rval)                       \
   378   PR_BEGIN_MACRO                                                              \
   379   if (IsOuterWindow()) {                                                      \
   380     if (!mInnerWindow) {                                                      \
   381       NS_WARNING("No inner window available!");                               \
   382       return err_rval;                                                        \
   383     }                                                                         \
   384     return ((nsGlobalChromeWindow *)mInnerWindow)->method args;               \
   385   }                                                                           \
   386   PR_END_MACRO
   388 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval)         \
   389   PR_BEGIN_MACRO                                                              \
   390   if (IsInnerWindow()) {                                                      \
   391     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   392     if (!HasActiveDocument()) {                                               \
   393       NS_WARNING(outer ?                                                      \
   394                  "Inner window does not have active document." :              \
   395                  "No outer window available!");                               \
   396       return err_rval;                                                        \
   397     }                                                                         \
   398     return ((nsGlobalModalWindow *)outer)->method args;                       \
   399   }                                                                           \
   400   PR_END_MACRO
   402 #define FORWARD_TO_INNER(method, args, err_rval)                              \
   403   PR_BEGIN_MACRO                                                              \
   404   if (IsOuterWindow()) {                                                      \
   405     if (!mInnerWindow) {                                                      \
   406       NS_WARNING("No inner window available!");                               \
   407       return err_rval;                                                        \
   408     }                                                                         \
   409     return GetCurrentInnerWindowInternal()->method args;                      \
   410   }                                                                           \
   411   PR_END_MACRO
   413 #define FORWARD_TO_INNER_OR_THROW(method, args, errorresult, err_rval)        \
   414   PR_BEGIN_MACRO                                                              \
   415   if (IsOuterWindow()) {                                                      \
   416     if (!mInnerWindow) {                                                      \
   417       NS_WARNING("No inner window available!");                               \
   418       errorresult.Throw(NS_ERROR_NOT_INITIALIZED);                            \
   419       return err_rval;                                                        \
   420     }                                                                         \
   421     return GetCurrentInnerWindowInternal()->method args;                      \
   422   }                                                                           \
   423   PR_END_MACRO
   425 #define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval)         \
   426   PR_BEGIN_MACRO                                                              \
   427   if (IsOuterWindow()) {                                                      \
   428     if (!mInnerWindow) {                                                      \
   429       NS_WARNING("No inner window available!");                               \
   430       return err_rval;                                                        \
   431     }                                                                         \
   432     return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
   433   }                                                                           \
   434   PR_END_MACRO
   436 #define FORWARD_TO_INNER_VOID(method, args)                                   \
   437   PR_BEGIN_MACRO                                                              \
   438   if (IsOuterWindow()) {                                                      \
   439     if (!mInnerWindow) {                                                      \
   440       NS_WARNING("No inner window available!");                               \
   441       return;                                                                 \
   442     }                                                                         \
   443     GetCurrentInnerWindowInternal()->method args;                             \
   444     return;                                                                   \
   445   }                                                                           \
   446   PR_END_MACRO
   448 // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
   449 // inner doesn't already exists.
   450 #define FORWARD_TO_INNER_CREATE(method, args, err_rval)                       \
   451   PR_BEGIN_MACRO                                                              \
   452   if (IsOuterWindow()) {                                                      \
   453     if (!mInnerWindow) {                                                      \
   454       if (mIsClosed) {                                                        \
   455         return err_rval;                                                      \
   456       }                                                                       \
   457       nsCOMPtr<nsIDOMDocument> doc;                                           \
   458       nsresult fwdic_nr = GetDocument(getter_AddRefs(doc));                   \
   459       NS_ENSURE_SUCCESS(fwdic_nr, err_rval);                                  \
   460       if (!mInnerWindow) {                                                    \
   461         return err_rval;                                                      \
   462       }                                                                       \
   463     }                                                                         \
   464     return GetCurrentInnerWindowInternal()->method args;                      \
   465   }                                                                           \
   466   PR_END_MACRO
   468 // CIDs
   469 static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
   471 static const char sPopStatePrefStr[] = "browser.history.allowPopState";
   473 #define NETWORK_UPLOAD_EVENT_NAME     NS_LITERAL_STRING("moznetworkupload")
   474 #define NETWORK_DOWNLOAD_EVENT_NAME   NS_LITERAL_STRING("moznetworkdownload")
   476 /**
   477  * An indirect observer object that means we don't have to implement nsIObserver
   478  * on nsGlobalWindow, where any script could see it.
   479  */
   480 class nsGlobalWindowObserver MOZ_FINAL : public nsIObserver,
   481                                          public nsIInterfaceRequestor
   482 {
   483 public:
   484   nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
   485   NS_DECL_ISUPPORTS
   486   NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
   487   {
   488     if (!mWindow)
   489       return NS_OK;
   490     return mWindow->Observe(aSubject, aTopic, aData);
   491   }
   492   void Forget() { mWindow = nullptr; }
   493   NS_IMETHODIMP GetInterface(const nsIID& aIID, void** aResult)
   494   {
   495     if (mWindow && aIID.Equals(NS_GET_IID(nsIDOMWindow)) && mWindow) {
   496       return mWindow->QueryInterface(aIID, aResult);
   497     }
   498     return NS_NOINTERFACE;
   499   }
   501 private:
   502   nsGlobalWindow* mWindow;
   503 };
   505 NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)
   507 nsTimeout::nsTimeout()
   508   : mCleared(false),
   509     mRunning(false),
   510     mIsInterval(false),
   511     mPublicId(0),
   512     mInterval(0),
   513     mFiringDepth(0),
   514     mNestingLevel(0),
   515     mPopupState(openAllowed)
   516 {
   517 #ifdef DEBUG_jst
   518   {
   519     extern int gTimeoutCnt;
   521     ++gTimeoutCnt;
   522   }
   523 #endif
   525   MOZ_COUNT_CTOR(nsTimeout);
   526 }
   528 nsTimeout::~nsTimeout()
   529 {
   530 #ifdef DEBUG_jst
   531   {
   532     extern int gTimeoutCnt;
   534     --gTimeoutCnt;
   535   }
   536 #endif
   538   if (mTimer) {
   539     mTimer->Cancel();
   540     mTimer = nullptr;
   541   }
   543   MOZ_COUNT_DTOR(nsTimeout);
   544 }
   546 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
   548 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsTimeout)
   549 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTimeout)
   550   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
   551   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
   552   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler)
   553 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   554 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
   555 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
   557 // Return true if this timeout has a refcount of 1. This is used to check
   558 // that dummy_timeout doesn't leak from nsGlobalWindow::RunTimeout.
   559 bool
   560 nsTimeout::HasRefCntOne()
   561 {
   562   return mRefCnt.get() == 1;
   563 }
   565 nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
   566 : mFrameElement(nullptr), mDocShell(nullptr), mModalStateDepth(0),
   567   mRunningTimeout(nullptr), mMutationBits(0), mIsDocumentLoaded(false),
   568   mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nullptr),
   569   mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
   570   mMayHaveMouseEnterLeaveEventListener(false),
   571   mMayHavePointerEnterLeaveEventListener(false),
   572   mIsModalContentWindow(false),
   573   mIsActive(false), mIsBackground(false),
   574   mAudioMuted(false), mAudioVolume(1.0),
   575   mInnerWindow(nullptr), mOuterWindow(aOuterWindow),
   576   // Make sure no actual window ends up with mWindowID == 0
   577   mWindowID(++gNextWindowID), mHasNotifiedGlobalCreated(false),
   578   mMarkedCCGeneration(0)
   579  {}
   581 nsPIDOMWindow::~nsPIDOMWindow() {}
   583 // DialogValueHolder CC goop.
   584 NS_IMPL_CYCLE_COLLECTION(DialogValueHolder, mValue)
   586 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DialogValueHolder)
   587   NS_INTERFACE_MAP_ENTRY(nsISupports)
   588 NS_INTERFACE_MAP_END
   590 NS_IMPL_CYCLE_COLLECTING_ADDREF(DialogValueHolder)
   591 NS_IMPL_CYCLE_COLLECTING_RELEASE(DialogValueHolder)
   593 //*****************************************************************************
   594 // nsOuterWindowProxy: Outer Window Proxy
   595 //*****************************************************************************
   597 class nsOuterWindowProxy : public js::Wrapper
   598 {
   599 public:
   600   nsOuterWindowProxy() : js::Wrapper(0) { }
   602   virtual bool finalizeInBackground(JS::Value priv) {
   603     return false;
   604   }
   606   virtual const char *className(JSContext *cx,
   607                                 JS::Handle<JSObject*> wrapper) MOZ_OVERRIDE;
   608   virtual void finalize(JSFreeOp *fop, JSObject *proxy) MOZ_OVERRIDE;
   610   // Fundamental traps
   611   virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
   612                            MOZ_OVERRIDE;
   613   virtual bool preventExtensions(JSContext *cx,
   614                                  JS::Handle<JSObject*> proxy) MOZ_OVERRIDE;
   615   virtual bool getPropertyDescriptor(JSContext* cx,
   616                                      JS::Handle<JSObject*> proxy,
   617                                      JS::Handle<jsid> id,
   618                                      JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   619   virtual bool getOwnPropertyDescriptor(JSContext* cx,
   620                                         JS::Handle<JSObject*> proxy,
   621                                         JS::Handle<jsid> id,
   622                                         JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   623   virtual bool defineProperty(JSContext* cx,
   624                               JS::Handle<JSObject*> proxy,
   625                               JS::Handle<jsid> id,
   626                               JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   627   virtual bool getOwnPropertyNames(JSContext *cx,
   628                                    JS::Handle<JSObject*> proxy,
   629                                    JS::AutoIdVector &props) MOZ_OVERRIDE;
   630   virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
   631                        JS::Handle<jsid> id,
   632                        bool *bp) MOZ_OVERRIDE;
   633   virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
   634                          JS::AutoIdVector &props) MOZ_OVERRIDE;
   636   virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
   637                      JS::Handle<jsid> id, JS::Handle<JSObject*> callable) MOZ_OVERRIDE;
   638   virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
   639                        JS::Handle<jsid> id) MOZ_OVERRIDE;
   641   // Derived traps
   642   virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
   643                    JS::Handle<jsid> id, bool *bp) MOZ_OVERRIDE;
   644   virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
   645                       JS::Handle<jsid> id, bool *bp) MOZ_OVERRIDE;
   646   virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
   647                    JS::Handle<JSObject*> receiver,
   648                    JS::Handle<jsid> id,
   649                    JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
   650   virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
   651                    JS::Handle<JSObject*> receiver,
   652                    JS::Handle<jsid> id,
   653                    bool strict,
   654                    JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
   655   virtual bool keys(JSContext *cx, JS::Handle<JSObject*> proxy,
   656                     JS::AutoIdVector &props) MOZ_OVERRIDE;
   657   virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
   658                        unsigned flags,
   659                        JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
   661   static nsOuterWindowProxy singleton;
   663 protected:
   664   nsGlobalWindow* GetWindow(JSObject *proxy)
   665   {
   666     return nsGlobalWindow::FromSupports(
   667       static_cast<nsISupports*>(js::GetProxyExtra(proxy, 0).toPrivate()));
   668   }
   670   // False return value means we threw an exception.  True return value
   671   // but false "found" means we didn't have a subframe at that index.
   672   bool GetSubframeWindow(JSContext *cx, JS::Handle<JSObject*> proxy,
   673                          JS::Handle<jsid> id,
   674                          JS::MutableHandle<JS::Value> vp,
   675                          bool &found);
   677   // Returns a non-null window only if id is an index and we have a
   678   // window at that index.
   679   already_AddRefed<nsIDOMWindow> GetSubframeWindow(JSContext *cx,
   680                                                    JS::Handle<JSObject*> proxy,
   681                                                    JS::Handle<jsid> id);
   683   bool AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
   684                                   JS::AutoIdVector &props);
   685 };
   687 const js::Class OuterWindowProxyClass =
   688     PROXY_CLASS_WITH_EXT(
   689         "Proxy",
   690         0, /* additional slots */
   691         0, /* additional class flags */
   692         nullptr, /* call */
   693         nullptr, /* construct */
   694         PROXY_MAKE_EXT(
   695             nullptr, /* outerObject */
   696             js::proxy_innerObject,
   697             nullptr, /* iteratorObject */
   698             false   /* isWrappedNative */
   699         ));
   701 bool
   702 nsOuterWindowProxy::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy,
   703                                  bool *extensible)
   704 {
   705   // If [[Extensible]] could be false, then navigating a window could navigate
   706   // to a window that's [[Extensible]] after being at one that wasn't: an
   707   // invariant violation.  So always report true for this.
   708   *extensible = true;
   709   return true;
   710 }
   712 bool
   713 nsOuterWindowProxy::preventExtensions(JSContext *cx,
   714                                       JS::Handle<JSObject*> proxy)
   715 {
   716   // See above.
   717   JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   718                        JSMSG_CANT_CHANGE_EXTENSIBILITY);
   719   return false;
   720 }
   722 const char *
   723 nsOuterWindowProxy::className(JSContext *cx, JS::Handle<JSObject*> proxy)
   724 {
   725     MOZ_ASSERT(js::IsProxy(proxy));
   727     return "Window";
   728 }
   730 void
   731 nsOuterWindowProxy::finalize(JSFreeOp *fop, JSObject *proxy)
   732 {
   733   nsGlobalWindow* global = GetWindow(proxy);
   734   if (global) {
   735     global->ClearWrapper();
   737     // Ideally we would use OnFinalize here, but it's possible that
   738     // EnsureScriptEnvironment will later be called on the window, and we don't
   739     // want to create a new script object in that case. Therefore, we need to
   740     // write a non-null value that will reliably crash when dereferenced.
   741     global->PoisonOuterWindowProxy(proxy);
   742   }
   743 }
   745 bool
   746 nsOuterWindowProxy::getPropertyDescriptor(JSContext* cx,
   747                                           JS::Handle<JSObject*> proxy,
   748                                           JS::Handle<jsid> id,
   749                                           JS::MutableHandle<JSPropertyDescriptor> desc)
   750 {
   751   // The only thing we can do differently from js::Wrapper is shadow stuff with
   752   // our indexed properties, so we can just try getOwnPropertyDescriptor and if
   753   // that gives us nothing call on through to js::Wrapper.
   754   desc.object().set(nullptr);
   755   if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) {
   756     return false;
   757   }
   759   if (desc.object()) {
   760     return true;
   761   }
   763   return js::Wrapper::getPropertyDescriptor(cx, proxy, id, desc);
   764 }
   766 bool
   767 nsOuterWindowProxy::getOwnPropertyDescriptor(JSContext* cx,
   768                                              JS::Handle<JSObject*> proxy,
   769                                              JS::Handle<jsid> id,
   770                                              JS::MutableHandle<JSPropertyDescriptor> desc)
   771 {
   772   bool found;
   773   if (!GetSubframeWindow(cx, proxy, id, desc.value(), found)) {
   774     return false;
   775   }
   776   if (found) {
   777     FillPropertyDescriptor(desc, proxy, true);
   778     return true;
   779   }
   780   // else fall through to js::Wrapper
   782   return js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
   783 }
   785 bool
   786 nsOuterWindowProxy::defineProperty(JSContext* cx,
   787                                    JS::Handle<JSObject*> proxy,
   788                                    JS::Handle<jsid> id,
   789                                    JS::MutableHandle<JSPropertyDescriptor> desc)
   790 {
   791   int32_t index = GetArrayIndexFromId(cx, id);
   792   if (IsArrayIndex(index)) {
   793     // Spec says to Reject whether this is a supported index or not,
   794     // since we have no indexed setter or indexed creator.  That means
   795     // throwing in strict mode (FIXME: Bug 828137), doing nothing in
   796     // non-strict mode.
   797     return true;
   798   }
   800   return js::Wrapper::defineProperty(cx, proxy, id, desc);
   801 }
   803 bool
   804 nsOuterWindowProxy::getOwnPropertyNames(JSContext *cx,
   805                                         JS::Handle<JSObject*> proxy,
   806                                         JS::AutoIdVector &props)
   807 {
   808   // Just our indexed stuff followed by our "normal" own property names.
   809   if (!AppendIndexedPropertyNames(cx, proxy, props)) {
   810     return false;
   811   }
   813   JS::AutoIdVector innerProps(cx);
   814   if (!js::Wrapper::getOwnPropertyNames(cx, proxy, innerProps)) {
   815     return false;
   816   }
   817   return js::AppendUnique(cx, props, innerProps);
   818 }
   820 bool
   821 nsOuterWindowProxy::delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
   822                             JS::Handle<jsid> id, bool *bp)
   823 {
   824   if (nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id)) {
   825     // Reject (which means throw if strict, else return false) the delete.
   826     // Except we don't even know whether we're strict.  See bug 803157.
   827     *bp = false;
   828     return true;
   829   }
   831   int32_t index = GetArrayIndexFromId(cx, id);
   832   if (IsArrayIndex(index)) {
   833     // Indexed, but not supported.  Spec says return true.
   834     *bp = true;
   835     return true;
   836   }
   838   return js::Wrapper::delete_(cx, proxy, id, bp);
   839 }
   841 bool
   842 nsOuterWindowProxy::enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
   843                               JS::AutoIdVector &props)
   844 {
   845   // Just our indexed stuff followed by our "normal" own property names.
   846   if (!AppendIndexedPropertyNames(cx, proxy, props)) {
   847     return false;
   848   }
   850   JS::AutoIdVector innerProps(cx);
   851   if (!js::Wrapper::enumerate(cx, proxy, innerProps)) {
   852     return false;
   853   }
   854   return js::AppendUnique(cx, props, innerProps);
   855 }
   857 bool
   858 nsOuterWindowProxy::has(JSContext *cx, JS::Handle<JSObject*> proxy,
   859                         JS::Handle<jsid> id, bool *bp)
   860 {
   861   if (nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id)) {
   862     *bp = true;
   863     return true;
   864   }
   866   return js::Wrapper::has(cx, proxy, id, bp);
   867 }
   869 bool
   870 nsOuterWindowProxy::hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
   871                            JS::Handle<jsid> id, bool *bp)
   872 {
   873   if (nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id)) {
   874     *bp = true;
   875     return true;
   876   }
   878   return js::Wrapper::hasOwn(cx, proxy, id, bp);
   879 }
   881 bool
   882 nsOuterWindowProxy::get(JSContext *cx, JS::Handle<JSObject*> proxy,
   883                         JS::Handle<JSObject*> receiver,
   884                         JS::Handle<jsid> id,
   885                         JS::MutableHandle<JS::Value> vp)
   886 {
   887   if (id == nsDOMClassInfo::sWrappedJSObject_id &&
   888       xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
   889     vp.set(JS::ObjectValue(*proxy));
   890     return true;
   891   }
   893   bool found;
   894   if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
   895     return false;
   896   }
   897   if (found) {
   898     return true;
   899   }
   900   // Else fall through to js::Wrapper
   902   return js::Wrapper::get(cx, proxy, receiver, id, vp);
   903 }
   905 bool
   906 nsOuterWindowProxy::set(JSContext *cx, JS::Handle<JSObject*> proxy,
   907                         JS::Handle<JSObject*> receiver,
   908                         JS::Handle<jsid> id,
   909                         bool strict,
   910                         JS::MutableHandle<JS::Value> vp)
   911 {
   912   int32_t index = GetArrayIndexFromId(cx, id);
   913   if (IsArrayIndex(index)) {
   914     // Reject (which means throw if and only if strict) the set.
   915     if (strict) {
   916       // XXXbz This needs to throw, but see bug 828137.
   917     }
   918     return true;
   919   }
   921   return js::Wrapper::set(cx, proxy, receiver, id, strict, vp);
   922 }
   924 bool
   925 nsOuterWindowProxy::keys(JSContext *cx, JS::Handle<JSObject*> proxy,
   926                          JS::AutoIdVector &props)
   927 {
   928   // BaseProxyHandler::keys seems to do what we want here: call
   929   // getOwnPropertyNames and then filter out the non-enumerable properties.
   930   return js::BaseProxyHandler::keys(cx, proxy, props);
   931 }
   933 bool
   934 nsOuterWindowProxy::iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
   935                             unsigned flags, JS::MutableHandle<JS::Value> vp)
   936 {
   937   // BaseProxyHandler::iterate seems to do what we want here: fall
   938   // back on the property names returned from keys() and enumerate().
   939   return js::BaseProxyHandler::iterate(cx, proxy, flags, vp);
   940 }
   942 bool
   943 nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
   944                                       JS::Handle<JSObject*> proxy,
   945                                       JS::Handle<jsid> id,
   946                                       JS::MutableHandle<JS::Value> vp,
   947                                       bool& found)
   948 {
   949   nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id);
   950   if (!frame) {
   951     found = false;
   952     return true;
   953   }
   955   found = true;
   956   // Just return the window's global
   957   nsGlobalWindow* global = static_cast<nsGlobalWindow*>(frame.get());
   958   global->EnsureInnerWindow();
   959   JSObject* obj = global->FastGetGlobalJSObject();
   960   // This null check fixes a hard-to-reproduce crash that occurs when we
   961   // get here when we're mid-call to nsDocShell::Destroy. See bug 640904
   962   // comment 105.
   963   if (MOZ_UNLIKELY(!obj)) {
   964     return xpc::Throw(cx, NS_ERROR_FAILURE);
   965   }
   967   vp.setObject(*obj);
   968   return JS_WrapValue(cx, vp);
   969 }
   971 already_AddRefed<nsIDOMWindow>
   972 nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
   973                                       JS::Handle<JSObject*> proxy,
   974                                       JS::Handle<jsid> id)
   975 {
   976   int32_t index = GetArrayIndexFromId(cx, id);
   977   if (!IsArrayIndex(index)) {
   978     return nullptr;
   979   }
   981   nsGlobalWindow* win = GetWindow(proxy);
   982   bool unused;
   983   return win->IndexedGetter(index, unused);
   984 }
   986 bool
   987 nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
   988                                                JS::AutoIdVector &props)
   989 {
   990   uint32_t length = GetWindow(proxy)->Length();
   991   MOZ_ASSERT(int32_t(length) >= 0);
   992   if (!props.reserve(props.length() + length)) {
   993     return false;
   994   }
   995   for (int32_t i = 0; i < int32_t(length); ++i) {
   996     props.append(INT_TO_JSID(i));
   997   }
   999   return true;
  1002 bool
  1003 nsOuterWindowProxy::watch(JSContext *cx, JS::Handle<JSObject*> proxy,
  1004                           JS::Handle<jsid> id, JS::Handle<JSObject*> callable)
  1006   return js::WatchGuts(cx, proxy, id, callable);
  1009 bool
  1010 nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
  1011                             JS::Handle<jsid> id)
  1013   return js::UnwatchGuts(cx, proxy, id);
  1016 nsOuterWindowProxy
  1017 nsOuterWindowProxy::singleton;
  1019 class nsChromeOuterWindowProxy : public nsOuterWindowProxy
  1021 public:
  1022   nsChromeOuterWindowProxy() : nsOuterWindowProxy() {}
  1024   virtual const char *className(JSContext *cx, JS::Handle<JSObject*> wrapper) MOZ_OVERRIDE;
  1026   static nsChromeOuterWindowProxy singleton;
  1027 };
  1029 const char *
  1030 nsChromeOuterWindowProxy::className(JSContext *cx,
  1031                                     JS::Handle<JSObject*> proxy)
  1033     MOZ_ASSERT(js::IsProxy(proxy));
  1035     return "ChromeWindow";
  1038 nsChromeOuterWindowProxy
  1039 nsChromeOuterWindowProxy::singleton;
  1041 static JSObject*
  1042 NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> parent, bool isChrome)
  1044   JSAutoCompartment ac(cx, parent);
  1045   js::WrapperOptions options;
  1046   options.setClass(&OuterWindowProxyClass);
  1047   options.setSingleton(true);
  1048   JSObject *obj = js::Wrapper::New(cx, parent, parent,
  1049                                    isChrome ? &nsChromeOuterWindowProxy::singleton
  1050                                             : &nsOuterWindowProxy::singleton,
  1051                                    &options);
  1053   NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
  1054   return obj;
  1057 //*****************************************************************************
  1058 //***    nsGlobalWindow: Object Management
  1059 //*****************************************************************************
  1061 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
  1062   : nsPIDOMWindow(aOuterWindow),
  1063     mIdleFuzzFactor(0),
  1064     mIdleCallbackIndex(-1),
  1065     mCurrentlyIdle(false),
  1066     mAddActiveEventFuzzTime(true),
  1067     mIsFrozen(false),
  1068     mFullScreen(false),
  1069     mIsClosed(false),
  1070     mInClose(false),
  1071     mHavePendingClose(false),
  1072     mHadOriginalOpener(false),
  1073     mIsPopupSpam(false),
  1074     mBlockScriptedClosingFlag(false),
  1075     mFireOfflineStatusChangeEventOnThaw(false),
  1076     mNotifyIdleObserversIdleOnThaw(false),
  1077     mNotifyIdleObserversActiveOnThaw(false),
  1078     mCreatingInnerWindow(false),
  1079     mIsChrome(false),
  1080     mCleanMessageManager(false),
  1081     mNeedsFocus(true),
  1082     mHasFocus(false),
  1083 #if defined(XP_MACOSX)
  1084     mShowAccelerators(false),
  1085     mShowFocusRings(false),
  1086 #else
  1087     mShowAccelerators(true),
  1088     mShowFocusRings(true),
  1089 #endif
  1090     mShowFocusRingForContent(false),
  1091     mFocusByKeyOccurred(false),
  1092     mInnerObjectsFreed(false),
  1093     mHasGamepad(false),
  1094 #ifdef MOZ_GAMEPAD
  1095     mHasSeenGamepadInput(false),
  1096 #endif
  1097     mNotifiedIDDestroyed(false),
  1098     mAllowScriptsToClose(false),
  1099     mTimeoutInsertionPoint(nullptr),
  1100     mTimeoutPublicIdCounter(1),
  1101     mTimeoutFiringDepth(0),
  1102     mTimeoutsSuspendDepth(0),
  1103     mFocusMethod(0),
  1104     mSerial(0),
  1105 #ifdef DEBUG
  1106     mSetOpenerWindowCalled(false),
  1107 #endif
  1108 #ifdef MOZ_B2G
  1109     mNetworkUploadObserverEnabled(false),
  1110     mNetworkDownloadObserverEnabled(false),
  1111 #endif
  1112     mCleanedUp(false),
  1113     mDialogAbuseCount(0),
  1114     mAreDialogsEnabled(true)
  1116   nsLayoutStatics::AddRef();
  1118   // Initialize the PRCList (this).
  1119   PR_INIT_CLIST(this);
  1121   if (aOuterWindow) {
  1122     // |this| is an inner window, add this inner window to the outer
  1123     // window list of inners.
  1124     PR_INSERT_AFTER(this, aOuterWindow);
  1126     mObserver = new nsGlobalWindowObserver(this);
  1127     if (mObserver) {
  1128       NS_ADDREF(mObserver);
  1129       nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
  1130       if (os) {
  1131         // Watch for online/offline status changes so we can fire events. Use
  1132         // a strong reference.
  1133         os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
  1134                         false);
  1136         // Watch for dom-storage2-changed so we can fire storage
  1137         // events. Use a strong reference.
  1138         os->AddObserver(mObserver, "dom-storage2-changed", false);
  1141   } else {
  1142     // |this| is an outer window. Outer windows start out frozen and
  1143     // remain frozen until they get an inner window, so freeze this
  1144     // outer window here.
  1145     Freeze();
  1147     mObserver = nullptr;
  1148     SetIsDOMBinding();
  1151   // We could have failed the first time through trying
  1152   // to create the entropy collector, so we should
  1153   // try to get one until we succeed.
  1155   gRefCnt++;
  1157   if (gRefCnt == 1) {
  1158     Preferences::AddIntVarCache(&gMinTimeoutValue,
  1159                                 "dom.min_timeout_value",
  1160                                 DEFAULT_MIN_TIMEOUT_VALUE);
  1161     Preferences::AddIntVarCache(&gMinBackgroundTimeoutValue,
  1162                                 "dom.min_background_timeout_value",
  1163                                 DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE);
  1164     Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled, 
  1165                                  "dom.idle-observers-api.fuzz_time.disabled",
  1166                                  false);
  1169   if (gDumpFile == nullptr) {
  1170     const nsAdoptingCString& fname =
  1171       Preferences::GetCString("browser.dom.window.dump.file");
  1172     if (!fname.IsEmpty()) {
  1173       // if this fails to open, Dump() knows to just go to stdout
  1174       // on null.
  1175       gDumpFile = fopen(fname, "wb+");
  1176     } else {
  1177       gDumpFile = stdout;
  1181   mSerial = ++gSerialCounter;
  1183 #ifdef DEBUG
  1184   if (!PR_GetEnv("MOZ_QUIET")) {
  1185     printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
  1186                   gRefCnt,
  1187                   static_cast<void*>(ToCanonicalSupports(this)),
  1188                   getpid(),
  1189                   gSerialCounter,
  1190                   static_cast<void*>(ToCanonicalSupports(aOuterWindow)));
  1192 #endif
  1194 #ifdef PR_LOGGING
  1195   if (gDOMLeakPRLog)
  1196     PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
  1197            ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
  1198 #endif
  1200   NS_ASSERTION(sWindowsById, "Windows hash table must be created!");
  1201   NS_ASSERTION(!sWindowsById->Get(mWindowID),
  1202                "This window shouldn't be in the hash table yet!");
  1203   // We seem to see crashes in release builds because of null |sWindowsById|.
  1204   if (sWindowsById) {
  1205     sWindowsById->Put(mWindowID, this);
  1209 /* static */
  1210 void
  1211 nsGlobalWindow::Init()
  1213   CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
  1214   NS_ASSERTION(gEntropyCollector,
  1215                "gEntropyCollector should have been initialized!");
  1217 #ifdef PR_LOGGING
  1218   gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
  1219   NS_ASSERTION(gDOMLeakPRLog, "gDOMLeakPRLog should have been initialized!");
  1220 #endif
  1222   sWindowsById = new WindowByIdTable();
  1225 static PLDHashOperator
  1226 DisconnectEventTargetObjects(nsPtrHashKey<DOMEventTargetHelper>* aKey,
  1227                              void* aClosure)
  1229   nsRefPtr<DOMEventTargetHelper> target = aKey->GetKey();
  1230   target->DisconnectFromOwner();
  1231   return PL_DHASH_NEXT;
  1234 nsGlobalWindow::~nsGlobalWindow()
  1236   mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
  1237   mEventTargetObjects.Clear();
  1239   // We have to check if sWindowsById isn't null because ::Shutdown might have
  1240   // been called.
  1241   if (sWindowsById) {
  1242     NS_ASSERTION(sWindowsById->Get(mWindowID),
  1243                  "This window should be in the hash table");
  1244     sWindowsById->Remove(mWindowID);
  1247   --gRefCnt;
  1249 #ifdef DEBUG
  1250   if (!PR_GetEnv("MOZ_QUIET")) {
  1251     nsAutoCString url;
  1252     if (mLastOpenedURI) {
  1253       mLastOpenedURI->GetSpec(url);
  1255       // Data URLs can be very long, so truncate to avoid flooding the log.
  1256       const uint32_t maxURLLength = 1000;
  1257       if (url.Length() > maxURLLength) {
  1258         url.Truncate(maxURLLength);
  1262     nsGlobalWindow* outer = static_cast<nsGlobalWindow*>(mOuterWindow.get());
  1263     printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n",
  1264                   gRefCnt,
  1265                   static_cast<void*>(ToCanonicalSupports(this)),
  1266                   getpid(),
  1267                   mSerial,
  1268                   static_cast<void*>(ToCanonicalSupports(outer)),
  1269                   url.get());
  1271 #endif
  1273 #ifdef PR_LOGGING
  1274   if (gDOMLeakPRLog)
  1275     PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
  1276            ("DOMWINDOW %p destroyed", this));
  1277 #endif
  1279   if (IsOuterWindow()) {
  1280     JSObject *proxy = GetWrapperPreserveColor();
  1281     if (proxy) {
  1282       js::SetProxyExtra(proxy, 0, js::PrivateValue(nullptr));
  1285     // An outer window is destroyed with inner windows still possibly
  1286     // alive, iterate through the inner windows and null out their
  1287     // back pointer to this outer, and pull them out of the list of
  1288     // inner windows.
  1290     nsGlobalWindow *w;
  1291     while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
  1292       PR_REMOVE_AND_INIT_LINK(w);
  1295     DropOuterWindowDocs();
  1296   } else {
  1297     Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
  1298                           mMutationBits ? 1 : 0);
  1300     if (mListenerManager) {
  1301       mListenerManager->Disconnect();
  1302       mListenerManager = nullptr;
  1305     // An inner window is destroyed, pull it out of the outer window's
  1306     // list if inner windows.
  1308     PR_REMOVE_LINK(this);
  1310     // If our outer window's inner window is this window, null out the
  1311     // outer window's reference to this window that's being deleted.
  1312     nsGlobalWindow *outer = GetOuterWindowInternal();
  1313     if (outer) {
  1314       outer->MaybeClearInnerWindow(this);
  1318   // Outer windows are always supposed to call CleanUp before letting themselves
  1319   // be destroyed. And while CleanUp generally seems to be intended to clean up
  1320   // outers, we've historically called it for both. Changing this would probably
  1321   // involve auditing all of the references that inners and outers can have, and
  1322   // separating the handling into CleanUp() and FreeInnerObjects.
  1323   if (IsInnerWindow()) {
  1324     CleanUp();
  1325   } else {
  1326     MOZ_ASSERT(mCleanedUp);
  1329   nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
  1330   if (ac)
  1331     ac->RemoveWindowAsListener(this);
  1333   nsLayoutStatics::Release();
  1336 void
  1337 nsGlobalWindow::AddEventTargetObject(DOMEventTargetHelper* aObject)
  1339   mEventTargetObjects.PutEntry(aObject);
  1342 void
  1343 nsGlobalWindow::RemoveEventTargetObject(DOMEventTargetHelper* aObject)
  1345   mEventTargetObjects.RemoveEntry(aObject);
  1348 // static
  1349 void
  1350 nsGlobalWindow::ShutDown()
  1352   if (gDumpFile && gDumpFile != stdout) {
  1353     fclose(gDumpFile);
  1355   gDumpFile = nullptr;
  1357   NS_IF_RELEASE(gEntropyCollector);
  1359   delete sWindowsById;
  1360   sWindowsById = nullptr;
  1363 // static
  1364 void
  1365 nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
  1367   if (aWindow->mCachedXBLPrototypeHandlers &&
  1368       aWindow->mCachedXBLPrototypeHandlers->Count() > 0) {
  1369     aWindow->mCachedXBLPrototypeHandlers->Clear();
  1373 void
  1374 nsGlobalWindow::MaybeForgiveSpamCount()
  1376   if (IsOuterWindow() &&
  1377       IsPopupSpamWindow())
  1379     SetPopupSpamWindow(false);
  1380     --gOpenPopupSpamCount;
  1381     NS_ASSERTION(gOpenPopupSpamCount >= 0,
  1382                  "Unbalanced decrement of gOpenPopupSpamCount");
  1386 void
  1387 nsGlobalWindow::DropOuterWindowDocs()
  1389   MOZ_ASSERT(IsOuterWindow());
  1390   MOZ_ASSERT_IF(mDoc, !mDoc->EventHandlingSuppressed());
  1391   mDoc = nullptr;
  1392   mSuspendedDoc = nullptr;
  1395 void
  1396 nsGlobalWindow::CleanUp()
  1398   // Guarantee idempotence.
  1399   if (mCleanedUp)
  1400     return;
  1401   mCleanedUp = true;
  1403   mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
  1404   mEventTargetObjects.Clear();
  1406   if (mObserver) {
  1407     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
  1408     if (os) {
  1409       os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
  1410       os->RemoveObserver(mObserver, "dom-storage2-changed");
  1413 #ifdef MOZ_B2G
  1414     DisableNetworkEvent(NS_NETWORK_UPLOAD_EVENT);
  1415     DisableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT);
  1416 #endif // MOZ_B2G
  1418     if (mIdleService) {
  1419       mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
  1422     // Drop its reference to this dying window, in case for some bogus reason
  1423     // the object stays around.
  1424     mObserver->Forget();
  1425     NS_RELEASE(mObserver);
  1428   if (mNavigator) {
  1429     mNavigator->Invalidate();
  1430     mNavigator = nullptr;
  1433   mScreen = nullptr;
  1434   mMenubar = nullptr;
  1435   mToolbar = nullptr;
  1436   mLocationbar = nullptr;
  1437   mPersonalbar = nullptr;
  1438   mStatusbar = nullptr;
  1439   mScrollbars = nullptr;
  1440   mLocation = nullptr;
  1441   mHistory = nullptr;
  1442   mFrames = nullptr;
  1443   mWindowUtils = nullptr;
  1444   mApplicationCache = nullptr;
  1445   mIndexedDB = nullptr;
  1447   mConsole = nullptr;
  1449   mExternal = nullptr;
  1451   mPerformance = nullptr;
  1453 #ifdef MOZ_WEBSPEECH
  1454   mSpeechSynthesis = nullptr;
  1455 #endif
  1457   ClearControllers();
  1459   mOpener = nullptr;             // Forces Release
  1460   if (mContext) {
  1461     mContext = nullptr;            // Forces Release
  1463   mChromeEventHandler = nullptr; // Forces Release
  1464   mParentTarget = nullptr;
  1466   nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
  1468   if (inner) {
  1469     inner->CleanUp();
  1472   DisableGamepadUpdates();
  1473   mHasGamepad = false;
  1475   if (mCleanMessageManager) {
  1476     NS_ABORT_IF_FALSE(mIsChrome, "only chrome should have msg manager cleaned");
  1477     nsGlobalChromeWindow *asChrome = static_cast<nsGlobalChromeWindow*>(this);
  1478     if (asChrome->mMessageManager) {
  1479       static_cast<nsFrameMessageManager*>(
  1480         asChrome->mMessageManager.get())->Disconnect();
  1484   mArguments = nullptr;
  1485   mDialogArguments = nullptr;
  1487   CleanupCachedXBLHandlers(this);
  1489   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
  1490     mAudioContexts[i]->Shutdown();
  1492   mAudioContexts.Clear();
  1494   if (mIdleTimer) {
  1495     mIdleTimer->Cancel();
  1496     mIdleTimer = nullptr;
  1499   DisableTimeChangeNotifications();
  1502 void
  1503 nsGlobalWindow::ClearControllers()
  1505   if (mControllers) {
  1506     uint32_t count;
  1507     mControllers->GetControllerCount(&count);
  1509     while (count--) {
  1510       nsCOMPtr<nsIController> controller;
  1511       mControllers->GetControllerAt(count, getter_AddRefs(controller));
  1513       nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
  1514       if (context)
  1515         context->SetCommandContext(nullptr);
  1518     mControllers = nullptr;
  1522 void
  1523 nsGlobalWindow::FreeInnerObjects()
  1525   NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
  1527   // Make sure that this is called before we null out the document and
  1528   // other members that the window destroyed observers could
  1529   // re-create.
  1530   NotifyDOMWindowDestroyed(this);
  1532   mInnerObjectsFreed = true;
  1534   // Kill all of the workers for this window.
  1535   mozilla::dom::workers::CancelWorkersForWindow(this);
  1537   // Close all offline storages for this window.
  1538   quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
  1539   if (quotaManager) {
  1540     quotaManager->AbortCloseStoragesForWindow(this);
  1543   ClearAllTimeouts();
  1545   if (mIdleTimer) {
  1546     mIdleTimer->Cancel();
  1547     mIdleTimer = nullptr;
  1550   mIdleObservers.Clear();
  1552   mChromeEventHandler = nullptr;
  1554   if (mListenerManager) {
  1555     mListenerManager->Disconnect();
  1556     mListenerManager = nullptr;
  1559   mLocation = nullptr;
  1560   mHistory = nullptr;
  1562   if (mNavigator) {
  1563     mNavigator->OnNavigation();
  1564     mNavigator->Invalidate();
  1565     mNavigator = nullptr;
  1568   if (mScreen) {
  1569     mScreen = nullptr;
  1572   if (mDoc) {
  1573     // Remember the document's principal and URI.
  1574     mDocumentPrincipal = mDoc->NodePrincipal();
  1575     mDocumentURI = mDoc->GetDocumentURI();
  1576     mDocBaseURI = mDoc->GetDocBaseURI();
  1578     while (mDoc->EventHandlingSuppressed()) {
  1579       mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false);
  1582     // Note: we don't have to worry about eAnimationsOnly suppressions because
  1583     // they won't leak.
  1586   // Remove our reference to the document and the document principal.
  1587   mFocusedNode = nullptr;
  1589   if (mApplicationCache) {
  1590     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
  1591     mApplicationCache = nullptr;
  1594   mIndexedDB = nullptr;
  1596   NotifyWindowIDDestroyed("inner-window-destroyed");
  1598   CleanupCachedXBLHandlers(this);
  1600   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
  1601     mAudioContexts[i]->Shutdown();
  1603   mAudioContexts.Clear();
  1605 #ifdef MOZ_GAMEPAD
  1606   DisableGamepadUpdates();
  1607   mHasGamepad = false;
  1608   mGamepads.Clear();
  1609 #endif
  1612 //*****************************************************************************
  1613 // nsGlobalWindow::nsISupports
  1614 //*****************************************************************************
  1616 DOMCI_DATA(Window, nsGlobalWindow)
  1618 // QueryInterface implementation for nsGlobalWindow
  1619 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
  1620   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  1621   // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
  1622   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
  1623   NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
  1624 #ifdef MOZ_B2G
  1625   NS_INTERFACE_MAP_ENTRY(nsIDOMWindowB2G)
  1626 #endif // MOZ_B2G
  1627 #ifdef MOZ_WEBSPEECH
  1628   NS_INTERFACE_MAP_ENTRY(nsISpeechSynthesisGetter)
  1629 #endif // MOZ_B2G
  1630   NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
  1631   if (aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) {
  1632     foundInterface = static_cast<nsIDOMWindowInternal*>(this);
  1633     if (!sWarnedAboutWindowInternal) {
  1634       sWarnedAboutWindowInternal = true;
  1635       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
  1636                                       NS_LITERAL_CSTRING("Extensions"), mDoc,
  1637                                       nsContentUtils::eDOM_PROPERTIES,
  1638                                       "nsIDOMWindowInternalWarning");
  1640   } else
  1641   NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
  1642   NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
  1643   NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
  1644   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
  1645   NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
  1646   NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
  1647   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  1648   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
  1649   NS_INTERFACE_MAP_ENTRY(nsIDOMWindowPerformance)
  1650   NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver)
  1651   NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
  1652   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
  1653 NS_INTERFACE_MAP_END
  1656 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
  1657 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
  1659 static PLDHashOperator
  1660 MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
  1662   JS::ExposeObjectToActiveJS(aData);
  1663   return PL_DHASH_NEXT;
  1666 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
  1667   if (tmp->IsBlackForCC(false)) {
  1668     if (tmp->mCachedXBLPrototypeHandlers) {
  1669       tmp->mCachedXBLPrototypeHandlers->Enumerate(MarkXBLHandlers, nullptr);
  1671     if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
  1672       elm->MarkForCC();
  1674     tmp->UnmarkGrayTimers();
  1675     return true;
  1677 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
  1679 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)
  1680   return tmp->IsBlackForCC(true);
  1681 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
  1683 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)
  1684   return tmp->IsBlackForCC(false);
  1685 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
  1687 inline void
  1688 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
  1689                             IdleObserverHolder& aField,
  1690                             const char* aName,
  1691                             unsigned aFlags)
  1693   CycleCollectionNoteChild(aCallback, aField.mIdleObserver.get(), aName, aFlags);
  1696 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
  1698 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
  1699   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
  1700     char name[512];
  1701     PR_snprintf(name, sizeof(name), "nsGlobalWindow #%ld", tmp->mWindowID);
  1702     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
  1703   } else {
  1704     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow, tmp->mRefCnt.get())
  1707   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
  1709   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
  1710   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
  1711   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments)
  1712   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue)
  1713   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
  1715   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
  1717 #ifdef MOZ_WEBSPEECH
  1718   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
  1719 #endif
  1721   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)
  1723   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
  1725   for (nsTimeout* timeout = tmp->mTimeouts.getFirst();
  1726        timeout;
  1727        timeout = timeout->getNext()) {
  1728     cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(nsTimeout));
  1731   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
  1732   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
  1733   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
  1734   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
  1735   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
  1736   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
  1737   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
  1738   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
  1740 #ifdef MOZ_GAMEPAD
  1741   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
  1742 #endif
  1744   // Traverse stuff from nsPIDOMWindow
  1745   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
  1746   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
  1747   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
  1748   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode)
  1750   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
  1751   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
  1752   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
  1753   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
  1754   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
  1755   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
  1756   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
  1757   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
  1758   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
  1759   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
  1760 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  1762 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
  1763   nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
  1765   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
  1767   NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
  1768   NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
  1769   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments)
  1770   NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue)
  1771   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
  1773   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
  1775 #ifdef MOZ_WEBSPEECH
  1776   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
  1777 #endif
  1779   if (tmp->mOuterWindow) {
  1780     static_cast<nsGlobalWindow*>(tmp->mOuterWindow.get())->MaybeClearInnerWindow(tmp);
  1781     NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
  1784   if (tmp->mListenerManager) {
  1785     tmp->mListenerManager->Disconnect();
  1786     NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
  1788   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
  1789   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
  1790   if (tmp->mApplicationCache) {
  1791     static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();
  1792     NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
  1794   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
  1795   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
  1796   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
  1797   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
  1798   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
  1800 #ifdef MOZ_GAMEPAD
  1801   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
  1802 #endif
  1804   // Unlink stuff from nsPIDOMWindow
  1805   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
  1806   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
  1807   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
  1808   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode)
  1810   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
  1811   NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
  1812   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
  1813   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
  1814   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
  1815   NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
  1816   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
  1817   NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
  1818   NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
  1819   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  1820 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  1822 #ifdef DEBUG
  1823 void
  1824 nsGlobalWindow::RiskyUnlink()
  1826   NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);
  1828 #endif
  1830 struct TraceData
  1832   const TraceCallbacks& callbacks;
  1833   void* closure;
  1834 };
  1836 static PLDHashOperator
  1837 TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
  1839   TraceData* data = static_cast<TraceData*>(aClosure);
  1840   data->callbacks.Trace(&aData, "Cached XBL prototype handler", data->closure);
  1841   return PL_DHASH_NEXT;
  1844 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
  1845   if (tmp->mCachedXBLPrototypeHandlers) {
  1846     TraceData data = { aCallbacks, aClosure };
  1847     tmp->mCachedXBLPrototypeHandlers->Enumerate(TraceXBLHandlers, &data);
  1849   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
  1850 NS_IMPL_CYCLE_COLLECTION_TRACE_END
  1852 bool
  1853 nsGlobalWindow::IsBlackForCC(bool aTracingNeeded)
  1855   if (!nsCCUncollectableMarker::sGeneration) {
  1856     return false;
  1859   return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
  1860           IsBlack()) &&
  1861          (!aTracingNeeded ||
  1862           HasNothingToTrace(static_cast<nsIDOMEventTarget*>(this)));
  1865 void
  1866 nsGlobalWindow::UnmarkGrayTimers()
  1868   for (nsTimeout* timeout = mTimeouts.getFirst();
  1869        timeout;
  1870        timeout = timeout->getNext()) {
  1871     if (timeout->mScriptHandler) {
  1872       Function* f = timeout->mScriptHandler->GetCallback();
  1873       if (f) {
  1874         // Callable() already does xpc_UnmarkGrayObject.
  1875         DebugOnly<JS::Handle<JSObject*> > o = f->Callable();
  1876         MOZ_ASSERT(!xpc_IsGrayGCThing(o.value), "Should have been unmarked");
  1882 //*****************************************************************************
  1883 // nsGlobalWindow::nsIScriptGlobalObject
  1884 //*****************************************************************************
  1886 nsresult
  1887 nsGlobalWindow::EnsureScriptEnvironment()
  1889   nsGlobalWindow* outer = GetOuterWindowInternal();
  1890   if (!outer) {
  1891     NS_WARNING("No outer window available!");
  1892     return NS_ERROR_FAILURE;
  1895   if (outer->GetWrapperPreserveColor()) {
  1896     return NS_OK;
  1899   NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(),
  1900                "No cached wrapper, but we have an inner window?");
  1902   // If this window is a [i]frame, don't bother GC'ing when the frame's context
  1903   // is destroyed since a GC will happen when the frameset or host document is
  1904   // destroyed anyway.
  1905   nsCOMPtr<nsIScriptContext> context = new nsJSContext(!IsFrame(), outer);
  1907   NS_ASSERTION(!outer->mContext, "Will overwrite mContext!");
  1909   // should probably assert the context is clean???
  1910   context->WillInitializeContext();
  1912   nsresult rv = context->InitContext();
  1913   NS_ENSURE_SUCCESS(rv, rv);
  1915   outer->mContext = context;
  1916   return NS_OK;
  1919 nsIScriptContext *
  1920 nsGlobalWindow::GetScriptContext()
  1922   nsGlobalWindow* outer = GetOuterWindowInternal();
  1923   return outer ? outer->mContext : nullptr;
  1926 JSObject *
  1927 nsGlobalWindow::GetGlobalJSObject()
  1929   return FastGetGlobalJSObject();
  1932 void
  1933 nsGlobalWindow::TraceGlobalJSObject(JSTracer* aTrc)
  1935   TraceWrapper(aTrc, "active window global");
  1938 /* static */
  1939 JSObject*
  1940 nsGlobalWindow::OuterObject(JSContext* aCx, JS::Handle<JSObject*> aObj)
  1942   nsGlobalWindow* origWin;
  1943   UNWRAP_OBJECT(Window, aObj, origWin);
  1944   nsGlobalWindow* win = origWin->GetOuterWindowInternal();
  1946   if (!win) {
  1947     // If we no longer have an outer window. No code should ever be
  1948     // running on a window w/o an outer, which means this hook should
  1949     // never be called when we have no outer. But just in case, return
  1950     // null to prevent leaking an inner window to code in a different
  1951     // window.
  1952     NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
  1953     return nullptr;
  1956   JS::Rooted<JSObject*> winObj(aCx, win->FastGetGlobalJSObject());
  1957   MOZ_ASSERT(winObj);
  1959   // Note that while |wrapper| is same-compartment with cx, the outer window
  1960   // might not be. If we're running script in an inactive scope and evalute
  1961   // |this|, the outer window is actually a cross-compartment wrapper. So we
  1962   // need to wrap here.
  1963   if (!JS_WrapObject(aCx, &winObj)) {
  1964     NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
  1965     return nullptr;
  1968   return winObj;
  1971 bool
  1972 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
  1974   // We reuse the inner window when:
  1975   // a. We are currently at our original document.
  1976   // b. At least one of the following conditions are true:
  1977   // -- The new document is the same as the old document. This means that we're
  1978   //    getting called from document.open().
  1979   // -- The new document has the same origin as what we have loaded right now.
  1981   if (!mDoc || !aNewDocument) {
  1982     return false;
  1985   if (!mDoc->IsInitialDocument()) {
  1986     return false;
  1989   NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
  1990                "How'd this happen?");
  1992   // Great, we're the original document, check for one of the other
  1993   // conditions.
  1995   if (mDoc == aNewDocument) {
  1996     return true;
  1999   bool equal;
  2000   if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
  2001                                                  &equal)) &&
  2002       equal) {
  2003     // The origin is the same.
  2004     return true;
  2007   return false;
  2010 void
  2011 nsGlobalWindow::SetInitialPrincipalToSubject()
  2013   FORWARD_TO_OUTER_VOID(SetInitialPrincipalToSubject, ());
  2015   // First, grab the subject principal.
  2016   nsCOMPtr<nsIPrincipal> newWindowPrincipal = nsContentUtils::GetSubjectPrincipal();
  2017   if (!newWindowPrincipal) {
  2018     newWindowPrincipal = nsContentUtils::GetSystemPrincipal();
  2021   // Now, if we're about to use the system principal or an nsExpandedPrincipal,
  2022   // make sure we're not using it for a content docshell.
  2023   if (nsContentUtils::IsSystemOrExpandedPrincipal(newWindowPrincipal) &&
  2024       GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome) {
  2025     newWindowPrincipal = nullptr;
  2028   // If there's an existing document, bail if it either:
  2029   if (mDoc) {
  2030     // (a) is not an initial about:blank document, or
  2031     if (!mDoc->IsInitialDocument())
  2032       return;
  2033     // (b) already has the correct principal.
  2034     if (mDoc->NodePrincipal() == newWindowPrincipal)
  2035       return;
  2037 #ifdef DEBUG
  2038     // If we have a document loaded at this point, it had better be about:blank.
  2039     // Otherwise, something is really weird.
  2040     nsCOMPtr<nsIURI> uri;
  2041     mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
  2042     NS_ASSERTION(uri && NS_IsAboutBlank(uri) &&
  2043                  NS_IsAboutBlank(mDoc->GetDocumentURI()),
  2044                  "Unexpected original document");
  2045 #endif
  2048   GetDocShell()->CreateAboutBlankContentViewer(newWindowPrincipal);
  2049   mDoc->SetIsInitialDocument(true);
  2051   nsCOMPtr<nsIPresShell> shell = GetDocShell()->GetPresShell();
  2053   if (shell && !shell->DidInitialize()) {
  2054     // Ensure that if someone plays with this document they will get
  2055     // layout happening.
  2056     nsRect r = shell->GetPresContext()->GetVisibleArea();
  2057     shell->Initialize(r.width, r.height);
  2061 PopupControlState
  2062 PushPopupControlState(PopupControlState aState, bool aForce)
  2064   MOZ_ASSERT(NS_IsMainThread());
  2066   PopupControlState oldState = gPopupControlState;
  2068   if (aState < gPopupControlState || aForce) {
  2069     gPopupControlState = aState;
  2072   return oldState;
  2075 void
  2076 PopPopupControlState(PopupControlState aState)
  2078   MOZ_ASSERT(NS_IsMainThread());
  2080   gPopupControlState = aState;
  2083 PopupControlState
  2084 nsGlobalWindow::PushPopupControlState(PopupControlState aState,
  2085                                       bool aForce) const
  2087   return ::PushPopupControlState(aState, aForce);
  2090 void
  2091 nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
  2093   ::PopPopupControlState(aState);
  2096 PopupControlState
  2097 nsGlobalWindow::GetPopupControlState() const
  2099   MOZ_ASSERT(NS_IsMainThread());
  2100   return gPopupControlState;
  2103 #define WINDOWSTATEHOLDER_IID \
  2104 {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
  2106 class WindowStateHolder MOZ_FINAL : public nsISupports
  2108 public:
  2109   NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
  2110   NS_DECL_ISUPPORTS
  2112   WindowStateHolder(nsGlobalWindow *aWindow);
  2114   nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
  2116   void DidRestoreWindow()
  2118     mInnerWindow = nullptr;
  2121 protected:
  2122   ~WindowStateHolder();
  2124   nsRefPtr<nsGlobalWindow> mInnerWindow;
  2125 };
  2127 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
  2129 WindowStateHolder::WindowStateHolder(nsGlobalWindow* aWindow)
  2130   : mInnerWindow(aWindow)
  2132   NS_PRECONDITION(aWindow, "null window");
  2133   NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
  2135   // We hold onto this to make sure the inner window doesn't go away. The outer
  2136   // window ends up recalculating it anyway.
  2137   mInnerWindow->PreserveWrapper(ToSupports(mInnerWindow));
  2139   aWindow->SuspendTimeouts();
  2141   // When a global goes into the bfcache, we disable script.
  2142   xpc::Scriptability::Get(aWindow->GetWrapperPreserveColor()).SetDocShellAllowsScript(false);
  2145 WindowStateHolder::~WindowStateHolder()
  2147   if (mInnerWindow) {
  2148     // This window was left in the bfcache and is now going away. We need to
  2149     // free it up.
  2150     // Note that FreeInnerObjects may already have been called on the
  2151     // inner window if its outer has already had SetDocShell(null)
  2152     // called.
  2153     mInnerWindow->FreeInnerObjects();
  2157 NS_IMPL_ISUPPORTS(WindowStateHolder, WindowStateHolder)
  2159 // We need certain special behavior for remote XUL whitelisted domains, but we
  2160 // don't want that behavior to take effect in automation, because we whitelist
  2161 // all the mochitest domains. So we need to check a pref here.
  2162 static bool
  2163 TreatAsRemoteXUL(nsIPrincipal* aPrincipal)
  2165   MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(aPrincipal));
  2166   return nsContentUtils::AllowXULXBLForPrincipal(aPrincipal) &&
  2167          !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
  2170 /**
  2171  * Create a new global object that will be used for an inner window.
  2172  * Return the native global and an nsISupports 'holder' that can be used
  2173  * to manage the lifetime of it.
  2174  */
  2175 static nsresult
  2176 CreateNativeGlobalForInner(JSContext* aCx,
  2177                            nsGlobalWindow* aNewInner,
  2178                            nsIURI* aURI,
  2179                            nsIPrincipal* aPrincipal,
  2180                            JS::MutableHandle<JSObject*> aGlobal)
  2182   MOZ_ASSERT(aCx);
  2183   MOZ_ASSERT(aNewInner);
  2184   MOZ_ASSERT(aNewInner->IsInnerWindow());
  2185   MOZ_ASSERT(aPrincipal);
  2187   // DOMWindow with nsEP is not supported, we have to make sure
  2188   // no one creates one accidentally.
  2189   nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(aPrincipal);
  2190   MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported");
  2192   nsGlobalWindow *top = nullptr;
  2193   if (aNewInner->GetOuterWindow()) {
  2194     top = aNewInner->GetTop();
  2196   JS::CompartmentOptions options;
  2197   if (top) {
  2198     if (top->GetGlobalJSObject()) {
  2199       options.setSameZoneAs(top->GetGlobalJSObject());
  2203   nsIXPConnect* xpc = nsContentUtils::XPConnect();
  2205   // Determine if we need the Components object.
  2206   bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
  2207                         TreatAsRemoteXUL(aPrincipal);
  2208   uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
  2209   flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
  2211   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
  2212   nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
  2213     aCx, ToSupports(aNewInner),
  2214     aPrincipal, flags, options, getter_AddRefs(holder));
  2215   NS_ENSURE_SUCCESS(rv, rv);
  2217   aGlobal.set(holder->GetJSObject());
  2219   // Set the location information for the new global, so that tools like
  2220   // about:memory may use that information
  2221   MOZ_ASSERT(aGlobal);
  2222   MOZ_ASSERT(aNewInner->GetWrapperPreserveColor() == aGlobal);
  2223   xpc::SetLocationForGlobal(aGlobal, aURI);
  2225   return NS_OK;
  2228 nsresult
  2229 nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
  2230                                nsISupports* aState,
  2231                                bool aForceReuseInnerWindow)
  2233   NS_PRECONDITION(mDocumentPrincipal == nullptr,
  2234                   "mDocumentPrincipal prematurely set!");
  2235   MOZ_ASSERT(aDocument);
  2237   if (IsInnerWindow()) {
  2238     if (!mOuterWindow) {
  2239       return NS_ERROR_NOT_INITIALIZED;
  2242     // Refuse to set a new document if the call came from an inner
  2243     // window that's not the current inner window.
  2244     if (mOuterWindow->GetCurrentInnerWindow() != this) {
  2245       return NS_ERROR_NOT_AVAILABLE;
  2248     return GetOuterWindowInternal()->SetNewDocument(aDocument, aState,
  2249                                                     aForceReuseInnerWindow);
  2252   NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
  2254   if (IsFrozen()) {
  2255     // This outer is now getting its first inner, thaw the outer now
  2256     // that it's ready and is getting an inner window.
  2258     Thaw();
  2261   NS_ASSERTION(!GetCurrentInnerWindow() ||
  2262                GetCurrentInnerWindow()->GetExtantDoc() == mDoc,
  2263                "Uh, mDoc doesn't match the current inner window "
  2264                "document!");
  2266   bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
  2267   if (aForceReuseInnerWindow &&
  2268       !wouldReuseInnerWindow &&
  2269       mDoc &&
  2270       mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
  2271     NS_ERROR("Attempted forced inner window reuse while changing principal");
  2272     return NS_ERROR_UNEXPECTED;
  2275   nsCOMPtr<nsIDocument> oldDoc = mDoc;
  2277   nsIScriptContext *scx = GetContextInternal();
  2278   NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
  2280   JSContext *cx = scx->GetNativeContext();
  2282 #ifndef MOZ_DISABLE_CRYPTOLEGACY
  2283   // clear smartcard events, our document has gone away.
  2284   if (mCrypto && XRE_GetProcessType() != GeckoProcessType_Content) {
  2285     nsresult rv = mCrypto->SetEnableSmartCardEvents(false);
  2286     NS_ENSURE_SUCCESS(rv, rv);
  2288 #endif
  2290   if (!mDoc) {
  2291     // First document load.
  2293     // Get our private root. If it is equal to us, then we need to
  2294     // attach our global key bindings that handles browser scrolling
  2295     // and other browser commands.
  2296     nsIDOMWindow* privateRoot = nsGlobalWindow::GetPrivateRoot();
  2298     if (privateRoot == static_cast<nsIDOMWindow*>(this)) {
  2299       nsXBLService::AttachGlobalKeyHandler(mChromeEventHandler);
  2303   /* No mDocShell means we're already been partially closed down.  When that
  2304      happens, setting status isn't a big requirement, so don't. (Doesn't happen
  2305      under normal circumstances, but bug 49615 describes a case.) */
  2307   nsContentUtils::AddScriptRunner(
  2308     NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
  2310   // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
  2311   // window (see bug 776497). Be safe.
  2312   bool reUseInnerWindow = (aForceReuseInnerWindow || wouldReuseInnerWindow) &&
  2313                           GetCurrentInnerWindowInternal();
  2315   nsresult rv = NS_OK;
  2317   // Set mDoc even if this is an outer window to avoid
  2318   // having to *always* reach into the inner window to find the
  2319   // document.
  2320   mDoc = aDocument;
  2321   if (IsInnerWindow() && IsDOMBinding()) {
  2322     WindowBinding::ClearCachedDocumentValue(cx, this);
  2325   // Take this opportunity to clear mSuspendedDoc. Our old inner window is now
  2326   // responsible for unsuspending it.
  2327   mSuspendedDoc = nullptr;
  2329 #ifdef DEBUG
  2330   mLastOpenedURI = aDocument->GetDocumentURI();
  2331 #endif
  2333   mContext->WillInitializeContext();
  2335   nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
  2337   if (currentInner && currentInner->mNavigator) {
  2338     currentInner->mNavigator->OnNavigation();
  2341   nsRefPtr<nsGlobalWindow> newInnerWindow;
  2342   bool createdInnerWindow = false;
  2344   bool thisChrome = IsChromeWindow();
  2346   nsCxPusher cxPusher;
  2347   cxPusher.Push(cx);
  2349   // Check if we're near the stack limit before we get anywhere near the
  2350   // transplanting code.
  2351   JS_CHECK_RECURSION(cx, return NS_ERROR_FAILURE);
  2353   nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
  2354   NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
  2356   JS::Rooted<JSObject*> newInnerGlobal(cx);
  2357   if (reUseInnerWindow) {
  2358     // We're reusing the current inner window.
  2359     NS_ASSERTION(!currentInner->IsFrozen(),
  2360                  "We should never be reusing a shared inner window");
  2361     newInnerWindow = currentInner;
  2362     newInnerGlobal = currentInner->GetWrapperPreserveColor();
  2364     if (aDocument != oldDoc) {
  2365       JS::ExposeObjectToActiveJS(newInnerGlobal);
  2368     // We're reusing the inner window, but this still counts as a navigation,
  2369     // so all expandos and such defined on the outer window should go away. Force
  2370     // all Xray wrappers to be recomputed.
  2371     JS::Rooted<JSObject*> rootedObject(cx, GetWrapperPreserveColor());
  2372     JS::ExposeObjectToActiveJS(rootedObject);
  2373     if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
  2374       return NS_ERROR_FAILURE;
  2377     // Inner windows are only reused for same-origin principals, but the principals
  2378     // don't necessarily match exactly. Update the principal on the compartment to
  2379     // match the new document.
  2380     // NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
  2381     // because we haven't yet set its mDoc to aDocument.
  2382     JSCompartment *compartment = js::GetObjectCompartment(newInnerGlobal);
  2383 #ifdef DEBUG
  2384     bool sameOrigin = false;
  2385     nsIPrincipal *existing =
  2386       nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment));
  2387     aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
  2388     MOZ_ASSERT(sameOrigin);
  2389 #endif
  2390     JS_SetCompartmentPrincipals(compartment,
  2391                                 nsJSPrincipals::get(aDocument->NodePrincipal()));
  2392   } else {
  2393     if (aState) {
  2394       newInnerWindow = wsh->GetInnerWindow();
  2395       newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
  2396     } else {
  2397       if (thisChrome) {
  2398         newInnerWindow = new nsGlobalChromeWindow(this);
  2399       } else if (mIsModalContentWindow) {
  2400         newInnerWindow = new nsGlobalModalWindow(this);
  2401       } else {
  2402         newInnerWindow = new nsGlobalWindow(this);
  2405       // Freeze the outer window and null out the inner window so
  2406       // that initializing classes on the new inner doesn't end up
  2407       // reaching into the old inner window for classes etc.
  2408       //
  2409       // [This happens with Object.prototype when XPConnect creates
  2410       // a temporary global while initializing classes; the reason
  2411       // being that xpconnect creates the temp global w/o a parent
  2412       // and proto, which makes the JS engine look up classes in
  2413       // cx->globalObject, i.e. this outer window].
  2415       mInnerWindow = nullptr;
  2417       Freeze();
  2418       mCreatingInnerWindow = true;
  2419       // Every script context we are initialized with must create a
  2420       // new global.
  2421       rv = CreateNativeGlobalForInner(cx, newInnerWindow,
  2422                                       aDocument->GetDocumentURI(),
  2423                                       aDocument->NodePrincipal(),
  2424                                       &newInnerGlobal);
  2425       NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
  2426                    newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
  2427                    "Failed to get script global");
  2429       mCreatingInnerWindow = false;
  2430       createdInnerWindow = true;
  2431       Thaw();
  2433       NS_ENSURE_SUCCESS(rv, rv);
  2436     if (currentInner && currentInner->GetWrapperPreserveColor()) {
  2437       if (oldDoc == aDocument) {
  2438         // Move the navigator from the old inner window to the new one since
  2439         // this is a document.write. This is safe from a same-origin point of
  2440         // view because document.write can only be used by the same origin.
  2441         newInnerWindow->mNavigator = currentInner->mNavigator;
  2442         currentInner->mNavigator = nullptr;
  2443         if (newInnerWindow->mNavigator) {
  2444           newInnerWindow->mNavigator->SetWindow(newInnerWindow);
  2447         // Make a copy of the old window's performance object on document.open.
  2448         // Note that we have to force eager creation of it here, because we need
  2449         // to grab the current document channel and whatnot before that changes.
  2450         currentInner->CreatePerformanceObjectIfNeeded();
  2451         if (currentInner->mPerformance) {
  2452           newInnerWindow->mPerformance =
  2453             new nsPerformance(newInnerWindow,
  2454                               currentInner->mPerformance->GetDOMTiming(),
  2455                               currentInner->mPerformance->GetChannel(),
  2456                               currentInner->mPerformance->GetParentPerformance());
  2460       // Don't free objects on our current inner window if it's going to be
  2461       // held in the bfcache.
  2462       if (!currentInner->IsFrozen()) {
  2463         currentInner->FreeInnerObjects();
  2467     mInnerWindow = newInnerWindow;
  2469     if (!GetWrapperPreserveColor()) {
  2470       JS::Rooted<JSObject*> outer(cx,
  2471         NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
  2472       NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
  2474       js::SetProxyExtra(outer, 0, js::PrivateValue(ToSupports(this)));
  2476       // Inform the nsJSContext, which is the canonical holder of the outer.
  2477       mContext->SetWindowProxy(outer);
  2478       mContext->DidInitializeContext();
  2480       SetWrapper(mContext->GetWindowProxy());
  2481     } else {
  2482       JS::ExposeObjectToActiveJS(newInnerGlobal);
  2483       JS::Rooted<JSObject*> outerObject(cx,
  2484         NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
  2485       if (!outerObject) {
  2486         NS_ERROR("out of memory");
  2487         return NS_ERROR_FAILURE;
  2490       JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
  2492       js::SetProxyExtra(obj, 0, js::PrivateValue(nullptr));
  2494       outerObject = xpc::TransplantObject(cx, obj, outerObject);
  2495       if (!outerObject) {
  2496         NS_ERROR("unable to transplant wrappers, probably OOM");
  2497         return NS_ERROR_FAILURE;
  2500       js::SetProxyExtra(outerObject, 0, js::PrivateValue(ToSupports(this)));
  2502       SetWrapper(outerObject);
  2505         JSAutoCompartment ac(cx, outerObject);
  2507         JS_SetParent(cx, outerObject, newInnerGlobal);
  2509         // Inform the nsJSContext, which is the canonical holder of the outer.
  2510         mContext->SetWindowProxy(outerObject);
  2512         NS_ASSERTION(!JS_IsExceptionPending(cx),
  2513                      "We might overwrite a pending exception!");
  2514         XPCWrappedNativeScope* scope = xpc::GetObjectScope(outerObject);
  2515         if (scope->mWaiverWrapperMap) {
  2516           scope->mWaiverWrapperMap->Reparent(cx, newInnerGlobal);
  2521     // Enter the new global's compartment.
  2522     JSAutoCompartment ac(cx, GetWrapperPreserveColor());
  2524     // Set scriptability based on the state of the docshell.
  2525     bool allow = GetDocShell()->GetCanExecuteScripts();
  2526     xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);
  2528     // If we created a new inner window above, we need to do the last little bit
  2529     // of initialization now that the dust has settled.
  2530     if (createdInnerWindow) {
  2531       nsIXPConnect *xpc = nsContentUtils::XPConnect();
  2532       nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
  2533       nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerGlobal,
  2534                                                     getter_AddRefs(wrapper));
  2535       NS_ENSURE_SUCCESS(rv, rv);
  2536       NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
  2537       rv = wrapper->FinishInitForWrappedGlobal();
  2538       NS_ENSURE_SUCCESS(rv, rv);
  2541     if (!aState) {
  2542       JS::Rooted<JSObject*> rootedWrapper(cx, GetWrapperPreserveColor());
  2543       if (!JS_DefineProperty(cx, newInnerGlobal, "window", rootedWrapper,
  2544                              JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
  2545                              JS_PropertyStub, JS_StrictPropertyStub)) {
  2546         NS_ERROR("can't create the 'window' property");
  2547         return NS_ERROR_FAILURE;
  2552   JSAutoCompartment ac(cx, GetWrapperPreserveColor());
  2554   if (!aState && !reUseInnerWindow) {
  2555     // Loading a new page and creating a new inner window, *not*
  2556     // restoring from session history.
  2558     // Now that both the the inner and outer windows are initialized
  2559     // let the script context do its magic to hook them together.
  2560     MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor());
  2561 #ifdef DEBUG
  2562     JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
  2563     JS::Rooted<JSObject*> proto1(cx), proto2(cx);
  2564     JS_GetPrototype(cx, rootedJSObject, &proto1);
  2565     JS_GetPrototype(cx, newInnerGlobal, &proto2);
  2566     NS_ASSERTION(proto1 == proto2,
  2567                  "outer and inner globals should have the same prototype");
  2568 #endif
  2570     nsCOMPtr<Element> frame = GetFrameElementInternal();
  2571     if (frame) {
  2572       nsPIDOMWindow* parentWindow = frame->OwnerDoc()->GetWindow();
  2573       if (parentWindow && parentWindow->TimeoutSuspendCount()) {
  2574         SuspendTimeouts(parentWindow->TimeoutSuspendCount());
  2579   // Add an extra ref in case we release mContext during GC.
  2580   nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
  2582   aDocument->SetScriptGlobalObject(newInnerWindow);
  2584   if (!aState) {
  2585     if (reUseInnerWindow) {
  2586       if (newInnerWindow->mDoc != aDocument) {
  2587         newInnerWindow->mDoc = aDocument;
  2589         if (newInnerWindow->IsDOMBinding()) {
  2590           WindowBinding::ClearCachedDocumentValue(cx, newInnerWindow);
  2591         } else {
  2592           // We're reusing the inner window for a new document. In this
  2593           // case we don't clear the inner window's scope, but we must
  2594           // make sure the cached document property gets updated.
  2596           JS::Rooted<JSObject*> obj(cx,
  2597                                     currentInner->GetWrapperPreserveColor());
  2598           ::JS_DeleteProperty(cx, obj, "document");
  2601     } else {
  2602       newInnerWindow->InnerSetNewDocument(cx, aDocument);
  2604       // Initialize DOM classes etc on the inner window.
  2605       JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
  2606       rv = mContext->InitClasses(obj);
  2607       NS_ENSURE_SUCCESS(rv, rv);
  2610     // If the document comes from a JAR, check if the channel was determined
  2611     // to be unsafe. If so, permanently disable script on the compartment by
  2612     // calling Block() and throwing away the key.
  2613     nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aDocument->GetChannel());
  2614     if (jarChannel && jarChannel->GetIsUnsafe()) {
  2615       xpc::Scriptability::Get(newInnerGlobal).Block();
  2618     if (mArguments) {
  2619       newInnerWindow->DefineArgumentsProperty(mArguments);
  2620       mArguments = nullptr;
  2623     // Give the new inner window our chrome event handler (since it
  2624     // doesn't have one).
  2625     newInnerWindow->mChromeEventHandler = mChromeEventHandler;
  2628   mContext->GC(JS::gcreason::SET_NEW_DOCUMENT);
  2629   mContext->DidInitializeContext();
  2631   // We wait to fire the debugger hook until the window is all set up and hooked
  2632   // up with the outer. See bug 969156.
  2633   if (createdInnerWindow) {
  2634     JS::Rooted<JSObject*> global(cx, newInnerWindow->GetWrapper());
  2635     JS_FireOnNewGlobalObject(cx, global);
  2638   if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
  2639     // We should probably notify. However if this is the, arguably bad,
  2640     // situation when we're creating a temporary non-chrome-about-blank
  2641     // document in a chrome docshell, don't notify just yet. Instead wait
  2642     // until we have a real chrome doc.
  2643     if (!mDocShell ||
  2644         mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome ||
  2645         nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
  2646       newInnerWindow->mHasNotifiedGlobalCreated = true;
  2647       nsContentUtils::AddScriptRunner(
  2648         NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated));
  2652   PreloadLocalStorage();
  2654   return NS_OK;
  2657 void
  2658 nsGlobalWindow::PreloadLocalStorage()
  2660   if (!Preferences::GetBool(kStorageEnabled)) {
  2661     return;
  2664   if (IsChromeWindow()) {
  2665     return;
  2668   nsIPrincipal* principal = GetPrincipal();
  2669   if (!principal) {
  2670     return;
  2673   nsresult rv;
  2674   nsCOMPtr<nsIURI> firstPartyIsolationURI;
  2675   rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
  2676   if (NS_FAILED(rv)) {
  2677     return;
  2680   nsCOMPtr<nsIDOMStorageManager> storageManager =
  2681     do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
  2682   if (NS_FAILED(rv)) {
  2683     return;
  2686   storageManager->PrecacheStorageForFirstParty(firstPartyIsolationURI, principal);
  2689 void
  2690 nsGlobalWindow::DispatchDOMWindowCreated()
  2692   if (!mDoc) {
  2693     return;
  2696   // Fire DOMWindowCreated at chrome event listeners
  2697   nsContentUtils::DispatchChromeEvent(mDoc, mDoc, NS_LITERAL_STRING("DOMWindowCreated"),
  2698                                       true /* bubbles */,
  2699                                       false /* not cancellable */);
  2701   nsCOMPtr<nsIObserverService> observerService =
  2702     mozilla::services::GetObserverService();
  2703   if (observerService) {
  2704     nsAutoString origin;
  2705     nsIPrincipal* principal = mDoc->NodePrincipal();
  2706     nsContentUtils::GetUTFOrigin(principal, origin);
  2707     observerService->
  2708       NotifyObservers(static_cast<nsIDOMWindow*>(this),
  2709                       nsContentUtils::IsSystemPrincipal(principal) ?
  2710                         "chrome-document-global-created" :
  2711                         "content-document-global-created",
  2712                       origin.get());
  2716 void
  2717 nsGlobalWindow::ClearStatus()
  2719   SetStatus(EmptyString());
  2722 void
  2723 nsGlobalWindow::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument)
  2725   NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
  2726   MOZ_ASSERT(aDocument);
  2728 #ifdef PR_LOGGING
  2729   if (gDOMLeakPRLog && PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
  2730     nsIURI *uri = aDocument->GetDocumentURI();
  2731     nsAutoCString spec;
  2732     if (uri)
  2733       uri->GetSpec(spec);
  2734     PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
  2736 #endif
  2738   mDoc = aDocument;
  2739   if (IsDOMBinding()) {
  2740     WindowBinding::ClearCachedDocumentValue(aCx, this);
  2742   mFocusedNode = nullptr;
  2743   mLocalStorage = nullptr;
  2744   mSessionStorage = nullptr;
  2746 #ifdef DEBUG
  2747   mLastOpenedURI = aDocument->GetDocumentURI();
  2748 #endif
  2750   Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
  2751                         mMutationBits ? 1 : 0);
  2753   // Clear our mutation bitfield.
  2754   mMutationBits = 0;
  2757 void
  2758 nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
  2760   NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
  2761   MOZ_ASSERT(aDocShell);
  2763   if (aDocShell == mDocShell) {
  2764     return;
  2767   mDocShell = aDocShell; // Weak Reference
  2769   NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
  2771   if (mFrames) {
  2772     mFrames->SetDocShell(aDocShell);
  2775   // Get our enclosing chrome shell and retrieve its global window impl, so
  2776   // that we can do some forwarding to the chrome document.
  2777   nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
  2778   mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
  2779   mChromeEventHandler = do_QueryInterface(chromeEventHandler);
  2780   if (!mChromeEventHandler) {
  2781     // We have no chrome event handler. If we have a parent,
  2782     // get our chrome event handler from the parent. If
  2783     // we don't have a parent, then we need to make a new
  2784     // window root object that will function as a chrome event
  2785     // handler and receive all events that occur anywhere inside
  2786     // our window.
  2787     nsCOMPtr<nsIDOMWindow> parentWindow;
  2788     GetParent(getter_AddRefs(parentWindow));
  2789     if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
  2790       nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
  2791       mChromeEventHandler = piWindow->GetChromeEventHandler();
  2793     else {
  2794       mChromeEventHandler = NS_NewWindowRoot(this);
  2798   bool docShellActive;
  2799   mDocShell->GetIsActive(&docShellActive);
  2800   mIsBackground = !docShellActive;
  2803 void
  2804 nsGlobalWindow::DetachFromDocShell()
  2806   NS_ASSERTION(IsOuterWindow(), "Uh, DetachFromDocShell() called on inner window!");
  2808   // DetachFromDocShell means the window is being torn down. Drop our
  2809   // reference to the script context, allowing it to be deleted
  2810   // later. Meanwhile, keep our weak reference to the script object
  2811   // so that it can be retrieved later (until it is finalized by the JS GC).
  2813   NS_ASSERTION(mTimeouts.isEmpty(), "Uh, outer window holds timeouts!");
  2815   // Call FreeInnerObjects on all inner windows, not just the current
  2816   // one, since some could be held by WindowStateHolder objects that
  2817   // are GC-owned.
  2818   for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
  2819        inner != this;
  2820        inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
  2821     NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
  2822                  "bad outer window pointer");
  2823     inner->FreeInnerObjects();
  2826   // Make sure that this is called before we null out the document.
  2827   NotifyDOMWindowDestroyed(this);
  2829   NotifyWindowIDDestroyed("outer-window-destroyed");
  2831   nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
  2833   if (currentInner) {
  2834     NS_ASSERTION(mDoc, "Must have doc!");
  2836     // Remember the document's principal and URI.
  2837     mDocumentPrincipal = mDoc->NodePrincipal();
  2838     mDocumentURI = mDoc->GetDocumentURI();
  2839     mDocBaseURI = mDoc->GetDocBaseURI();
  2841     // Release our document reference
  2842     DropOuterWindowDocs();
  2843     mFocusedNode = nullptr;
  2846   ClearControllers();
  2848   mChromeEventHandler = nullptr; // force release now
  2850   if (mContext) {
  2851     mContext->GC(JS::gcreason::SET_DOC_SHELL);
  2852     mContext = nullptr;
  2855   mDocShell = nullptr; // Weak Reference
  2857   NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
  2859   if (mFrames) {
  2860     mFrames->SetDocShell(nullptr);
  2863   MaybeForgiveSpamCount();
  2864   CleanUp();
  2867 void
  2868 nsGlobalWindow::SetOpenerWindow(nsIDOMWindow* aOpener,
  2869                                 bool aOriginalOpener)
  2871   FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
  2873   NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
  2874                "aOriginalOpener is true, but not first call to "
  2875                "SetOpenerWindow!");
  2876   NS_ASSERTION(aOpener || !aOriginalOpener,
  2877                "Shouldn't set mHadOriginalOpener if aOpener is null");
  2879   mOpener = do_GetWeakReference(aOpener);
  2880   NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
  2882   if (aOriginalOpener) {
  2883     mHadOriginalOpener = true;
  2886 #ifdef DEBUG
  2887   mSetOpenerWindowCalled = true;
  2888 #endif
  2891 static
  2892 already_AddRefed<EventTarget>
  2893 TryGetTabChildGlobalAsEventTarget(nsISupports *aFrom)
  2895   nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(aFrom);
  2896   if (!frameLoaderOwner) {
  2897     return nullptr;
  2900   nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
  2901   if (!frameLoader) {
  2902     return nullptr;
  2905   nsCOMPtr<EventTarget> target = frameLoader->GetTabChildGlobalAsEventTarget();
  2906   return target.forget();
  2909 void
  2910 nsGlobalWindow::UpdateParentTarget()
  2912   // Try to get our frame element's tab child global (its in-process message
  2913   // manager).  If that fails, fall back to the chrome event handler's tab
  2914   // child global, and if it doesn't have one, just use the chrome event
  2915   // handler itself.
  2917   nsCOMPtr<Element> frameElement = GetFrameElementInternal();
  2918   nsCOMPtr<EventTarget> eventTarget =
  2919     TryGetTabChildGlobalAsEventTarget(frameElement);
  2921   if (!eventTarget) {
  2922     nsGlobalWindow* topWin = GetScriptableTop();
  2923     if (topWin) {
  2924       frameElement = topWin->GetFrameElementInternal();
  2925       eventTarget = TryGetTabChildGlobalAsEventTarget(frameElement);
  2929   if (!eventTarget) {
  2930     eventTarget = TryGetTabChildGlobalAsEventTarget(mChromeEventHandler);
  2933   if (!eventTarget) {
  2934     eventTarget = mChromeEventHandler;
  2937   mParentTarget = eventTarget;
  2940 EventTarget*
  2941 nsGlobalWindow::GetTargetForDOMEvent()
  2943   return GetOuterWindowInternal();
  2946 EventTarget*
  2947 nsGlobalWindow::GetTargetForEventTargetChain()
  2949   return IsInnerWindow() ? this : GetCurrentInnerWindowInternal();
  2952 nsresult
  2953 nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor)
  2955   return NS_OK;
  2958 JSContext*
  2959 nsGlobalWindow::GetJSContextForEventHandlers()
  2961   return nullptr;
  2964 nsresult
  2965 nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
  2967   NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
  2968   static uint32_t count = 0;
  2969   uint32_t msg = aVisitor.mEvent->message;
  2971   aVisitor.mCanHandle = true;
  2972   aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
  2973   if ((msg == NS_MOUSE_MOVE) && gEntropyCollector) {
  2974     //Chances are this counter will overflow during the life of the
  2975     //process, but that's OK for our case. Means we get a little
  2976     //more entropy.
  2977     if (count++ % 100 == 0) {
  2978       //Since the high bits seem to be zero's most of the time,
  2979       //let's only take the lowest half of the point structure.
  2980       int16_t myCoord[2];
  2982       myCoord[0] = aVisitor.mEvent->refPoint.x;
  2983       myCoord[1] = aVisitor.mEvent->refPoint.y;
  2984       gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
  2985       gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
  2986                                       sizeof(uint32_t));
  2988   } else if (msg == NS_RESIZE_EVENT) {
  2989     mIsHandlingResizeEvent = true;
  2990   } else if (msg == NS_MOUSE_BUTTON_DOWN &&
  2991              aVisitor.mEvent->mFlags.mIsTrusted) {
  2992     gMouseDown = true;
  2993   } else if ((msg == NS_MOUSE_BUTTON_UP ||
  2994               msg == NS_DRAGDROP_END) &&
  2995              aVisitor.mEvent->mFlags.mIsTrusted) {
  2996     gMouseDown = false;
  2997     if (gDragServiceDisabled) {
  2998       nsCOMPtr<nsIDragService> ds =
  2999         do_GetService("@mozilla.org/widget/dragservice;1");
  3000       if (ds) {
  3001         gDragServiceDisabled = false;
  3002         ds->Unsuppress();
  3007   aVisitor.mParentTarget = GetParentTarget();
  3009   // Handle 'active' event.
  3010   if (!mIdleObservers.IsEmpty() &&
  3011       aVisitor.mEvent->mFlags.mIsTrusted &&
  3012       (aVisitor.mEvent->HasMouseEventMessage() ||
  3013        aVisitor.mEvent->HasDragEventMessage())) {
  3014     mAddActiveEventFuzzTime = false;
  3017   return NS_OK;
  3020 bool
  3021 nsGlobalWindow::ShouldPromptToBlockDialogs()
  3023   MOZ_ASSERT(IsOuterWindow());
  3025   nsGlobalWindow *topWindow = GetScriptableTop();
  3026   if (!topWindow) {
  3027     NS_ASSERTION(!mDocShell, "ShouldPromptToBlockDialogs() called without a top window?");
  3028     return true;
  3031   topWindow = topWindow->GetCurrentInnerWindowInternal();
  3032   if (!topWindow) {
  3033     return true;
  3036   return topWindow->DialogsAreBeingAbused();
  3039 bool
  3040 nsGlobalWindow::AreDialogsEnabled()
  3042   nsGlobalWindow *topWindow = GetScriptableTop();
  3043   if (!topWindow) {
  3044     NS_ERROR("AreDialogsEnabled() called without a top window?");
  3045     return false;
  3048   // TODO: Warn if no top window?
  3049   topWindow = topWindow->GetCurrentInnerWindowInternal();
  3050   if (!topWindow) {
  3051     return false;
  3054   // Dialogs are blocked if the content viewer is hidden
  3055   if (mDocShell) {
  3056     nsCOMPtr<nsIContentViewer> cv;
  3057     mDocShell->GetContentViewer(getter_AddRefs(cv));
  3059     bool isHidden;
  3060     cv->GetIsHidden(&isHidden);
  3061     if (isHidden) {
  3062       return false;
  3066   return topWindow->mAreDialogsEnabled;
  3069 bool
  3070 nsGlobalWindow::DialogsAreBeingAbused()
  3072   MOZ_ASSERT(IsInnerWindow());
  3073   NS_ASSERTION(GetScriptableTop() &&
  3074                GetScriptableTop()->GetCurrentInnerWindowInternal() == this,
  3075                "DialogsAreBeingAbused called with invalid window");
  3077   if (mLastDialogQuitTime.IsNull() ||
  3078       nsContentUtils::IsCallerChrome()) {
  3079     return false;
  3082   TimeDuration dialogInterval(TimeStamp::Now() - mLastDialogQuitTime);
  3083   if (dialogInterval.ToSeconds() <
  3084       Preferences::GetInt("dom.successive_dialog_time_limit",
  3085                           DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT)) {
  3086     mDialogAbuseCount++;
  3088     return GetPopupControlState() > openAllowed ||
  3089            mDialogAbuseCount > MAX_SUCCESSIVE_DIALOG_COUNT;
  3092   // Reset the abuse counter
  3093   mDialogAbuseCount = 0;
  3095   return false;
  3098 bool
  3099 nsGlobalWindow::ConfirmDialogIfNeeded()
  3101   MOZ_ASSERT(IsOuterWindow());
  3103   NS_ENSURE_TRUE(mDocShell, false);
  3104   nsCOMPtr<nsIPromptService> promptSvc =
  3105     do_GetService("@mozilla.org/embedcomp/prompt-service;1");
  3107   if (!promptSvc) {
  3108     return true;
  3111   // Reset popup state while opening a modal dialog, and firing events
  3112   // about the dialog, to prevent the current state from being active
  3113   // the whole time a modal dialog is open.
  3114   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  3116   bool disableDialog = false;
  3117   nsXPIDLString label, title;
  3118   nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  3119                                      "ScriptDialogLabel", label);
  3120   nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  3121                                      "ScriptDialogPreventTitle", title);
  3122   promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
  3123   if (disableDialog) {
  3124     DisableDialogs();
  3125     return false;
  3128   return true;
  3131 void
  3132 nsGlobalWindow::DisableDialogs()
  3134   nsGlobalWindow *topWindow = GetScriptableTop();
  3135   if (!topWindow) {
  3136     NS_ERROR("DisableDialogs() called without a top window?");
  3137     return;
  3140   topWindow = topWindow->GetCurrentInnerWindowInternal();
  3141   // TODO: Warn if no top window?
  3142   if (topWindow) {
  3143     topWindow->mAreDialogsEnabled = false;
  3147 void
  3148 nsGlobalWindow::EnableDialogs()
  3150   nsGlobalWindow *topWindow = GetScriptableTop();
  3151   if (!topWindow) {
  3152     NS_ERROR("EnableDialogs() called without a top window?");
  3153     return;
  3156   // TODO: Warn if no top window?
  3157   topWindow = topWindow->GetCurrentInnerWindowInternal();
  3158   if (topWindow) {
  3159     topWindow->mAreDialogsEnabled = true;
  3163 nsresult
  3164 nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
  3166   NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
  3168   // Return early if there is nothing to do.
  3169   switch (aVisitor.mEvent->message) {
  3170     case NS_RESIZE_EVENT:
  3171     case NS_PAGE_UNLOAD:
  3172     case NS_LOAD:
  3173       break;
  3174     default:
  3175       return NS_OK;
  3178   /* mChromeEventHandler and mContext go dangling in the middle of this
  3179    function under some circumstances (events that destroy the window)
  3180    without this addref. */
  3181   nsCOMPtr<nsIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
  3182   nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
  3184   if (aVisitor.mEvent->message == NS_RESIZE_EVENT) {
  3185     mIsHandlingResizeEvent = false;
  3186   } else if (aVisitor.mEvent->message == NS_PAGE_UNLOAD &&
  3187              aVisitor.mEvent->mFlags.mIsTrusted) {
  3188     // Execute bindingdetached handlers before we tear ourselves
  3189     // down.
  3190     if (mDoc) {
  3191       mDoc->BindingManager()->ExecuteDetachedHandlers();
  3193     mIsDocumentLoaded = false;
  3194   } else if (aVisitor.mEvent->message == NS_LOAD &&
  3195              aVisitor.mEvent->mFlags.mIsTrusted) {
  3196     // This is page load event since load events don't propagate to |window|.
  3197     // @see nsDocument::PreHandleEvent.
  3198     mIsDocumentLoaded = true;
  3200     nsCOMPtr<Element> element = GetFrameElementInternal();
  3201     nsIDocShell* docShell = GetDocShell();
  3202     if (element && GetParentInternal() &&
  3203         docShell && docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
  3204       // If we're not in chrome, or at a chrome boundary, fire the
  3205       // onload event for the frame element.
  3207       nsEventStatus status = nsEventStatus_eIgnore;
  3208       WidgetEvent event(aVisitor.mEvent->mFlags.mIsTrusted, NS_LOAD);
  3209       event.mFlags.mBubbles = false;
  3211       // Most of the time we could get a pres context to pass in here,
  3212       // but not always (i.e. if this window is not shown there won't
  3213       // be a pres context available). Since we're not firing a GUI
  3214       // event we don't need a pres context anyway so we just pass
  3215       // null as the pres context all the time here.
  3216       EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status);
  3220   return NS_OK;
  3223 nsresult
  3224 nsGlobalWindow::DispatchDOMEvent(WidgetEvent* aEvent,
  3225                                  nsIDOMEvent* aDOMEvent,
  3226                                  nsPresContext* aPresContext,
  3227                                  nsEventStatus* aEventStatus)
  3229   return EventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),
  3230                                            aEvent, aDOMEvent, aPresContext,
  3231                                            aEventStatus);
  3234 void
  3235 nsGlobalWindow::PoisonOuterWindowProxy(JSObject *aObject)
  3237   MOZ_ASSERT(IsOuterWindow());
  3238   if (aObject == GetWrapperPreserveColor()) {
  3239     PoisonWrapper();
  3243 nsresult
  3244 nsGlobalWindow::SetArguments(nsIArray *aArguments)
  3246   MOZ_ASSERT(IsOuterWindow());
  3247   nsresult rv;
  3249   // Historically, we've used the same machinery to handle openDialog arguments
  3250   // (exposed via window.arguments) and showModalDialog arguments (exposed via
  3251   // window.dialogArguments), even though the former is XUL-only and uses an XPCOM
  3252   // array while the latter is web-exposed and uses an arbitrary JS value.
  3253   // Moreover, per-spec |dialogArguments| is a property of the browsing context
  3254   // (outer), whereas |arguments| lives on the inner.
  3255   //
  3256   // We've now mostly separated them, but the difference is still opaque to
  3257   // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
  3258   // embedding waltz we do here).
  3259   //
  3260   // So we need to demultiplex the two cases here.
  3261   nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
  3262   if (mIsModalContentWindow) {
  3263     // nsWindowWatcher blindly converts the original nsISupports into an array
  3264     // of length 1. We need to recover it, and then cast it back to the concrete
  3265     // object we know it to be.
  3266     nsCOMPtr<nsISupports> supports = do_QueryElementAt(aArguments, 0, &rv);
  3267     NS_ENSURE_SUCCESS(rv, rv);
  3268     mDialogArguments = static_cast<DialogValueHolder*>(supports.get());
  3269   } else {
  3270     mArguments = aArguments;
  3271     rv = currentInner->DefineArgumentsProperty(aArguments);
  3272     NS_ENSURE_SUCCESS(rv, rv);
  3275   return NS_OK;
  3278 nsresult
  3279 nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
  3281   MOZ_ASSERT(!mIsModalContentWindow); // Handled separately.
  3282   nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
  3283   NS_ENSURE_TRUE(aArguments && ctx, NS_ERROR_NOT_INITIALIZED);
  3284   AutoJSContext cx;
  3286   JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
  3287   return ctx->SetProperty(obj, "arguments", aArguments);
  3290 //*****************************************************************************
  3291 // nsGlobalWindow::nsIScriptObjectPrincipal
  3292 //*****************************************************************************
  3294 nsIPrincipal*
  3295 nsGlobalWindow::GetPrincipal()
  3297   if (mDoc) {
  3298     // If we have a document, get the principal from the document
  3299     return mDoc->NodePrincipal();
  3302   if (mDocumentPrincipal) {
  3303     return mDocumentPrincipal;
  3306   // If we don't have a principal and we don't have a document we
  3307   // ask the parent window for the principal. This can happen when
  3308   // loading a frameset that has a <frame src="javascript:xxx">, in
  3309   // that case the global window is used in JS before we've loaded
  3310   // a document into the window.
  3312   nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
  3313     do_QueryInterface(GetParentInternal());
  3315   if (objPrincipal) {
  3316     return objPrincipal->GetPrincipal();
  3319   return nullptr;
  3322 //*****************************************************************************
  3323 // nsGlobalWindow::nsIDOMWindow
  3324 //*****************************************************************************
  3326 nsIURI*
  3327 nsPIDOMWindow::GetDocumentURI() const
  3329   return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
  3332 nsIURI*
  3333 nsPIDOMWindow::GetDocBaseURI() const
  3335   return mDoc ? mDoc->GetDocBaseURI() : mDocBaseURI.get();
  3338 void
  3339 nsPIDOMWindow::MaybeCreateDoc()
  3341   MOZ_ASSERT(!mDoc);
  3342   if (nsIDocShell* docShell = GetDocShell()) {
  3343     // Note that |document| here is the same thing as our mDoc, but we
  3344     // don't have to explicitly set the member variable because the docshell
  3345     // has already called SetNewDocument().
  3346     nsCOMPtr<nsIDocument> document = do_GetInterface(docShell);
  3350 Element*
  3351 nsPIDOMWindow::GetFrameElementInternal() const
  3353   if (mOuterWindow) {
  3354     return mOuterWindow->GetFrameElementInternal();
  3357   NS_ASSERTION(!IsInnerWindow(),
  3358                "GetFrameElementInternal() called on orphan inner window");
  3360   return mFrameElement;
  3363 void
  3364 nsPIDOMWindow::SetFrameElementInternal(Element* aFrameElement)
  3366   if (IsOuterWindow()) {
  3367     mFrameElement = aFrameElement;
  3369     return;
  3372   if (!mOuterWindow) {
  3373     NS_ERROR("frameElement set on inner window with no outer!");
  3375     return;
  3378   mOuterWindow->SetFrameElementInternal(aFrameElement);
  3381 void
  3382 nsPIDOMWindow::AddAudioContext(AudioContext* aAudioContext)
  3384   mAudioContexts.AppendElement(aAudioContext);
  3386   nsIDocShell* docShell = GetDocShell();
  3387   if (docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline()) {
  3388     aAudioContext->Mute();
  3392 void
  3393 nsPIDOMWindow::RemoveAudioContext(AudioContext* aAudioContext)
  3395   mAudioContexts.RemoveElement(aAudioContext);
  3398 void
  3399 nsPIDOMWindow::MuteAudioContexts()
  3401   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
  3402     if (!mAudioContexts[i]->IsOffline()) {
  3403       mAudioContexts[i]->Mute();
  3408 void
  3409 nsPIDOMWindow::UnmuteAudioContexts()
  3411   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
  3412     if (!mAudioContexts[i]->IsOffline()) {
  3413       mAudioContexts[i]->Unmute();
  3418 NS_IMETHODIMP
  3419 nsGlobalWindow::GetDocument(nsIDOMDocument** aDocument)
  3421   nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(GetDocument());
  3422   document.forget(aDocument);
  3423   return NS_OK;
  3426 nsIDOMWindow*
  3427 nsGlobalWindow::GetWindow(ErrorResult& aError)
  3429   FORWARD_TO_OUTER_OR_THROW(GetWindow, (aError), aError, nullptr);
  3431   return this;
  3434 NS_IMETHODIMP
  3435 nsGlobalWindow::GetWindow(nsIDOMWindow** aWindow)
  3437   ErrorResult rv;
  3438   nsCOMPtr<nsIDOMWindow> window = GetWindow(rv);
  3439   window.forget(aWindow);
  3441   return rv.ErrorCode();
  3444 nsIDOMWindow*
  3445 nsGlobalWindow::GetSelf(ErrorResult& aError)
  3447   FORWARD_TO_OUTER_OR_THROW(GetSelf, (aError), aError, nullptr);
  3449   return this;
  3452 NS_IMETHODIMP
  3453 nsGlobalWindow::GetSelf(nsIDOMWindow** aWindow)
  3455   ErrorResult rv;
  3456   nsCOMPtr<nsIDOMWindow> window = GetSelf(rv);
  3457   window.forget(aWindow);
  3459   return rv.ErrorCode();
  3462 Navigator*
  3463 nsGlobalWindow::GetNavigator(ErrorResult& aError)
  3465   FORWARD_TO_INNER_OR_THROW(GetNavigator, (aError), aError, nullptr);
  3467   if (!mNavigator) {
  3468     mNavigator = new Navigator(this);
  3471   return mNavigator;
  3474 NS_IMETHODIMP
  3475 nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
  3477   ErrorResult rv;
  3478   nsCOMPtr<nsIDOMNavigator> navigator = GetNavigator(rv);
  3479   navigator.forget(aNavigator);
  3481   return rv.ErrorCode();
  3484 nsScreen*
  3485 nsGlobalWindow::GetScreen(ErrorResult& aError)
  3487   FORWARD_TO_INNER_OR_THROW(GetScreen, (aError), aError, nullptr);
  3489   if (!mScreen) {
  3490     mScreen = nsScreen::Create(this);
  3491     if (!mScreen) {
  3492       aError.Throw(NS_ERROR_UNEXPECTED);
  3493       return nullptr;
  3497   return mScreen;
  3500 NS_IMETHODIMP
  3501 nsGlobalWindow::GetScreen(nsIDOMScreen** aScreen)
  3503   ErrorResult rv;
  3504   nsRefPtr<nsScreen> screen = GetScreen(rv);
  3505   screen.forget(aScreen);
  3507   return rv.ErrorCode();
  3510 nsHistory*
  3511 nsGlobalWindow::GetHistory(ErrorResult& aError)
  3513   FORWARD_TO_INNER_OR_THROW(GetHistory, (aError), aError, nullptr);
  3515   if (!mHistory) {
  3516     mHistory = new nsHistory(this);
  3519   return mHistory;
  3522 NS_IMETHODIMP
  3523 nsGlobalWindow::GetHistory(nsISupports** aHistory)
  3525   ErrorResult rv;
  3526   nsCOMPtr<nsISupports> history = GetHistory(rv);
  3527   history.forget(aHistory);
  3529   return rv.ErrorCode();
  3532 nsPerformance*
  3533 nsGlobalWindow::GetPerformance(ErrorResult& aError)
  3535   FORWARD_TO_INNER_OR_THROW(GetPerformance, (aError), aError, nullptr);
  3537   nsPerformance* p = nsPIDOMWindow::GetPerformance();
  3538   if (!p) {
  3539     aError.Throw(NS_ERROR_FAILURE);
  3541   return p;
  3544 NS_IMETHODIMP
  3545 nsGlobalWindow::GetPerformance(nsISupports** aPerformance)
  3547   ErrorResult rv;
  3548   nsCOMPtr<nsISupports> performance = GetPerformance(rv);
  3549   performance.forget(aPerformance);
  3551   return rv.ErrorCode();
  3554 nsPerformance*
  3555 nsPIDOMWindow::GetPerformance()
  3557   MOZ_ASSERT(IsInnerWindow());
  3558   CreatePerformanceObjectIfNeeded();
  3559   return mPerformance;
  3562 void
  3563 nsPIDOMWindow::CreatePerformanceObjectIfNeeded()
  3565   if (mPerformance || !mDoc) {
  3566     return;
  3568   nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
  3569   nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
  3570   bool timingEnabled = false;
  3571   if (!timedChannel ||
  3572       !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
  3573       !timingEnabled) {
  3574     timedChannel = nullptr;
  3576   if (timing) {
  3577     // If we are dealing with an iframe, we will need the parent's performance
  3578     // object (so we can add the iframe as a resource of that page).
  3579     nsPerformance* parentPerformance = nullptr;
  3580     nsCOMPtr<nsIDOMWindow> parentWindow;
  3581     GetScriptableParent(getter_AddRefs(parentWindow));
  3582     nsCOMPtr<nsPIDOMWindow> parentPWindow = do_GetInterface(parentWindow);
  3583     if (GetOuterWindow() != parentPWindow) {
  3584       if (parentPWindow && !parentPWindow->IsInnerWindow()) {
  3585         parentPWindow = parentPWindow->GetCurrentInnerWindow();
  3587       if (parentPWindow) {
  3588         parentPerformance = parentPWindow->GetPerformance();
  3591     mPerformance =
  3592       new nsPerformance(this, timing, timedChannel, parentPerformance);
  3596 bool
  3597 nsPIDOMWindow::GetAudioMuted() const
  3599   if (!IsInnerWindow()) {
  3600     return mInnerWindow->GetAudioMuted();
  3603   return mAudioMuted;
  3606 void
  3607 nsPIDOMWindow::SetAudioMuted(bool aMuted)
  3609   if (!IsInnerWindow()) {
  3610     mInnerWindow->SetAudioMuted(aMuted);
  3611     return;
  3614   if (mAudioMuted == aMuted) {
  3615     return;
  3618   mAudioMuted = aMuted;
  3619   RefreshMediaElements();
  3622 float
  3623 nsPIDOMWindow::GetAudioVolume() const
  3625   if (!IsInnerWindow()) {
  3626     return mInnerWindow->GetAudioVolume();
  3629   return mAudioVolume;
  3632 nsresult
  3633 nsPIDOMWindow::SetAudioVolume(float aVolume)
  3635   if (!IsInnerWindow()) {
  3636     return mInnerWindow->SetAudioVolume(aVolume);
  3639   if (aVolume < 0.0) {
  3640     return NS_ERROR_DOM_INDEX_SIZE_ERR;
  3643   if (mAudioVolume == aVolume) {
  3644     return NS_OK;
  3647   mAudioVolume = aVolume;
  3648   RefreshMediaElements();
  3649   return NS_OK;
  3652 float
  3653 nsPIDOMWindow::GetAudioGlobalVolume()
  3655   float globalVolume = 1.0;
  3656   nsCOMPtr<nsPIDOMWindow> window = this;
  3658   do {
  3659     if (window->GetAudioMuted()) {
  3660       return 0;
  3663     globalVolume *= window->GetAudioVolume();
  3665     nsCOMPtr<nsIDOMWindow> win;
  3666     window->GetParent(getter_AddRefs(win));
  3667     if (window == win) {
  3668       break;
  3671     window = do_QueryInterface(win);
  3673     // If there is not parent, or we are the toplevel or the volume is
  3674     // already 0.0, we don't continue.
  3675   } while (window && window != this && globalVolume);
  3677   return globalVolume;
  3680 void
  3681 nsPIDOMWindow::RefreshMediaElements()
  3683   nsRefPtr<AudioChannelService> service =
  3684     AudioChannelService::GetAudioChannelService();
  3685   if (service) {
  3686     service->RefreshAgentsVolume(this);
  3690 // nsISpeechSynthesisGetter
  3692 #ifdef MOZ_WEBSPEECH
  3693 SpeechSynthesis*
  3694 nsGlobalWindow::GetSpeechSynthesis(ErrorResult& aError)
  3696   FORWARD_TO_INNER_OR_THROW(GetSpeechSynthesis, (aError), aError, nullptr);
  3698   if (!mSpeechSynthesis) {
  3699     mSpeechSynthesis = new SpeechSynthesis(this);
  3702   return mSpeechSynthesis;
  3705 NS_IMETHODIMP
  3706 nsGlobalWindow::GetSpeechSynthesis(nsISupports** aSpeechSynthesis)
  3708   ErrorResult rv;
  3709   nsCOMPtr<nsISupports> speechSynthesis;
  3710   if (Preferences::GetBool("media.webspeech.synth.enabled")) {
  3711     speechSynthesis = GetSpeechSynthesis(rv);
  3713   speechSynthesis.forget(aSpeechSynthesis);
  3715   return rv.ErrorCode();
  3717 #endif
  3719 already_AddRefed<nsIDOMWindow>
  3720 nsGlobalWindow::GetParent(ErrorResult& aError)
  3722   FORWARD_TO_OUTER_OR_THROW(GetParent, (aError), aError, nullptr);
  3724   if (!mDocShell) {
  3725     return nullptr;
  3728   nsCOMPtr<nsIDOMWindow> parent;
  3729   if (mDocShell->GetIsBrowserOrApp()) {
  3730     parent = this;
  3731   } else {
  3732     aError = GetRealParent(getter_AddRefs(parent));
  3735   return parent.forget();
  3738 /**
  3739  * GetScriptableParent is called when script reads window.parent.
  3741  * In contrast to GetRealParent, GetScriptableParent respects <iframe
  3742  * mozbrowser> boundaries, so if |this| is contained by an <iframe
  3743  * mozbrowser>, we will return |this| as its own parent.
  3744  */
  3745 NS_IMETHODIMP
  3746 nsGlobalWindow::GetScriptableParent(nsIDOMWindow** aParent)
  3748   ErrorResult rv;
  3749   nsCOMPtr<nsIDOMWindow> parent = GetParent(rv);
  3750   parent.forget(aParent);
  3752   return rv.ErrorCode();
  3755 /**
  3756  * nsIDOMWindow::GetParent (when called from C++) is just a wrapper around
  3757  * GetRealParent.
  3758  */
  3759 NS_IMETHODIMP
  3760 nsGlobalWindow::GetRealParent(nsIDOMWindow** aParent)
  3762   FORWARD_TO_OUTER(GetRealParent, (aParent), NS_ERROR_NOT_INITIALIZED);
  3764   *aParent = nullptr;
  3765   if (!mDocShell) {
  3766     return NS_OK;
  3769   nsCOMPtr<nsIDocShell> parent;
  3770   mDocShell->GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
  3772   if (parent) {
  3773     nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(parent));
  3774     NS_ENSURE_SUCCESS(CallQueryInterface(globalObject.get(), aParent),
  3775                       NS_ERROR_FAILURE);
  3777   else {
  3778     *aParent = static_cast<nsIDOMWindow*>(this);
  3779     NS_ADDREF(*aParent);
  3781   return NS_OK;
  3784 static nsresult
  3785 GetTopImpl(nsGlobalWindow* aWin, nsIDOMWindow** aTop, bool aScriptable)
  3787   *aTop = nullptr;
  3789   // Walk up the parent chain.
  3791   nsCOMPtr<nsIDOMWindow> prevParent = aWin;
  3792   nsCOMPtr<nsIDOMWindow> parent = aWin;
  3793   do {
  3794     if (!parent) {
  3795       break;
  3798     prevParent = parent;
  3800     nsCOMPtr<nsIDOMWindow> newParent;
  3801     nsresult rv;
  3802     if (aScriptable) {
  3803       rv = parent->GetScriptableParent(getter_AddRefs(newParent));
  3805     else {
  3806       rv = parent->GetParent(getter_AddRefs(newParent));
  3808     NS_ENSURE_SUCCESS(rv, rv);
  3810     parent = newParent;
  3812   } while (parent != prevParent);
  3814   if (parent) {
  3815     parent.swap(*aTop);
  3818   return NS_OK;
  3821 /**
  3822  * GetScriptableTop is called when script reads window.top.
  3824  * In contrast to GetRealTop, GetScriptableTop respects <iframe mozbrowser>
  3825  * boundaries.  If we encounter a window owned by an <iframe mozbrowser> while
  3826  * walking up the window hierarchy, we'll stop and return that window.
  3827  */
  3828 NS_IMETHODIMP
  3829 nsGlobalWindow::GetScriptableTop(nsIDOMWindow **aTop)
  3831   FORWARD_TO_OUTER(GetScriptableTop, (aTop), NS_ERROR_NOT_INITIALIZED);
  3832   return GetTopImpl(this, aTop, /* aScriptable = */ true);
  3835 /**
  3836  * nsIDOMWindow::GetTop (when called from C++) is just a wrapper around
  3837  * GetRealTop.
  3838  */
  3839 NS_IMETHODIMP
  3840 nsGlobalWindow::GetRealTop(nsIDOMWindow** aTop)
  3842   nsGlobalWindow* outer;
  3843   if (IsInnerWindow()) {
  3844     outer = GetOuterWindowInternal();
  3845     if (!outer) {
  3846       NS_WARNING("No outer window available!");
  3847       return NS_ERROR_NOT_INITIALIZED;
  3849   } else {
  3850     outer = this;
  3852   return GetTopImpl(outer, aTop, /* aScriptable = */ false);
  3855 void
  3856 nsGlobalWindow::GetContent(JSContext* aCx,
  3857                            JS::MutableHandle<JSObject*> aRetval,
  3858                            ErrorResult& aError)
  3860   FORWARD_TO_OUTER_OR_THROW(GetContent, (aCx, aRetval, aError), aError, );
  3862   nsCOMPtr<nsIDOMWindow> content = GetContentInternal(aError);
  3863   if (aError.Failed()) {
  3864     return;
  3867   if (content) {
  3868     JS::Rooted<JS::Value> val(aCx);
  3869     aError = nsContentUtils::WrapNative(aCx, content, &val);
  3870     if (aError.Failed()) {
  3871       return;
  3874     aRetval.set(&val.toObject());
  3875     return;
  3878   if (!nsContentUtils::IsCallerChrome() || !IsChromeWindow()) {
  3879     aError.Throw(NS_ERROR_FAILURE);
  3880     return;
  3883   // Something tries to get .content on a ChromeWindow, try to fetch the CPOW.
  3884   nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  3885   if (!treeOwner) {
  3886     aError.Throw(NS_ERROR_FAILURE);
  3887     return;
  3890   JS::Rooted<JS::Value> val(aCx, JS::NullValue());
  3891   aError = treeOwner->GetContentWindow(aCx, &val);
  3892   if (aError.Failed()) {
  3893     return;
  3896   aRetval.set(val.toObjectOrNull());
  3899 already_AddRefed<nsIDOMWindow>
  3900 nsGlobalWindow::GetContentInternal(ErrorResult& aError)
  3902   // First check for a named frame named "content"
  3903   nsCOMPtr<nsIDOMWindow> domWindow =
  3904     GetChildWindow(NS_LITERAL_STRING("content"));
  3905   if (domWindow) {
  3906     return domWindow.forget();
  3909   // If we're contained in <iframe mozbrowser> or <iframe mozapp>, then
  3910   // GetContent is the same as window.top.
  3911   if (mDocShell && mDocShell->GetIsInBrowserOrApp()) {
  3912     return GetTop(aError);
  3915   nsCOMPtr<nsIDocShellTreeItem> primaryContent;
  3916   if (!nsContentUtils::IsCallerChrome()) {
  3917     // If we're called by non-chrome code, make sure we don't return
  3918     // the primary content window if the calling tab is hidden. In
  3919     // such a case we return the same-type root in the hidden tab,
  3920     // which is "good enough", for now.
  3921     nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
  3923     if (baseWin) {
  3924       bool visible = false;
  3925       baseWin->GetVisibility(&visible);
  3927       if (!visible) {
  3928         mDocShell->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
  3933   if (!primaryContent) {
  3934     nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  3935     if (!treeOwner) {
  3936       aError.Throw(NS_ERROR_FAILURE);
  3937       return nullptr;
  3940     treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
  3943   domWindow = do_GetInterface(primaryContent);
  3944   return domWindow.forget();
  3947 NS_IMETHODIMP
  3948 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
  3950   ErrorResult rv;
  3951   *aContent = GetContentInternal(rv).take();
  3953   return rv.ErrorCode();
  3956 NS_IMETHODIMP
  3957 nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
  3959   ErrorResult rv;
  3960   JS::Rooted<JSObject*> content(aCx);
  3961   GetContent(aCx, &content, rv);
  3962   if (!rv.Failed()) {
  3963     aVal.setObjectOrNull(content);
  3966   return rv.ErrorCode();
  3969 NS_IMETHODIMP
  3970 nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
  3972   if (IsInnerWindow()) {
  3973     nsGlobalWindow* outer = GetOuterWindowInternal();
  3974     if (!outer) {
  3975       NS_WARNING("No outer window available!");
  3976       return NS_ERROR_NOT_INITIALIZED;
  3978     return outer->GetPrompter(aPrompt);
  3981   if (!mDocShell)
  3982     return NS_ERROR_FAILURE;
  3984   nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
  3985   NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
  3987   NS_ADDREF(*aPrompt = prompter);
  3988   return NS_OK;
  3991 BarProp*
  3992 nsGlobalWindow::GetMenubar(ErrorResult& aError)
  3994   FORWARD_TO_INNER_OR_THROW(GetMenubar, (aError), aError, nullptr);
  3996   if (!mMenubar) {
  3997     mMenubar = new MenubarProp(this);
  4000   return mMenubar;
  4003 NS_IMETHODIMP
  4004 nsGlobalWindow::GetMenubar(nsISupports** aMenubar)
  4006   ErrorResult rv;
  4007   nsCOMPtr<nsISupports> menubar = GetMenubar(rv);
  4008   menubar.forget(aMenubar);
  4010   return rv.ErrorCode();
  4013 BarProp*
  4014 nsGlobalWindow::GetToolbar(ErrorResult& aError)
  4016   FORWARD_TO_INNER_OR_THROW(GetToolbar, (aError), aError, nullptr);
  4018   if (!mToolbar) {
  4019     mToolbar = new ToolbarProp(this);
  4022   return mToolbar;
  4025 NS_IMETHODIMP
  4026 nsGlobalWindow::GetToolbar(nsISupports** aToolbar)
  4028   ErrorResult rv;
  4029   nsCOMPtr<nsISupports> toolbar = GetToolbar(rv);
  4030   toolbar.forget(aToolbar);
  4032   return rv.ErrorCode();
  4035 BarProp*
  4036 nsGlobalWindow::GetLocationbar(ErrorResult& aError)
  4038   FORWARD_TO_INNER_OR_THROW(GetLocationbar, (aError), aError, nullptr);
  4040   if (!mLocationbar) {
  4041     mLocationbar = new LocationbarProp(this);
  4043   return mLocationbar;
  4046 NS_IMETHODIMP
  4047 nsGlobalWindow::GetLocationbar(nsISupports** aLocationbar)
  4049   ErrorResult rv;
  4050   nsCOMPtr<nsISupports> locationbar = GetLocationbar(rv);
  4051   locationbar.forget(aLocationbar);
  4053   return rv.ErrorCode();
  4056 BarProp*
  4057 nsGlobalWindow::GetPersonalbar(ErrorResult& aError)
  4059   FORWARD_TO_INNER_OR_THROW(GetPersonalbar, (aError), aError, nullptr);
  4061   if (!mPersonalbar) {
  4062     mPersonalbar = new PersonalbarProp(this);
  4064   return mPersonalbar;
  4067 NS_IMETHODIMP
  4068 nsGlobalWindow::GetPersonalbar(nsISupports** aPersonalbar)
  4070   ErrorResult rv;
  4071   nsCOMPtr<nsISupports> personalbar = GetPersonalbar(rv);
  4072   personalbar.forget(aPersonalbar);
  4074   return rv.ErrorCode();
  4077 BarProp*
  4078 nsGlobalWindow::GetStatusbar(ErrorResult& aError)
  4080   FORWARD_TO_INNER_OR_THROW(GetStatusbar, (aError), aError, nullptr);
  4082   if (!mStatusbar) {
  4083     mStatusbar = new StatusbarProp(this);
  4085   return mStatusbar;
  4088 NS_IMETHODIMP
  4089 nsGlobalWindow::GetStatusbar(nsISupports** aStatusbar)
  4091   ErrorResult rv;
  4092   nsCOMPtr<nsISupports> statusbar = GetStatusbar(rv);
  4093   statusbar.forget(aStatusbar);
  4095   return rv.ErrorCode();
  4098 BarProp*
  4099 nsGlobalWindow::GetScrollbars(ErrorResult& aError)
  4101   FORWARD_TO_INNER_OR_THROW(GetScrollbars, (aError), aError, nullptr);
  4103   if (!mScrollbars) {
  4104     mScrollbars = new ScrollbarsProp(this);
  4107   return mScrollbars;
  4110 NS_IMETHODIMP
  4111 nsGlobalWindow::GetScrollbars(nsISupports** aScrollbars)
  4113   ErrorResult rv;
  4114   nsCOMPtr<nsISupports> scrollbars = GetScrollbars(rv);
  4115   scrollbars.forget(aScrollbars);
  4117   return rv.ErrorCode();
  4120 bool
  4121 nsGlobalWindow::GetClosed(ErrorResult& aError)
  4123   FORWARD_TO_OUTER_OR_THROW(GetClosed, (aError), aError, false);
  4125   // If someone called close(), or if we don't have a docshell, we're closed.
  4126   return mIsClosed || !mDocShell;
  4129 NS_IMETHODIMP
  4130 nsGlobalWindow::GetClosed(bool* aClosed)
  4132   ErrorResult rv;
  4133   *aClosed = GetClosed(rv);
  4135   return rv.ErrorCode();
  4138 nsDOMWindowList*
  4139 nsGlobalWindow::GetWindowList()
  4141   MOZ_ASSERT(IsOuterWindow());
  4143   if (!mFrames && mDocShell) {
  4144     mFrames = new nsDOMWindowList(mDocShell);
  4147   return mFrames;
  4150 NS_IMETHODIMP
  4151 nsGlobalWindow::GetFrames(nsIDOMWindowCollection** aFrames)
  4153   FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
  4155   *aFrames = GetWindowList();
  4156   NS_IF_ADDREF(*aFrames);
  4157   return NS_OK;
  4160 already_AddRefed<nsIDOMWindow>
  4161 nsGlobalWindow::IndexedGetter(uint32_t aIndex, bool& aFound)
  4163   aFound = false;
  4165   FORWARD_TO_OUTER(IndexedGetter, (aIndex, aFound), nullptr);
  4167   nsDOMWindowList* windows = GetWindowList();
  4168   NS_ENSURE_TRUE(windows, nullptr);
  4170   return windows->IndexedGetter(aIndex, aFound);
  4173 void
  4174 nsGlobalWindow::GetSupportedNames(nsTArray<nsString>& aNames)
  4176   FORWARD_TO_OUTER_VOID(GetSupportedNames, (aNames));
  4178   nsDOMWindowList* windows = GetWindowList();
  4179   if (windows) {
  4180     uint32_t length = windows->GetLength();
  4181     nsString* name = aNames.AppendElements(length);
  4182     for (uint32_t i = 0; i < length; ++i, ++name) {
  4183       nsCOMPtr<nsIDocShellTreeItem> item =
  4184         windows->GetDocShellTreeItemAt(i);
  4185       item->GetName(*name);
  4190 bool
  4191 nsGlobalWindow::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
  4192                              JS::Handle<jsid> aId,
  4193                              JS::MutableHandle<JSPropertyDescriptor> aDesc)
  4195   MOZ_ASSERT(IsInnerWindow());
  4197   if (!JSID_IS_STRING(aId)) {
  4198     return true;
  4201   nsresult rv = nsWindowSH::GlobalResolve(this, aCx, aObj, aId, aDesc);
  4202   if (NS_FAILED(rv)) {
  4203     return Throw(aCx, rv);
  4206   return true;
  4209 struct GlobalNameEnumeratorClosure
  4211   GlobalNameEnumeratorClosure(JSContext* aCx, nsGlobalWindow* aWindow,
  4212                               nsTArray<nsString>& aNames)
  4213     : mCx(aCx),
  4214       mWindow(aWindow),
  4215       mWrapper(aCx, aWindow->GetWrapper()),
  4216       mNames(aNames)
  4220   JSContext* mCx;
  4221   nsGlobalWindow* mWindow;
  4222   JS::Rooted<JSObject*> mWrapper;
  4223   nsTArray<nsString>& mNames;
  4224 };
  4226 static PLDHashOperator
  4227 EnumerateGlobalName(const nsAString& aName,
  4228                     const nsGlobalNameStruct& aNameStruct,
  4229                     void* aClosure)
  4231   GlobalNameEnumeratorClosure* closure =
  4232     static_cast<GlobalNameEnumeratorClosure*>(aClosure);
  4234   if (aNameStruct.mType == nsGlobalNameStruct::eTypeStaticNameSet) {
  4235     // We have no idea what names this might install.
  4236     return PL_DHASH_NEXT;
  4239   if (nsWindowSH::NameStructEnabled(closure->mCx, closure->mWindow, aName,
  4240                                     aNameStruct) &&
  4241       (!aNameStruct.mConstructorEnabled ||
  4242        aNameStruct.mConstructorEnabled(closure->mCx, closure->mWrapper))) {
  4243     closure->mNames.AppendElement(aName);
  4245   return PL_DHASH_NEXT;
  4248 void
  4249 nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
  4250                                     ErrorResult& aRv)
  4252   // "Components" is marked as enumerable but only resolved on demand :-/.
  4253   //aNames.AppendElement(NS_LITERAL_STRING("Components"));
  4255   nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
  4256   if (nameSpaceManager) {
  4257     GlobalNameEnumeratorClosure closure(aCx, this, aNames);
  4258     nameSpaceManager->EnumerateGlobalNames(EnumerateGlobalName, &closure);
  4262 /* static */ bool
  4263 nsGlobalWindow::IsChromeWindow(JSContext* aCx, JSObject* aObj)
  4265   // For now, have to deal with XPConnect objects here.
  4266   return xpc::WindowOrNull(aObj)->IsChromeWindow();
  4269 nsIDOMOfflineResourceList*
  4270 nsGlobalWindow::GetApplicationCache(ErrorResult& aError)
  4272   FORWARD_TO_INNER_OR_THROW(GetApplicationCache, (aError), aError, nullptr);
  4274   if (!mApplicationCache) {
  4275     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
  4276     if (!webNav) {
  4277       aError.Throw(NS_ERROR_FAILURE);
  4278       return nullptr;
  4281     nsCOMPtr<nsIURI> uri;
  4282     aError = webNav->GetCurrentURI(getter_AddRefs(uri));
  4283     if (aError.Failed()) {
  4284       return nullptr;
  4287     nsCOMPtr<nsIURI> manifestURI;
  4288     nsContentUtils::GetOfflineAppManifest(mDoc, getter_AddRefs(manifestURI));
  4290     nsRefPtr<nsDOMOfflineResourceList> applicationCache =
  4291       new nsDOMOfflineResourceList(manifestURI, uri, this);
  4293     applicationCache->Init();
  4295     mApplicationCache = applicationCache;
  4298   return mApplicationCache;
  4301 NS_IMETHODIMP
  4302 nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
  4304   ErrorResult rv;
  4305   nsCOMPtr<nsIDOMOfflineResourceList> applicationCache =
  4306     GetApplicationCache(rv);
  4307   applicationCache.forget(aApplicationCache);
  4309   return rv.ErrorCode();
  4312 nsIDOMCrypto*
  4313 nsGlobalWindow::GetCrypto(ErrorResult& aError)
  4315   FORWARD_TO_INNER_OR_THROW(GetCrypto, (aError), aError, nullptr);
  4317   if (!mCrypto) {
  4318 #ifndef MOZ_DISABLE_CRYPTOLEGACY
  4319     if (XRE_GetProcessType() != GeckoProcessType_Content) {
  4320       nsresult rv;
  4321       mCrypto = do_CreateInstance(NS_CRYPTO_CONTRACTID, &rv);
  4322       if (NS_FAILED(rv)) {
  4323         aError.Throw(rv);
  4324         return nullptr;
  4326     } else
  4327 #endif
  4329       mCrypto = new Crypto();
  4332     mCrypto->Init(this);
  4334   return mCrypto;
  4337 NS_IMETHODIMP
  4338 nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
  4340   ErrorResult rv;
  4341   nsCOMPtr<nsIDOMCrypto> crypto = GetCrypto(rv);
  4342   crypto.forget(aCrypto);
  4344   return rv.ErrorCode();
  4347 nsIControllers*
  4348 nsGlobalWindow::GetControllers(ErrorResult& aError)
  4350   FORWARD_TO_OUTER_OR_THROW(GetControllers, (aError), aError, nullptr);
  4352   if (!mControllers) {
  4353     nsresult rv;
  4354     mControllers = do_CreateInstance(kXULControllersCID, &rv);
  4355     if (NS_FAILED(rv)) {
  4356       aError.Throw(rv);
  4357       return nullptr;
  4360     // Add in the default controller
  4361     nsCOMPtr<nsIController> controller = do_CreateInstance(
  4362                                NS_WINDOWCONTROLLER_CONTRACTID, &rv);
  4363     if (NS_FAILED(rv)) {
  4364       aError.Throw(rv);
  4365       return nullptr;
  4368     mControllers->InsertControllerAt(0, controller);
  4369     nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
  4370     if (!controllerContext) {
  4371       aError.Throw(NS_ERROR_FAILURE);
  4372       return nullptr;
  4375     controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
  4378   return mControllers;
  4381 NS_IMETHODIMP
  4382 nsGlobalWindow::GetControllers(nsIControllers** aResult)
  4384   ErrorResult rv;
  4385   nsCOMPtr<nsIControllers> controllers = GetControllers(rv);
  4386   controllers.forget(aResult);
  4388   return rv.ErrorCode();
  4391 nsIDOMWindow*
  4392 nsGlobalWindow::GetOpenerWindow(ErrorResult& aError)
  4394   FORWARD_TO_OUTER_OR_THROW(GetOpenerWindow, (aError), aError, nullptr);
  4396   nsCOMPtr<nsPIDOMWindow> opener = do_QueryReferent(mOpener);
  4397   if (!opener) {
  4398     return nullptr;
  4401   // First, check if we were called from a privileged chrome script
  4402   if (nsContentUtils::IsCallerChrome()) {
  4403     return opener;
  4406   // First, ensure that we're not handing back a chrome window.
  4407   nsGlobalWindow *win = static_cast<nsGlobalWindow *>(opener.get());
  4408   if (win->IsChromeWindow()) {
  4409     return nullptr;
  4412   // We don't want to reveal the opener if the opener is a mail window,
  4413   // because opener can be used to spoof the contents of a message (bug 105050).
  4414   // So, we look in the opener's root docshell to see if it's a mail window.
  4415   nsCOMPtr<nsIDocShell> openerDocShell = opener->GetDocShell();
  4417   if (openerDocShell) {
  4418     nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
  4419     openerDocShell->GetRootTreeItem(getter_AddRefs(openerRootItem));
  4420     nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
  4421     if (openerRootDocShell) {
  4422       uint32_t appType;
  4423       nsresult rv = openerRootDocShell->GetAppType(&appType);
  4424       if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
  4425         return opener;
  4430   return nullptr;
  4433 void
  4434 nsGlobalWindow::GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
  4435                           ErrorResult& aError)
  4437   nsCOMPtr<nsIDOMWindow> opener = GetOpenerWindow(aError);
  4438   if (aError.Failed() || !opener) {
  4439     aRetval.setNull();
  4440     return;
  4443   aError = nsContentUtils::WrapNative(aCx, opener, aRetval);
  4446 NS_IMETHODIMP
  4447 nsGlobalWindow::GetScriptableOpener(JSContext* aCx,
  4448                                     JS::MutableHandle<JS::Value> aOpener)
  4450   ErrorResult rv;
  4451   GetOpener(aCx, aOpener, rv);
  4453   return rv.ErrorCode();
  4456 NS_IMETHODIMP
  4457 nsGlobalWindow::GetOpener(nsIDOMWindow** aOpener)
  4459   ErrorResult rv;
  4460   nsCOMPtr<nsIDOMWindow> opener = GetOpenerWindow(rv);
  4461   opener.forget(aOpener);
  4462   return rv.ErrorCode();
  4465 void
  4466 nsGlobalWindow::SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
  4467                           ErrorResult& aError)
  4469   // Check if we were called from a privileged chrome script.  If not, and if
  4470   // aOpener is not null, just define aOpener on our inner window's JS object,
  4471   // wrapped into the current compartment so that for Xrays we define on the
  4472   // Xray expando object, but don't set it on the outer window, so that it'll
  4473   // get reset on navigation.  This is just like replaceable properties, but
  4474   // we're not quite readonly.
  4475   if (!aOpener.isNull() && !nsContentUtils::IsCallerChrome()) {
  4476     JS::Rooted<JSObject*> thisObj(aCx, GetWrapperPreserveColor());
  4477     if (!thisObj) {
  4478       aError.Throw(NS_ERROR_UNEXPECTED);
  4479       return;
  4482     if (!JS_WrapObject(aCx, &thisObj) ||
  4483         !JS_DefineProperty(aCx, thisObj, "opener", aOpener, JSPROP_ENUMERATE,
  4484                            JS_PropertyStub, JS_StrictPropertyStub)) {
  4485       aError.Throw(NS_ERROR_FAILURE);
  4488     return;
  4491   if (!aOpener.isObjectOrNull()) {
  4492     // Chrome code trying to set some random value as opener
  4493     aError.Throw(NS_ERROR_INVALID_ARG);
  4494     return;
  4497   nsGlobalWindow* win = nullptr;
  4498   if (aOpener.isObject()) {
  4499     JSObject* unwrapped = js::CheckedUnwrap(&aOpener.toObject(),
  4500                                             /* stopAtOuter = */ false);
  4501     if (!unwrapped) {
  4502       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
  4503       return;
  4506     win = xpc::WindowOrNull(unwrapped);
  4507     if (!win) {
  4508       // Wasn't a window
  4509       aError.Throw(NS_ERROR_INVALID_ARG);
  4510       return;
  4514   SetOpenerWindow(win, false);
  4517 NS_IMETHODIMP
  4518 nsGlobalWindow::SetScriptableOpener(JSContext* aCx,
  4519                                     JS::Handle<JS::Value> aOpener)
  4521   ErrorResult rv;
  4522   SetOpener(aCx, aOpener, rv);
  4524   return rv.ErrorCode();
  4527 NS_IMETHODIMP
  4528 nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener)
  4530   SetOpenerWindow(aOpener, false);
  4531   return NS_OK;
  4534 void
  4535 nsGlobalWindow::GetStatus(nsAString& aStatus, ErrorResult& aError)
  4537   FORWARD_TO_OUTER_OR_THROW(GetStatus, (aStatus, aError), aError, );
  4539   aStatus = mStatus;
  4542 NS_IMETHODIMP
  4543 nsGlobalWindow::GetStatus(nsAString& aStatus)
  4545   ErrorResult rv;
  4546   GetStatus(aStatus, rv);
  4548   return rv.ErrorCode();
  4551 void
  4552 nsGlobalWindow::SetStatus(const nsAString& aStatus, ErrorResult& aError)
  4554   FORWARD_TO_OUTER_OR_THROW(SetStatus, (aStatus, aError), aError, );
  4556   mStatus = aStatus;
  4558   /*
  4559    * If caller is not chrome and dom.disable_window_status_change is true,
  4560    * prevent propagating window.status to the UI by exiting early
  4561    */
  4563   if (!CanSetProperty("dom.disable_window_status_change")) {
  4564     return;
  4567   nsCOMPtr<nsIWebBrowserChrome> browserChrome = GetWebBrowserChrome();
  4568   if (browserChrome) {
  4569     browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
  4570                              PromiseFlatString(aStatus).get());
  4574 NS_IMETHODIMP
  4575 nsGlobalWindow::SetStatus(const nsAString& aStatus)
  4577   ErrorResult rv;
  4578   SetStatus(aStatus, rv);
  4580   return rv.ErrorCode();
  4583 void
  4584 nsGlobalWindow::GetName(nsAString& aName, ErrorResult& aError)
  4586   FORWARD_TO_OUTER_OR_THROW(GetName, (aName, aError), aError, );
  4588   if (mDocShell) {
  4589     mDocShell->GetName(aName);
  4593 NS_IMETHODIMP
  4594 nsGlobalWindow::GetName(nsAString& aName)
  4596   ErrorResult rv;
  4597   GetName(aName, rv);
  4599   return rv.ErrorCode();
  4602 void
  4603 nsGlobalWindow::SetName(const nsAString& aName, mozilla::ErrorResult& aError)
  4605   FORWARD_TO_OUTER_OR_THROW(SetName, (aName, aError), aError, );
  4607   if (mDocShell) {
  4608     aError = mDocShell->SetName(aName);
  4612 NS_IMETHODIMP
  4613 nsGlobalWindow::SetName(const nsAString& aName)
  4615   ErrorResult rv;
  4616   SetName(aName, rv);
  4618   return rv.ErrorCode();
  4621 // Helper functions used by many methods below.
  4622 int32_t
  4623 nsGlobalWindow::DevToCSSIntPixels(int32_t px)
  4625   if (!mDocShell)
  4626     return px; // assume 1:1
  4628   nsRefPtr<nsPresContext> presContext;
  4629   mDocShell->GetPresContext(getter_AddRefs(presContext));
  4630   if (!presContext)
  4631     return px;
  4633   return presContext->DevPixelsToIntCSSPixels(px);
  4636 int32_t
  4637 nsGlobalWindow::CSSToDevIntPixels(int32_t px)
  4639   if (!mDocShell)
  4640     return px; // assume 1:1
  4642   nsRefPtr<nsPresContext> presContext;
  4643   mDocShell->GetPresContext(getter_AddRefs(presContext));
  4644   if (!presContext)
  4645     return px;
  4647   return presContext->CSSPixelsToDevPixels(px);
  4650 nsIntSize
  4651 nsGlobalWindow::DevToCSSIntPixels(nsIntSize px)
  4653   if (!mDocShell)
  4654     return px; // assume 1:1
  4656   nsRefPtr<nsPresContext> presContext;
  4657   mDocShell->GetPresContext(getter_AddRefs(presContext));
  4658   if (!presContext)
  4659     return px;
  4661   return nsIntSize(
  4662       presContext->DevPixelsToIntCSSPixels(px.width),
  4663       presContext->DevPixelsToIntCSSPixels(px.height));
  4666 nsIntSize
  4667 nsGlobalWindow::CSSToDevIntPixels(nsIntSize px)
  4669   if (!mDocShell)
  4670     return px; // assume 1:1
  4672   nsRefPtr<nsPresContext> presContext;
  4673   mDocShell->GetPresContext(getter_AddRefs(presContext));
  4674   if (!presContext)
  4675     return px;
  4677   return nsIntSize(
  4678     presContext->CSSPixelsToDevPixels(px.width),
  4679     presContext->CSSPixelsToDevPixels(px.height));
  4682 nsresult
  4683 nsGlobalWindow::GetInnerSize(CSSIntSize& aSize)
  4685   MOZ_ASSERT(IsOuterWindow());
  4687   EnsureSizeUpToDate();
  4689   NS_ENSURE_STATE(mDocShell);
  4691   nsRefPtr<nsPresContext> presContext;
  4692   mDocShell->GetPresContext(getter_AddRefs(presContext));
  4693   nsRefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  4695   if (!presContext || !presShell) {
  4696     aSize = CSSIntSize(0, 0);
  4697     return NS_OK;
  4700   /*
  4701    * On platforms with resolution-based zooming, the CSS viewport
  4702    * and visual viewport may not be the same. The inner size should
  4703    * be the visual viewport, but we fall back to the CSS viewport
  4704    * if it is not set.
  4705    */
  4706   if (presShell->IsScrollPositionClampingScrollPortSizeSet()) {
  4707     aSize = CSSIntRect::FromAppUnitsRounded(
  4708       presShell->GetScrollPositionClampingScrollPortSize());
  4709   } else {
  4710     nsRefPtr<nsViewManager> viewManager = presShell->GetViewManager();
  4711     if (viewManager) {
  4712       viewManager->FlushDelayedResize(false);
  4715     aSize = CSSIntRect::FromAppUnitsRounded(
  4716       presContext->GetVisibleArea().Size());
  4718   return NS_OK;
  4721 int32_t
  4722 nsGlobalWindow::GetInnerWidth(ErrorResult& aError)
  4724   FORWARD_TO_OUTER_OR_THROW(GetInnerWidth, (aError), aError, 0);
  4726   CSSIntSize size;
  4727   aError = GetInnerSize(size);
  4728   return size.width;
  4731 NS_IMETHODIMP
  4732 nsGlobalWindow::GetInnerWidth(int32_t* aInnerWidth)
  4734   ErrorResult rv;
  4735   *aInnerWidth = GetInnerWidth(rv);
  4737   return rv.ErrorCode();
  4740 void
  4741 nsGlobalWindow::SetInnerWidth(int32_t aInnerWidth, ErrorResult& aError)
  4743   FORWARD_TO_OUTER_OR_THROW(SetInnerWidth, (aInnerWidth, aError), aError, );
  4745   if (!mDocShell) {
  4746     aError.Throw(NS_ERROR_UNEXPECTED);
  4747     return;
  4750   /*
  4751    * If caller is not chrome and the user has not explicitly exempted the site,
  4752    * prevent setting window.innerWidth by exiting early
  4753    */
  4754   if (!CanMoveResizeWindows() || IsFrame()) {
  4755     return;
  4758   CheckSecurityWidthAndHeight(&aInnerWidth, nullptr);
  4760   nsRefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  4762   if (presShell && presShell->GetIsViewportOverridden())
  4764     nscoord height = 0;
  4766     nsRefPtr<nsPresContext> presContext;
  4767     presContext = presShell->GetPresContext();
  4769     nsRect shellArea = presContext->GetVisibleArea();
  4770     height = shellArea.height;
  4771     SetCSSViewportWidthAndHeight(nsPresContext::CSSPixelsToAppUnits(aInnerWidth),
  4772                                  height);
  4773     return;
  4776   int32_t height = 0;
  4777   int32_t unused  = 0;
  4779   nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
  4780   docShellAsWin->GetSize(&unused, &height);
  4781   aError = SetDocShellWidthAndHeight(CSSToDevIntPixels(aInnerWidth), height);
  4784 NS_IMETHODIMP
  4785 nsGlobalWindow::SetInnerWidth(int32_t aInnerWidth)
  4787   ErrorResult rv;
  4788   SetInnerWidth(aInnerWidth, rv);
  4790   return rv.ErrorCode();
  4793 int32_t
  4794 nsGlobalWindow::GetInnerHeight(ErrorResult& aError)
  4796   FORWARD_TO_OUTER_OR_THROW(GetInnerHeight, (aError), aError, 0);
  4798   CSSIntSize size;
  4799   aError = GetInnerSize(size);
  4800   return size.height;
  4803 NS_IMETHODIMP
  4804 nsGlobalWindow::GetInnerHeight(int32_t* aInnerHeight)
  4806   ErrorResult rv;
  4807   *aInnerHeight = GetInnerHeight(rv);
  4809   return rv.ErrorCode();
  4812 void
  4813 nsGlobalWindow::SetInnerHeight(int32_t aInnerHeight, ErrorResult& aError)
  4815   FORWARD_TO_OUTER_OR_THROW(SetInnerHeight, (aInnerHeight, aError), aError, );
  4817   if (!mDocShell) {
  4818     aError.Throw(NS_ERROR_UNEXPECTED);
  4819     return;
  4822   /*
  4823    * If caller is not chrome and the user has not explicitly exempted the site,
  4824    * prevent setting window.innerHeight by exiting early
  4825    */
  4826   if (!CanMoveResizeWindows() || IsFrame()) {
  4827     return;
  4830   nsRefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  4832   if (presShell && presShell->GetIsViewportOverridden())
  4834     nsRefPtr<nsPresContext> presContext;
  4835     presContext = presShell->GetPresContext();
  4837     nsRect shellArea = presContext->GetVisibleArea();
  4838     nscoord height = aInnerHeight;
  4839     nscoord width = shellArea.width;
  4840     CheckSecurityWidthAndHeight(nullptr, &height);
  4841     SetCSSViewportWidthAndHeight(width,
  4842                                  nsPresContext::CSSPixelsToAppUnits(height));
  4843     return;
  4846   int32_t height = 0;
  4847   int32_t width  = 0;
  4849   nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
  4850   docShellAsWin->GetSize(&width, &height);
  4851   CheckSecurityWidthAndHeight(nullptr, &aInnerHeight);
  4852   aError = SetDocShellWidthAndHeight(width, CSSToDevIntPixels(aInnerHeight));
  4855 NS_IMETHODIMP
  4856 nsGlobalWindow::SetInnerHeight(int32_t aInnerHeight)
  4858   ErrorResult rv;
  4859   SetInnerHeight(aInnerHeight, rv);
  4861   return rv.ErrorCode();
  4864 nsIntSize
  4865 nsGlobalWindow::GetOuterSize(ErrorResult& aError)
  4867   MOZ_ASSERT(IsOuterWindow());
  4869   if (!IsChrome()) {
  4870     CSSIntSize size;                                                                                                                                                                                       
  4871     aError = GetInnerSize(size);                                                                                                                                                                           
  4872     return nsIntSize(size.width, size.height);  
  4875   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  4876   if (!treeOwnerAsWin) {
  4877     aError.Throw(NS_ERROR_FAILURE);
  4878     return nsIntSize(0, 0);
  4881   nsGlobalWindow* rootWindow =
  4882     static_cast<nsGlobalWindow *>(GetPrivateRoot());
  4883   if (rootWindow) {
  4884     rootWindow->FlushPendingNotifications(Flush_Layout);
  4887   nsIntSize sizeDevPixels;
  4888   aError = treeOwnerAsWin->GetSize(&sizeDevPixels.width, &sizeDevPixels.height);
  4889   if (aError.Failed()) {
  4890     return nsIntSize();
  4893   return DevToCSSIntPixels(sizeDevPixels);
  4896 int32_t
  4897 nsGlobalWindow::GetOuterWidth(ErrorResult& aError)
  4899   FORWARD_TO_OUTER_OR_THROW(GetOuterWidth, (aError), aError, 0);
  4900   return GetOuterSize(aError).width;
  4903 NS_IMETHODIMP
  4904 nsGlobalWindow::GetOuterWidth(int32_t* aOuterWidth)
  4906   ErrorResult rv;
  4907   *aOuterWidth = GetOuterWidth(rv);
  4909   return rv.ErrorCode();
  4912 int32_t
  4913 nsGlobalWindow::GetOuterHeight(ErrorResult& aError)
  4915   FORWARD_TO_OUTER_OR_THROW(GetOuterHeight, (aError), aError, 0);
  4916   return GetOuterSize(aError).height;
  4919 NS_IMETHODIMP
  4920 nsGlobalWindow::GetOuterHeight(int32_t* aOuterHeight)
  4922   ErrorResult rv;
  4923   *aOuterHeight = GetOuterHeight(rv);
  4925   return rv.ErrorCode();
  4928 void
  4929 nsGlobalWindow::SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth,
  4930                              ErrorResult& aError)
  4932   MOZ_ASSERT(IsOuterWindow());
  4934   /*
  4935    * If caller is not chrome and the user has not explicitly exempted the site,
  4936    * prevent setting window.outerWidth by exiting early
  4937    */
  4939   if (!CanMoveResizeWindows() || IsFrame()) {
  4940     return;
  4943   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  4944   if (!treeOwnerAsWin) {
  4945     aError.Throw(NS_ERROR_FAILURE);
  4946     return;
  4949   CheckSecurityWidthAndHeight(aIsWidth ? &aLengthCSSPixels : nullptr,
  4950                               aIsWidth ? nullptr : &aLengthCSSPixels);
  4952   int32_t width, height;
  4953   aError = treeOwnerAsWin->GetSize(&width, &height);
  4954   if (aError.Failed()) {
  4955     return;
  4958   int32_t lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
  4959   if (aIsWidth) {
  4960     width = lengthDevPixels;
  4961   } else {
  4962     height = lengthDevPixels;
  4964   aError = treeOwnerAsWin->SetSize(width, height, true);    
  4967 void
  4968 nsGlobalWindow::SetOuterWidth(int32_t aOuterWidth, ErrorResult& aError)
  4970   FORWARD_TO_OUTER_OR_THROW(SetOuterWidth, (aOuterWidth, aError), aError, );
  4972   SetOuterSize(aOuterWidth, true, aError);
  4975 NS_IMETHODIMP
  4976 nsGlobalWindow::SetOuterWidth(int32_t aOuterWidth)
  4978   ErrorResult rv;
  4979   SetOuterWidth(aOuterWidth, rv);
  4981   return rv.ErrorCode();
  4984 void
  4985 nsGlobalWindow::SetOuterHeight(int32_t aOuterHeight, ErrorResult& aError)
  4987   FORWARD_TO_OUTER_OR_THROW(SetOuterHeight, (aOuterHeight, aError), aError, );
  4989   SetOuterSize(aOuterHeight, false, aError);
  4992 NS_IMETHODIMP
  4993 nsGlobalWindow::SetOuterHeight(int32_t aOuterHeight)
  4995   ErrorResult rv;
  4996   SetOuterHeight(aOuterHeight, rv);
  4998   return rv.ErrorCode();
  5001 nsIntPoint
  5002 nsGlobalWindow::GetScreenXY(ErrorResult& aError)
  5004   MOZ_ASSERT(IsOuterWindow());
  5006   // For non-chrome callers, always return (0,0) to prevent fingerprinting.
  5007   if (!IsChrome()) {
  5008     return nsIntPoint(0, 0);
  5011   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  5012   if (!treeOwnerAsWin) {
  5013     aError.Throw(NS_ERROR_FAILURE);
  5014     return nsIntPoint(0, 0);
  5017   int32_t x = 0, y = 0;
  5018   aError = treeOwnerAsWin->GetPosition(&x, &y);
  5019   return nsIntPoint(x, y);
  5022 int32_t
  5023 nsGlobalWindow::GetScreenX(ErrorResult& aError)
  5025   FORWARD_TO_OUTER_OR_THROW(GetScreenX, (aError), aError, 0);
  5027   return DevToCSSIntPixels(GetScreenXY(aError).x);
  5030 NS_IMETHODIMP
  5031 nsGlobalWindow::GetScreenX(int32_t* aScreenX)
  5033   ErrorResult rv;
  5034   *aScreenX = GetScreenX(rv);
  5036   return rv.ErrorCode();
  5039 nsRect
  5040 nsGlobalWindow::GetInnerScreenRect()
  5042   MOZ_ASSERT(IsOuterWindow());
  5044   if (!mDocShell) {
  5045     return nsRect();
  5048   nsGlobalWindow* rootWindow =
  5049     static_cast<nsGlobalWindow*>(GetPrivateRoot());
  5050   if (rootWindow) {
  5051     rootWindow->FlushPendingNotifications(Flush_Layout);
  5054   if (!mDocShell) {
  5055     return nsRect();
  5058   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  5059   if (!presShell) {
  5060     return nsRect();
  5062   nsIFrame* rootFrame = presShell->GetRootFrame();
  5063   if (!rootFrame) {
  5064     return nsRect();
  5067   return rootFrame->GetScreenRectInAppUnits();
  5070 float
  5071 nsGlobalWindow::GetMozInnerScreenX(ErrorResult& aError)
  5073   FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenX, (aError), aError, 0);
  5075   // For non-chrome callers, always return 0 to prevent fingerprinting.
  5076   if (!IsChrome()) return 0.0;
  5078   nsRect r = GetInnerScreenRect();
  5079   return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
  5082 NS_IMETHODIMP
  5083 nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
  5085   ErrorResult rv;
  5086   *aScreenX = GetMozInnerScreenX(rv);
  5088   return rv.ErrorCode();
  5091 float
  5092 nsGlobalWindow::GetMozInnerScreenY(ErrorResult& aError)
  5094   FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenY, (aError), aError, 0);
  5096   // For non-chrome callers, always return 0 to prevent fingerprinting.
  5097   if (!IsChrome()) return 0.0;
  5099   nsRect r = GetInnerScreenRect();
  5100   return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
  5103 NS_IMETHODIMP
  5104 nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
  5106   ErrorResult rv;
  5107   *aScreenY = GetMozInnerScreenY(rv);
  5109   return rv.ErrorCode();
  5112 float
  5113 nsGlobalWindow::GetDevicePixelRatio(ErrorResult& aError)
  5115   FORWARD_TO_OUTER_OR_THROW(GetDevicePixelRatio, (aError), aError, 0.0);
  5117   if (!mDocShell) {
  5118     return 1.0;
  5121   nsRefPtr<nsPresContext> presContext;
  5122   mDocShell->GetPresContext(getter_AddRefs(presContext));
  5123   if (!presContext) {
  5124     return 1.0;
  5127   return float(nsPresContext::AppUnitsPerCSSPixel())/
  5128       presContext->AppUnitsPerDevPixel();
  5131 NS_IMETHODIMP
  5132 nsGlobalWindow::GetDevicePixelRatio(float* aRatio)
  5134   ErrorResult rv;
  5135   *aRatio = GetDevicePixelRatio(rv);
  5137   return rv.ErrorCode();
  5140 uint64_t
  5141 nsGlobalWindow::GetMozPaintCount(ErrorResult& aError)
  5143   FORWARD_TO_OUTER_OR_THROW(GetMozPaintCount, (aError), aError, 0);
  5145   if (!mDocShell) {
  5146     return 0;
  5149   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  5150   return presShell ? presShell->GetPaintCount() : 0;
  5153 NS_IMETHODIMP
  5154 nsGlobalWindow::GetMozPaintCount(uint64_t* aResult)
  5156   ErrorResult rv;
  5157   *aResult = GetMozPaintCount(rv);
  5159   return rv.ErrorCode();
  5162 NS_IMETHODIMP
  5163 nsGlobalWindow::MozRequestAnimationFrame(nsIFrameRequestCallback* aCallback,
  5164                                          int32_t *aHandle)
  5166   if (!aCallback) {
  5167     if (mDoc) {
  5168       mDoc->WarnOnceAbout(nsIDocument::eMozBeforePaint);
  5170     return NS_ERROR_XPC_BAD_CONVERT_JS;
  5173   ErrorResult rv;
  5174   nsIDocument::FrameRequestCallbackHolder holder(aCallback);
  5175   *aHandle = RequestAnimationFrame(holder, rv);
  5177   return rv.ErrorCode();
  5180 int32_t
  5181 nsGlobalWindow::RequestAnimationFrame(FrameRequestCallback& aCallback,
  5182                                       ErrorResult& aError)
  5184   nsIDocument::FrameRequestCallbackHolder holder(&aCallback);
  5185   return RequestAnimationFrame(holder, aError);
  5188 int32_t
  5189 nsGlobalWindow::MozRequestAnimationFrame(nsIFrameRequestCallback* aCallback,
  5190                                          ErrorResult& aError)
  5192   nsIDocument::FrameRequestCallbackHolder holder(aCallback);
  5193   return RequestAnimationFrame(holder, aError);
  5196 int32_t
  5197 nsGlobalWindow::RequestAnimationFrame(const nsIDocument::FrameRequestCallbackHolder& aCallback,
  5198                                       ErrorResult& aError)
  5200   FORWARD_TO_INNER_OR_THROW(RequestAnimationFrame, (aCallback, aError), aError,
  5201                             0);
  5203   if (!mDoc) {
  5204     return 0;
  5207   if (GetWrapperPreserveColor()) {
  5208     js::NotifyAnimationActivity(GetWrapperPreserveColor());
  5211   int32_t handle;
  5212   aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle);
  5213   return handle;
  5216 NS_IMETHODIMP
  5217 nsGlobalWindow::RequestAnimationFrame(JS::Handle<JS::Value> aCallback,
  5218                                       JSContext* cx,
  5219                                       int32_t* aHandle)
  5221   if (!aCallback.isObject() || !JS_ObjectIsCallable(cx, &aCallback.toObject())) {
  5222     return NS_ERROR_INVALID_ARG;
  5225   JS::Rooted<JSObject*> callbackObj(cx, &aCallback.toObject());
  5226   nsRefPtr<FrameRequestCallback> callback =
  5227     new FrameRequestCallback(callbackObj, GetIncumbentGlobal());
  5229   ErrorResult rv;
  5230   *aHandle = RequestAnimationFrame(*callback, rv);
  5232   return rv.ErrorCode();
  5235 NS_IMETHODIMP
  5236 nsGlobalWindow::MozCancelRequestAnimationFrame(int32_t aHandle)
  5238   return CancelAnimationFrame(aHandle);
  5241 NS_IMETHODIMP
  5242 nsGlobalWindow::MozCancelAnimationFrame(int32_t aHandle)
  5244   return CancelAnimationFrame(aHandle);
  5247 void
  5248 nsGlobalWindow::CancelAnimationFrame(int32_t aHandle, ErrorResult& aError)
  5250   FORWARD_TO_INNER_OR_THROW(CancelAnimationFrame, (aHandle, aError), aError, );
  5252   if (!mDoc) {
  5253     return;
  5256   mDoc->CancelFrameRequestCallback(aHandle);
  5259 NS_IMETHODIMP
  5260 nsGlobalWindow::CancelAnimationFrame(int32_t aHandle)
  5262   ErrorResult rv;
  5263   CancelAnimationFrame(aHandle, rv);
  5265   return rv.ErrorCode();
  5268 int64_t
  5269 nsGlobalWindow::GetMozAnimationStartTime(ErrorResult& aError)
  5271   FORWARD_TO_INNER_OR_THROW(GetMozAnimationStartTime, (aError), aError, 0);
  5273   if (mDoc) {
  5274     nsIPresShell* presShell = mDoc->GetShell();
  5275     if (presShell) {
  5276       return presShell->GetPresContext()->RefreshDriver()->
  5277         MostRecentRefreshEpochTime() / PR_USEC_PER_MSEC;
  5281   // If all else fails, just be compatible with Date.now()
  5282   return JS_Now() / PR_USEC_PER_MSEC;
  5285 NS_IMETHODIMP
  5286 nsGlobalWindow::GetMozAnimationStartTime(int64_t *aTime)
  5288   ErrorResult rv;
  5289   *aTime = GetMozAnimationStartTime(rv);
  5291   return rv.ErrorCode();
  5294 already_AddRefed<MediaQueryList>
  5295 nsGlobalWindow::MatchMedia(const nsAString& aMediaQueryList,
  5296                            ErrorResult& aError)
  5298   // FIXME: This whole forward-to-outer and then get a pres
  5299   // shell/context off the docshell dance is sort of silly; it'd make
  5300   // more sense to forward to the inner, but it's what everyone else
  5301   // (GetSelection, GetScrollXY, etc.) does around here.
  5302   FORWARD_TO_OUTER_OR_THROW(MatchMedia, (aMediaQueryList, aError), aError,
  5303                             nullptr);
  5305   // We need this now to ensure that we have a non-null |presContext|
  5306   // when we ought to.
  5307   // This is similar to EnsureSizeUpToDate, but only flushes frames.
  5308   nsGlobalWindow *parent = static_cast<nsGlobalWindow*>(GetPrivateParent());
  5309   if (parent) {
  5310     parent->FlushPendingNotifications(Flush_Frames);
  5313   if (!mDocShell) {
  5314     return nullptr;
  5317   nsRefPtr<nsPresContext> presContext;
  5318   mDocShell->GetPresContext(getter_AddRefs(presContext));
  5320   if (!presContext) {
  5321     return nullptr;
  5324   return presContext->MatchMedia(aMediaQueryList);
  5327 NS_IMETHODIMP
  5328 nsGlobalWindow::MatchMedia(const nsAString& aMediaQueryList,
  5329                            nsISupports** aResult)
  5331   ErrorResult rv;
  5332   nsRefPtr<MediaQueryList> mediaQueryList = MatchMedia(aMediaQueryList, rv);
  5333   mediaQueryList.forget(aResult);
  5335   return rv.ErrorCode();
  5338 void
  5339 nsGlobalWindow::SetScreenX(int32_t aScreenX, ErrorResult& aError)
  5341   FORWARD_TO_OUTER_OR_THROW(SetScreenX, (aScreenX, aError), aError, );
  5343   /*
  5344    * If caller is not chrome and the user has not explicitly exempted the site,
  5345    * prevent setting window.screenX by exiting early
  5346    */
  5348   if (!CanMoveResizeWindows() || IsFrame()) {
  5349     return;
  5352   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  5353   if (!treeOwnerAsWin) {
  5354     aError.Throw(NS_ERROR_FAILURE);
  5355     return;
  5358   int32_t x, y;
  5359   aError = treeOwnerAsWin->GetPosition(&x, &y);
  5360   if (aError.Failed()) {
  5361     return;
  5364   CheckSecurityLeftAndTop(&aScreenX, nullptr);
  5365   x = CSSToDevIntPixels(aScreenX);
  5367   aError = treeOwnerAsWin->SetPosition(x, y);
  5370 NS_IMETHODIMP
  5371 nsGlobalWindow::SetScreenX(int32_t aScreenX)
  5373   ErrorResult rv;
  5374   SetScreenX(aScreenX, rv);
  5376   return rv.ErrorCode();
  5379 int32_t
  5380 nsGlobalWindow::GetScreenY(ErrorResult& aError)
  5382   FORWARD_TO_OUTER_OR_THROW(GetScreenY, (aError), aError, 0);
  5384   return DevToCSSIntPixels(GetScreenXY(aError).y);
  5387 NS_IMETHODIMP
  5388 nsGlobalWindow::GetScreenY(int32_t* aScreenY)
  5390   ErrorResult rv;
  5391   *aScreenY = GetScreenY(rv);
  5393   return rv.ErrorCode();
  5396 void
  5397 nsGlobalWindow::SetScreenY(int32_t aScreenY, ErrorResult& aError)
  5399   FORWARD_TO_OUTER_OR_THROW(SetScreenY, (aScreenY, aError), aError, );
  5401   /*
  5402    * If caller is not chrome and the user has not explicitly exempted the site,
  5403    * prevent setting window.screenY by exiting early
  5404    */
  5406   if (!CanMoveResizeWindows() || IsFrame()) {
  5407     return;
  5410   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  5411   if (!treeOwnerAsWin) {
  5412     aError.Throw(NS_ERROR_FAILURE);
  5413     return;
  5416   int32_t x, y;
  5417   aError = treeOwnerAsWin->GetPosition(&x, &y);
  5418   if (aError.Failed()) {
  5419     return;
  5422   CheckSecurityLeftAndTop(nullptr, &aScreenY);
  5423   y = CSSToDevIntPixels(aScreenY);
  5425   aError = treeOwnerAsWin->SetPosition(x, y);
  5428 NS_IMETHODIMP
  5429 nsGlobalWindow::SetScreenY(int32_t aScreenY)
  5431   ErrorResult rv;
  5432   SetScreenY(aScreenY, rv);
  5434   return rv.ErrorCode();
  5437 bool
  5438 nsGlobalWindow::IsChrome() const
  5440   bool isChrome = false;
  5442   if (mDocShell) {
  5443     nsRefPtr<nsPresContext> presContext;
  5444     mDocShell->GetPresContext(getter_AddRefs(presContext));
  5445     isChrome = (presContext && presContext->IsChrome());
  5448   return isChrome;
  5451 // NOTE: Arguments to this function should have values scaled to
  5452 // CSS pixels, not device pixels.
  5453 void
  5454 nsGlobalWindow::CheckSecurityWidthAndHeight(int32_t* aWidth, int32_t* aHeight)
  5456   MOZ_ASSERT(IsOuterWindow());
  5458 #ifdef MOZ_XUL
  5459   if (!nsContentUtils::IsCallerChrome()) {
  5460     // if attempting to resize the window, hide any open popups
  5461     nsContentUtils::HidePopupsInDocument(mDoc);
  5463 #endif
  5465   // This one is easy. Just ensure the variable is greater than 100;
  5466   if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
  5467     // Check security state for use in determing window dimensions
  5469     if (!nsContentUtils::IsCallerChrome()) {
  5470       //sec check failed
  5471       if (aWidth && *aWidth < 100) {
  5472         *aWidth = 100;
  5474       if (aHeight && *aHeight < 100) {
  5475         *aHeight = 100;
  5481 // NOTE: Arguments to this function should have values in device pixels
  5482 nsresult
  5483 nsGlobalWindow::SetDocShellWidthAndHeight(int32_t aInnerWidth, int32_t aInnerHeight)
  5485   MOZ_ASSERT(IsOuterWindow());
  5487   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
  5489   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
  5490   mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
  5491   NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
  5493   NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(mDocShell, aInnerWidth, aInnerHeight),
  5494                     NS_ERROR_FAILURE);
  5496   return NS_OK;
  5499 // NOTE: Arguments to this function should have values in app units
  5500 void
  5501 nsGlobalWindow::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
  5503   MOZ_ASSERT(IsOuterWindow());
  5505   nsRefPtr<nsPresContext> presContext;
  5506   mDocShell->GetPresContext(getter_AddRefs(presContext));
  5508   nsRect shellArea = presContext->GetVisibleArea();
  5509   shellArea.height = aInnerHeight;
  5510   shellArea.width = aInnerWidth;
  5512   presContext->SetVisibleArea(shellArea);
  5515 // NOTE: Arguments to this function should have values scaled to
  5516 // CSS pixels, not device pixels.
  5517 void
  5518 nsGlobalWindow::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop)
  5520   MOZ_ASSERT(IsOuterWindow());
  5522   // This one is harder. We have to get the screen size and window dimensions.
  5524   // Check security state for use in determing window dimensions
  5526   if (!nsContentUtils::IsCallerChrome()) {
  5527 #ifdef MOZ_XUL
  5528     // if attempting to move the window, hide any open popups
  5529     nsContentUtils::HidePopupsInDocument(mDoc);
  5530 #endif
  5532     nsGlobalWindow* rootWindow =
  5533       static_cast<nsGlobalWindow*>(GetPrivateRoot());
  5534     if (rootWindow) {
  5535       rootWindow->FlushPendingNotifications(Flush_Layout);
  5538     nsCOMPtr<nsIBaseWindow> treeOwner = GetTreeOwnerWindow();
  5540     nsCOMPtr<nsIDOMScreen> screen;
  5541     GetScreen(getter_AddRefs(screen));
  5543     if (treeOwner && screen) {
  5544       int32_t screenLeft, screenTop, screenWidth, screenHeight;
  5545       int32_t winLeft, winTop, winWidth, winHeight;
  5547       // Get the window size
  5548       treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
  5550       // convert those values to CSS pixels
  5551       // XXX four separate retrievals of the prescontext
  5552       winLeft   = DevToCSSIntPixels(winLeft);
  5553       winTop    = DevToCSSIntPixels(winTop);
  5554       winWidth  = DevToCSSIntPixels(winWidth);
  5555       winHeight = DevToCSSIntPixels(winHeight);
  5557       // Get the screen dimensions
  5558       // XXX This should use nsIScreenManager once it's fully fleshed out.
  5559       screen->GetAvailLeft(&screenLeft);
  5560       screen->GetAvailWidth(&screenWidth);
  5561       screen->GetAvailHeight(&screenHeight);
  5562 #if defined(XP_MACOSX)
  5563       /* The mac's coordinate system is different from the assumed Windows'
  5564          system. It offsets by the height of the menubar so that a window
  5565          placed at (0,0) will be entirely visible. Unfortunately that
  5566          correction is made elsewhere (in Widget) and the meaning of
  5567          the Avail... coordinates is overloaded. Here we allow a window
  5568          to be placed at (0,0) because it does make sense to do so.
  5569       */
  5570       screen->GetTop(&screenTop);
  5571 #else
  5572       screen->GetAvailTop(&screenTop);
  5573 #endif
  5575       if (aLeft) {
  5576         if (screenLeft+screenWidth < *aLeft+winWidth)
  5577           *aLeft = screenLeft+screenWidth - winWidth;
  5578         if (screenLeft > *aLeft)
  5579           *aLeft = screenLeft;
  5581       if (aTop) {
  5582         if (screenTop+screenHeight < *aTop+winHeight)
  5583           *aTop = screenTop+screenHeight - winHeight;
  5584         if (screenTop > *aTop)
  5585           *aTop = screenTop;
  5587     } else {
  5588       if (aLeft)
  5589         *aLeft = 0;
  5590       if (aTop)
  5591         *aTop = 0;
  5596 NS_IMETHODIMP
  5597 nsGlobalWindow::GetPageXOffset(int32_t* aPageXOffset)
  5599   return GetScrollX(aPageXOffset);
  5602 NS_IMETHODIMP
  5603 nsGlobalWindow::GetPageYOffset(int32_t* aPageYOffset)
  5605   return GetScrollY(aPageYOffset);
  5608 void
  5609 nsGlobalWindow::GetScrollMaxXY(int32_t* aScrollMaxX, int32_t* aScrollMaxY,
  5610                                ErrorResult& aError)
  5612   FORWARD_TO_OUTER_OR_THROW(GetScrollMaxXY, (aScrollMaxX, aScrollMaxY, aError),
  5613                             aError, );
  5615   FlushPendingNotifications(Flush_Layout);
  5616   nsIScrollableFrame *sf = GetScrollFrame();
  5617   if (!sf) {
  5618     return;
  5621   nsRect scrollRange = sf->GetScrollRange();
  5623   if (aScrollMaxX) {
  5624     *aScrollMaxX = std::max(0,
  5625       (int32_t)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.XMost())));
  5627   if (aScrollMaxY) {
  5628     *aScrollMaxY = std::max(0,
  5629       (int32_t)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.YMost())));
  5633 int32_t
  5634 nsGlobalWindow::GetScrollMaxX(ErrorResult& aError)
  5636   int32_t scrollMaxX = 0;
  5637   GetScrollMaxXY(&scrollMaxX, nullptr, aError);
  5638   return scrollMaxX;
  5641 NS_IMETHODIMP
  5642 nsGlobalWindow::GetScrollMaxX(int32_t* aScrollMaxX)
  5644   NS_ENSURE_ARG_POINTER(aScrollMaxX);
  5645   ErrorResult rv;
  5646   *aScrollMaxX = GetScrollMaxX(rv);
  5648   return rv.ErrorCode();
  5651 int32_t
  5652 nsGlobalWindow::GetScrollMaxY(ErrorResult& aError)
  5654   int32_t scrollMaxY = 0;
  5655   GetScrollMaxXY(nullptr, &scrollMaxY, aError);
  5656   return scrollMaxY;
  5659 NS_IMETHODIMP
  5660 nsGlobalWindow::GetScrollMaxY(int32_t* aScrollMaxY)
  5662   NS_ENSURE_ARG_POINTER(aScrollMaxY);
  5663   ErrorResult rv;
  5664   *aScrollMaxY = GetScrollMaxY(rv);
  5666   return rv.ErrorCode();
  5669 CSSIntPoint
  5670 nsGlobalWindow::GetScrollXY(bool aDoFlush, ErrorResult& aError)
  5672   FORWARD_TO_OUTER_OR_THROW(GetScrollXY, (aDoFlush, aError), aError,
  5673                             CSSIntPoint(0, 0));
  5675   if (aDoFlush) {
  5676     FlushPendingNotifications(Flush_Layout);
  5677   } else {
  5678     EnsureSizeUpToDate();
  5681   nsIScrollableFrame *sf = GetScrollFrame();
  5682   if (!sf) {
  5683     return CSSIntPoint(0, 0);
  5686   nsPoint scrollPos = sf->GetScrollPosition();
  5687   if (scrollPos != nsPoint(0,0) && !aDoFlush) {
  5688     // Oh, well.  This is the expensive case -- the window is scrolled and we
  5689     // didn't actually flush yet.  Repeat, but with a flush, since the content
  5690     // may get shorter and hence our scroll position may decrease.
  5691     return GetScrollXY(true, aError);
  5694   return sf->GetScrollPositionCSSPixels();
  5697 int32_t
  5698 nsGlobalWindow::GetScrollX(ErrorResult& aError)
  5700   return GetScrollXY(false, aError).x;
  5703 NS_IMETHODIMP
  5704 nsGlobalWindow::GetScrollX(int32_t* aScrollX)
  5706   NS_ENSURE_ARG_POINTER(aScrollX);
  5707   ErrorResult rv;
  5708   *aScrollX = GetScrollXY(false, rv).x;
  5709   return rv.ErrorCode();
  5712 int32_t
  5713 nsGlobalWindow::GetScrollY(ErrorResult& aError)
  5715   return GetScrollXY(false, aError).y;
  5718 NS_IMETHODIMP
  5719 nsGlobalWindow::GetScrollY(int32_t* aScrollY)
  5721   NS_ENSURE_ARG_POINTER(aScrollY);
  5722   ErrorResult rv;
  5723   *aScrollY = GetScrollXY(false, rv).y;
  5724   return rv.ErrorCode();
  5727 uint32_t
  5728 nsGlobalWindow::Length()
  5730   FORWARD_TO_OUTER(Length, (), 0);
  5732   nsDOMWindowList* windows = GetWindowList();
  5734   return windows ? windows->GetLength() : 0;
  5737 NS_IMETHODIMP
  5738 nsGlobalWindow::GetLength(uint32_t* aLength)
  5740   *aLength = Length();
  5741   return NS_OK;
  5744 already_AddRefed<nsIDOMWindow>
  5745 nsGlobalWindow::GetChildWindow(const nsAString& aName)
  5747   nsCOMPtr<nsIDocShell> docShell(GetDocShell());
  5748   NS_ENSURE_TRUE(docShell, nullptr);
  5750   nsCOMPtr<nsIDocShellTreeItem> child;
  5751   docShell->FindChildWithName(PromiseFlatString(aName).get(),
  5752                               false, true, nullptr, nullptr,
  5753                               getter_AddRefs(child));
  5755   nsCOMPtr<nsIDOMWindow> child_win(do_GetInterface(child));
  5756   return child_win.forget();
  5759 bool
  5760 nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
  5762   bool defaultActionEnabled = true;
  5763   nsContentUtils::DispatchTrustedEvent(mDoc,
  5764                                        GetOuterWindow(),
  5765                                        NS_ConvertASCIItoUTF16(aEventName),
  5766                                        true, true, &defaultActionEnabled);
  5768   return defaultActionEnabled;
  5771 // NOTE: Arguments to this function should be CSS pixels, not device pixels.
  5772 bool
  5773 nsGlobalWindow::DispatchResizeEvent(const nsIntSize& aSize)
  5775   ErrorResult res;
  5776   nsRefPtr<Event> domEvent =
  5777     mDoc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), res);
  5778   if (res.Failed()) {
  5779     return false;
  5782   AutoSafeJSContext cx;
  5783   JSAutoCompartment ac(cx, GetWrapperPreserveColor());
  5784   DOMWindowResizeEventDetail detail;
  5785   detail.mWidth = aSize.width;
  5786   detail.mHeight = aSize.height;
  5787   JS::Rooted<JS::Value> detailValue(cx);
  5788   if (!detail.ToObject(cx, &detailValue)) {
  5789     return false;
  5792   CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
  5793   customEvent->InitCustomEvent(cx,
  5794                                NS_LITERAL_STRING("DOMWindowResize"),
  5795                                /* bubbles = */ true,
  5796                                /* cancelable = */ true,
  5797                                detailValue,
  5798                                res);
  5799   if (res.Failed()) {
  5800     return false;
  5803   domEvent->SetTrusted(true);
  5804   domEvent->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
  5806   nsCOMPtr<EventTarget> target = do_QueryInterface(GetOuterWindow());
  5807   domEvent->SetTarget(target);
  5809   bool defaultActionEnabled = true;
  5810   target->DispatchEvent(domEvent, &defaultActionEnabled);
  5812   return defaultActionEnabled;
  5815 void
  5816 nsGlobalWindow::RefreshCompartmentPrincipal()
  5818   FORWARD_TO_INNER(RefreshCompartmentPrincipal, (), /* void */ );
  5820   JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),
  5821                               nsJSPrincipals::get(mDoc->NodePrincipal()));
  5824 static already_AddRefed<nsIDocShellTreeItem>
  5825 GetCallerDocShellTreeItem()
  5827   JSContext *cx = nsContentUtils::GetCurrentJSContext();
  5828   nsCOMPtr<nsIDocShellTreeItem> callerItem;
  5830   if (cx) {
  5831     nsCOMPtr<nsIWebNavigation> callerWebNav =
  5832       do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
  5834     callerItem = do_QueryInterface(callerWebNav);
  5837   return callerItem.forget();
  5840 bool
  5841 nsGlobalWindow::WindowExists(const nsAString& aName,
  5842                              bool aLookForCallerOnJSStack)
  5844   NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
  5845   NS_PRECONDITION(mDocShell, "Must have docshell");
  5847   nsCOMPtr<nsIDocShellTreeItem> caller;
  5848   if (aLookForCallerOnJSStack) {
  5849     caller = GetCallerDocShellTreeItem();
  5852   if (!caller) {
  5853     caller = mDocShell;
  5856   nsCOMPtr<nsIDocShellTreeItem> namedItem;
  5857   mDocShell->FindItemWithName(PromiseFlatString(aName).get(), nullptr, caller,
  5858                               getter_AddRefs(namedItem));
  5859   return namedItem != nullptr;
  5862 already_AddRefed<nsIWidget>
  5863 nsGlobalWindow::GetMainWidget()
  5865   FORWARD_TO_OUTER(GetMainWidget, (), nullptr);
  5867   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  5869   nsCOMPtr<nsIWidget> widget;
  5871   if (treeOwnerAsWin) {
  5872     treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
  5875   return widget.forget();
  5878 nsIWidget*
  5879 nsGlobalWindow::GetNearestWidget()
  5881   nsIDocShell* docShell = GetDocShell();
  5882   NS_ENSURE_TRUE(docShell, nullptr);
  5883   nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
  5884   NS_ENSURE_TRUE(presShell, nullptr);
  5885   nsIFrame* rootFrame = presShell->GetRootFrame();
  5886   NS_ENSURE_TRUE(rootFrame, nullptr);
  5887   return rootFrame->GetView()->GetNearestWidget(nullptr);
  5890 void
  5891 nsGlobalWindow::SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError)
  5893   aError = SetFullScreenInternal(aFullScreen, true);
  5896 NS_IMETHODIMP
  5897 nsGlobalWindow::SetFullScreen(bool aFullScreen)
  5899   return SetFullScreenInternal(aFullScreen, true);
  5902 nsresult
  5903 nsGlobalWindow::SetFullScreenInternal(bool aFullScreen, bool aRequireTrust)
  5905   FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
  5907   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
  5909   bool rootWinFullScreen;
  5910   GetFullScreen(&rootWinFullScreen);
  5911   // Only chrome can change our fullScreen mode, unless we're running in
  5912   // untrusted mode.
  5913   if (aFullScreen == rootWinFullScreen ||
  5914       (aRequireTrust && !nsContentUtils::IsCallerChrome())) {
  5915     return NS_OK;
  5918   // SetFullScreen needs to be called on the root window, so get that
  5919   // via the DocShell tree, and if we are not already the root,
  5920   // call SetFullScreen on that window instead.
  5921   nsCOMPtr<nsIDocShellTreeItem> rootItem;
  5922   mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
  5923   nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(rootItem);
  5924   if (!window)
  5925     return NS_ERROR_FAILURE;
  5926   if (rootItem != mDocShell)
  5927     return window->SetFullScreenInternal(aFullScreen, aRequireTrust);
  5929   // make sure we don't try to set full screen on a non-chrome window,
  5930   // which might happen in embedding world
  5931   if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
  5932     return NS_ERROR_FAILURE;
  5934   // If we are already in full screen mode, just return.
  5935   if (mFullScreen == aFullScreen)
  5936     return NS_OK;
  5938   // dispatch a "fullscreen" DOM event so that XUL apps can
  5939   // respond visually if we are kicked into full screen mode
  5940   if (!DispatchCustomEvent("fullscreen")) {
  5941     return NS_OK;
  5944   // Prevent chrome documents which are still loading from resizing
  5945   // the window after we set fullscreen mode.
  5946   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  5947   nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
  5948   if (aFullScreen && xulWin) {
  5949     xulWin->SetIntrinsicallySized(false);
  5952   // Set this before so if widget sends an event indicating its
  5953   // gone full screen, the state trap above works.
  5954   mFullScreen = aFullScreen;
  5956   // Sometimes we don't want the top-level widget to actually go fullscreen,
  5957   // for example in the B2G desktop client, we don't want the emulated screen
  5958   // dimensions to appear to increase when entering fullscreen mode; we just
  5959   // want the content to fill the entire client area of the emulator window.
  5960   if (!Preferences::GetBool("full-screen-api.ignore-widgets", false)) {
  5961     nsCOMPtr<nsIWidget> widget = GetMainWidget();
  5962     if (widget)
  5963       widget->MakeFullScreen(aFullScreen);
  5966   if (!mFullScreen) {
  5967     // Force exit from DOM full-screen mode. This is so that if we're in
  5968     // DOM full-screen mode and the user exits full-screen mode with
  5969     // the browser full-screen mode toggle keyboard-shortcut, we'll detect
  5970     // that and leave DOM API full-screen mode too.
  5971     nsIDocument::ExitFullscreen(mDoc, /* async */ false);
  5974   if (!mWakeLock && mFullScreen) {
  5975     nsRefPtr<power::PowerManagerService> pmService =
  5976       power::PowerManagerService::GetInstance();
  5977     NS_ENSURE_TRUE(pmService, NS_OK);
  5979     ErrorResult rv;
  5980     mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"),
  5981                                        this, rv);
  5982     if (rv.Failed()) {
  5983       return rv.ErrorCode();
  5986   } else if (mWakeLock && !mFullScreen) {
  5987     ErrorResult rv;
  5988     mWakeLock->Unlock(rv);
  5989     NS_WARN_IF_FALSE(!rv.Failed(), "Failed to unlock the wakelock.");
  5990     mWakeLock = nullptr;
  5993   return NS_OK;
  5996 bool
  5997 nsGlobalWindow::GetFullScreen(ErrorResult& aError)
  5999   FORWARD_TO_OUTER_OR_THROW(GetFullScreen, (aError), aError, false);
  6001   // Get the fullscreen value of the root window, to always have the value
  6002   // accurate, even when called from content.
  6003   if (mDocShell) {
  6004     nsCOMPtr<nsIDocShellTreeItem> rootItem;
  6005     mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
  6006     if (rootItem != mDocShell) {
  6007       nsCOMPtr<nsIDOMWindow> window = do_GetInterface(rootItem);
  6008       if (window) {
  6009         bool fullScreen = false;
  6010         aError = window->GetFullScreen(&fullScreen);
  6011         return fullScreen;
  6016   // We are the root window, or something went wrong. Return our internal value.
  6017   return mFullScreen;
  6020 NS_IMETHODIMP
  6021 nsGlobalWindow::GetFullScreen(bool* aFullScreen)
  6023   ErrorResult rv;
  6024   *aFullScreen = GetFullScreen(rv);
  6026   return rv.ErrorCode();
  6029 NS_IMETHODIMP
  6030 nsGlobalWindow::Dump(const nsAString& aStr)
  6032   if (!nsContentUtils::DOMWindowDumpEnabled()) {
  6033     return NS_OK;
  6036   char *cstr = ToNewUTF8String(aStr);
  6038 #if defined(XP_MACOSX)
  6039   // have to convert \r to \n so that printing to the console works
  6040   char *c = cstr, *cEnd = cstr + strlen(cstr);
  6041   while (c < cEnd) {
  6042     if (*c == '\r')
  6043       *c = '\n';
  6044     c++;
  6046 #endif
  6048   if (cstr) {
  6049 #ifdef XP_WIN
  6050     PrintToDebugger(cstr);
  6051 #endif
  6052 #ifdef ANDROID
  6053     __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
  6054 #endif
  6055     FILE *fp = gDumpFile ? gDumpFile : stdout;
  6056     fputs(cstr, fp);
  6057     fflush(fp);
  6058     nsMemory::Free(cstr);
  6061   return NS_OK;
  6064 void
  6065 nsGlobalWindow::EnsureReflowFlushAndPaint()
  6067   MOZ_ASSERT(IsOuterWindow());
  6068   NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
  6069                "docshell!");
  6071   if (!mDocShell)
  6072     return;
  6074   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  6076   if (!presShell)
  6077     return;
  6079   // Flush pending reflows.
  6080   if (mDoc) {
  6081     mDoc->FlushPendingNotifications(Flush_Layout);
  6084   // Unsuppress painting.
  6085   presShell->UnsuppressPainting();
  6088 NS_IMETHODIMP
  6089 nsGlobalWindow::GetTextZoom(float *aZoom)
  6091   FORWARD_TO_OUTER(GetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
  6093   if (mDocShell) {
  6094     nsCOMPtr<nsIContentViewer> contentViewer;
  6095     mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
  6096     nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
  6098     if (markupViewer) {
  6099       return markupViewer->GetTextZoom(aZoom);
  6102   return NS_ERROR_FAILURE;
  6105 NS_IMETHODIMP
  6106 nsGlobalWindow::SetTextZoom(float aZoom)
  6108   FORWARD_TO_OUTER(SetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
  6110   if (mDocShell) {
  6111     nsCOMPtr<nsIContentViewer> contentViewer;
  6112     mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
  6113     nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
  6115     if (markupViewer)
  6116       return markupViewer->SetTextZoom(aZoom);
  6118   return NS_ERROR_FAILURE;
  6121 // static
  6122 void
  6123 nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
  6125   aOutTitle.Truncate();
  6127   // Try to get a host from the running principal -- this will do the
  6128   // right thing for javascript: and data: documents.
  6130   nsresult rv = NS_OK;
  6131   NS_ASSERTION(nsContentUtils::GetSecurityManager(),
  6132     "Global Window has no security manager!");
  6133   if (nsContentUtils::GetSecurityManager()) {
  6134     nsCOMPtr<nsIPrincipal> principal;
  6135     rv = nsContentUtils::GetSecurityManager()->
  6136       GetSubjectPrincipal(getter_AddRefs(principal));
  6138     if (NS_SUCCEEDED(rv) && principal) {
  6139       nsCOMPtr<nsIURI> uri;
  6140       rv = principal->GetURI(getter_AddRefs(uri));
  6142       if (NS_SUCCEEDED(rv) && uri) {
  6143         // remove user:pass for privacy and spoof prevention
  6145         nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
  6146         if (fixup) {
  6147           nsCOMPtr<nsIURI> fixedURI;
  6148           rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
  6149           if (NS_SUCCEEDED(rv) && fixedURI) {
  6150             nsAutoCString host;
  6151             fixedURI->GetHost(host);
  6153             if (!host.IsEmpty()) {
  6154               // if this URI has a host we'll show it. For other
  6155               // schemes (e.g. file:) we fall back to the localized
  6156               // generic string
  6158               nsAutoCString prepath;
  6159               fixedURI->GetPrePath(prepath);
  6161               NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
  6162               const char16_t *formatStrings[] = { ucsPrePath.get() };
  6163               nsXPIDLString tempString;
  6164               nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  6165                                                     "ScriptDlgHeading",
  6166                                                     formatStrings,
  6167                                                     tempString);
  6168               aOutTitle = tempString;
  6174     else { // failed to get subject principal
  6175       NS_WARNING("No script principal? Who is calling alert/confirm/prompt?!");
  6179   if (aOutTitle.IsEmpty()) {
  6180     // We didn't find a host so use the generic heading
  6181     nsXPIDLString tempString;
  6182     nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  6183                                        "ScriptDlgGenericHeading",
  6184                                        tempString);
  6185     aOutTitle = tempString;
  6188   // Just in case
  6189   if (aOutTitle.IsEmpty()) {
  6190     NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
  6191     aOutTitle.AssignLiteral("[Script]");
  6195 bool
  6196 nsGlobalWindow::CanMoveResizeWindows()
  6198   MOZ_ASSERT(IsOuterWindow());
  6200   // When called from chrome, we can avoid the following checks.
  6201   if (!nsContentUtils::IsCallerChrome()) {
  6202     // Don't allow scripts to move or resize windows that were not opened by a
  6203     // script.
  6204     if (!mHadOriginalOpener) {
  6205       return false;
  6208     if (!CanSetProperty("dom.disable_window_move_resize")) {
  6209       return false;
  6212     // Ignore the request if we have more than one tab in the window.
  6213     nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  6214     if (treeOwner) {
  6215       uint32_t itemCount;
  6216       if (NS_SUCCEEDED(treeOwner->GetTargetableShellCount(&itemCount)) &&
  6217           itemCount > 1) {
  6218         return false;
  6223   // The preference is useful for the webapp runtime. Webapps should be able
  6224   // to resize or move their window.
  6225   if (mDocShell && !Preferences::GetBool("dom.always_allow_move_resize_window",
  6226                                          false)) {
  6227     bool allow;
  6228     nsresult rv = mDocShell->GetAllowWindowControl(&allow);
  6229     if (NS_SUCCEEDED(rv) && !allow)
  6230       return false;
  6233   if (gMouseDown && !gDragServiceDisabled) {
  6234     nsCOMPtr<nsIDragService> ds =
  6235       do_GetService("@mozilla.org/widget/dragservice;1");
  6236     if (ds) {
  6237       gDragServiceDisabled = true;
  6238       ds->Suppress();
  6241   return true;
  6244 bool
  6245 nsGlobalWindow::AlertOrConfirm(bool aAlert,
  6246                                const nsAString& aMessage,
  6247                                mozilla::ErrorResult& aError)
  6249   // XXX This method is very similar to nsGlobalWindow::Prompt, make
  6250   // sure any modifications here don't need to happen over there!
  6251   MOZ_ASSERT(IsOuterWindow());
  6253   if (!AreDialogsEnabled()) {
  6254     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  6255     return false;
  6258   // Reset popup state while opening a modal dialog, and firing events
  6259   // about the dialog, to prevent the current state from being active
  6260   // the whole time a modal dialog is open.
  6261   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  6263   // Before bringing up the window, unsuppress painting and flush
  6264   // pending reflows.
  6265   EnsureReflowFlushAndPaint();
  6267   nsAutoString title;
  6268   MakeScriptDialogTitle(title);
  6270   // Remove non-terminating null characters from the 
  6271   // string. See bug #310037. 
  6272   nsAutoString final;
  6273   nsContentUtils::StripNullChars(aMessage, final);
  6275   nsresult rv;
  6276   nsCOMPtr<nsIPromptFactory> promptFac =
  6277     do_GetService("@mozilla.org/prompter;1", &rv);
  6278   if (NS_FAILED(rv)) {
  6279     aError.Throw(rv);
  6280     return false;
  6283   nsCOMPtr<nsIPrompt> prompt;
  6284   aError = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
  6285                                 getter_AddRefs(prompt));
  6286   if (aError.Failed()) {
  6287     return false;
  6290   // Always allow tab modal prompts for alert and confirm.
  6291   if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
  6292     promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
  6295   bool result = false;
  6296   nsAutoSyncOperation sync(mDoc);
  6297   if (ShouldPromptToBlockDialogs()) {
  6298     bool disallowDialog = false;
  6299     nsXPIDLString label;
  6300     nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  6301                                        "ScriptDialogLabel", label);
  6303     aError = aAlert ?
  6304                prompt->AlertCheck(title.get(), final.get(), label.get(),
  6305                                   &disallowDialog) :
  6306                prompt->ConfirmCheck(title.get(), final.get(), label.get(),
  6307                                     &disallowDialog, &result);
  6309     if (disallowDialog)
  6310       DisableDialogs();
  6311   } else {
  6312     aError = aAlert ?
  6313                prompt->Alert(title.get(), final.get()) :
  6314                prompt->Confirm(title.get(), final.get(), &result);
  6317   return result;
  6320 void
  6321 nsGlobalWindow::Alert(const nsAString& aMessage, mozilla::ErrorResult& aError)
  6323   FORWARD_TO_OUTER_OR_THROW(Alert, (aMessage, aError), aError, );
  6324   AlertOrConfirm(/* aAlert = */ true, aMessage, aError);
  6327 NS_IMETHODIMP
  6328 nsGlobalWindow::Alert(const nsAString& aString)
  6330   ErrorResult rv;
  6331   Alert(aString, rv);
  6333   return rv.ErrorCode();
  6336 bool
  6337 nsGlobalWindow::Confirm(const nsAString& aMessage, ErrorResult& aError)
  6339   FORWARD_TO_OUTER_OR_THROW(Confirm, (aMessage, aError), aError, false);
  6341   return AlertOrConfirm(/* aAlert = */ false, aMessage, aError);
  6344 NS_IMETHODIMP
  6345 nsGlobalWindow::Confirm(const nsAString& aString, bool* aReturn)
  6347   ErrorResult rv;
  6348   *aReturn = Confirm(aString, rv);
  6350   return rv.ErrorCode();
  6353 void
  6354 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
  6355                        nsAString& aReturn, ErrorResult& aError)
  6357   // XXX This method is very similar to nsGlobalWindow::AlertOrConfirm, make
  6358   // sure any modifications here don't need to happen over there!
  6359   FORWARD_TO_OUTER_OR_THROW(Prompt, (aMessage, aInitial, aReturn, aError),
  6360                             aError, );
  6362   SetDOMStringToNull(aReturn);
  6364   if (!AreDialogsEnabled()) {
  6365     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  6366     return;
  6369   // Reset popup state while opening a modal dialog, and firing events
  6370   // about the dialog, to prevent the current state from being active
  6371   // the whole time a modal dialog is open.
  6372   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  6374   // Before bringing up the window, unsuppress painting and flush
  6375   // pending reflows.
  6376   EnsureReflowFlushAndPaint();
  6378   nsAutoString title;
  6379   MakeScriptDialogTitle(title);
  6381   // Remove non-terminating null characters from the 
  6382   // string. See bug #310037. 
  6383   nsAutoString fixedMessage, fixedInitial;
  6384   nsContentUtils::StripNullChars(aMessage, fixedMessage);
  6385   nsContentUtils::StripNullChars(aInitial, fixedInitial);
  6387   nsresult rv;
  6388   nsCOMPtr<nsIPromptFactory> promptFac =
  6389     do_GetService("@mozilla.org/prompter;1", &rv);
  6390   if (NS_FAILED(rv)) {
  6391     aError.Throw(rv);
  6392     return;
  6395   nsCOMPtr<nsIPrompt> prompt;
  6396   aError = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
  6397                                 getter_AddRefs(prompt));
  6398   if (aError.Failed()) {
  6399     return;
  6402   // Always allow tab modal prompts for prompt.
  6403   if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
  6404     promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
  6407   // Pass in the default value, if any.
  6408   char16_t *inoutValue = ToNewUnicode(fixedInitial);
  6409   bool disallowDialog = false;
  6411   nsXPIDLString label;
  6412   if (ShouldPromptToBlockDialogs()) {
  6413     nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  6414                                        "ScriptDialogLabel", label);
  6417   nsAutoSyncOperation sync(mDoc);
  6418   bool ok;
  6419   aError = prompt->Prompt(title.get(), fixedMessage.get(),
  6420                           &inoutValue, label.get(), &disallowDialog, &ok);
  6422   if (disallowDialog) {
  6423     DisableDialogs();
  6426   if (aError.Failed()) {
  6427     return;
  6430   nsAdoptingString outValue(inoutValue);
  6432   if (ok && outValue) {
  6433     aReturn.Assign(outValue);
  6437 NS_IMETHODIMP
  6438 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
  6439                        nsAString& aReturn)
  6441   ErrorResult rv;
  6442   Prompt(aMessage, aInitial, aReturn, rv);
  6444   return rv.ErrorCode();
  6447 void
  6448 nsGlobalWindow::Focus(ErrorResult& aError)
  6450   FORWARD_TO_OUTER_OR_THROW(Focus, (aError), aError, );
  6452   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  6453   if (!fm) {
  6454     return;
  6457   nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
  6459   bool isVisible = false;
  6460   if (baseWin) {
  6461     baseWin->GetVisibility(&isVisible);
  6464   if (!isVisible) {
  6465     // A hidden tab is being focused, ignore this call.
  6466     return;
  6469   nsIDOMWindow *caller = nsContentUtils::GetWindowFromCaller();
  6470   nsCOMPtr<nsIDOMWindow> opener;
  6471   GetOpener(getter_AddRefs(opener));
  6473   // Enforce dom.disable_window_flip (for non-chrome), but still allow the
  6474   // window which opened us to raise us at times when popups are allowed
  6475   // (bugs 355482 and 369306).
  6476   bool canFocus = CanSetProperty("dom.disable_window_flip") ||
  6477                     (opener == caller &&
  6478                      RevisePopupAbuseLevel(gPopupControlState) < openAbused);
  6480   nsCOMPtr<nsIDOMWindow> activeWindow;
  6481   fm->GetActiveWindow(getter_AddRefs(activeWindow));
  6483   nsCOMPtr<nsIDocShellTreeItem> rootItem;
  6484   mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
  6485   nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
  6486   bool isActive = (rootWin == activeWindow);
  6488   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  6489   if (treeOwnerAsWin && (canFocus || isActive)) {
  6490     bool isEnabled = true;
  6491     if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
  6492       NS_WARNING( "Should not try to set the focus on a disabled window" );
  6493       return;
  6496     // XXXndeakin not sure what this is for or if it should go somewhere else
  6497     nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
  6498     if (embeddingWin)
  6499       embeddingWin->SetFocus();
  6502   if (!mDocShell) {
  6503     return;
  6506   nsCOMPtr<nsIPresShell> presShell;
  6507   // Don't look for a presshell if we're a root chrome window that's got
  6508   // about:blank loaded.  We don't want to focus our widget in that case.
  6509   // XXXbz should we really be checking for IsInitialDocument() instead?
  6510   bool lookForPresShell = true;
  6511   if (mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome &&
  6512       GetPrivateRoot() == static_cast<nsIDOMWindow*>(this) &&
  6513       mDoc) {
  6514     nsIURI* ourURI = mDoc->GetDocumentURI();
  6515     if (ourURI) {
  6516       lookForPresShell = !NS_IsAboutBlank(ourURI);
  6520   if (lookForPresShell) {
  6521     mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
  6524   nsCOMPtr<nsIDocShellTreeItem> parentDsti;
  6525   mDocShell->GetParent(getter_AddRefs(parentDsti));
  6527   // set the parent's current focus to the frame containing this window.
  6528   nsCOMPtr<nsPIDOMWindow> parent = do_GetInterface(parentDsti);
  6529   if (parent) {
  6530     nsCOMPtr<nsIDocument> parentdoc = parent->GetDoc();
  6531     if (!parentdoc) {
  6532       return;
  6535     nsIContent* frame = parentdoc->FindContentForSubDocument(mDoc);
  6536     nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
  6537     if (frameElement) {
  6538       uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
  6539       if (canFocus)
  6540         flags |= nsIFocusManager::FLAG_RAISE;
  6541       aError = fm->SetFocus(frameElement, flags);
  6543     return;
  6545   if (nsCOMPtr<nsITabChild> child = do_GetInterface(mDocShell)) {
  6546     child->SendRequestFocus(canFocus);
  6547     return;
  6549   if (canFocus) {
  6550     // if there is no parent, this must be a toplevel window, so raise the
  6551     // window if canFocus is true
  6552     aError = fm->SetActiveWindow(this);
  6556 NS_IMETHODIMP
  6557 nsGlobalWindow::Focus()
  6559   ErrorResult rv;
  6560   Focus(rv);
  6562   return rv.ErrorCode();
  6565 void
  6566 nsGlobalWindow::Blur(ErrorResult& aError)
  6568   FORWARD_TO_OUTER_OR_THROW(Blur, (aError), aError, );
  6570   // If dom.disable_window_flip == true, then content should not be allowed
  6571   // to call this function (this would allow popunders, bug 369306)
  6572   if (!CanSetProperty("dom.disable_window_flip")) {
  6573     return;
  6576   // If embedding apps don't implement nsIEmbeddingSiteWindow, we
  6577   // shouldn't throw exceptions to web content.
  6579   nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  6580   nsCOMPtr<nsIEmbeddingSiteWindow> siteWindow(do_GetInterface(treeOwner));
  6581   if (siteWindow) {
  6582     // This method call may cause mDocShell to become nullptr.
  6583     siteWindow->Blur();
  6585     // if the root is focused, clear the focus
  6586     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  6587     if (fm && mDoc) {
  6588       nsCOMPtr<nsIDOMElement> element;
  6589       fm->GetFocusedElementForWindow(this, false, nullptr, getter_AddRefs(element));
  6590       nsCOMPtr<nsIContent> content = do_QueryInterface(element);
  6591       if (content == mDoc->GetRootElement())
  6592         fm->ClearFocus(this);
  6597 NS_IMETHODIMP
  6598 nsGlobalWindow::Blur()
  6600   ErrorResult rv;
  6601   Blur(rv);
  6603   return rv.ErrorCode();
  6606 void
  6607 nsGlobalWindow::Back(ErrorResult& aError)
  6609   FORWARD_TO_OUTER_OR_THROW(Back, (aError), aError, );
  6611   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  6612   if (!webNav) {
  6613     aError.Throw(NS_ERROR_FAILURE);
  6614     return;
  6617   aError = webNav->GoBack();
  6620 NS_IMETHODIMP
  6621 nsGlobalWindow::Back()
  6623   ErrorResult rv;
  6624   Back(rv);
  6626   return rv.ErrorCode();
  6629 void
  6630 nsGlobalWindow::Forward(ErrorResult& aError)
  6632   FORWARD_TO_OUTER_OR_THROW(Forward, (aError), aError, );
  6634   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  6635   if (!webNav) {
  6636     aError.Throw(NS_ERROR_FAILURE);
  6637     return;
  6640   aError = webNav->GoForward();
  6643 NS_IMETHODIMP
  6644 nsGlobalWindow::Forward()
  6646   ErrorResult rv;
  6647   Forward(rv);
  6649   return rv.ErrorCode();
  6652 void
  6653 nsGlobalWindow::Home(ErrorResult& aError)
  6655   FORWARD_TO_OUTER_OR_THROW(Home, (aError), aError, );
  6657   if (!mDocShell) {
  6658     return;
  6661   nsAdoptingString homeURL =
  6662     Preferences::GetLocalizedString(PREF_BROWSER_STARTUP_HOMEPAGE);
  6664   if (homeURL.IsEmpty()) {
  6665     // if all else fails, use this
  6666 #ifdef DEBUG_seth
  6667     printf("all else failed.  using %s as the home page\n", DEFAULT_HOME_PAGE);
  6668 #endif
  6669     CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
  6672 #ifdef MOZ_PHOENIX
  6674     // Firefox lets the user specify multiple home pages to open in
  6675     // individual tabs by separating them with '|'. Since we don't
  6676     // have the machinery in place to easily open new tabs from here,
  6677     // simply truncate the homeURL at the first '|' character to
  6678     // prevent any possibilities of leaking the users list of home
  6679     // pages to the first home page.
  6680     //
  6681     // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
  6682     // fixed we can revisit this.
  6683     int32_t firstPipe = homeURL.FindChar('|');
  6685     if (firstPipe > 0) {
  6686       homeURL.Truncate(firstPipe);
  6689 #endif
  6691   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  6692   if (!webNav) {
  6693     aError.Throw(NS_ERROR_FAILURE);
  6694     return;
  6697   aError = webNav->LoadURI(homeURL.get(),
  6698                            nsIWebNavigation::LOAD_FLAGS_NONE,
  6699                            nullptr,
  6700                            nullptr,
  6701                            nullptr);
  6704 NS_IMETHODIMP
  6705 nsGlobalWindow::Home()
  6707   ErrorResult rv;
  6708   Home(rv);
  6710   return rv.ErrorCode();
  6713 void
  6714 nsGlobalWindow::Stop(ErrorResult& aError)
  6716   FORWARD_TO_OUTER_OR_THROW(Stop, (aError), aError, );
  6718   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  6719   if (webNav) {
  6720     aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
  6724 NS_IMETHODIMP
  6725 nsGlobalWindow::Stop()
  6727   ErrorResult rv;
  6728   Stop(rv);
  6730   return rv.ErrorCode();
  6733 void
  6734 nsGlobalWindow::Print(ErrorResult& aError)
  6736 #ifdef NS_PRINTING
  6737   FORWARD_TO_OUTER_OR_THROW(Print, (aError), aError, );
  6739   if (Preferences::GetBool("dom.disable_window_print", false)) {
  6740     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  6741     return;
  6744   if (!AreDialogsEnabled()) {
  6745     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  6746     return;
  6749   if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
  6750     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  6751     return;
  6754   nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
  6755   if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
  6756                                 getter_AddRefs(webBrowserPrint)))) {
  6757     nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
  6758                                GetCurrentInnerWindowInternal()->mDoc :
  6759                                nullptr);
  6761     nsCOMPtr<nsIPrintSettingsService> printSettingsService = 
  6762       do_GetService("@mozilla.org/gfx/printsettings-service;1");
  6764     nsCOMPtr<nsIPrintSettings> printSettings;
  6765     if (printSettingsService) {
  6766       bool printSettingsAreGlobal =
  6767         Preferences::GetBool("print.use_global_printsettings", false);
  6769       if (printSettingsAreGlobal) {
  6770         printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
  6772         nsXPIDLString printerName;
  6773         printSettings->GetPrinterName(getter_Copies(printerName));
  6774         if (printerName.IsEmpty()) {
  6775           printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
  6776           printSettings->SetPrinterName(printerName);
  6778         printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
  6779         printSettingsService->InitPrintSettingsFromPrefs(printSettings, 
  6780                                                          true, 
  6781                                                          nsIPrintSettings::kInitSaveAll);
  6782       } else {
  6783         printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
  6786       EnterModalState();
  6787       webBrowserPrint->Print(printSettings, nullptr);
  6788       LeaveModalState();
  6790       bool savePrintSettings =
  6791         Preferences::GetBool("print.save_print_settings", false);
  6792       if (printSettingsAreGlobal && savePrintSettings) {
  6793         printSettingsService->
  6794           SavePrintSettingsToPrefs(printSettings,
  6795                                    true,
  6796                                    nsIPrintSettings::kInitSaveAll);
  6797         printSettingsService->
  6798           SavePrintSettingsToPrefs(printSettings,
  6799                                    false,
  6800                                    nsIPrintSettings::kInitSavePrinterName);
  6802     } else {
  6803       webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
  6804       webBrowserPrint->Print(printSettings, nullptr);
  6807 #endif //NS_PRINTING
  6810 NS_IMETHODIMP
  6811 nsGlobalWindow::Print()
  6813   ErrorResult rv;
  6814   Print(rv);
  6816   return rv.ErrorCode();
  6819 void
  6820 nsGlobalWindow::MoveTo(int32_t aXPos, int32_t aYPos, ErrorResult& aError)
  6822   FORWARD_TO_OUTER_OR_THROW(MoveTo, (aXPos, aYPos, aError), aError, );
  6824   /*
  6825    * If caller is not chrome and the user has not explicitly exempted the site,
  6826    * prevent window.moveTo() by exiting early
  6827    */
  6829   if (!CanMoveResizeWindows() || IsFrame()) {
  6830     return;
  6833   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  6834   if (!treeOwnerAsWin) {
  6835     aError.Throw(NS_ERROR_FAILURE);
  6836     return;
  6839   // Mild abuse of a "size" object so we don't need more helper functions.
  6840   nsIntSize cssPos(aXPos, aYPos);
  6841   CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height);
  6843   nsIntSize devPos = CSSToDevIntPixels(cssPos);
  6845   aError = treeOwnerAsWin->SetPosition(devPos.width, devPos.height);
  6848 NS_IMETHODIMP
  6849 nsGlobalWindow::MoveTo(int32_t aXPos, int32_t aYPos)
  6851   ErrorResult rv;
  6852   MoveTo(aXPos, aYPos, rv);
  6854   return rv.ErrorCode();
  6857 void
  6858 nsGlobalWindow::MoveBy(int32_t aXDif, int32_t aYDif, ErrorResult& aError)
  6860   FORWARD_TO_OUTER_OR_THROW(MoveBy, (aXDif, aYDif, aError), aError, );
  6862   /*
  6863    * If caller is not chrome and the user has not explicitly exempted the site,
  6864    * prevent window.moveBy() by exiting early
  6865    */
  6867   if (!CanMoveResizeWindows() || IsFrame()) {
  6868     return;
  6871   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  6872   if (!treeOwnerAsWin) {
  6873     aError.Throw(NS_ERROR_FAILURE);
  6874     return;
  6877   // To do this correctly we have to convert what we get from GetPosition
  6878   // into CSS pixels, add the arguments, do the security check, and
  6879   // then convert back to device pixels for the call to SetPosition.
  6881   int32_t x, y;
  6882   aError = treeOwnerAsWin->GetPosition(&x, &y);
  6883   if (aError.Failed()) {
  6884     return;
  6887   // mild abuse of a "size" object so we don't need more helper functions
  6888   nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
  6890   cssPos.width += aXDif;
  6891   cssPos.height += aYDif;
  6893   CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height);
  6895   nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
  6897   aError = treeOwnerAsWin->SetPosition(newDevPos.width, newDevPos.height);
  6900 NS_IMETHODIMP
  6901 nsGlobalWindow::MoveBy(int32_t aXDif, int32_t aYDif)
  6903   ErrorResult rv;
  6904   MoveBy(aXDif, aYDif, rv);
  6906   return rv.ErrorCode();
  6909 void
  6910 nsGlobalWindow::ResizeTo(int32_t aWidth, int32_t aHeight, ErrorResult& aError)
  6912   FORWARD_TO_OUTER_OR_THROW(ResizeTo, (aWidth, aHeight, aError), aError, );
  6914   /*
  6915    * If caller is a browser-element then dispatch a resize event to
  6916    * the embedder.
  6917    */
  6918   if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
  6919     nsIntSize size(aWidth, aHeight);
  6920     if (!DispatchResizeEvent(size)) {
  6921       // The embedder chose to prevent the default action for this
  6922       // event, so let's not resize this window after all...
  6923       return;
  6927   /*
  6928    * If caller is not chrome and the user has not explicitly exempted the site,
  6929    * prevent window.resizeTo() by exiting early
  6930    */
  6932   if (!CanMoveResizeWindows() || IsFrame()) {
  6933     return;
  6936   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  6937   if (!treeOwnerAsWin) {
  6938     aError.Throw(NS_ERROR_FAILURE);
  6939     return;
  6942   nsIntSize cssSize(aWidth, aHeight);
  6943   CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height);
  6945   nsIntSize devSz(CSSToDevIntPixels(cssSize));
  6947   aError = treeOwnerAsWin->SetSize(devSz.width, devSz.height, true);
  6950 NS_IMETHODIMP
  6951 nsGlobalWindow::ResizeTo(int32_t aWidth, int32_t aHeight)
  6953   ErrorResult rv;
  6954   ResizeTo(aWidth, aHeight, rv);
  6956   return rv.ErrorCode();
  6959 void
  6960 nsGlobalWindow::ResizeBy(int32_t aWidthDif, int32_t aHeightDif,
  6961                          ErrorResult& aError)
  6963   FORWARD_TO_OUTER_OR_THROW(ResizeBy, (aWidthDif, aHeightDif, aError), aError, );
  6965   /*
  6966    * If caller is a browser-element then dispatch a resize event to
  6967    * parent.
  6968    */
  6969   if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
  6970     CSSIntSize size;
  6971     if (NS_FAILED(GetInnerSize(size))) {
  6972       return;
  6975     size.width += aWidthDif;
  6976     size.height += aHeightDif;
  6978     if (!DispatchResizeEvent(nsIntSize(size.width, size.height))) {
  6979       // The embedder chose to prevent the default action for this
  6980       // event, so let's not resize this window after all...
  6981       return;
  6985   /*
  6986    * If caller is not chrome and the user has not explicitly exempted the site,
  6987    * prevent window.resizeBy() by exiting early
  6988    */
  6990   if (!CanMoveResizeWindows() || IsFrame()) {
  6991     return;
  6994   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  6995   if (!treeOwnerAsWin) {
  6996     aError.Throw(NS_ERROR_FAILURE);
  6997     return;
  7000   int32_t width, height;
  7001   aError = treeOwnerAsWin->GetSize(&width, &height);
  7002   if (aError.Failed()) {
  7003     return;
  7006   // To do this correctly we have to convert what we got from GetSize
  7007   // into CSS pixels, add the arguments, do the security check, and
  7008   // then convert back to device pixels for the call to SetSize.
  7010   nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
  7012   cssSize.width += aWidthDif;
  7013   cssSize.height += aHeightDif;
  7015   CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height);
  7017   nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
  7019   aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
  7022 NS_IMETHODIMP
  7023 nsGlobalWindow::ResizeBy(int32_t aWidthDif, int32_t aHeightDif)
  7025   ErrorResult rv;
  7026   ResizeBy(aWidthDif, aHeightDif, rv);
  7028   return rv.ErrorCode();
  7031 void
  7032 nsGlobalWindow::SizeToContent(ErrorResult& aError)
  7034   FORWARD_TO_OUTER_OR_THROW(SizeToContent, (aError), aError, );
  7036   if (!mDocShell) {
  7037     return;
  7040   /*
  7041    * If caller is not chrome and the user has not explicitly exempted the site,
  7042    * prevent window.sizeToContent() by exiting early
  7043    */
  7045   if (!CanMoveResizeWindows() || IsFrame()) {
  7046     return;
  7049   // The content viewer does a check to make sure that it's a content
  7050   // viewer for a toplevel docshell.
  7051   nsCOMPtr<nsIContentViewer> cv;
  7052   mDocShell->GetContentViewer(getter_AddRefs(cv));
  7053   nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
  7054   if (!markupViewer) {
  7055     aError.Throw(NS_ERROR_FAILURE);
  7056     return;
  7059   int32_t width, height;
  7060   aError = markupViewer->GetContentSize(&width, &height);
  7061   if (aError.Failed()) {
  7062     return;
  7065   // Make sure the new size is following the CheckSecurityWidthAndHeight
  7066   // rules.
  7067   nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  7068   if (!treeOwner) {
  7069     aError.Throw(NS_ERROR_FAILURE);
  7070     return;
  7073   nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
  7074   CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height);
  7076   nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
  7078   aError = treeOwner->SizeShellTo(mDocShell, newDevSize.width,
  7079                                   newDevSize.height);
  7082 NS_IMETHODIMP
  7083 nsGlobalWindow::SizeToContent()
  7085   ErrorResult rv;
  7086   SizeToContent(rv);
  7088   return rv.ErrorCode();
  7091 NS_IMETHODIMP
  7092 nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
  7094   nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
  7095   return CallQueryInterface(root, aWindowRoot);
  7098 already_AddRefed<nsPIWindowRoot>
  7099 nsGlobalWindow::GetTopWindowRoot()
  7101   nsPIDOMWindow* piWin = GetPrivateRoot();
  7102   if (!piWin) {
  7103     return nullptr;
  7106   nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
  7107   return window.forget();
  7110 NS_IMETHODIMP
  7111 nsGlobalWindow::Scroll(int32_t aXScroll, int32_t aYScroll)
  7113   ScrollTo(CSSIntPoint(aXScroll, aYScroll));
  7114   return NS_OK;
  7117 NS_IMETHODIMP
  7118 nsGlobalWindow::ScrollTo(int32_t aXScroll, int32_t aYScroll)
  7120   ScrollTo(CSSIntPoint(aXScroll, aYScroll));
  7121   return NS_OK;
  7124 void
  7125 nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll)
  7127   FlushPendingNotifications(Flush_Layout);
  7128   nsIScrollableFrame *sf = GetScrollFrame();
  7130   if (sf) {
  7131     // Here we calculate what the max pixel value is that we can
  7132     // scroll to, we do this by dividing maxint with the pixel to
  7133     // twips conversion factor, and subtracting 4, the 4 comes from
  7134     // experimenting with this value, anything less makes the view
  7135     // code not scroll correctly, I have no idea why. -- jst
  7136     const int32_t maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
  7138     CSSIntPoint scroll(aScroll);
  7139     if (scroll.x > maxpx) {
  7140       scroll.x = maxpx;
  7143     if (scroll.y > maxpx) {
  7144       scroll.y = maxpx;
  7146     sf->ScrollToCSSPixels(scroll);
  7150 NS_IMETHODIMP
  7151 nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif)
  7153   FlushPendingNotifications(Flush_Layout);
  7154   nsIScrollableFrame *sf = GetScrollFrame();
  7156   if (sf) {
  7157     CSSIntPoint scrollPos =
  7158       sf->GetScrollPositionCSSPixels() + CSSIntPoint(aXScrollDif, aYScrollDif);
  7159     // It seems like it would make more sense for ScrollBy to use
  7160     // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
  7161     // Perhaps Web content does too.
  7162     ScrollTo(scrollPos);
  7165   return NS_OK;
  7168 NS_IMETHODIMP
  7169 nsGlobalWindow::ScrollByLines(int32_t numLines)
  7171   FlushPendingNotifications(Flush_Layout);
  7172   nsIScrollableFrame *sf = GetScrollFrame();
  7173   if (sf) {
  7174     // It seems like it would make more sense for ScrollByLines to use
  7175     // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
  7176     // Perhaps Web content does too.
  7177     sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
  7178                  nsIScrollableFrame::INSTANT);
  7181   return NS_OK;
  7184 NS_IMETHODIMP
  7185 nsGlobalWindow::ScrollByPages(int32_t numPages)
  7187   FlushPendingNotifications(Flush_Layout);
  7188   nsIScrollableFrame *sf = GetScrollFrame();
  7189   if (sf) {
  7190     // It seems like it would make more sense for ScrollByPages to use
  7191     // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
  7192     // Perhaps Web content does too.
  7193     sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
  7194                  nsIScrollableFrame::INSTANT);
  7197   return NS_OK;
  7200 void
  7201 nsGlobalWindow::ClearTimeout(int32_t aHandle, ErrorResult& aError)
  7203   if (aHandle > 0) {
  7204     ClearTimeoutOrInterval(aHandle, aError);
  7208 NS_IMETHODIMP
  7209 nsGlobalWindow::ClearTimeout(int32_t aHandle)
  7211   ErrorResult rv;
  7212   ClearTimeout(aHandle, rv);
  7214   return rv.ErrorCode();
  7217 void
  7218 nsGlobalWindow::ClearInterval(int32_t aHandle, ErrorResult& aError)
  7220   if (aHandle > 0) {
  7221     ClearTimeoutOrInterval(aHandle, aError);
  7225 NS_IMETHODIMP
  7226 nsGlobalWindow::ClearInterval(int32_t aHandle)
  7228   ErrorResult rv;
  7229   ClearInterval(aHandle, rv);
  7231   return rv.ErrorCode();
  7234 NS_IMETHODIMP
  7235 nsGlobalWindow::SetTimeout(int32_t *_retval)
  7237   return SetTimeoutOrInterval(false, _retval);
  7240 NS_IMETHODIMP
  7241 nsGlobalWindow::SetInterval(int32_t *_retval)
  7243   return SetTimeoutOrInterval(true, _retval);
  7246 NS_IMETHODIMP
  7247 nsGlobalWindow::SetResizable(bool aResizable)
  7249   // nop
  7251   return NS_OK;
  7254 NS_IMETHODIMP
  7255 nsGlobalWindow::CaptureEvents()
  7257   if (mDoc) {
  7258     mDoc->WarnOnceAbout(nsIDocument::eUseOfCaptureEvents);
  7261   return NS_OK;
  7264 NS_IMETHODIMP
  7265 nsGlobalWindow::ReleaseEvents()
  7267   if (mDoc) {
  7268     mDoc->WarnOnceAbout(nsIDocument::eUseOfReleaseEvents);
  7271   return NS_OK;
  7274 static
  7275 bool IsPopupBlocked(nsIDocument* aDoc)
  7277   nsCOMPtr<nsIPopupWindowManager> pm =
  7278     do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
  7280   if (!pm) {
  7281     return false;
  7284   if (!aDoc) {
  7285     return true;
  7288   uint32_t permission = nsIPopupWindowManager::ALLOW_POPUP;
  7289   pm->TestPermission(aDoc->NodePrincipal(), &permission);
  7290   return permission == nsIPopupWindowManager::DENY_POPUP;
  7293 /* static */
  7294 void
  7295 nsGlobalWindow::FirePopupBlockedEvent(nsIDocument* aDoc,
  7296                                       nsIDOMWindow *aRequestingWindow, nsIURI *aPopupURI,
  7297                                       const nsAString &aPopupWindowName,
  7298                                       const nsAString &aPopupWindowFeatures)
  7300   if (aDoc) {
  7301     // Fire a "DOMPopupBlocked" event so that the UI can hear about
  7302     // blocked popups.
  7303     nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDoc);
  7304     nsCOMPtr<nsIDOMEvent> event;
  7305     doc->CreateEvent(NS_LITERAL_STRING("PopupBlockedEvents"), getter_AddRefs(event));
  7306     if (event) {
  7307       nsCOMPtr<nsIDOMPopupBlockedEvent> pbev(do_QueryInterface(event));
  7308       pbev->InitPopupBlockedEvent(NS_LITERAL_STRING("DOMPopupBlocked"),
  7309                                   true, true, aRequestingWindow,
  7310                                   aPopupURI, aPopupWindowName,
  7311                                   aPopupWindowFeatures);
  7312       event->SetTrusted(true);
  7314       bool defaultActionEnabled;
  7315       aDoc->DispatchEvent(event, &defaultActionEnabled);
  7320 static void FirePopupWindowEvent(nsIDocument* aDoc)
  7322   // Fire a "PopupWindow" event
  7323   nsContentUtils::DispatchTrustedEvent(aDoc, aDoc,
  7324                                        NS_LITERAL_STRING("PopupWindow"),
  7325                                        true, true);
  7328 // static
  7329 bool
  7330 nsGlobalWindow::CanSetProperty(const char *aPrefName)
  7332   // Chrome can set any property.
  7333   if (nsContentUtils::IsCallerChrome()) {
  7334     return true;
  7337   // If the pref is set to true, we can not set the property
  7338   // and vice versa.
  7339   return !Preferences::GetBool(aPrefName, true);
  7342 bool
  7343 nsGlobalWindow::PopupWhitelisted()
  7345   if (!IsPopupBlocked(mDoc))
  7346     return true;
  7348   nsCOMPtr<nsIDOMWindow> parent;
  7350   if (NS_FAILED(GetParent(getter_AddRefs(parent))) ||
  7351       parent == static_cast<nsIDOMWindow*>(this))
  7353     return false;
  7356   return static_cast<nsGlobalWindow*>
  7357                     (static_cast<nsIDOMWindow*>
  7358                                 (parent.get()))->PopupWhitelisted();
  7361 /*
  7362  * Examine the current document state to see if we're in a way that is
  7363  * typically abused by web designers. The window.open code uses this
  7364  * routine to determine whether to allow the new window.
  7365  * Returns a value from the PopupControlState enum.
  7366  */
  7367 PopupControlState
  7368 nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
  7370   MOZ_ASSERT(IsOuterWindow());
  7372   NS_ASSERTION(mDocShell, "Must have docshell");
  7374   if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
  7375     return openAllowed;
  7378   PopupControlState abuse = aControl;
  7379   switch (abuse) {
  7380   case openControlled:
  7381   case openAbused:
  7382   case openOverridden:
  7383     if (PopupWhitelisted())
  7384       abuse = PopupControlState(abuse - 1);
  7385   case openAllowed: break;
  7386   default:
  7387     NS_WARNING("Strange PopupControlState!");
  7390   // limit the number of simultaneously open popups
  7391   if (abuse == openAbused || abuse == openControlled) {
  7392     int32_t popupMax = Preferences::GetInt("dom.popup_maximum", -1);
  7393     if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
  7394       abuse = openOverridden;
  7397   return abuse;
  7400 /* If a window open is blocked, fire the appropriate DOM events.
  7401    aBlocked signifies we just blocked a popup.
  7402    aWindow signifies we just opened what is probably a popup.
  7403 */
  7404 void
  7405 nsGlobalWindow::FireAbuseEvents(bool aBlocked, bool aWindow,
  7406                                 const nsAString &aPopupURL,
  7407                                 const nsAString &aPopupWindowName,
  7408                                 const nsAString &aPopupWindowFeatures)
  7410   // fetch the URI of the window requesting the opened window
  7412   nsCOMPtr<nsIDOMWindow> topWindow;
  7413   GetTop(getter_AddRefs(topWindow));
  7414   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(topWindow);
  7415   if (!window) {
  7416     return;
  7419   nsCOMPtr<nsIDocument> topDoc = window->GetDoc();
  7420   nsCOMPtr<nsIURI> popupURI;
  7422   // build the URI of the would-have-been popup window
  7423   // (see nsWindowWatcher::URIfromURL)
  7425   // first, fetch the opener's base URI
  7427   nsIURI *baseURL = nullptr;
  7429   JSContext *cx = nsContentUtils::GetCurrentJSContext();
  7430   nsCOMPtr<nsPIDOMWindow> contextWindow;
  7432   if (cx) {
  7433     nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
  7434     if (currentCX) {
  7435       contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
  7438   if (!contextWindow) {
  7439     contextWindow = this;
  7442   nsCOMPtr<nsIDocument> doc = contextWindow->GetDoc();
  7443   if (doc)
  7444     baseURL = doc->GetDocBaseURI();
  7446   // use the base URI to build what would have been the popup's URI
  7447   nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
  7448   if (ios)
  7449     ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
  7450                 getter_AddRefs(popupURI));
  7452   // fire an event chock full of informative URIs
  7453   if (aBlocked) {
  7454     FirePopupBlockedEvent(topDoc, this, popupURI, aPopupWindowName,
  7455                           aPopupWindowFeatures);
  7457   if (aWindow)
  7458     FirePopupWindowEvent(topDoc);
  7461 already_AddRefed<nsIDOMWindow>
  7462 nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
  7463                      const nsAString& aOptions, ErrorResult& aError)
  7465   nsCOMPtr<nsIDOMWindow> window;
  7466   aError = OpenJS(aUrl, aName, aOptions, getter_AddRefs(window));
  7467   return window.forget();
  7470 NS_IMETHODIMP
  7471 nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
  7472                      const nsAString& aOptions, nsIDOMWindow **_retval)
  7474   return OpenInternal(aUrl, aName, aOptions,
  7475                       false,          // aDialog
  7476                       false,          // aContentModal
  7477                       true,           // aCalledNoScript
  7478                       false,          // aDoJSFixups
  7479                       true,           // aNavigate
  7480                       nullptr, nullptr,  // No args
  7481                       GetPrincipal(),    // aCalleePrincipal
  7482                       nullptr,           // aJSCallerContext
  7483                       _retval);
  7486 NS_IMETHODIMP
  7487 nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
  7488                        const nsAString& aOptions, nsIDOMWindow **_retval)
  7490   return OpenInternal(aUrl, aName, aOptions,
  7491                       false,          // aDialog
  7492                       false,          // aContentModal
  7493                       false,          // aCalledNoScript
  7494                       true,           // aDoJSFixups
  7495                       true,           // aNavigate
  7496                       nullptr, nullptr,  // No args
  7497                       GetPrincipal(),    // aCalleePrincipal
  7498                       nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
  7499                       _retval);
  7502 // like Open, but attaches to the new window any extra parameters past
  7503 // [features] as a JS property named "arguments"
  7504 NS_IMETHODIMP
  7505 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
  7506                            const nsAString& aOptions,
  7507                            nsISupports* aExtraArgument, nsIDOMWindow** _retval)
  7509   return OpenInternal(aUrl, aName, aOptions,
  7510                       true,                    // aDialog
  7511                       false,                   // aContentModal
  7512                       true,                    // aCalledNoScript
  7513                       false,                   // aDoJSFixups
  7514                       true,                    // aNavigate
  7515                       nullptr, aExtraArgument,    // Arguments
  7516                       GetPrincipal(),             // aCalleePrincipal
  7517                       nullptr,                    // aJSCallerContext
  7518                       _retval);
  7521 // Like Open, but passes aNavigate=false.
  7522 /* virtual */ nsresult
  7523 nsGlobalWindow::OpenNoNavigate(const nsAString& aUrl,
  7524                                const nsAString& aName,
  7525                                const nsAString& aOptions,
  7526                                nsIDOMWindow **_retval)
  7528   return OpenInternal(aUrl, aName, aOptions,
  7529                       false,          // aDialog
  7530                       false,          // aContentModal
  7531                       true,           // aCalledNoScript
  7532                       false,          // aDoJSFixups
  7533                       false,          // aNavigate
  7534                       nullptr, nullptr,  // No args
  7535                       GetPrincipal(),    // aCalleePrincipal
  7536                       nullptr,           // aJSCallerContext
  7537                       _retval);
  7541 already_AddRefed<nsIDOMWindow>
  7542 nsGlobalWindow::OpenDialog(JSContext* aCx, const nsAString& aUrl,
  7543                            const nsAString& aName, const nsAString& aOptions,
  7544                            const Sequence<JS::Value>& aExtraArgument,
  7545                            ErrorResult& aError)
  7547   nsCOMPtr<nsIJSArgArray> argvArray;
  7548   aError = NS_CreateJSArgv(aCx, aExtraArgument.Length(),
  7549                            const_cast<JS::Value*>(aExtraArgument.Elements()),
  7550                            getter_AddRefs(argvArray));
  7551   if (aError.Failed()) {
  7552     return nullptr;
  7555   nsCOMPtr<nsIDOMWindow> dialog;
  7556   aError = OpenInternal(aUrl, aName, aOptions,
  7557                         true,             // aDialog
  7558                         false,            // aContentModal
  7559                         false,            // aCalledNoScript
  7560                         false,            // aDoJSFixups
  7561                         true,                // aNavigate
  7562                         argvArray, nullptr,  // Arguments
  7563                         GetPrincipal(),      // aCalleePrincipal
  7564                         aCx,                 // aJSCallerContext
  7565                         getter_AddRefs(dialog));
  7566   return dialog.forget();
  7569 NS_IMETHODIMP
  7570 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
  7571                            const nsAString& aOptions, nsIDOMWindow** _retval)
  7573   if (!nsContentUtils::IsCallerChrome()) {
  7574     return NS_ERROR_DOM_SECURITY_ERR;
  7577   nsAXPCNativeCallContext *ncc = nullptr;
  7578   nsresult rv = nsContentUtils::XPConnect()->
  7579     GetCurrentNativeCallContext(&ncc);
  7580   NS_ENSURE_SUCCESS(rv, rv);
  7582   if (!ncc)
  7583     return NS_ERROR_NOT_AVAILABLE;
  7585   JSContext *cx = nullptr;
  7587   rv = ncc->GetJSContext(&cx);
  7588   NS_ENSURE_SUCCESS(rv, rv);
  7590   uint32_t argc;
  7591   JS::Value *argv = nullptr;
  7593   // XXX - need to get this as nsISupports?
  7594   ncc->GetArgc(&argc);
  7595   ncc->GetArgvPtr(&argv);
  7597   // Strip the url, name and options from the args seen by scripts.
  7598   uint32_t argOffset = argc < 3 ? argc : 3;
  7599   nsCOMPtr<nsIJSArgArray> argvArray;
  7600   rv = NS_CreateJSArgv(cx, argc - argOffset, argv + argOffset,
  7601                        getter_AddRefs(argvArray));
  7602   NS_ENSURE_SUCCESS(rv, rv);
  7604   return OpenInternal(aUrl, aName, aOptions,
  7605                       true,             // aDialog
  7606                       false,            // aContentModal
  7607                       false,            // aCalledNoScript
  7608                       false,            // aDoJSFixups
  7609                       true,                // aNavigate
  7610                       argvArray, nullptr,  // Arguments
  7611                       GetPrincipal(),      // aCalleePrincipal
  7612                       cx,                  // aJSCallerContext
  7613                       _retval);
  7616 already_AddRefed<nsIDOMWindow>
  7617 nsGlobalWindow::GetFrames(ErrorResult& aError)
  7619   FORWARD_TO_OUTER_OR_THROW(GetFrames, (aError), aError, nullptr);
  7621   nsRefPtr<nsGlobalWindow> frames(this);
  7622   FlushPendingNotifications(Flush_ContentAndNotify);
  7623   return frames.forget();
  7626 NS_IMETHODIMP
  7627 nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
  7629   ErrorResult rv;
  7630   nsCOMPtr<nsIDOMWindow> frames = GetFrames(rv);
  7631   frames.forget(aFrames);
  7633   return rv.ErrorCode();
  7636 JSObject* nsGlobalWindow::CallerGlobal()
  7638   JSContext *cx = nsContentUtils::GetCurrentJSContext();
  7639   if (!cx) {
  7640     NS_ERROR("Please don't call this method from C++!");
  7642     return nullptr;
  7645   // If somebody does sameOriginIframeWindow.postMessage(...), they probably
  7646   // expect the .source attribute of the resulting message event to be |window|
  7647   // rather than |sameOriginIframeWindow|, even though the transparent wrapper
  7648   // semantics of same-origin access will cause us to be in the iframe's
  7649   // compartment at the time of the call. This means that we want the incumbent
  7650   // global here, rather than the global of the current compartment.
  7651   //
  7652   // There are various edge cases in which the incumbent global and the current
  7653   // global would not be same-origin. They include:
  7654   // * A privileged caller (System Principal or Expanded Principal) manipulating
  7655   //   less-privileged content via Xray Waivers.
  7656   // * An unprivileged caller invoking a cross-origin function that was exposed
  7657   //   to it by privileged code (i.e. Sandbox.importFunction).
  7658   //
  7659   // In these cases, we probably don't want the privileged global appearing in the
  7660   // .source attribute. So we fall back to the compartment global there.
  7661   JS::Rooted<JSObject*> incumbentGlobal(cx, &IncumbentJSGlobal());
  7662   JS::Rooted<JSObject*> compartmentGlobal(cx, JS::CurrentGlobalOrNull(cx));
  7663   nsIPrincipal* incumbentPrin = nsContentUtils::GetObjectPrincipal(incumbentGlobal);
  7664   nsIPrincipal* compartmentPrin = nsContentUtils::GetObjectPrincipal(compartmentGlobal);
  7665   return incumbentPrin->EqualsConsideringDomain(compartmentPrin) ? incumbentGlobal
  7666                                                                  : compartmentGlobal;
  7670 nsGlobalWindow*
  7671 nsGlobalWindow::CallerInnerWindow()
  7673   JSContext *cx = nsContentUtils::GetCurrentJSContext();
  7674   NS_ENSURE_TRUE(cx, nullptr);
  7675   JS::Rooted<JSObject*> scope(cx, CallerGlobal());
  7677   // When Jetpack runs content scripts inside a sandbox, it uses
  7678   // sandboxPrototype to make them appear as though they're running in the
  7679   // scope of the page. So when a content script invokes postMessage, it expects
  7680   // the |source| of the received message to be the window set as the
  7681   // sandboxPrototype. This used to work incidentally for unrelated reasons, but
  7682   // now we need to do some special handling to support it.
  7684     JSAutoCompartment ac(cx, scope);
  7685     JS::Rooted<JSObject*> scopeProto(cx);
  7686     bool ok = JS_GetPrototype(cx, scope, &scopeProto);
  7687     NS_ENSURE_TRUE(ok, nullptr);
  7688     if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
  7689         (scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtOuter = */ false)))
  7691       scope = scopeProto;
  7694   JSAutoCompartment ac(cx, scope);
  7696   // We don't use xpc::WindowOrNull here because we want to be able to tell
  7697   // apart the cases of "scope is not an nsISupports at all" and "scope is an
  7698   // nsISupports that's not a window". It's not clear whether that's desirable,
  7699   // see bug 984467.
  7700   nsISupports* native =
  7701     nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, scope);
  7702   if (!native)
  7703     return nullptr;
  7705   // The calling window must be holding a reference, so we can just return a
  7706   // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
  7707   // destructor's release.
  7708   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(native);
  7709   if (!win)
  7710     return GetCurrentInnerWindowInternal();
  7711   return static_cast<nsGlobalWindow*>(win.get());
  7714 nsresult
  7715 nsGlobalWindow::GetFirstPartyIsolationURI(nsIURI** aFirstPartyIsolationURI)
  7717   nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
  7718                                do_GetService(THIRDPARTYUTIL_CONTRACTID);
  7719   if (!thirdPartyUtil)
  7720     return NS_ERROR_FAILURE;
  7722   nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDoc);
  7723   return thirdPartyUtil->GetFirstPartyIsolationURI(NULL, doc, aFirstPartyIsolationURI);
  7727 /**
  7728  * Class used to represent events generated by calls to Window.postMessage,
  7729  * which asynchronously creates and dispatches events.
  7730  */
  7731 class PostMessageEvent : public nsRunnable
  7733   public:
  7734     NS_DECL_NSIRUNNABLE
  7736     PostMessageEvent(nsGlobalWindow* aSource,
  7737                      const nsAString& aCallerOrigin,
  7738                      nsGlobalWindow* aTargetWindow,
  7739                      nsIPrincipal* aProvidedPrincipal,
  7740                      bool aTrustedCaller)
  7741     : mSource(aSource),
  7742       mCallerOrigin(aCallerOrigin),
  7743       mTargetWindow(aTargetWindow),
  7744       mProvidedPrincipal(aProvidedPrincipal),
  7745       mTrustedCaller(aTrustedCaller)
  7747       MOZ_COUNT_CTOR(PostMessageEvent);
  7750     ~PostMessageEvent()
  7752       MOZ_COUNT_DTOR(PostMessageEvent);
  7755     JSAutoStructuredCloneBuffer& Buffer()
  7757       return mBuffer;
  7760     bool StoreISupports(nsISupports* aSupports)
  7762       mSupportsArray.AppendElement(aSupports);
  7763       return true;
  7766   private:
  7767     JSAutoStructuredCloneBuffer mBuffer;
  7768     nsRefPtr<nsGlobalWindow> mSource;
  7769     nsString mCallerOrigin;
  7770     nsRefPtr<nsGlobalWindow> mTargetWindow;
  7771     nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
  7772     bool mTrustedCaller;
  7773     nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
  7774 };
  7776 namespace {
  7778 struct StructuredCloneInfo {
  7779   PostMessageEvent* event;
  7780   bool subsumes;
  7781   nsPIDOMWindow* window;
  7782   nsRefPtrHashtable<nsRefPtrHashKey<MessagePortBase>, MessagePortBase> ports;
  7783 };
  7785 static JSObject*
  7786 PostMessageReadStructuredClone(JSContext* cx,
  7787                                JSStructuredCloneReader* reader,
  7788                                uint32_t tag,
  7789                                uint32_t data,
  7790                                void* closure)
  7792   if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
  7793     NS_ASSERTION(!data, "Data should be empty");
  7795     nsISupports* supports;
  7796     if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
  7797       JS::Rooted<JS::Value> val(cx);
  7798       if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
  7799         return val.toObjectOrNull();
  7804   const JSStructuredCloneCallbacks* runtimeCallbacks =
  7805     js::GetContextStructuredCloneCallbacks(cx);
  7807   if (runtimeCallbacks) {
  7808     return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
  7811   return nullptr;
  7814 static bool
  7815 PostMessageWriteStructuredClone(JSContext* cx,
  7816                                 JSStructuredCloneWriter* writer,
  7817                                 JS::Handle<JSObject*> obj,
  7818                                 void *closure)
  7820   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
  7821   NS_ASSERTION(scInfo, "Must have scInfo!");
  7823   nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
  7824   nsContentUtils::XPConnect()->
  7825     GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
  7826   if (wrappedNative) {
  7827     uint32_t scTag = 0;
  7828     nsISupports* supports = wrappedNative->Native();
  7830     nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
  7831     if (blob && scInfo->subsumes)
  7832       scTag = SCTAG_DOM_BLOB;
  7834     nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
  7835     if (list && scInfo->subsumes)
  7836       scTag = SCTAG_DOM_FILELIST;
  7838     if (scTag)
  7839       return JS_WriteUint32Pair(writer, scTag, 0) &&
  7840              JS_WriteBytes(writer, &supports, sizeof(supports)) &&
  7841              scInfo->event->StoreISupports(supports);
  7844   const JSStructuredCloneCallbacks* runtimeCallbacks =
  7845     js::GetContextStructuredCloneCallbacks(cx);
  7847   if (runtimeCallbacks) {
  7848     return runtimeCallbacks->write(cx, writer, obj, nullptr);
  7851   return false;
  7854 static bool
  7855 PostMessageReadTransferStructuredClone(JSContext* aCx,
  7856                                        JSStructuredCloneReader* reader,
  7857                                        uint32_t tag, void* aData,
  7858                                        uint64_t aExtraData,
  7859                                        void* aClosure,
  7860                                        JS::MutableHandle<JSObject*> returnObject)
  7862   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
  7863   NS_ASSERTION(scInfo, "Must have scInfo!");
  7865   if (MessageChannel::PrefEnabled() && tag == SCTAG_DOM_MAP_MESSAGEPORT) {
  7866     MessagePort* port = static_cast<MessagePort*>(aData);
  7867     port->BindToOwner(scInfo->window);
  7868     scInfo->ports.Put(port, nullptr);
  7870     JS::Rooted<JSObject*> obj(aCx, port->WrapObject(aCx));
  7871     if (JS_WrapObject(aCx, &obj)) {
  7872       MOZ_ASSERT(port->GetOwner() == scInfo->window);
  7873       returnObject.set(obj);
  7876     return true;
  7879   return false;
  7882 static bool
  7883 PostMessageTransferStructuredClone(JSContext* aCx,
  7884                                    JS::Handle<JSObject*> aObj,
  7885                                    void* aClosure,
  7886                                    uint32_t* aTag,
  7887                                    JS::TransferableOwnership* aOwnership,
  7888                                    void** aContent,
  7889                                    uint64_t* aExtraData)
  7891   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
  7892   NS_ASSERTION(scInfo, "Must have scInfo!");
  7894   if (MessageChannel::PrefEnabled()) {
  7895     MessagePortBase* port = nullptr;
  7896     nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
  7897     if (NS_SUCCEEDED(rv)) {
  7898       nsRefPtr<MessagePortBase> newPort;
  7899       if (scInfo->ports.Get(port, getter_AddRefs(newPort))) {
  7900         // No duplicate.
  7901         return false;
  7904       newPort = port->Clone();
  7905       scInfo->ports.Put(port, newPort);
  7907       *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
  7908       *aOwnership = JS::SCTAG_TMO_CUSTOM;
  7909       *aContent = newPort;
  7910       *aExtraData = 0;
  7912       return true;
  7916   return false;
  7919 void
  7920 PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership,
  7921                                        void *aContent, uint64_t aExtraData, void* aClosure)
  7923   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
  7924   NS_ASSERTION(scInfo, "Must have scInfo!");
  7926   if (MessageChannel::PrefEnabled() && aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
  7927     nsRefPtr<MessagePortBase> port(static_cast<MessagePort*>(aContent));
  7928     scInfo->ports.Remove(port);
  7932 JSStructuredCloneCallbacks kPostMessageCallbacks = {
  7933   PostMessageReadStructuredClone,
  7934   PostMessageWriteStructuredClone,
  7935   nullptr,
  7936   PostMessageReadTransferStructuredClone,
  7937   PostMessageTransferStructuredClone,
  7938   PostMessageFreeTransferStructuredClone
  7939 };
  7941 } // anonymous namespace
  7943 static PLDHashOperator
  7944 PopulateMessagePortList(MessagePortBase* aKey, MessagePortBase* aValue, void* aClosure)
  7946   nsTArray<nsRefPtr<MessagePortBase> > *array =
  7947     static_cast<nsTArray<nsRefPtr<MessagePortBase> > *>(aClosure);
  7949   array->AppendElement(aKey);
  7950   return PL_DHASH_NEXT;
  7953 NS_IMETHODIMP
  7954 PostMessageEvent::Run()
  7956   NS_ABORT_IF_FALSE(mTargetWindow->IsOuterWindow(),
  7957                     "should have been passed an outer window!");
  7958   NS_ABORT_IF_FALSE(!mSource || mSource->IsOuterWindow(),
  7959                     "should have been passed an outer window!");
  7961   AutoJSAPI jsapi;
  7962   JSContext* cx = jsapi.cx();
  7964   // If we bailed before this point we're going to leak mMessage, but
  7965   // that's probably better than crashing.
  7967   nsRefPtr<nsGlobalWindow> targetWindow;
  7968   if (mTargetWindow->IsClosedOrClosing() ||
  7969       !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
  7970       targetWindow->IsClosedOrClosing())
  7971     return NS_OK;
  7973   NS_ABORT_IF_FALSE(targetWindow->IsInnerWindow(),
  7974                     "we ordered an inner window!");
  7975   JSAutoCompartment ac(cx, targetWindow->GetWrapperPreserveColor());
  7977   // Ensure that any origin which might have been provided is the origin of this
  7978   // window's document.  Note that we do this *now* instead of when postMessage
  7979   // is called because the target window might have been navigated to a
  7980   // different location between then and now.  If this check happened when
  7981   // postMessage was called, it would be fairly easy for a malicious webpage to
  7982   // intercept messages intended for another site by carefully timing navigation
  7983   // of the target window so it changed location after postMessage but before
  7984   // now.
  7985   if (mProvidedPrincipal) {
  7986     // Get the target's origin either from its principal or, in the case the
  7987     // principal doesn't carry a URI (e.g. the system principal), the target's
  7988     // document.
  7989     nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
  7990     if (NS_WARN_IF(!targetPrin))
  7991       return NS_OK;
  7993     // Note: This is contrary to the spec with respect to file: URLs, which
  7994     //       the spec groups into a single origin, but given we intentionally
  7995     //       don't do that in other places it seems better to hold the line for
  7996     //       now.  Long-term, we want HTML5 to address this so that we can
  7997     //       be compliant while being safer.
  7998     if (!targetPrin->Equals(mProvidedPrincipal)) {
  7999       return NS_OK;
  8003   // Deserialize the structured clone data
  8004   JS::Rooted<JS::Value> messageData(cx);
  8005   StructuredCloneInfo scInfo;
  8006   scInfo.event = this;
  8007   scInfo.window = targetWindow;
  8009   if (!mBuffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo)) {
  8010     return NS_ERROR_DOM_DATA_CLONE_ERR;
  8013   // Create the event
  8014   nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
  8015     do_QueryInterface(static_cast<nsPIDOMWindow*>(targetWindow.get()));
  8016   nsRefPtr<MessageEvent> event =
  8017     new MessageEvent(eventTarget, nullptr, nullptr);
  8019   event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */,
  8020                           false /*cancelable */, messageData, mCallerOrigin,
  8021                           EmptyString(), mSource);
  8023   nsTArray<nsRefPtr<MessagePortBase> > ports;
  8024   scInfo.ports.EnumerateRead(PopulateMessagePortList, &ports);
  8025   event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()), ports));
  8027   // We can't simply call dispatchEvent on the window because doing so ends
  8028   // up flipping the trusted bit on the event, and we don't want that to
  8029   // happen because then untrusted content can call postMessage on a chrome
  8030   // window if it can get a reference to it.
  8032   nsIPresShell *shell = targetWindow->mDoc->GetShell();
  8033   nsRefPtr<nsPresContext> presContext;
  8034   if (shell)
  8035     presContext = shell->GetPresContext();
  8037   event->SetTrusted(mTrustedCaller);
  8038   WidgetEvent* internalEvent = event->GetInternalNSEvent();
  8040   nsEventStatus status = nsEventStatus_eIgnore;
  8041   EventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
  8042                             presContext,
  8043                             internalEvent,
  8044                             static_cast<dom::Event*>(event.get()),
  8045                             &status);
  8046   return NS_OK;
  8049 void
  8050 nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
  8051                                const nsAString& aTargetOrigin,
  8052                                JS::Handle<JS::Value> aTransfer,
  8053                                ErrorResult& aError)
  8055   FORWARD_TO_OUTER_OR_THROW(PostMessageMoz,
  8056                             (aCx, aMessage, aTargetOrigin, aTransfer, aError),
  8057                             aError, );
  8059   //
  8060   // Window.postMessage is an intentional subversion of the same-origin policy.
  8061   // As such, this code must be particularly careful in the information it
  8062   // exposes to calling code.
  8063   //
  8064   // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
  8065   //
  8067   // First, get the caller's window
  8068   nsRefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
  8069   nsIPrincipal* callerPrin;
  8070   if (callerInnerWin) {
  8071     NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(),
  8072                       "should have gotten an inner window here");
  8074     // Compute the caller's origin either from its principal or, in the case the
  8075     // principal doesn't carry a URI (e.g. the system principal), the caller's
  8076     // document.  We must get this now instead of when the event is created and
  8077     // dispatched, because ultimately it is the identity of the calling window
  8078     // *now* that determines who sent the message (and not an identity which might
  8079     // have changed due to intervening navigations).
  8080     callerPrin = callerInnerWin->GetPrincipal();
  8082   else {
  8083     // In case the global is not a window, it can be a sandbox, and the sandbox's
  8084     // principal can be used for the security check.
  8085     JSObject *global = CallerGlobal();
  8086     NS_ASSERTION(global, "Why is there no global object?");
  8087     JSCompartment *compartment = js::GetObjectCompartment(global);
  8088     callerPrin = xpc::GetCompartmentPrincipal(compartment);
  8090   if (!callerPrin) {
  8091     return;
  8094   nsCOMPtr<nsIURI> callerOuterURI;
  8095   if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI)))) {
  8096     return;
  8099   nsAutoString origin;
  8100   if (callerOuterURI) {
  8101     // if the principal has a URI, use that to generate the origin
  8102     nsContentUtils::GetUTFOrigin(callerPrin, origin);
  8104   else if (callerInnerWin) {
  8105     // otherwise use the URI of the document to generate origin
  8106     nsCOMPtr<nsIDocument> doc = callerInnerWin->GetExtantDoc();
  8107     if (!doc) {
  8108       return;
  8110     callerOuterURI = doc->GetDocumentURI();
  8111     // if the principal has a URI, use that to generate the origin
  8112     nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
  8114   else {
  8115     // in case of a sandbox with a system principal origin can be empty
  8116     if (!nsContentUtils::IsSystemPrincipal(callerPrin)) {
  8117       return;
  8121   // Convert the provided origin string into a URI for comparison purposes.
  8122   nsCOMPtr<nsIPrincipal> providedPrincipal;
  8124   if (aTargetOrigin.EqualsASCII("/")) {
  8125     providedPrincipal = BrokenGetEntryGlobal()->PrincipalOrNull();
  8126     if (NS_WARN_IF(!providedPrincipal))
  8127       return;
  8130   // "*" indicates no specific origin is required.
  8131   else if (!aTargetOrigin.EqualsASCII("*")) {
  8132     nsCOMPtr<nsIURI> originURI;
  8133     if (NS_FAILED(NS_NewURI(getter_AddRefs(originURI), aTargetOrigin))) {
  8134       aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  8135       return;
  8138     if (NS_FAILED(originURI->SetUserPass(EmptyCString())) ||
  8139         NS_FAILED(originURI->SetPath(EmptyCString()))) {
  8140       return;
  8143     nsCOMPtr<nsIScriptSecurityManager> ssm =
  8144       nsContentUtils::GetSecurityManager();
  8145     MOZ_ASSERT(ssm);
  8147     nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetSubjectPrincipal();
  8148     MOZ_ASSERT(principal);
  8150     uint32_t appId;
  8151     if (NS_WARN_IF(NS_FAILED(principal->GetAppId(&appId))))
  8152       return;
  8154     bool isInBrowser;
  8155     if (NS_WARN_IF(NS_FAILED(principal->GetIsInBrowserElement(&isInBrowser))))
  8156       return;
  8158     // Create a nsIPrincipal inheriting the app/browser attributes from the
  8159     // caller.
  8160     nsresult rv = ssm->GetAppCodebasePrincipal(originURI, appId, isInBrowser,
  8161                                              getter_AddRefs(providedPrincipal));
  8162     if (NS_WARN_IF(NS_FAILED(rv))) {
  8163       return;
  8167   // Create and asynchronously dispatch a runnable which will handle actual DOM
  8168   // event creation and dispatch.
  8169   nsRefPtr<PostMessageEvent> event =
  8170     new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin
  8171                          ? nullptr
  8172                          : callerInnerWin->GetOuterWindowInternal(),
  8173                          origin,
  8174                          this,
  8175                          providedPrincipal,
  8176                          nsContentUtils::IsCallerChrome());
  8178   // We *must* clone the data here, or the JS::Value could be modified
  8179   // by script
  8180   StructuredCloneInfo scInfo;
  8181   scInfo.event = event;
  8182   scInfo.window = this;
  8184   nsIPrincipal* principal = GetPrincipal();
  8185   JS::Rooted<JS::Value> message(aCx, aMessage);
  8186   JS::Rooted<JS::Value> transfer(aCx, aTransfer);
  8187   if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)) ||
  8188       !event->Buffer().write(aCx, message, transfer, &kPostMessageCallbacks,
  8189                              &scInfo)) {
  8190     aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
  8191     return;
  8194   aError = NS_DispatchToCurrentThread(event);
  8197 void
  8198 nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
  8199                                const nsAString& aTargetOrigin,
  8200                                const Optional<Sequence<JS::Value > >& aTransfer,
  8201                                ErrorResult& aError)
  8203   JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
  8204   if (aTransfer.WasPassed()) {
  8205     const Sequence<JS::Value >& values = aTransfer.Value();
  8207     // The input sequence only comes from the generated bindings code, which
  8208     // ensures it is rooted.
  8209     JS::HandleValueArray elements =
  8210       JS::HandleValueArray::fromMarkedLocation(values.Length(), values.Elements());
  8212     transferArray = JS::ObjectOrNullValue(JS_NewArrayObject(aCx, elements));
  8213     if (transferArray.isNull()) {
  8214       aError.Throw(NS_ERROR_OUT_OF_MEMORY);
  8215       return;
  8219   PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray, aError);
  8222 NS_IMETHODIMP
  8223 nsGlobalWindow::PostMessageMoz(JS::Handle<JS::Value> aMessage,
  8224                                const nsAString& aOrigin,
  8225                                JS::Handle<JS::Value> aTransfer,
  8226                                JSContext* aCx)
  8228   ErrorResult rv;
  8229   PostMessageMoz(aCx, aMessage, aOrigin, aTransfer, rv);
  8231   return rv.ErrorCode();
  8234 class nsCloseEvent : public nsRunnable {
  8236   nsRefPtr<nsGlobalWindow> mWindow;
  8237   bool mIndirect;
  8239   nsCloseEvent(nsGlobalWindow *aWindow, bool aIndirect)
  8240     : mWindow(aWindow)
  8241     , mIndirect(aIndirect)
  8242   {}
  8244 public:
  8246   static nsresult
  8247   PostCloseEvent(nsGlobalWindow* aWindow, bool aIndirect) {
  8248     nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
  8249     nsresult rv = NS_DispatchToCurrentThread(ev);
  8250     if (NS_SUCCEEDED(rv))
  8251       aWindow->MaybeForgiveSpamCount();
  8252     return rv;
  8255   NS_IMETHOD Run() {
  8256     if (mWindow) {
  8257       if (mIndirect) {
  8258         return PostCloseEvent(mWindow, false);
  8260       mWindow->ReallyCloseWindow();
  8262     return NS_OK;
  8265 };
  8267 bool
  8268 nsGlobalWindow::CanClose()
  8270   if (!mDocShell)
  8271     return true;
  8273   // Ask the content viewer whether the toplevel window can close.
  8274   // If the content viewer returns false, it is responsible for calling
  8275   // Close() as soon as it is possible for the window to close.
  8276   // This allows us to not close the window while printing is happening.
  8278   nsCOMPtr<nsIContentViewer> cv;
  8279   mDocShell->GetContentViewer(getter_AddRefs(cv));
  8280   if (cv) {
  8281     bool canClose;
  8282     nsresult rv = cv->PermitUnload(false, &canClose);
  8283     if (NS_SUCCEEDED(rv) && !canClose)
  8284       return false;
  8286     rv = cv->RequestWindowClose(&canClose);
  8287     if (NS_SUCCEEDED(rv) && !canClose)
  8288       return false;
  8291   return true;
  8294 void
  8295 nsGlobalWindow::Close(ErrorResult& aError)
  8297   FORWARD_TO_OUTER_OR_THROW(Close, (aError), aError, );
  8299   if (!mDocShell || IsInModalState() ||
  8300       (IsFrame() && !mDocShell->GetIsBrowserOrApp())) {
  8301     // window.close() is called on a frame in a frameset, on a window
  8302     // that's already closed, or on a window for which there's
  8303     // currently a modal dialog open. Ignore such calls.
  8304     return;
  8307   if (mHavePendingClose) {
  8308     // We're going to be closed anyway; do nothing since we don't want
  8309     // to double-close
  8310     return;
  8313   if (mBlockScriptedClosingFlag)
  8315     // A script's popup has been blocked and we don't want
  8316     // the window to be closed directly after this event,
  8317     // so the user can see that there was a blocked popup.
  8318     return;
  8321   // Don't allow scripts from content to close non-app or non-neterror
  8322   // windows that were not opened by script.
  8323   nsAutoString url;
  8324   mDoc->GetURL(url);
  8325   if (!mDocShell->GetIsApp() &&
  8326       !StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
  8327       !mHadOriginalOpener && !nsContentUtils::IsCallerChrome()) {
  8328     bool allowClose = mAllowScriptsToClose ||
  8329       Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
  8330     if (!allowClose) {
  8331       // We're blocking the close operation
  8332       // report localized error msg in JS console
  8333       nsContentUtils::ReportToConsole(
  8334           nsIScriptError::warningFlag,
  8335           NS_LITERAL_CSTRING("DOM Window"), mDoc,  // Better name for the category?
  8336           nsContentUtils::eDOM_PROPERTIES,
  8337           "WindowCloseBlockedWarning");
  8339       return;
  8343   if (!mInClose && !mIsClosed && !CanClose()) {
  8344     return;
  8347   // Fire a DOM event notifying listeners that this window is about to
  8348   // be closed. The tab UI code may choose to cancel the default
  8349   // action for this event, if so, we won't actually close the window
  8350   // (since the tab UI code will close the tab in stead). Sure, this
  8351   // could be abused by content code, but do we care? I don't think
  8352   // so...
  8354   bool wasInClose = mInClose;
  8355   mInClose = true;
  8357   if (!DispatchCustomEvent("DOMWindowClose")) {
  8358     // Someone chose to prevent the default action for this event, if
  8359     // so, let's not close this window after all...
  8361     mInClose = wasInClose;
  8362     return;
  8365   aError = FinalClose();
  8368 NS_IMETHODIMP
  8369 nsGlobalWindow::Close()
  8371   ErrorResult rv;
  8372   Close(rv);
  8374   return rv.ErrorCode();
  8377 nsresult
  8378 nsGlobalWindow::ForceClose()
  8380   if (IsFrame() || !mDocShell) {
  8381     // This may be a frame in a frameset, or a window that's already closed.
  8382     // Ignore such calls.
  8384     return NS_OK;
  8387   if (mHavePendingClose) {
  8388     // We're going to be closed anyway; do nothing since we don't want
  8389     // to double-close
  8390     return NS_OK;
  8393   mInClose = true;
  8395   DispatchCustomEvent("DOMWindowClose");
  8397   return FinalClose();
  8400 nsresult
  8401 nsGlobalWindow::FinalClose()
  8403   // Flag that we were closed.
  8404   mIsClosed = true;
  8406   // This stuff is non-sensical but incredibly fragile. The reasons for the
  8407   // behavior here don't make sense today and may not have ever made sense,
  8408   // but various bits of frontend code break when you change them. If you need
  8409   // to fix up this behavior, feel free to. It's a righteous task, but involves
  8410   // wrestling with various download manager tests, frontend code, and possible
  8411   // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
  8412   // testing ground.
  8413   //
  8414   // In particular, if |win|'s JSContext is at the top of the stack, we must
  8415   // complete _two_ round-trips to the event loop before the call to
  8416   // ReallyCloseWindow. This allows setTimeout handlers that are set after
  8417   // FinalClose() is called to run before the window is torn down.
  8418   bool indirect = GetContextInternal() && // Occasionally null. See bug 877390.
  8419                   (nsContentUtils::GetCurrentJSContext() ==
  8420                    GetContextInternal()->GetNativeContext());
  8421   if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))) {
  8422     ReallyCloseWindow();
  8423   } else {
  8424     mHavePendingClose = true;
  8427   return NS_OK;
  8431 void
  8432 nsGlobalWindow::ReallyCloseWindow()
  8434   FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
  8436   // Make sure we never reenter this method.
  8437   mHavePendingClose = true;
  8439   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  8441   // If there's no treeOwnerAsWin, this window must already be closed.
  8443   if (treeOwnerAsWin) {
  8445     // but if we're a browser window we could be in some nasty
  8446     // self-destroying cascade that we should mostly ignore
  8448     if (mDocShell) {
  8449       nsCOMPtr<nsIBrowserDOMWindow> bwin;
  8450       nsCOMPtr<nsIDocShellTreeItem> rootItem;
  8451       mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
  8452       nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
  8453       nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
  8454       if (chromeWin)
  8455         chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
  8457       if (rootWin) {
  8458         /* Normally we destroy the entire window, but not if
  8459            this DOM window belongs to a tabbed browser and doesn't
  8460            correspond to a tab. This allows a well-behaved tab
  8461            to destroy the container as it should but is a final measure
  8462            to prevent an errant tab from doing so when it shouldn't.
  8463            This works because we reach this code when we shouldn't only
  8464            in the particular circumstance that we belong to a tab
  8465            that has just been closed (and is therefore already missing
  8466            from the list of browsers) (and has an unload handler
  8467            that closes the window). */
  8468         // XXXbz now that we have mHavePendingClose, is this needed?
  8469         bool isTab = false;
  8470         if (rootWin == this ||
  8471             !bwin || (bwin->IsTabContentWindow(GetOuterWindowInternal(),
  8472                                                &isTab), isTab))
  8473           treeOwnerAsWin->Destroy();
  8477     CleanUp();
  8481 void
  8482 nsGlobalWindow::EnterModalState()
  8484   MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
  8486   // GetScriptableTop, not GetTop, so that EnterModalState works properly with
  8487   // <iframe mozbrowser>.
  8488   nsGlobalWindow* topWin = GetScriptableTop();
  8490   if (!topWin) {
  8491     NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
  8492     return;
  8495   // If there is an active ESM in this window, clear it. Otherwise, this can
  8496   // cause a problem if a modal state is entered during a mouseup event.
  8497   EventStateManager* activeESM =
  8498     static_cast<EventStateManager*>(
  8499       EventStateManager::GetActiveEventStateManager());
  8500   if (activeESM && activeESM->GetPresContext()) {
  8501     nsIPresShell* activeShell = activeESM->GetPresContext()->GetPresShell();
  8502     if (activeShell && (
  8503         nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(), mDoc) ||
  8504         nsContentUtils::ContentIsCrossDocDescendantOf(mDoc, activeShell->GetDocument()))) {
  8505       EventStateManager::ClearGlobalActiveContent(activeESM);
  8507       activeShell->SetCapturingContent(nullptr, 0);
  8509       if (activeShell) {
  8510         nsRefPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
  8511         frameSelection->SetMouseDownState(false);
  8516   // If there are any drag and drop operations in flight, try to end them.
  8517   nsCOMPtr<nsIDragService> ds =
  8518     do_GetService("@mozilla.org/widget/dragservice;1");
  8519   if (ds) {
  8520     ds->EndDragSession(true);
  8523   // Clear the capturing content if it is under topDoc.
  8524   // Usually the activeESM check above does that, but there are cases when
  8525   // we don't have activeESM, or it is for different document.
  8526   nsIDocument* topDoc = topWin->GetExtantDoc();
  8527   nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
  8528   if (capturingContent && topDoc &&
  8529       nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
  8530     nsIPresShell::SetCapturingContent(nullptr, 0);
  8533   if (topWin->mModalStateDepth == 0) {
  8534     NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
  8536     mSuspendedDoc = topDoc;
  8537     if (mSuspendedDoc) {
  8538       mSuspendedDoc->SuppressEventHandling(nsIDocument::eAnimationsOnly);
  8541   topWin->mModalStateDepth++;
  8544 // static
  8545 void
  8546 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
  8547                                             nsGlobalWindow *aWindow)
  8549   nsGlobalWindow *inner;
  8551   // Return early if we're frozen or have no inner window.
  8552   if (!(inner = aWindow->GetCurrentInnerWindowInternal()) ||
  8553       inner->IsFrozen()) {
  8554     return;
  8557   inner->RunTimeout(nullptr);
  8559   // Check again if we're frozen since running pending timeouts
  8560   // could've frozen us.
  8561   if (inner->IsFrozen()) {
  8562     return;
  8565   nsCOMPtr<nsIDOMWindowCollection> frames;
  8566   aWindow->GetFrames(getter_AddRefs(frames));
  8568   if (!frames) {
  8569     return;
  8572   uint32_t i, length;
  8573   if (NS_FAILED(frames->GetLength(&length)) || !length) {
  8574     return;
  8577   for (i = 0; i < length && aTopWindow->mModalStateDepth == 0; i++) {
  8578     nsCOMPtr<nsIDOMWindow> child;
  8579     frames->Item(i, getter_AddRefs(child));
  8581     if (!child) {
  8582       return;
  8585     nsGlobalWindow *childWin =
  8586       static_cast<nsGlobalWindow *>
  8587                  (static_cast<nsIDOMWindow *>
  8588                              (child.get()));
  8590     RunPendingTimeoutsRecursive(aTopWindow, childWin);
  8594 class nsPendingTimeoutRunner : public nsRunnable
  8596 public:
  8597   nsPendingTimeoutRunner(nsGlobalWindow *aWindow)
  8598     : mWindow(aWindow)
  8600     NS_ASSERTION(mWindow, "mWindow is null.");
  8603   NS_IMETHOD Run()
  8605     nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow, mWindow);
  8607     return NS_OK;
  8610 private:
  8611   nsRefPtr<nsGlobalWindow> mWindow;
  8612 };
  8614 void
  8615 nsGlobalWindow::LeaveModalState()
  8617   MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
  8619   nsGlobalWindow* topWin = GetScriptableTop();
  8621   if (!topWin) {
  8622     NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
  8623     return;
  8626   topWin->mModalStateDepth--;
  8628   if (topWin->mModalStateDepth == 0) {
  8629     nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
  8630     if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
  8631       NS_WARNING("failed to dispatch pending timeout runnable");
  8633     if (mSuspendedDoc) {
  8634       nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
  8635       mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly,
  8636                                                           currentDoc == mSuspendedDoc);
  8637       mSuspendedDoc = nullptr;
  8641   // Remember the time of the last dialog quit.
  8642   nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
  8643   if (inner)
  8644     inner->mLastDialogQuitTime = TimeStamp::Now();
  8647 bool
  8648 nsGlobalWindow::IsInModalState()
  8650   nsGlobalWindow *topWin = GetScriptableTop();
  8652   if (!topWin) {
  8653     NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
  8655     return false;
  8658   return topWin->mModalStateDepth != 0;
  8661 // static
  8662 void
  8663 nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
  8664   nsCOMPtr<nsIObserverService> observerService =
  8665     services::GetObserverService();
  8666   if (observerService) {
  8667     observerService->
  8668       NotifyObservers(ToSupports(aWindow),
  8669                       DOM_WINDOW_DESTROYED_TOPIC, nullptr);
  8673 class WindowDestroyedEvent : public nsRunnable
  8675 public:
  8676   WindowDestroyedEvent(nsPIDOMWindow* aWindow, uint64_t aID,
  8677                        const char* aTopic) :
  8678     mID(aID), mTopic(aTopic)
  8680     mWindow = do_GetWeakReference(aWindow);
  8683   NS_IMETHOD Run()
  8685     nsCOMPtr<nsIObserverService> observerService =
  8686       do_GetService("@mozilla.org/observer-service;1");
  8687     if (observerService) {
  8688       nsCOMPtr<nsISupportsPRUint64> wrapper =
  8689         do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
  8690       if (wrapper) {
  8691         wrapper->SetData(mID);
  8692         observerService->NotifyObservers(wrapper, mTopic.get(), nullptr);
  8696     bool skipNukeCrossCompartment = false;
  8697 #ifndef DEBUG
  8698     nsCOMPtr<nsIAppStartup> appStartup =
  8699       do_GetService(NS_APPSTARTUP_CONTRACTID);
  8701     if (appStartup) {
  8702       appStartup->GetShuttingDown(&skipNukeCrossCompartment);
  8704 #endif
  8706     nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
  8707     if (!skipNukeCrossCompartment && window) {
  8708       nsGlobalWindow* currentInner =
  8709         window->IsInnerWindow() ? static_cast<nsGlobalWindow*>(window.get()) :
  8710                                   static_cast<nsGlobalWindow*>(window->GetCurrentInnerWindow());
  8711       NS_ENSURE_TRUE(currentInner, NS_OK);
  8713       AutoSafeJSContext cx;
  8714       JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
  8715       // We only want to nuke wrappers for the chrome->content case
  8716       if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
  8717         js::NukeCrossCompartmentWrappers(cx,
  8718                                          js::ChromeCompartmentsOnly(),
  8719                                          js::SingleCompartment(js::GetObjectCompartment(obj)),
  8720                                          window->IsInnerWindow() ? js::DontNukeWindowReferences :
  8721                                                                    js::NukeWindowReferences);
  8725     return NS_OK;
  8728 private:
  8729   uint64_t mID;
  8730   nsCString mTopic;
  8731   nsWeakPtr mWindow;
  8732 };
  8734 void
  8735 nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
  8737   nsRefPtr<nsIRunnable> runnable = new WindowDestroyedEvent(this, mWindowID, aTopic);
  8738   nsresult rv = NS_DispatchToCurrentThread(runnable);
  8739   if (NS_SUCCEEDED(rv)) {
  8740     mNotifiedIDDestroyed = true;
  8744 // static
  8745 void
  8746 nsGlobalWindow::NotifyDOMWindowFrozen(nsGlobalWindow* aWindow) {
  8747   if (aWindow && aWindow->IsInnerWindow()) {
  8748     nsCOMPtr<nsIObserverService> observerService =
  8749       services::GetObserverService();
  8750     if (observerService) {
  8751       observerService->
  8752         NotifyObservers(ToSupports(aWindow),
  8753                         DOM_WINDOW_FROZEN_TOPIC, nullptr);
  8758 // static
  8759 void
  8760 nsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindow* aWindow) {
  8761   if (aWindow && aWindow->IsInnerWindow()) {
  8762     nsCOMPtr<nsIObserverService> observerService =
  8763       services::GetObserverService();
  8764     if (observerService) {
  8765       observerService->
  8766         NotifyObservers(ToSupports(aWindow),
  8767                         DOM_WINDOW_THAWED_TOPIC, nullptr);
  8772 JSObject*
  8773 nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
  8775   AutoSafeJSContext cx;
  8776   JS::Rooted<JSObject*> handler(cx);
  8777   if (mCachedXBLPrototypeHandlers) {
  8778     mCachedXBLPrototypeHandlers->Get(aKey, handler.address());
  8780   return handler;
  8783 void
  8784 nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
  8785                                          JS::Handle<JSObject*> aHandler)
  8787   if (!mCachedXBLPrototypeHandlers) {
  8788     mCachedXBLPrototypeHandlers = new nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>();
  8789     PreserveWrapper(ToSupports(this));
  8792   mCachedXBLPrototypeHandlers->Put(aKey, aHandler);
  8795 /**
  8796  * GetScriptableFrameElement is called when script reads
  8797  * nsIGlobalWindow::frameElement.
  8799  * In contrast to GetRealFrameElement, GetScriptableFrameElement says that the
  8800  * window contained by an <iframe mozbrowser> or <iframe mozapp> has no frame
  8801  * element (effectively treating a mozbrowser the same as a content/chrome
  8802  * boundary).
  8803  */
  8804 NS_IMETHODIMP
  8805 nsGlobalWindow::GetScriptableFrameElement(nsIDOMElement** aFrameElement)
  8807   ErrorResult rv;
  8808   nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(GetFrameElement(rv));
  8809   if (rv.Failed()) {
  8810     return rv.ErrorCode();
  8813   frameElement.forget(aFrameElement);
  8815   return NS_OK;
  8818 Element*
  8819 nsGlobalWindow::GetFrameElement(ErrorResult& aError)
  8821   FORWARD_TO_OUTER_OR_THROW(GetFrameElement, (aError), aError, nullptr);
  8823   if (!mDocShell || mDocShell->GetIsBrowserOrApp()) {
  8824     return nullptr;
  8827   // Per HTML5, the frameElement getter returns null in cross-origin situations.
  8828   Element* element = GetRealFrameElement(aError);
  8829   if (aError.Failed() || !element) {
  8830     return nullptr;
  8832   if (!nsContentUtils::GetSubjectPrincipal()->
  8833          SubsumesConsideringDomain(element->NodePrincipal())) {
  8834     return nullptr;
  8836   return element;
  8839 Element*
  8840 nsGlobalWindow::GetRealFrameElement(ErrorResult& aError)
  8842   FORWARD_TO_OUTER_OR_THROW(GetRealFrameElement, (aError), aError, nullptr);
  8844   if (!mDocShell) {
  8845     return nullptr;
  8848   nsCOMPtr<nsIDocShell> parent;
  8849   mDocShell->GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
  8851   if (!parent || parent == mDocShell) {
  8852     // We're at a chrome boundary, don't expose the chrome iframe
  8853     // element to content code.
  8854     return nullptr;
  8857   return mFrameElement;
  8860 /**
  8861  * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper
  8862  * around GetRealFrameElement.
  8863  */
  8864 NS_IMETHODIMP
  8865 nsGlobalWindow::GetRealFrameElement(nsIDOMElement** aFrameElement)
  8867   ErrorResult rv;
  8868   nsCOMPtr<nsIDOMElement> frameElement =
  8869     do_QueryInterface(GetRealFrameElement(rv));
  8870   frameElement.forget(aFrameElement);
  8872   return rv.ErrorCode();
  8875 // Helper for converting window.showModalDialog() options (list of ';'
  8876 // separated name (:|=) value pairs) to a format that's parsable by
  8877 // our normal window opening code.
  8879 void
  8880 ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult)
  8882   nsAString::const_iterator end;
  8883   aOptions.EndReading(end);
  8885   nsAString::const_iterator iter;
  8886   aOptions.BeginReading(iter);
  8888   while (iter != end) {
  8889     // Skip whitespace.
  8890     while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
  8891       ++iter;
  8894     nsAString::const_iterator name_start = iter;
  8896     // Skip characters until we find whitespace, ';', ':', or '='
  8897     while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
  8898            *iter != ';' &&
  8899            *iter != ':' &&
  8900            *iter != '=') {
  8901       ++iter;
  8904     nsAString::const_iterator name_end = iter;
  8906     // Skip whitespace.
  8907     while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
  8908       ++iter;
  8911     if (*iter == ';') {
  8912       // No value found, skip the ';' and keep going.
  8913       ++iter;
  8915       continue;
  8918     nsAString::const_iterator value_start = iter;
  8919     nsAString::const_iterator value_end = iter;
  8921     if (*iter == ':' || *iter == '=') {
  8922       // We found name followed by ':' or '='. Look for a value.
  8924       iter++; // Skip the ':' or '='
  8926       // Skip whitespace.
  8927       while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
  8928         ++iter;
  8931       value_start = iter;
  8933       // Skip until we find whitespace, or ';'.
  8934       while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
  8935              *iter != ';') {
  8936         ++iter;
  8939       value_end = iter;
  8941       // Skip whitespace.
  8942       while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
  8943         ++iter;
  8947     const nsDependentSubstring& name = Substring(name_start, name_end);
  8948     const nsDependentSubstring& value = Substring(value_start, value_end);
  8950     if (name.LowerCaseEqualsLiteral("center")) {
  8951       if (value.LowerCaseEqualsLiteral("on")  ||
  8952           value.LowerCaseEqualsLiteral("yes") ||
  8953           value.LowerCaseEqualsLiteral("1")) {
  8954         aResult.AppendLiteral(",centerscreen=1");
  8956     } else if (name.LowerCaseEqualsLiteral("dialogwidth")) {
  8957       if (!value.IsEmpty()) {
  8958         aResult.AppendLiteral(",width=");
  8959         aResult.Append(value);
  8961     } else if (name.LowerCaseEqualsLiteral("dialogheight")) {
  8962       if (!value.IsEmpty()) {
  8963         aResult.AppendLiteral(",height=");
  8964         aResult.Append(value);
  8966     } else if (name.LowerCaseEqualsLiteral("dialogtop")) {
  8967       if (!value.IsEmpty()) {
  8968         aResult.AppendLiteral(",top=");
  8969         aResult.Append(value);
  8971     } else if (name.LowerCaseEqualsLiteral("dialogleft")) {
  8972       if (!value.IsEmpty()) {
  8973         aResult.AppendLiteral(",left=");
  8974         aResult.Append(value);
  8976     } else if (name.LowerCaseEqualsLiteral("resizable")) {
  8977       if (value.LowerCaseEqualsLiteral("on")  ||
  8978           value.LowerCaseEqualsLiteral("yes") ||
  8979           value.LowerCaseEqualsLiteral("1")) {
  8980         aResult.AppendLiteral(",resizable=1");
  8982     } else if (name.LowerCaseEqualsLiteral("scroll")) {
  8983       if (value.LowerCaseEqualsLiteral("off")  ||
  8984           value.LowerCaseEqualsLiteral("no") ||
  8985           value.LowerCaseEqualsLiteral("0")) {
  8986         aResult.AppendLiteral(",scrollbars=0");
  8990     if (iter == end) {
  8991       break;
  8994     iter++;
  8998 already_AddRefed<nsIVariant>
  8999 nsGlobalWindow::ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument,
  9000                                 const nsAString& aOptions, ErrorResult& aError)
  9002   if (mDoc) {
  9003     mDoc->WarnOnceAbout(nsIDocument::eShowModalDialog);
  9006   FORWARD_TO_OUTER_OR_THROW(ShowModalDialog,
  9007                             (aUrl, aArgument, aOptions, aError), aError,
  9008                             nullptr);
  9010   if (Preferences::GetBool("dom.disable_window_showModalDialog", false)) {
  9011     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  9012     return nullptr;
  9015   nsRefPtr<DialogValueHolder> argHolder =
  9016     new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(), aArgument);
  9018   // Before bringing up the window/dialog, unsuppress painting and flush
  9019   // pending reflows.
  9020   EnsureReflowFlushAndPaint();
  9022   if (!AreDialogsEnabled()) {
  9023     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  9024     return nullptr;
  9027   if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
  9028     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  9029     return nullptr;
  9032   nsCOMPtr<nsIDOMWindow> dlgWin;
  9033   nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
  9035   ConvertDialogOptions(aOptions, options);
  9037   options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
  9039   EnterModalState();
  9040   uint32_t oldMicroTaskLevel = nsContentUtils::MicroTaskLevel();
  9041   nsContentUtils::SetMicroTaskLevel(0);
  9042   aError = OpenInternal(aUrl, EmptyString(), options,
  9043                         false,          // aDialog
  9044                         true,           // aContentModal
  9045                         true,           // aCalledNoScript
  9046                         true,           // aDoJSFixups
  9047                         true,           // aNavigate
  9048                         nullptr, argHolder, // args
  9049                         GetPrincipal(),     // aCalleePrincipal
  9050                         nullptr,            // aJSCallerContext
  9051                         getter_AddRefs(dlgWin));
  9052   nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel);
  9053   LeaveModalState();
  9054   if (aError.Failed()) {
  9055     return nullptr;
  9058   nsCOMPtr<nsIDOMModalContentWindow> dialog = do_QueryInterface(dlgWin);
  9059   if (!dialog) {
  9060     return nullptr;
  9063   nsCOMPtr<nsIVariant> retVal;
  9064   aError = dialog->GetReturnValue(getter_AddRefs(retVal));
  9065   MOZ_ASSERT(!aError.Failed());
  9067   return retVal.forget();
  9070 void
  9071 nsGlobalWindow::ShowModalDialog(JSContext* aCx, const nsAString& aUrl,
  9072                                 JS::Handle<JS::Value> aArgument,
  9073                                 const nsAString& aOptions,
  9074                                 JS::MutableHandle<JS::Value> aRetval,
  9075                                 ErrorResult& aError)
  9077   nsCOMPtr<nsIVariant> args;
  9078   aError = nsContentUtils::XPConnect()->JSToVariant(aCx,
  9079                                                     aArgument,
  9080                                                     getter_AddRefs(args));
  9082   nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aUrl, args, aOptions, aError);
  9083   if (aError.Failed()) {
  9084     return;
  9087   JS::Rooted<JS::Value> result(aCx);
  9088   if (retVal) {
  9089     aError = nsContentUtils::XPConnect()->VariantToJS(aCx,
  9090                                                       FastGetGlobalJSObject(),
  9091                                                       retVal, aRetval);
  9092   } else {
  9093     aRetval.setNull();
  9097 NS_IMETHODIMP
  9098 nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs_,
  9099                                 const nsAString& aOptions, uint8_t aArgc,
  9100                                 nsIVariant **aRetVal)
  9102   // Per-spec the |arguments| parameter is supposed to pass through unmodified.
  9103   // However, XPConnect default-initializes variants to null, rather than
  9104   // undefined. Fix this up here.
  9105   nsCOMPtr<nsIVariant> aArgs = aArgs_;
  9106   if (aArgc < 1) {
  9107     aArgs = CreateVoidVariant();
  9110   ErrorResult rv;
  9111   nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aURI, aArgs, aOptions, rv);
  9112   retVal.forget(aRetVal);
  9114   return rv.ErrorCode();
  9117 class CommandDispatcher : public nsRunnable
  9119 public:
  9120   CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
  9121                     const nsAString& aAction)
  9122   : mDispatcher(aDispatcher), mAction(aAction) {}
  9124   NS_IMETHOD Run()
  9126     return mDispatcher->UpdateCommands(mAction);
  9129   nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
  9130   nsString                             mAction;
  9131 };
  9133 NS_IMETHODIMP
  9134 nsGlobalWindow::UpdateCommands(const nsAString& anAction)
  9136   nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
  9137   if (!rootWindow)
  9138     return NS_OK;
  9140   nsCOMPtr<nsIDOMXULDocument> xulDoc =
  9141     do_QueryInterface(rootWindow->GetExtantDoc());
  9142   // See if we contain a XUL document.
  9143   if (xulDoc) {
  9144     // Retrieve the command dispatcher and call updateCommands on it.
  9145     nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
  9146     xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
  9147     if (xulCommandDispatcher) {
  9148       nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
  9149                                                             anAction));
  9153   return NS_OK;
  9156 Selection*
  9157 nsGlobalWindow::GetSelection(ErrorResult& aError)
  9159   FORWARD_TO_OUTER_OR_THROW(GetSelection, (aError), aError, nullptr);
  9161   if (!mDocShell) {
  9162     return nullptr;
  9165   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  9166   if (!presShell) {
  9167     return nullptr;
  9170   return static_cast<Selection*>(presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL));
  9173 NS_IMETHODIMP
  9174 nsGlobalWindow::GetSelection(nsISelection** aSelection)
  9176   ErrorResult rv;
  9177   nsCOMPtr<nsISelection> selection = GetSelection(rv);
  9178   selection.forget(aSelection);
  9180   return rv.ErrorCode();
  9183 bool
  9184 nsGlobalWindow::Find(const nsAString& aString, bool aCaseSensitive,
  9185                      bool aBackwards, bool aWrapAround, bool aWholeWord,
  9186                      bool aSearchInFrames, bool aShowDialog,
  9187                      ErrorResult& aError)
  9189   if (Preferences::GetBool("dom.disable_window_find", false)) {
  9190     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  9191     return false;
  9194   FORWARD_TO_OUTER_OR_THROW(Find,
  9195                             (aString, aCaseSensitive, aBackwards, aWrapAround,
  9196                              aWholeWord, aSearchInFrames, aShowDialog, aError),
  9197                             aError, false);
  9199   nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
  9200   if (!finder) {
  9201     aError.Throw(NS_ERROR_NOT_AVAILABLE);
  9202     return false;
  9205   // Set the options of the search
  9206   aError = finder->SetSearchString(PromiseFlatString(aString).get());
  9207   if (aError.Failed()) {
  9208     return false;
  9210   finder->SetMatchCase(aCaseSensitive);
  9211   finder->SetFindBackwards(aBackwards);
  9212   finder->SetWrapFind(aWrapAround);
  9213   finder->SetEntireWord(aWholeWord);
  9214   finder->SetSearchFrames(aSearchInFrames);
  9216   // the nsIWebBrowserFind is initialized to use this window
  9217   // as the search root, but uses focus to set the current search
  9218   // frame. If we're being called from JS (as here), this window
  9219   // should be the current search frame.
  9220   nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
  9221   if (framesFinder) {
  9222     framesFinder->SetRootSearchFrame(this);   // paranoia
  9223     framesFinder->SetCurrentSearchFrame(this);
  9226   // The Find API does not accept empty strings. Launch the Find Dialog.
  9227   if (aString.IsEmpty() || aShowDialog) {
  9228     // See if the find dialog is already up using nsIWindowMediator
  9229     nsCOMPtr<nsIWindowMediator> windowMediator =
  9230       do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
  9232     nsCOMPtr<nsIDOMWindow> findDialog;
  9234     if (windowMediator) {
  9235       windowMediator->GetMostRecentWindow(MOZ_UTF16("findInPage"),
  9236                                           getter_AddRefs(findDialog));
  9239     if (findDialog) {
  9240       // The Find dialog is already open, bring it to the top.
  9241       aError = findDialog->Focus();
  9242     } else if (finder) {
  9243       // Open a Find dialog
  9244       nsCOMPtr<nsIDOMWindow> dialog;
  9245       aError = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
  9246                           NS_LITERAL_STRING("_blank"),
  9247                           NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
  9248                           finder, getter_AddRefs(dialog));
  9251     return false;
  9254   // Launch the search with the passed in search string
  9255   bool didFind = false;
  9256   aError = finder->FindNext(&didFind);
  9257   return didFind;
  9260 NS_IMETHODIMP
  9261 nsGlobalWindow::Find(const nsAString& aStr, bool aCaseSensitive,
  9262                      bool aBackwards, bool aWrapAround, bool aWholeWord,
  9263                      bool aSearchInFrames, bool aShowDialog,
  9264                      bool *aDidFind)
  9266   ErrorResult rv;
  9267   *aDidFind = Find(aStr, aCaseSensitive, aBackwards, aWrapAround, aWholeWord,
  9268                    aSearchInFrames, aShowDialog, rv);
  9270   return rv.ErrorCode();
  9273 void
  9274 nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
  9275                      nsAString& aBinaryData, ErrorResult& aError)
  9277   aError = nsContentUtils::Atob(aAsciiBase64String, aBinaryData);
  9280 NS_IMETHODIMP
  9281 nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
  9282                      nsAString& aBinaryData)
  9284   ErrorResult rv;
  9285   Atob(aAsciiBase64String, aBinaryData, rv);
  9287   return rv.ErrorCode();
  9290 void
  9291 nsGlobalWindow::Btoa(const nsAString& aBinaryData,
  9292                      nsAString& aAsciiBase64String, ErrorResult& aError)
  9294   aError = nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
  9297 NS_IMETHODIMP
  9298 nsGlobalWindow::Btoa(const nsAString& aBinaryData,
  9299                      nsAString& aAsciiBase64String)
  9301   ErrorResult rv;
  9302   Btoa(aBinaryData, aAsciiBase64String, rv);
  9304   return rv.ErrorCode();
  9307 //*****************************************************************************
  9308 // nsGlobalWindow::nsIDOMEventTarget
  9309 //*****************************************************************************
  9311 NS_IMETHODIMP
  9312 nsGlobalWindow::RemoveEventListener(const nsAString& aType,
  9313                                     nsIDOMEventListener* aListener,
  9314                                     bool aUseCapture)
  9316   if (nsRefPtr<EventListenerManager> elm = GetExistingListenerManager()) {
  9317     elm->RemoveEventListener(aType, aListener, aUseCapture);
  9319   return NS_OK;
  9322 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)
  9324 NS_IMETHODIMP
  9325 nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
  9327   FORWARD_TO_INNER(DispatchEvent, (aEvent, aRetVal), NS_OK);
  9329   if (!IsCurrentInnerWindow()) {
  9330     NS_WARNING("DispatchEvent called on non-current inner window, dropping. "
  9331                "Please check the window in the caller instead.");
  9332     return NS_ERROR_FAILURE;
  9335   if (!mDoc) {
  9336     return NS_ERROR_FAILURE;
  9339   // Obtain a presentation shell
  9340   nsIPresShell *shell = mDoc->GetShell();
  9341   nsRefPtr<nsPresContext> presContext;
  9342   if (shell) {
  9343     // Retrieve the context
  9344     presContext = shell->GetPresContext();
  9347   nsEventStatus status = nsEventStatus_eIgnore;
  9348   nsresult rv =
  9349     EventDispatcher::DispatchDOMEvent(GetOuterWindow(), nullptr, aEvent,
  9350                                       presContext, &status);
  9352   *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
  9353   return rv;
  9356 NS_IMETHODIMP
  9357 nsGlobalWindow::AddEventListener(const nsAString& aType,
  9358                                  nsIDOMEventListener *aListener,
  9359                                  bool aUseCapture, bool aWantsUntrusted,
  9360                                  uint8_t aOptionalArgc)
  9362   NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
  9363                "Won't check if this is chrome, you want to set "
  9364                "aWantsUntrusted to false or make the aWantsUntrusted "
  9365                "explicit by making optional_argc non-zero.");
  9367   if (IsOuterWindow() && mInnerWindow &&
  9368       !nsContentUtils::CanCallerAccess(mInnerWindow)) {
  9369     return NS_ERROR_DOM_SECURITY_ERR;
  9372   if (!aWantsUntrusted &&
  9373       (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
  9374     aWantsUntrusted = true;
  9377   EventListenerManager* manager = GetOrCreateListenerManager();
  9378   NS_ENSURE_STATE(manager);
  9379   manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
  9380   return NS_OK;
  9383 void
  9384 nsGlobalWindow::AddEventListener(const nsAString& aType,
  9385                                  EventListener* aListener,
  9386                                  bool aUseCapture,
  9387                                  const Nullable<bool>& aWantsUntrusted,
  9388                                  ErrorResult& aRv)
  9390   if (IsOuterWindow() && mInnerWindow &&
  9391       !nsContentUtils::CanCallerAccess(mInnerWindow)) {
  9392     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  9393     return;
  9396   bool wantsUntrusted;
  9397   if (aWantsUntrusted.IsNull()) {
  9398     wantsUntrusted = !nsContentUtils::IsChromeDoc(mDoc);
  9399   } else {
  9400     wantsUntrusted = aWantsUntrusted.Value();
  9403   EventListenerManager* manager = GetOrCreateListenerManager();
  9404   if (!manager) {
  9405     aRv.Throw(NS_ERROR_UNEXPECTED);
  9406     return;
  9408   manager->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
  9411 NS_IMETHODIMP
  9412 nsGlobalWindow::AddSystemEventListener(const nsAString& aType,
  9413                                        nsIDOMEventListener *aListener,
  9414                                        bool aUseCapture,
  9415                                        bool aWantsUntrusted,
  9416                                        uint8_t aOptionalArgc)
  9418   NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
  9419                "Won't check if this is chrome, you want to set "
  9420                "aWantsUntrusted to false or make the aWantsUntrusted "
  9421                "explicit by making optional_argc non-zero.");
  9423   if (IsOuterWindow() && mInnerWindow &&
  9424       !nsContentUtils::CanCallerAccess(mInnerWindow)) {
  9425     return NS_ERROR_DOM_SECURITY_ERR;
  9428   if (!aWantsUntrusted &&
  9429       (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
  9430     aWantsUntrusted = true;
  9433   return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
  9434                                    aWantsUntrusted);
  9437 EventListenerManager*
  9438 nsGlobalWindow::GetOrCreateListenerManager()
  9440   FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager, (), nullptr);
  9442   if (!mListenerManager) {
  9443     mListenerManager =
  9444       new EventListenerManager(static_cast<EventTarget*>(this));
  9447   return mListenerManager;
  9450 EventListenerManager*
  9451 nsGlobalWindow::GetExistingListenerManager() const
  9453   FORWARD_TO_INNER(GetExistingListenerManager, (), nullptr);
  9455   return mListenerManager;
  9458 nsIScriptContext*
  9459 nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
  9461   *aRv = NS_ERROR_UNEXPECTED;
  9462   NS_ENSURE_TRUE(!IsInnerWindow() || IsCurrentInnerWindow(), nullptr);
  9464   nsIScriptContext* scx;
  9465   if ((scx = GetContext())) {
  9466     *aRv = NS_OK;
  9467     return scx;
  9469   return nullptr;
  9472 //*****************************************************************************
  9473 // nsGlobalWindow::nsPIDOMWindow
  9474 //*****************************************************************************
  9476 nsPIDOMWindow*
  9477 nsGlobalWindow::GetPrivateParent()
  9479   MOZ_ASSERT(IsOuterWindow());
  9481   nsCOMPtr<nsIDOMWindow> parent;
  9482   GetParent(getter_AddRefs(parent));
  9484   if (static_cast<nsIDOMWindow *>(this) == parent.get()) {
  9485     nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
  9486     if (!chromeElement)
  9487       return nullptr;             // This is ok, just means a null parent.
  9489     nsIDocument* doc = chromeElement->GetDocument();
  9490     if (!doc)
  9491       return nullptr;             // This is ok, just means a null parent.
  9493     return doc->GetWindow();
  9496   if (parent) {
  9497     return static_cast<nsGlobalWindow *>
  9498                       (static_cast<nsIDOMWindow*>(parent.get()));
  9501   return nullptr;
  9504 nsPIDOMWindow*
  9505 nsGlobalWindow::GetPrivateRoot()
  9507   if (IsInnerWindow()) {
  9508     nsGlobalWindow* outer = GetOuterWindowInternal();
  9509     if (!outer) {
  9510       NS_WARNING("No outer window available!");
  9511       return nullptr;
  9513     return outer->GetPrivateRoot();
  9516   nsCOMPtr<nsIDOMWindow> top;
  9517   GetTop(getter_AddRefs(top));
  9519   nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
  9520   if (chromeElement) {
  9521     nsIDocument* doc = chromeElement->GetDocument();
  9522     if (doc) {
  9523       nsIDOMWindow *parent = doc->GetWindow();
  9524       if (parent) {
  9525         parent->GetTop(getter_AddRefs(top));
  9530   return static_cast<nsGlobalWindow*>(top.get());
  9534 nsIDOMLocation*
  9535 nsGlobalWindow::GetLocation(ErrorResult& aError)
  9537   FORWARD_TO_INNER_OR_THROW(GetLocation, (aError), aError, nullptr);
  9539   nsIDocShell *docShell = GetDocShell();
  9540   if (!mLocation && docShell) {
  9541     mLocation = new nsLocation(docShell);
  9543   return mLocation;
  9546 NS_IMETHODIMP
  9547 nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
  9549   ErrorResult rv;
  9550   nsCOMPtr<nsIDOMLocation> location = GetLocation(rv);
  9551   location.forget(aLocation);
  9553   return rv.ErrorCode();
  9556 void
  9557 nsGlobalWindow::ActivateOrDeactivate(bool aActivate)
  9559   MOZ_ASSERT(IsOuterWindow());
  9561   // Set / unset mIsActive on the top level window, which is used for the
  9562   // :-moz-window-inactive pseudoclass, and its sheet (if any).
  9563   nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
  9564   if (!mainWidget)
  9565     return;
  9567   // Get the top level widget (if the main widget is a sheet, this will
  9568   // be the sheet's top (non-sheet) parent).
  9569   nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
  9570   if (!topLevelWidget) {
  9571     topLevelWidget = mainWidget;
  9574   nsCOMPtr<nsPIDOMWindow> piMainWindow(
  9575     do_QueryInterface(static_cast<nsIDOMWindow*>(this)));
  9576   piMainWindow->SetActive(aActivate);
  9578   if (mainWidget != topLevelWidget) {
  9579     // This is a workaround for the following problem:
  9580     // When a window with an open sheet gains or loses focus, only the sheet
  9581     // window receives the NS_ACTIVATE/NS_DEACTIVATE event.  However the
  9582     // styling of the containing top level window also needs to change.  We
  9583     // get around this by calling nsPIDOMWindow::SetActive() on both windows.
  9585     // Get the top level widget's nsGlobalWindow
  9586     nsCOMPtr<nsIDOMWindow> topLevelWindow;
  9588     // widgetListener should be a nsXULWindow
  9589     nsIWidgetListener* listener = topLevelWidget->GetWidgetListener();
  9590     if (listener) {
  9591       nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
  9592       nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
  9593       topLevelWindow = do_GetInterface(req);
  9596     if (topLevelWindow) {
  9597       nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
  9598       piWin->SetActive(aActivate);
  9603 static bool
  9604 NotifyDocumentTree(nsIDocument* aDocument, void* aData)
  9606   aDocument->EnumerateSubDocuments(NotifyDocumentTree, nullptr);
  9607   aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
  9608   return true;
  9611 void
  9612 nsGlobalWindow::SetActive(bool aActive)
  9614   nsPIDOMWindow::SetActive(aActive);
  9615   NotifyDocumentTree(mDoc, nullptr);
  9618 void nsGlobalWindow::SetIsBackground(bool aIsBackground)
  9620   MOZ_ASSERT(IsOuterWindow());
  9622   bool resetTimers = (!aIsBackground && IsBackground());
  9623   nsPIDOMWindow::SetIsBackground(aIsBackground);
  9624   if (resetTimers) {
  9625     ResetTimersForNonBackgroundWindow();
  9627 #ifdef MOZ_GAMEPAD
  9628   if (!aIsBackground) {
  9629     nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
  9630     if (inner) {
  9631       inner->SyncGamepadState();
  9634 #endif
  9637 void nsGlobalWindow::MaybeUpdateTouchState()
  9639   FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
  9641   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  9643   nsCOMPtr<nsIDOMWindow> focusedWindow;
  9644   fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
  9646   if(this == focusedWindow) {
  9647     UpdateTouchState();
  9650   if (mMayHaveTouchEventListener) {
  9651     nsCOMPtr<nsIObserverService> observerService =
  9652       services::GetObserverService();
  9654     if (observerService) {
  9655       observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
  9656                                        DOM_TOUCH_LISTENER_ADDED,
  9657                                        nullptr);
  9662 void nsGlobalWindow::UpdateTouchState()
  9664   FORWARD_TO_INNER_VOID(UpdateTouchState, ());
  9666   nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
  9667   if (!mainWidget) {
  9668     return;
  9671   if (mMayHaveTouchEventListener) {
  9672     mainWidget->RegisterTouchWindow();
  9673   } else {
  9674     mainWidget->UnregisterTouchWindow();
  9678 void
  9679 nsGlobalWindow::EnableGamepadUpdates()
  9681   FORWARD_TO_INNER_VOID(EnableGamepadUpdates, ());
  9682   if (mHasGamepad) {
  9683 #ifdef MOZ_GAMEPAD
  9684     nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
  9685     if (gamepadsvc) {
  9686       gamepadsvc->AddListener(this);
  9688 #endif
  9692 void
  9693 nsGlobalWindow::DisableGamepadUpdates()
  9695   FORWARD_TO_INNER_VOID(DisableGamepadUpdates, ());
  9696   if (mHasGamepad) {
  9697 #ifdef MOZ_GAMEPAD
  9698     nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
  9699     if (gamepadsvc) {
  9700       gamepadsvc->RemoveListener(this);
  9702 #endif
  9706 void
  9707 nsGlobalWindow::SetChromeEventHandler(EventTarget* aChromeEventHandler)
  9709   MOZ_ASSERT(IsOuterWindow());
  9711   SetChromeEventHandlerInternal(aChromeEventHandler);
  9712   // update the chrome event handler on all our inner windows
  9713   for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
  9714        inner != this;
  9715        inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
  9716     NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
  9717                  "bad outer window pointer");
  9718     inner->SetChromeEventHandlerInternal(aChromeEventHandler);
  9722 static bool IsLink(nsIContent* aContent)
  9724   return aContent && (aContent->IsHTML(nsGkAtoms::a) ||
  9725                       aContent->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
  9726                                             nsGkAtoms::simple, eCaseMatters));
  9729 void
  9730 nsGlobalWindow::SetFocusedNode(nsIContent* aNode,
  9731                                uint32_t aFocusMethod,
  9732                                bool aNeedsFocus)
  9734   FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
  9736   if (aNode && aNode->GetCurrentDoc() != mDoc) {
  9737     NS_WARNING("Trying to set focus to a node from a wrong document");
  9738     return;
  9741   if (mCleanedUp) {
  9742     NS_ASSERTION(!aNode, "Trying to focus cleaned up window!");
  9743     aNode = nullptr;
  9744     aNeedsFocus = false;
  9746   if (mFocusedNode != aNode) {
  9747     UpdateCanvasFocus(false, aNode);
  9748     mFocusedNode = aNode;
  9749     mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
  9750     mShowFocusRingForContent = false;
  9753   if (mFocusedNode) {
  9754     // if a node was focused by a keypress, turn on focus rings for the
  9755     // window.
  9756     if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
  9757       mFocusByKeyOccurred = true;
  9758     } else if (
  9759       // otherwise, we set mShowFocusRingForContent, as we don't want this to
  9760       // be permanent for the window. On Windows, focus rings are only shown
  9761       // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
  9762       // are only hidden for clicks on links.
  9763 #ifndef XP_WIN
  9764       !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) || !IsLink(aNode) ||
  9765 #endif
  9766       aFocusMethod & nsIFocusManager::FLAG_SHOWRING) {
  9767         mShowFocusRingForContent = true;
  9771   if (aNeedsFocus)
  9772     mNeedsFocus = aNeedsFocus;
  9775 uint32_t
  9776 nsGlobalWindow::GetFocusMethod()
  9778   FORWARD_TO_INNER(GetFocusMethod, (), 0);
  9780   return mFocusMethod;
  9783 bool
  9784 nsGlobalWindow::ShouldShowFocusRing()
  9786   FORWARD_TO_INNER(ShouldShowFocusRing, (), false);
  9788   return mShowFocusRings || mShowFocusRingForContent || mFocusByKeyOccurred;
  9791 void
  9792 nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
  9793                                       UIStateChangeType aShowFocusRings)
  9795   FORWARD_TO_INNER_VOID(SetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
  9797   bool oldShouldShowFocusRing = ShouldShowFocusRing();
  9799   // only change the flags that have been modified
  9800   if (aShowAccelerators != UIStateChangeType_NoChange)
  9801     mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
  9802   if (aShowFocusRings != UIStateChangeType_NoChange)
  9803     mShowFocusRings = aShowFocusRings == UIStateChangeType_Set;
  9805   // propagate the indicators to child windows
  9806   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
  9807   if (docShell) {
  9808     int32_t childCount = 0;
  9809     docShell->GetChildCount(&childCount);
  9811     for (int32_t i = 0; i < childCount; ++i) {
  9812       nsCOMPtr<nsIDocShellTreeItem> childShell;
  9813       docShell->GetChildAt(i, getter_AddRefs(childShell));
  9814       nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(childShell);
  9815       if (childWindow) {
  9816         childWindow->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
  9821   bool newShouldShowFocusRing = ShouldShowFocusRing();
  9822   if (mHasFocus && mFocusedNode &&
  9823       oldShouldShowFocusRing != newShouldShowFocusRing &&
  9824       mFocusedNode->IsElement()) {
  9825     // Update mFocusedNode's state.
  9826     if (newShouldShowFocusRing) {
  9827       mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);
  9828     } else {
  9829       mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);
  9834 void
  9835 nsGlobalWindow::GetKeyboardIndicators(bool* aShowAccelerators,
  9836                                       bool* aShowFocusRings)
  9838   FORWARD_TO_INNER_VOID(GetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
  9840   *aShowAccelerators = mShowAccelerators;
  9841   *aShowFocusRings = mShowFocusRings;
  9844 bool
  9845 nsGlobalWindow::TakeFocus(bool aFocus, uint32_t aFocusMethod)
  9847   FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false);
  9849   if (mCleanedUp) {
  9850     return false;
  9853   if (aFocus)
  9854     mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
  9856   if (mHasFocus != aFocus) {
  9857     mHasFocus = aFocus;
  9858     UpdateCanvasFocus(true, mFocusedNode);
  9861   // if mNeedsFocus is true, then the document has not yet received a
  9862   // document-level focus event. If there is a root content node, then return
  9863   // true to tell the calling focus manager that a focus event is expected. If
  9864   // there is no root content node, the document hasn't loaded enough yet, or
  9865   // there isn't one and there is no point in firing a focus event.
  9866   if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nullptr) {
  9867     mNeedsFocus = false;
  9868     return true;
  9871   mNeedsFocus = false;
  9872   return false;
  9875 void
  9876 nsGlobalWindow::SetReadyForFocus()
  9878   FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
  9880   bool oldNeedsFocus = mNeedsFocus;
  9881   mNeedsFocus = false;
  9883   // update whether focus rings need to be shown using the state from the
  9884   // root window
  9885   nsPIDOMWindow* root = GetPrivateRoot();
  9886   if (root) {
  9887     bool showAccelerators, showFocusRings;
  9888     root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
  9889     mShowFocusRings = showFocusRings;
  9892   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  9893   if (fm)
  9894     fm->WindowShown(this, oldNeedsFocus);
  9897 void
  9898 nsGlobalWindow::PageHidden()
  9900   FORWARD_TO_INNER_VOID(PageHidden, ());
  9902   // the window is being hidden, so tell the focus manager that the frame is
  9903   // no longer valid. Use the persisted field to determine if the document
  9904   // is being destroyed.
  9906   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  9907   if (fm)
  9908     fm->WindowHidden(this);
  9910   mNeedsFocus = true;
  9913 class HashchangeCallback : public nsRunnable
  9915 public:
  9916   HashchangeCallback(const nsAString &aOldURL,
  9917                      const nsAString &aNewURL,
  9918                      nsGlobalWindow* aWindow)
  9919     : mWindow(aWindow)
  9921     MOZ_ASSERT(mWindow);
  9922     MOZ_ASSERT(mWindow->IsInnerWindow());
  9923     mOldURL.Assign(aOldURL);
  9924     mNewURL.Assign(aNewURL);
  9927   NS_IMETHOD Run()
  9929     NS_PRECONDITION(NS_IsMainThread(), "Should be called on the main thread.");
  9930     return mWindow->FireHashchange(mOldURL, mNewURL);
  9933 private:
  9934   nsString mOldURL;
  9935   nsString mNewURL;
  9936   nsRefPtr<nsGlobalWindow> mWindow;
  9937 };
  9939 nsresult
  9940 nsGlobalWindow::DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI)
  9942   FORWARD_TO_INNER(DispatchAsyncHashchange, (aOldURI, aNewURI), NS_OK);
  9944   // Make sure that aOldURI and aNewURI are identical up to the '#', and that
  9945   // their hashes are different.
  9946   nsAutoCString oldBeforeHash, oldHash, newBeforeHash, newHash;
  9947   nsContentUtils::SplitURIAtHash(aOldURI, oldBeforeHash, oldHash);
  9948   nsContentUtils::SplitURIAtHash(aNewURI, newBeforeHash, newHash);
  9950   NS_ENSURE_STATE(oldBeforeHash.Equals(newBeforeHash));
  9951   NS_ENSURE_STATE(!oldHash.Equals(newHash));
  9953   nsAutoCString oldSpec, newSpec;
  9954   aOldURI->GetSpec(oldSpec);
  9955   aNewURI->GetSpec(newSpec);
  9957   NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
  9958   NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
  9960   nsCOMPtr<nsIRunnable> callback =
  9961     new HashchangeCallback(oldWideSpec, newWideSpec, this);
  9962   return NS_DispatchToMainThread(callback);
  9965 nsresult
  9966 nsGlobalWindow::FireHashchange(const nsAString &aOldURL,
  9967                                const nsAString &aNewURL)
  9969   MOZ_ASSERT(IsInnerWindow());
  9971   // Don't do anything if the window is frozen.
  9972   if (IsFrozen())
  9973     return NS_OK;
  9975   // Get a presentation shell for use in creating the hashchange event.
  9976   NS_ENSURE_STATE(IsCurrentInnerWindow());
  9978   nsIPresShell *shell = mDoc->GetShell();
  9979   nsRefPtr<nsPresContext> presContext;
  9980   if (shell) {
  9981     presContext = shell->GetPresContext();
  9984   // Create a new hashchange event.
  9985   nsCOMPtr<nsIDOMEvent> domEvent;
  9986   nsresult rv =
  9987     EventDispatcher::CreateEvent(this, presContext, nullptr,
  9988                                  NS_LITERAL_STRING("hashchangeevent"),
  9989                                  getter_AddRefs(domEvent));
  9990   NS_ENSURE_SUCCESS(rv, rv);
  9992   nsCOMPtr<nsIDOMHashChangeEvent> hashchangeEvent = do_QueryInterface(domEvent);
  9993   NS_ENSURE_TRUE(hashchangeEvent, NS_ERROR_UNEXPECTED);
  9995   // The hashchange event bubbles and isn't cancellable.
  9996   rv = hashchangeEvent->InitHashChangeEvent(NS_LITERAL_STRING("hashchange"),
  9997                                             true, false,
  9998                                             aOldURL, aNewURL);
  9999   NS_ENSURE_SUCCESS(rv, rv);
 10001   domEvent->SetTrusted(true);
 10003   bool dummy;
 10004   return DispatchEvent(hashchangeEvent, &dummy);
 10007 nsresult
 10008 nsGlobalWindow::DispatchSyncPopState()
 10010   FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK);
 10012   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
 10013                "Must be safe to run script here.");
 10015   // Check that PopState hasn't been pref'ed off.
 10016   if (!Preferences::GetBool(sPopStatePrefStr, false)) {
 10017     return NS_OK;
 10020   nsresult rv = NS_OK;
 10022   // Bail if the window is frozen.
 10023   if (IsFrozen()) {
 10024     return NS_OK;
 10027   // Get the document's pending state object -- it contains the data we're
 10028   // going to send along with the popstate event.  The object is serialized
 10029   // using structured clone.
 10030   nsCOMPtr<nsIVariant> stateObj;
 10031   rv = mDoc->GetStateObject(getter_AddRefs(stateObj));
 10032   NS_ENSURE_SUCCESS(rv, rv);
 10034   // Obtain a presentation shell for use in creating a popstate event.
 10035   nsIPresShell *shell = mDoc->GetShell();
 10036   nsRefPtr<nsPresContext> presContext;
 10037   if (shell) {
 10038     presContext = shell->GetPresContext();
 10041   // Create a new popstate event
 10042   nsCOMPtr<nsIDOMEvent> domEvent;
 10043   rv = EventDispatcher::CreateEvent(this, presContext, nullptr,
 10044                                     NS_LITERAL_STRING("popstateevent"),
 10045                                     getter_AddRefs(domEvent));
 10046   NS_ENSURE_SUCCESS(rv, rv);
 10048   // Initialize the popstate event, which does bubble but isn't cancellable.
 10049   nsCOMPtr<nsIDOMPopStateEvent> popstateEvent = do_QueryInterface(domEvent);
 10050   rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"),
 10051                                         true, false,
 10052                                         stateObj);
 10053   NS_ENSURE_SUCCESS(rv, rv);
 10055   domEvent->SetTrusted(true);
 10057   nsCOMPtr<EventTarget> outerWindow =
 10058     do_QueryInterface(GetOuterWindow());
 10059   NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
 10061   rv = domEvent->SetTarget(outerWindow);
 10062   NS_ENSURE_SUCCESS(rv, rv);
 10064   bool dummy; // default action
 10065   return DispatchEvent(popstateEvent, &dummy);
 10068 // Find an nsICanvasFrame under aFrame.  Only search the principal
 10069 // child lists.  aFrame must be non-null.
 10070 static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
 10072     nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
 10073     if (canvasFrame) {
 10074         return canvasFrame;
 10077     nsIFrame* kid = aFrame->GetFirstPrincipalChild();
 10078     while (kid) {
 10079         canvasFrame = FindCanvasFrame(kid);
 10080         if (canvasFrame) {
 10081             return canvasFrame;
 10083         kid = kid->GetNextSibling();
 10086     return nullptr;
 10089 //-------------------------------------------------------
 10090 // Tells the HTMLFrame/CanvasFrame that is now has focus
 10091 void
 10092 nsGlobalWindow::UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent)
 10094   MOZ_ASSERT(IsInnerWindow());
 10096   // this is called from the inner window so use GetDocShell
 10097   nsIDocShell* docShell = GetDocShell();
 10098   if (!docShell)
 10099     return;
 10101   bool editable;
 10102   docShell->GetEditable(&editable);
 10103   if (editable)
 10104     return;
 10106   nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
 10107   if (!presShell || !mDoc)
 10108     return;
 10110   Element *rootElement = mDoc->GetRootElement();
 10111   if (rootElement) {
 10112       if ((mHasFocus || aFocusChanged) &&
 10113           (mFocusedNode == rootElement || aNewContent == rootElement)) {
 10114           nsIFrame* frame = rootElement->GetPrimaryFrame();
 10115           if (frame) {
 10116               frame = frame->GetParent();
 10117               nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
 10118               if (canvasFrame) {
 10119                   canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
 10123   } else {
 10124       // Look for the frame the hard way
 10125       nsIFrame* frame = presShell->GetRootFrame();
 10126       if (frame) {
 10127           nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
 10128           if (canvasFrame) {
 10129               canvasFrame->SetHasFocus(false);
 10135 already_AddRefed<nsICSSDeclaration>
 10136 nsGlobalWindow::GetComputedStyle(Element& aElt, const nsAString& aPseudoElt,
 10137                                  ErrorResult& aError)
 10139   return GetComputedStyleHelper(aElt, aPseudoElt, false, aError);
 10142 NS_IMETHODIMP
 10143 nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
 10144                                  const nsAString& aPseudoElt,
 10145                                  nsIDOMCSSStyleDeclaration** aReturn)
 10147   return GetComputedStyleHelper(aElt, aPseudoElt, false, aReturn);
 10150 already_AddRefed<nsICSSDeclaration>
 10151 nsGlobalWindow::GetDefaultComputedStyle(Element& aElt,
 10152                                         const nsAString& aPseudoElt,
 10153                                         ErrorResult& aError)
 10155   return GetComputedStyleHelper(aElt, aPseudoElt, true, aError);
 10158 NS_IMETHODIMP
 10159 nsGlobalWindow::GetDefaultComputedStyle(nsIDOMElement* aElt,
 10160                                         const nsAString& aPseudoElt,
 10161                                         nsIDOMCSSStyleDeclaration** aReturn)
 10163   return GetComputedStyleHelper(aElt, aPseudoElt, true, aReturn);
 10166 nsresult
 10167 nsGlobalWindow::GetComputedStyleHelper(nsIDOMElement* aElt,
 10168                                        const nsAString& aPseudoElt,
 10169                                        bool aDefaultStylesOnly,
 10170                                        nsIDOMCSSStyleDeclaration** aReturn)
 10172   NS_ENSURE_ARG_POINTER(aReturn);
 10173   *aReturn = nullptr;
 10175   nsCOMPtr<dom::Element> element = do_QueryInterface(aElt);
 10176   if (!element) {
 10177     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 10180   ErrorResult rv;
 10181   nsCOMPtr<nsIDOMCSSStyleDeclaration> declaration =
 10182     GetComputedStyleHelper(*element, aPseudoElt, aDefaultStylesOnly, rv);
 10183   declaration.forget(aReturn);
 10185   return rv.ErrorCode();
 10188 already_AddRefed<nsICSSDeclaration>
 10189 nsGlobalWindow::GetComputedStyleHelper(Element& aElt,
 10190                                        const nsAString& aPseudoElt,
 10191                                        bool aDefaultStylesOnly,
 10192                                        ErrorResult& aError)
 10194   FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelper,
 10195                             (aElt, aPseudoElt, aDefaultStylesOnly, aError),
 10196                             aError, nullptr);
 10198   if (!mDocShell) {
 10199     return nullptr;
 10202   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
 10204   if (!presShell) {
 10205     // Try flushing frames on our parent in case there's a pending
 10206     // style change that will create the presshell.
 10207     nsGlobalWindow *parent =
 10208       static_cast<nsGlobalWindow *>(GetPrivateParent());
 10209     if (!parent) {
 10210       return nullptr;
 10213     parent->FlushPendingNotifications(Flush_Frames);
 10215     // Might have killed mDocShell
 10216     if (!mDocShell) {
 10217       return nullptr;
 10220     presShell = mDocShell->GetPresShell();
 10221     if (!presShell) {
 10222       return nullptr;
 10226   nsRefPtr<nsComputedDOMStyle> compStyle =
 10227     NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell,
 10228                            aDefaultStylesOnly ? nsComputedDOMStyle::eDefaultOnly :
 10229                                                 nsComputedDOMStyle::eAll);
 10231   return compStyle.forget();
 10234 nsIDOMStorage*
 10235 nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
 10237   FORWARD_TO_INNER_OR_THROW(GetSessionStorage, (aError), aError, nullptr);
 10239   nsIPrincipal *principal = GetPrincipal();
 10240   nsIDocShell* docShell = GetDocShell();
 10242   if (!principal || !docShell || !Preferences::GetBool(kStorageEnabled)) {
 10243     return nullptr;
 10246   if (mSessionStorage) {
 10247 #ifdef PR_LOGGING
 10248     if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
 10249       PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get());
 10251 #endif
 10252     nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(mSessionStorage);
 10253     if (piStorage) {
 10254       bool canAccess = piStorage->CanAccess(principal);
 10255       NS_ASSERTION(canAccess,
 10256                    "window %x owned sessionStorage "
 10257                    "that could not be accessed!");
 10258       if (!canAccess) {
 10259         mSessionStorage = nullptr;
 10264   if (!mSessionStorage) {
 10265     nsString documentURI;
 10266     if (mDoc) {
 10267       mDoc->GetDocumentURI(documentURI);
 10270     // If the document has the sandboxed origin flag set
 10271     // don't allow access to sessionStorage.
 10272     if (!mDoc) {
 10273       aError.Throw(NS_ERROR_FAILURE);
 10274       return nullptr;
 10277     if (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
 10278       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
 10279       return nullptr;
 10282     nsresult rv;
 10284     nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(docShell, &rv);
 10285     if (NS_FAILED(rv)) {
 10286       aError.Throw(rv);
 10287       return nullptr;
 10290     nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
 10292     nsCOMPtr<nsIURI> firstPartyIsolationURI;
 10293     rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
 10294     if (NS_FAILED(rv)) {
 10295       aError.Throw(rv);
 10296       return nullptr;
 10299     aError =  storageManager->CreateStorageForFirstParty(firstPartyIsolationURI, principal,
 10300                                            documentURI,
 10301                                            loadContext && loadContext->UsePrivateBrowsing(),
 10302                                            getter_AddRefs(mSessionStorage));
 10303     if (aError.Failed()) {
 10304       return nullptr;
 10307 #ifdef PR_LOGGING
 10308     if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
 10309       PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
 10311 #endif
 10313     if (!mSessionStorage) {
 10314       aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 10315       return nullptr;
 10319 #ifdef PR_LOGGING
 10320   if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
 10321     PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get());
 10323 #endif
 10325   return mSessionStorage;
 10328 NS_IMETHODIMP
 10329 nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
 10331   ErrorResult rv;
 10332   nsCOMPtr<nsIDOMStorage> storage = GetSessionStorage(rv);
 10333   storage.forget(aSessionStorage);
 10335   return rv.ErrorCode();
 10338 nsIDOMStorage*
 10339 nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
 10341   FORWARD_TO_INNER_OR_THROW(GetLocalStorage, (aError), aError, nullptr);
 10343   if (!Preferences::GetBool(kStorageEnabled)) {
 10344     return nullptr;
 10347   if (!mLocalStorage) {
 10348     if (!DOMStorage::CanUseStorage()) {
 10349       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
 10350       return nullptr;
 10353     nsIPrincipal *principal = GetPrincipal();
 10354     if (!principal) {
 10355       return nullptr;
 10358     nsresult rv;
 10359     nsCOMPtr<nsIDOMStorageManager> storageManager =
 10360       do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
 10361     if (NS_FAILED(rv)) {
 10362       aError.Throw(rv);
 10363       return nullptr;
 10366     // If the document has the sandboxed origin flag set
 10367     // don't allow access to localStorage.
 10368     if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
 10369       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
 10370       return nullptr;
 10373     nsString documentURI;
 10374     if (mDoc) {
 10375       mDoc->GetDocumentURI(documentURI);
 10378     nsCOMPtr<nsIURI> firstPartyIsolationURI;
 10379     rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
 10380     if (NS_FAILED(rv)) {
 10381       aError.Throw(rv);
 10382       return nullptr;
 10385     nsIDocShell* docShell = GetDocShell();
 10386     nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
 10388     aError = storageManager->CreateStorageForFirstParty(firstPartyIsolationURI, principal,
 10389                                            documentURI,
 10390                                            loadContext && loadContext->UsePrivateBrowsing(),
 10391                                            getter_AddRefs(mLocalStorage));
 10394   return mLocalStorage;
 10397 NS_IMETHODIMP
 10398 nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
 10400   NS_ENSURE_ARG(aLocalStorage);
 10402   ErrorResult rv;
 10403   nsCOMPtr<nsIDOMStorage> storage = GetLocalStorage(rv);
 10404   storage.forget(aLocalStorage);
 10406   return rv.ErrorCode();
 10409 indexedDB::IDBFactory*
 10410 nsGlobalWindow::GetIndexedDB(ErrorResult& aError)
 10412   if (!mIndexedDB) {
 10413     // If the document has the sandboxed origin flag set
 10414     // don't allow access to indexedDB.
 10415     if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
 10416       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
 10417       return nullptr;
 10420     if (!IsChromeWindow()) {
 10421       // Whitelist about:home, since it doesn't have a base domain it would not
 10422       // pass the thirdPartyUtil check, though it should be able to use
 10423       // indexedDB.
 10424       bool skipThirdPartyCheck = false;
 10425       nsIPrincipal *principal = GetPrincipal();
 10426       if (principal) {
 10427         nsCOMPtr<nsIURI> uri;
 10428         principal->GetURI(getter_AddRefs(uri));
 10429         bool isAbout = false;
 10430         if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
 10431           nsAutoCString path;
 10432           skipThirdPartyCheck = NS_SUCCEEDED(uri->GetPath(path)) &&
 10433                                 path.EqualsLiteral("home");
 10437       if (!skipThirdPartyCheck) {
 10438         nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
 10439           do_GetService(THIRDPARTYUTIL_CONTRACTID);
 10440         if (!thirdPartyUtil) {
 10441           aError.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 10442           return nullptr;
 10445         bool isThirdParty;
 10446         aError = thirdPartyUtil->IsThirdPartyWindow(this, nullptr,
 10447                                                     &isThirdParty);
 10448         if (aError.Failed() || isThirdParty) {
 10449           NS_WARN_IF_FALSE(aError.Failed(),
 10450                            "IndexedDB is not permitted in a third-party window.");
 10451           return nullptr;
 10456     // This may be null if being created from a file.
 10457     aError = indexedDB::IDBFactory::Create(this, nullptr,
 10458                                            getter_AddRefs(mIndexedDB));
 10461   return mIndexedDB;
 10464 NS_IMETHODIMP
 10465 nsGlobalWindow::GetIndexedDB(nsISupports** _retval)
 10467   ErrorResult rv;
 10468   nsCOMPtr<nsISupports> request(GetIndexedDB(rv));
 10469   request.forget(_retval);
 10471   return rv.ErrorCode();
 10474 NS_IMETHODIMP
 10475 nsGlobalWindow::GetMozIndexedDB(nsISupports** _retval)
 10477   return GetIndexedDB(_retval);
 10480 //*****************************************************************************
 10481 // nsGlobalWindow::nsIInterfaceRequestor
 10482 //*****************************************************************************
 10484 NS_IMETHODIMP
 10485 nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
 10487   NS_ENSURE_ARG_POINTER(aSink);
 10488   *aSink = nullptr;
 10490   if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
 10491     nsGlobalWindow* outer = GetOuterWindowInternal();
 10492     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 10494     NS_WARNING("Using deprecated nsIDocCharset: use nsIDocShell.GetCharset() instead ");
 10495     nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(outer->mDocShell));
 10496     docCharset.forget(aSink);
 10498   else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
 10499     nsGlobalWindow* outer = GetOuterWindowInternal();
 10500     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 10502     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(outer->mDocShell));
 10503     webNav.forget(aSink);
 10505   else if (aIID.Equals(NS_GET_IID(nsIDocShell))) {
 10506     nsGlobalWindow* outer = GetOuterWindowInternal();
 10507     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 10509     nsCOMPtr<nsIDocShell> docShell = outer->mDocShell;
 10510     docShell.forget(aSink);
 10512 #ifdef NS_PRINTING
 10513   else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
 10514     nsGlobalWindow* outer = GetOuterWindowInternal();
 10515     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 10517     if (outer->mDocShell) {
 10518       nsCOMPtr<nsIContentViewer> viewer;
 10519       outer->mDocShell->GetContentViewer(getter_AddRefs(viewer));
 10520       if (viewer) {
 10521         nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
 10522         webBrowserPrint.forget(aSink);
 10526 #endif
 10527   else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
 10528     nsGlobalWindow* outer = GetOuterWindowInternal();
 10529     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 10531     if (!mWindowUtils) {
 10532       mWindowUtils = new nsDOMWindowUtils(outer);
 10535     *aSink = mWindowUtils;
 10536     NS_ADDREF(((nsISupports *) *aSink));
 10538   else if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
 10539     nsGlobalWindow* outer = GetOuterWindowInternal();
 10540     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 10542     nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(outer->mDocShell));
 10543     loadContext.forget(aSink);
 10545   else {
 10546     return QueryInterface(aIID, aSink);
 10549   return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
 10552 void
 10553 nsGlobalWindow::GetInterface(JSContext* aCx, nsIJSID* aIID,
 10554                              JS::MutableHandle<JS::Value> aRetval,
 10555                              ErrorResult& aError)
 10557   dom::GetInterface(aCx, this, aIID, aRetval, aError);
 10560 void
 10561 nsGlobalWindow::FireOfflineStatusEvent()
 10563   if (!IsCurrentInnerWindow())
 10564     return;
 10565   nsAutoString name;
 10566   if (NS_IsOffline()) {
 10567     name.AssignLiteral("offline");
 10568   } else {
 10569     name.AssignLiteral("online");
 10571   // The event is fired at the body element, or if there is no body element,
 10572   // at the document.
 10573   nsCOMPtr<EventTarget> eventTarget = mDoc.get();
 10574   nsHTMLDocument* htmlDoc = mDoc->AsHTMLDocument();
 10575   if (htmlDoc) {
 10576     Element* body = htmlDoc->GetBody();
 10577     if (body) {
 10578       eventTarget = body;
 10580   } else {
 10581     Element* documentElement = mDoc->GetDocumentElement();
 10582     if (documentElement) {
 10583       eventTarget = documentElement;
 10586   nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, true, false);
 10589 class NotifyIdleObserverRunnable : public nsRunnable
 10591 public:
 10592   NotifyIdleObserverRunnable(nsIIdleObserver* aIdleObserver,
 10593                              uint32_t aTimeInS,
 10594                              bool aCallOnidle,
 10595                              nsGlobalWindow* aIdleWindow)
 10596     : mIdleObserver(aIdleObserver), mTimeInS(aTimeInS), mIdleWindow(aIdleWindow),
 10597       mCallOnidle(aCallOnidle)
 10598   { }
 10600   NS_IMETHOD Run()
 10602     if (mIdleWindow->ContainsIdleObserver(mIdleObserver, mTimeInS)) {
 10603       return mCallOnidle ? mIdleObserver->Onidle() : mIdleObserver->Onactive();
 10605     return NS_OK;
 10608 private:
 10609   nsCOMPtr<nsIIdleObserver> mIdleObserver;
 10610   uint32_t mTimeInS;
 10611   nsRefPtr<nsGlobalWindow> mIdleWindow;
 10613   // If false then call on active
 10614   bool mCallOnidle;
 10615 };
 10617 void
 10618 nsGlobalWindow::NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
 10619                                    bool aCallOnidle)
 10621   MOZ_ASSERT(aIdleObserverHolder);
 10622   aIdleObserverHolder->mPrevNotificationIdle = aCallOnidle;
 10624   nsCOMPtr<nsIRunnable> caller =
 10625     new NotifyIdleObserverRunnable(aIdleObserverHolder->mIdleObserver,
 10626                                    aIdleObserverHolder->mTimeInS,
 10627                                    aCallOnidle, this);
 10628   if (NS_FAILED(NS_DispatchToCurrentThread(caller))) {
 10629     NS_WARNING("Failed to dispatch thread for idle observer notification.");
 10633 bool
 10634 nsGlobalWindow::ContainsIdleObserver(nsIIdleObserver* aIdleObserver, uint32_t aTimeInS)
 10636   MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
 10637   bool found = false;
 10638   nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
 10639   while (iter.HasMore()) {
 10640     IdleObserverHolder& idleObserver = iter.GetNext();
 10641     if (idleObserver.mIdleObserver == aIdleObserver &&
 10642         idleObserver.mTimeInS == aTimeInS) {
 10643       found = true;
 10644       break;
 10647   return found;
 10650 void
 10651 IdleActiveTimerCallback(nsITimer* aTimer, void* aClosure)
 10653   nsRefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
 10654   MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
 10655   idleWindow->HandleIdleActiveEvent();
 10658 void
 10659 IdleObserverTimerCallback(nsITimer* aTimer, void* aClosure)
 10661   nsRefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
 10662   MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
 10663   idleWindow->HandleIdleObserverCallback();
 10666 void
 10667 nsGlobalWindow::HandleIdleObserverCallback()
 10669   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 10670   MOZ_ASSERT(static_cast<uint32_t>(mIdleCallbackIndex) < mIdleObservers.Length(),
 10671                                   "Idle callback index exceeds array bounds!");
 10672   IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(mIdleCallbackIndex);
 10673   NotifyIdleObserver(&idleObserver, true);
 10674   mIdleCallbackIndex++;
 10675   if (NS_FAILED(ScheduleNextIdleObserverCallback())) {
 10676     NS_WARNING("Failed to set next idle observer callback.");
 10680 nsresult
 10681 nsGlobalWindow::ScheduleNextIdleObserverCallback()
 10683   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 10684   MOZ_ASSERT(mIdleService, "No idle service!");
 10686   if (mIdleCallbackIndex < 0 ||
 10687       static_cast<uint32_t>(mIdleCallbackIndex) >= mIdleObservers.Length()) {
 10688     return NS_OK;
 10691   IdleObserverHolder& idleObserver =
 10692     mIdleObservers.ElementAt(mIdleCallbackIndex);
 10694   uint32_t userIdleTimeMS = 0;
 10695   nsresult rv = mIdleService->GetIdleTime(&userIdleTimeMS);
 10696   NS_ENSURE_SUCCESS(rv, rv);
 10698   uint32_t callbackTimeMS = 0;
 10699   if (idleObserver.mTimeInS * 1000 + mIdleFuzzFactor > userIdleTimeMS) {
 10700     callbackTimeMS = idleObserver.mTimeInS * 1000 - userIdleTimeMS + mIdleFuzzFactor;
 10703   mIdleTimer->Cancel();
 10704   rv = mIdleTimer->InitWithFuncCallback(IdleObserverTimerCallback,
 10705                                         this,
 10706                                         callbackTimeMS,
 10707                                         nsITimer::TYPE_ONE_SHOT);
 10708   NS_ENSURE_SUCCESS(rv, rv);
 10710   return NS_OK;
 10713 uint32_t
 10714 nsGlobalWindow::GetFuzzTimeMS()
 10716   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 10718   if (sIdleObserversAPIFuzzTimeDisabled) {
 10719     return 0;
 10722   uint32_t randNum = MAX_IDLE_FUZZ_TIME_MS;
 10723   size_t nbytes = PR_GetRandomNoise(&randNum, sizeof(randNum));
 10724   if (nbytes != sizeof(randNum)) {
 10725     NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!");
 10726     return MAX_IDLE_FUZZ_TIME_MS;
 10729   if (randNum > MAX_IDLE_FUZZ_TIME_MS) {
 10730     randNum %= MAX_IDLE_FUZZ_TIME_MS;
 10733   return randNum;
 10736 nsresult
 10737 nsGlobalWindow::ScheduleActiveTimerCallback()
 10739   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 10741   if (!mAddActiveEventFuzzTime) {
 10742     return HandleIdleActiveEvent();
 10745   MOZ_ASSERT(mIdleTimer);
 10746   mIdleTimer->Cancel();
 10748   uint32_t fuzzFactorInMS = GetFuzzTimeMS();
 10749   nsresult rv = mIdleTimer->InitWithFuncCallback(IdleActiveTimerCallback,
 10750                                                  this,
 10751                                                  fuzzFactorInMS,
 10752                                                  nsITimer::TYPE_ONE_SHOT);
 10753   NS_ENSURE_SUCCESS(rv, rv);
 10754   return NS_OK;
 10757 nsresult
 10758 nsGlobalWindow::HandleIdleActiveEvent()
 10760   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 10762   if (mCurrentlyIdle) {
 10763     mIdleCallbackIndex = 0;
 10764     mIdleFuzzFactor = GetFuzzTimeMS();
 10765     nsresult rv = ScheduleNextIdleObserverCallback();
 10766     NS_ENSURE_SUCCESS(rv, rv);
 10767     return NS_OK;
 10770   mIdleCallbackIndex = -1;
 10771   MOZ_ASSERT(mIdleTimer);
 10772   mIdleTimer->Cancel();
 10773   nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
 10774   while (iter.HasMore()) {
 10775     IdleObserverHolder& idleObserver = iter.GetNext();
 10776     if (idleObserver.mPrevNotificationIdle) {
 10777       NotifyIdleObserver(&idleObserver, false);
 10781   return NS_OK;
 10784 nsGlobalWindow::SlowScriptResponse
 10785 nsGlobalWindow::ShowSlowScriptDialog()
 10787   MOZ_ASSERT(IsInnerWindow());
 10789   nsresult rv;
 10790   AutoJSContext cx;
 10792   // If it isn't safe to run script, then it isn't safe to bring up the prompt
 10793   // (since that spins the event loop). In that (rare) case, we just kill the
 10794   // script and report a warning.
 10795   if (!nsContentUtils::IsSafeToRunScript()) {
 10796     JS_ReportWarning(cx, "A long running script was terminated");
 10797     return KillSlowScript;
 10800   // If our document is not active, just kill the script: we've been unloaded
 10801   if (!HasActiveDocument()) {
 10802     return KillSlowScript;
 10805   // Get the nsIPrompt interface from the docshell
 10806   nsCOMPtr<nsIDocShell> ds = GetDocShell();
 10807   NS_ENSURE_TRUE(ds, KillSlowScript);
 10808   nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
 10809   NS_ENSURE_TRUE(prompt, KillSlowScript);
 10811   // Check if we should offer the option to debug
 10812   JS::AutoFilename filename;
 10813   unsigned lineno;
 10814   bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
 10816   bool debugPossible = hasFrame && js::CanCallContextDebugHandler(cx);
 10817 #ifdef MOZ_JSDEBUGGER
 10818   // Get the debugger service if necessary.
 10819   if (debugPossible) {
 10820     bool jsds_IsOn = false;
 10821     const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
 10822     nsCOMPtr<jsdIExecutionHook> jsdHook;
 10823     nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
 10825     // Check if there's a user for the debugger service that's 'on' for us
 10826     if (NS_SUCCEEDED(rv)) {
 10827       jsds->GetDebuggerHook(getter_AddRefs(jsdHook));
 10828       jsds->GetIsOn(&jsds_IsOn);
 10831     // If there is a debug handler registered for this runtime AND
 10832     // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
 10833     // then something useful will be done with our request to debug.
 10834     debugPossible = ((jsds_IsOn && (jsdHook != nullptr)) || !jsds_IsOn);
 10836 #endif
 10838   // Get localizable strings
 10839   nsXPIDLString title, msg, stopButton, waitButton, debugButton, neverShowDlg;
 10841   rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 10842                                           "KillScriptTitle",
 10843                                           title);
 10845   nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 10846                                            "StopScriptButton",
 10847                                            stopButton);
 10848   if (NS_FAILED(tmp)) {
 10849     rv = tmp;
 10852   tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 10853                                            "WaitForScriptButton",
 10854                                            waitButton);
 10855   if (NS_FAILED(tmp)) {
 10856     rv = tmp;
 10859   tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 10860                                            "DontAskAgain",
 10861                                            neverShowDlg);
 10862   if (NS_FAILED(tmp)) {
 10863     rv = tmp;
 10867   if (debugPossible) {
 10868     tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 10869                                              "DebugScriptButton",
 10870                                              debugButton);
 10871     if (NS_FAILED(tmp)) {
 10872       rv = tmp;
 10875     tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 10876                                              "KillScriptWithDebugMessage",
 10877                                              msg);
 10878     if (NS_FAILED(tmp)) {
 10879       rv = tmp;
 10882   else {
 10883     tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 10884                                              "KillScriptMessage",
 10885                                              msg);
 10886     if (NS_FAILED(tmp)) {
 10887       rv = tmp;
 10891   // GetStringFromName can return NS_OK and still give nullptr string
 10892   if (NS_FAILED(rv) || !title || !msg || !stopButton || !waitButton ||
 10893       (!debugButton && debugPossible) || !neverShowDlg) {
 10894     NS_ERROR("Failed to get localized strings.");
 10895     return ContinueSlowScript;
 10898   // Append file and line number information, if available
 10899   if (filename.get()) {
 10900     nsXPIDLString scriptLocation;
 10901     NS_ConvertUTF8toUTF16 filenameUTF16(filename.get());
 10902     const char16_t *formatParams[] = { filenameUTF16.get() };
 10903     rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 10904                                                "KillScriptLocation",
 10905                                                formatParams,
 10906                                                scriptLocation);
 10908     if (NS_SUCCEEDED(rv) && scriptLocation) {
 10909       msg.AppendLiteral("\n\n");
 10910       msg.Append(scriptLocation);
 10911       msg.Append(':');
 10912       msg.AppendInt(lineno);
 10916   int32_t buttonPressed = 0; // In case the user exits dialog by clicking X.
 10917   bool neverShowDlgChk = false;
 10918   uint32_t buttonFlags = nsIPrompt::BUTTON_POS_1_DEFAULT +
 10919                          (nsIPrompt::BUTTON_TITLE_IS_STRING *
 10920                           (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
 10922   // Add a third button if necessary.
 10923   if (debugPossible)
 10924     buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
 10926   // Null out the operation callback while we're re-entering JS here.
 10927   JSRuntime* rt = JS_GetRuntime(cx);
 10928   JSInterruptCallback old = JS_SetInterruptCallback(rt, nullptr);
 10930   // Open the dialog.
 10931   rv = prompt->ConfirmEx(title, msg, buttonFlags, waitButton, stopButton,
 10932                          debugButton, neverShowDlg, &neverShowDlgChk,
 10933                          &buttonPressed);
 10935   JS_SetInterruptCallback(rt, old);
 10937   if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) {
 10938     return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript;
 10940   if ((buttonPressed == 2) && debugPossible) {
 10941     return js_CallContextDebugHandler(cx) ? ContinueSlowScript : KillSlowScript;
 10943   JS_ClearPendingException(cx);
 10944   return KillSlowScript;
 10947 uint32_t
 10948 nsGlobalWindow::FindInsertionIndex(IdleObserverHolder* aIdleObserver)
 10950   MOZ_ASSERT(IsInnerWindow());
 10951   MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
 10953   uint32_t i = 0;
 10954   nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
 10955   while (iter.HasMore()) {
 10956     IdleObserverHolder& idleObserver = iter.GetNext();
 10957     if (idleObserver.mTimeInS > aIdleObserver->mTimeInS) {
 10958       break;
 10960     i++;
 10961     MOZ_ASSERT(i <= mIdleObservers.Length(), "Array index out of bounds error.");
 10964   return i;
 10967 nsresult
 10968 nsGlobalWindow::RegisterIdleObserver(nsIIdleObserver* aIdleObserver)
 10970   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 10972   nsresult rv;
 10973   if (mIdleObservers.IsEmpty()) {
 10974     mIdleService = do_GetService("@mozilla.org/widget/idleservice;1", &rv);
 10975     NS_ENSURE_SUCCESS(rv, rv);
 10977     rv = mIdleService->AddIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
 10978     NS_ENSURE_SUCCESS(rv, rv);
 10980     if (!mIdleTimer) {
 10981       mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
 10982       NS_ENSURE_SUCCESS(rv, rv);
 10983     } else {
 10984       mIdleTimer->Cancel();
 10988   MOZ_ASSERT(mIdleService);
 10989   MOZ_ASSERT(mIdleTimer);
 10991   IdleObserverHolder tmpIdleObserver;
 10992   tmpIdleObserver.mIdleObserver = aIdleObserver;
 10993   rv = aIdleObserver->GetTime(&tmpIdleObserver.mTimeInS);
 10994   NS_ENSURE_SUCCESS(rv, rv);
 10995   NS_ENSURE_ARG_MAX(tmpIdleObserver.mTimeInS, UINT32_MAX / 1000);
 10996   NS_ENSURE_ARG_MIN(tmpIdleObserver.mTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
 10998   uint32_t insertAtIndex = FindInsertionIndex(&tmpIdleObserver);
 10999   if (insertAtIndex == mIdleObservers.Length()) {
 11000     mIdleObservers.AppendElement(tmpIdleObserver);
 11002   else {
 11003     mIdleObservers.InsertElementAt(insertAtIndex, tmpIdleObserver);
 11006   bool userIsIdle = false;
 11007   rv = nsContentUtils::IsUserIdle(MIN_IDLE_NOTIFICATION_TIME_S, &userIsIdle);
 11008   NS_ENSURE_SUCCESS(rv, rv);
 11010   // Special case. First idle observer added to empty list while the user is idle.
 11011   // Haven't received 'idle' topic notification from slow idle service yet.
 11012   // Need to wait for the idle notification and then notify idle observers in the list.
 11013   if (userIsIdle && mIdleCallbackIndex == -1) {
 11014     return NS_OK;
 11017   if (!mCurrentlyIdle) {
 11018     return NS_OK;
 11021   MOZ_ASSERT(mIdleCallbackIndex >= 0);
 11023   if (static_cast<int32_t>(insertAtIndex) < mIdleCallbackIndex) {
 11024     IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(insertAtIndex);
 11025     NotifyIdleObserver(&idleObserver, true);
 11026     mIdleCallbackIndex++;
 11027     return NS_OK;
 11030   if (static_cast<int32_t>(insertAtIndex) == mIdleCallbackIndex) {
 11031     mIdleTimer->Cancel();
 11032     rv = ScheduleNextIdleObserverCallback();
 11033     NS_ENSURE_SUCCESS(rv, rv);
 11035   return NS_OK;
 11038 nsresult
 11039 nsGlobalWindow::FindIndexOfElementToRemove(nsIIdleObserver* aIdleObserver,
 11040                                            int32_t* aRemoveElementIndex)
 11042   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 11043   MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
 11045   *aRemoveElementIndex = 0;
 11046   if (mIdleObservers.IsEmpty()) {
 11047     return NS_ERROR_FAILURE;
 11050   uint32_t aIdleObserverTimeInS;
 11051   nsresult rv = aIdleObserver->GetTime(&aIdleObserverTimeInS);
 11052   NS_ENSURE_SUCCESS(rv, rv);
 11053   NS_ENSURE_ARG_MIN(aIdleObserverTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
 11055   nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
 11056   while (iter.HasMore()) {
 11057     IdleObserverHolder& idleObserver = iter.GetNext();
 11058     if (idleObserver.mTimeInS == aIdleObserverTimeInS &&
 11059         idleObserver.mIdleObserver == aIdleObserver ) {
 11060       break;
 11062     (*aRemoveElementIndex)++;
 11064   return static_cast<uint32_t>(*aRemoveElementIndex) >= mIdleObservers.Length() ?
 11065     NS_ERROR_FAILURE : NS_OK;
 11068 nsresult
 11069 nsGlobalWindow::UnregisterIdleObserver(nsIIdleObserver* aIdleObserver)
 11071   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 11073   int32_t removeElementIndex;
 11074   nsresult rv = FindIndexOfElementToRemove(aIdleObserver, &removeElementIndex);
 11075   if (NS_FAILED(rv)) {
 11076     NS_WARNING("Idle observer not found in list of idle observers. No idle observer removed.");
 11077     return NS_OK;
 11079   mIdleObservers.RemoveElementAt(removeElementIndex);
 11081   MOZ_ASSERT(mIdleTimer);
 11082   if (mIdleObservers.IsEmpty() && mIdleService) {
 11083     rv = mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
 11084     NS_ENSURE_SUCCESS(rv, rv);
 11085     mIdleService = nullptr;
 11087     mIdleTimer->Cancel();
 11088     mIdleCallbackIndex = -1;
 11089     return NS_OK;
 11092   if (!mCurrentlyIdle) {
 11093     return NS_OK;
 11096   if (removeElementIndex < mIdleCallbackIndex) {
 11097     mIdleCallbackIndex--;
 11098     return NS_OK;
 11101   if (removeElementIndex != mIdleCallbackIndex) {
 11102     return NS_OK;
 11105   mIdleTimer->Cancel();
 11107   // If the last element in the array had been notified then decrement
 11108   // mIdleCallbackIndex because an idle was removed from the list of
 11109   // idle observers.
 11110   // Example: add idle observer with time 1, 2, 3,
 11111   // Idle notifications for idle observers with time 1, 2, 3 are complete
 11112   // Remove idle observer with time 3 while the user is still idle.
 11113   // The user never transitioned to active state.
 11114   // Add an idle observer with idle time 4
 11115   if (static_cast<uint32_t>(mIdleCallbackIndex) == mIdleObservers.Length()) {
 11116     mIdleCallbackIndex--;
 11118   rv = ScheduleNextIdleObserverCallback();
 11119   NS_ENSURE_SUCCESS(rv, rv);
 11121   return NS_OK;
 11124 nsresult
 11125 nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
 11126                         const char16_t* aData)
 11128   if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
 11129     if (IsFrozen()) {
 11130       // if an even number of notifications arrive while we're frozen,
 11131       // we don't need to fire.
 11132       mFireOfflineStatusChangeEventOnThaw = !mFireOfflineStatusChangeEventOnThaw;
 11133     } else {
 11134       FireOfflineStatusEvent();
 11136     return NS_OK;
 11139   if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE)) {
 11140     mCurrentlyIdle = true;
 11141     if (IsFrozen()) {
 11142       // need to fire only one idle event while the window is frozen.
 11143       mNotifyIdleObserversIdleOnThaw = true;
 11144       mNotifyIdleObserversActiveOnThaw = false;
 11145     } else if (IsCurrentInnerWindow()) {
 11146       HandleIdleActiveEvent();
 11148     return NS_OK;
 11151   if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_ACTIVE)) {
 11152     mCurrentlyIdle = false;
 11153     if (IsFrozen()) {
 11154       mNotifyIdleObserversActiveOnThaw = true;
 11155       mNotifyIdleObserversIdleOnThaw = false;
 11156     } else if (IsCurrentInnerWindow()) {
 11157       MOZ_ASSERT(IsInnerWindow());
 11158       ScheduleActiveTimerCallback();
 11160     return NS_OK;
 11163   if (!nsCRT::strcmp(aTopic, "dom-storage2-changed")) {
 11164     if (!IsInnerWindow() || !IsCurrentInnerWindow()) {
 11165       return NS_OK;
 11168     nsIPrincipal *principal;
 11169     nsresult rv;
 11171     nsCOMPtr<nsIDOMStorageEvent> event = do_QueryInterface(aSubject, &rv);
 11172     NS_ENSURE_SUCCESS(rv, rv);
 11174     nsCOMPtr<nsIDOMStorage> changingStorage;
 11175     rv = event->GetStorageArea(getter_AddRefs(changingStorage));
 11176     NS_ENSURE_SUCCESS(rv, rv);
 11178     bool fireMozStorageChanged = false;
 11179     principal = GetPrincipal();
 11180     if (!principal) {
 11181       return NS_OK;
 11184     nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
 11186     nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell());
 11187     bool isPrivate = loadContext && loadContext->UsePrivateBrowsing();
 11188     if (pistorage->IsPrivate() != isPrivate) {
 11189       return NS_OK;
 11192     switch (pistorage->GetType())
 11194     case nsPIDOMStorage::SessionStorage:
 11196       bool check = false;
 11198       nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(GetDocShell());
 11199       if (storageManager) {
 11200         nsresult rv;
 11201         nsCOMPtr<nsIURI> firstPartyIsolationURI;
 11202         rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
 11203         NS_ENSURE_SUCCESS(rv, rv);
 11205         rv = storageManager->CheckStorageForFirstParty(firstPartyIsolationURI,
 11206                                           principal, changingStorage, &check);
 11207         if (NS_FAILED(rv)) {
 11208           return rv;
 11212       if (!check) {
 11213         // This storage event is not coming from our storage or is coming
 11214         // from a different docshell, i.e. it is a clone, ignore this event.
 11215         return NS_OK;
 11218 #ifdef PR_LOGGING
 11219       if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
 11220         PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
 11222 #endif
 11224       fireMozStorageChanged = SameCOMIdentity(mSessionStorage, changingStorage);
 11225       break;
 11228     case nsPIDOMStorage::LocalStorage:
 11230       // Allow event fire only for the same principal storages
 11231       // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
 11232       nsIPrincipal* storagePrincipal = pistorage->GetPrincipal();
 11234       bool equals = false;
 11235       rv = storagePrincipal->Equals(principal, &equals);
 11236       NS_ENSURE_SUCCESS(rv, rv);
 11238       if (!equals)
 11239         return NS_OK;
 11241       fireMozStorageChanged = SameCOMIdentity(mLocalStorage, changingStorage);
 11242       break;
 11244     default:
 11245       return NS_OK;
 11248     // Clone the storage event included in the observer notification. We want
 11249     // to dispatch clones rather than the original event.
 11250     rv = CloneStorageEvent(fireMozStorageChanged ?
 11251                            NS_LITERAL_STRING("MozStorageChanged") :
 11252                            NS_LITERAL_STRING("storage"),
 11253                            event);
 11254     NS_ENSURE_SUCCESS(rv, rv);
 11256     event->SetTrusted(true);
 11258     if (fireMozStorageChanged) {
 11259       WidgetEvent* internalEvent = event->GetInternalNSEvent();
 11260       internalEvent->mFlags.mOnlyChromeDispatch = true;
 11263     if (IsFrozen()) {
 11264       // This window is frozen, rather than firing the events here,
 11265       // store the domain in which the change happened and fire the
 11266       // events if we're ever thawed.
 11268       mPendingStorageEvents.AppendObject(event);
 11269       return NS_OK;
 11272     bool defaultActionEnabled;
 11273     DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
 11275     return NS_OK;
 11278   if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) {
 11279     if (mApplicationCache)
 11280       return NS_OK;
 11282     // Instantiate the application object now. It observes update belonging to
 11283     // this window's document and correctly updates the applicationCache object
 11284     // state.
 11285     nsCOMPtr<nsIDOMOfflineResourceList> applicationCache;
 11286     GetApplicationCache(getter_AddRefs(applicationCache));
 11287     nsCOMPtr<nsIObserver> observer = do_QueryInterface(applicationCache);
 11288     if (observer)
 11289       observer->Observe(aSubject, aTopic, aData);
 11291     return NS_OK;
 11294 #ifdef MOZ_B2G
 11295   if (!nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC) ||
 11296       !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC)) {
 11297     MOZ_ASSERT(IsInnerWindow());
 11298     if (!IsCurrentInnerWindow()) {
 11299       return NS_OK;
 11302     nsCOMPtr<nsIDOMEvent> event;
 11303     NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
 11304     nsresult rv = event->InitEvent(
 11305       !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC)
 11306         ? NETWORK_UPLOAD_EVENT_NAME
 11307         : NETWORK_DOWNLOAD_EVENT_NAME,
 11308       false, false);
 11309     NS_ENSURE_SUCCESS(rv, rv);
 11311     event->SetTrusted(true);
 11313     bool dummy;
 11314     return DispatchEvent(event, &dummy);
 11316 #endif // MOZ_B2G
 11318   NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
 11319   return NS_ERROR_FAILURE;
 11322 nsresult
 11323 nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
 11324                                   nsCOMPtr<nsIDOMStorageEvent>& aEvent)
 11326   nsresult rv;
 11328   bool canBubble;
 11329   bool cancelable;
 11330   nsAutoString key;
 11331   nsAutoString oldValue;
 11332   nsAutoString newValue;
 11333   nsAutoString url;
 11334   nsCOMPtr<nsIDOMStorage> storageArea;
 11336   nsCOMPtr<nsIDOMEvent> domEvent = do_QueryInterface(aEvent, &rv);
 11337   NS_ENSURE_SUCCESS(rv, rv);
 11339   domEvent->GetBubbles(&canBubble);
 11340   domEvent->GetCancelable(&cancelable);
 11342   aEvent->GetKey(key);
 11343   aEvent->GetOldValue(oldValue);
 11344   aEvent->GetNewValue(newValue);
 11345   aEvent->GetUrl(url);
 11346   aEvent->GetStorageArea(getter_AddRefs(storageArea));
 11348   NS_NewDOMStorageEvent(getter_AddRefs(domEvent), this, nullptr, nullptr);
 11349   aEvent = do_QueryInterface(domEvent);
 11350   return aEvent->InitStorageEvent(aType, canBubble, cancelable,
 11351                                   key, oldValue, newValue,
 11352                                   url, storageArea);
 11355 nsresult
 11356 nsGlobalWindow::FireDelayedDOMEvents()
 11358   FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
 11360   for (int32_t i = 0; i < mPendingStorageEvents.Count(); ++i) {
 11361     Observe(mPendingStorageEvents[i], "dom-storage2-changed", nullptr);
 11364   if (mApplicationCache) {
 11365     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
 11368   if (mFireOfflineStatusChangeEventOnThaw) {
 11369     mFireOfflineStatusChangeEventOnThaw = false;
 11370     FireOfflineStatusEvent();
 11373   if (mNotifyIdleObserversIdleOnThaw) {
 11374     mNotifyIdleObserversIdleOnThaw = false;
 11375     HandleIdleActiveEvent();
 11378   if (mNotifyIdleObserversActiveOnThaw) {
 11379     mNotifyIdleObserversActiveOnThaw = false;
 11380     ScheduleActiveTimerCallback();
 11383   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
 11384   if (docShell) {
 11385     int32_t childCount = 0;
 11386     docShell->GetChildCount(&childCount);
 11388     for (int32_t i = 0; i < childCount; ++i) {
 11389       nsCOMPtr<nsIDocShellTreeItem> childShell;
 11390       docShell->GetChildAt(i, getter_AddRefs(childShell));
 11391       NS_ASSERTION(childShell, "null child shell");
 11393       nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
 11394       if (pWin) {
 11395         nsGlobalWindow *win =
 11396           static_cast<nsGlobalWindow*>
 11397                      (static_cast<nsPIDOMWindow*>(pWin));
 11398         win->FireDelayedDOMEvents();
 11403   return NS_OK;
 11406 //*****************************************************************************
 11407 // nsGlobalWindow: Window Control Functions
 11408 //*****************************************************************************
 11410 nsIDOMWindow *
 11411 nsGlobalWindow::GetParentInternal()
 11413   if (IsInnerWindow()) {
 11414     nsGlobalWindow* outer = GetOuterWindowInternal();
 11415     if (!outer) {
 11416       NS_WARNING("No outer window available!");
 11417       return nullptr;
 11419     return outer->GetParentInternal();
 11422   nsCOMPtr<nsIDOMWindow> parent;
 11423   GetParent(getter_AddRefs(parent));
 11425   if (parent && parent != static_cast<nsIDOMWindow *>(this)) {
 11426     return parent;
 11429   return nullptr;
 11432 void
 11433 nsGlobalWindow::UnblockScriptedClosing()
 11435   MOZ_ASSERT(IsOuterWindow());
 11436   mBlockScriptedClosingFlag = false;
 11439 class AutoUnblockScriptClosing
 11441 private:
 11442   nsRefPtr<nsGlobalWindow> mWin;
 11443 public:
 11444   AutoUnblockScriptClosing(nsGlobalWindow* aWin)
 11445     : mWin(aWin)
 11447     MOZ_ASSERT(mWin);
 11448     MOZ_ASSERT(mWin->IsOuterWindow());
 11450   ~AutoUnblockScriptClosing()
 11452     void (nsGlobalWindow::*run)() = &nsGlobalWindow::UnblockScriptedClosing;
 11453     NS_DispatchToCurrentThread(NS_NewRunnableMethod(mWin, run));
 11455 };
 11457 nsresult
 11458 nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
 11459                              const nsAString& aOptions, bool aDialog,
 11460                              bool aContentModal, bool aCalledNoScript,
 11461                              bool aDoJSFixups, bool aNavigate,
 11462                              nsIArray *argv,
 11463                              nsISupports *aExtraArgument,
 11464                              nsIPrincipal *aCalleePrincipal,
 11465                              JSContext *aJSCallerContext,
 11466                              nsIDOMWindow **aReturn)
 11468   FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
 11469                                   aContentModal, aCalledNoScript, aDoJSFixups,
 11470                                   aNavigate, argv, aExtraArgument,
 11471                                   aCalleePrincipal, aJSCallerContext, aReturn),
 11472                    NS_ERROR_NOT_INITIALIZED);
 11474 #ifdef DEBUG
 11475   uint32_t argc = 0;
 11476   if (argv)
 11477       argv->GetLength(&argc);
 11478 #endif
 11479   NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
 11480                   "Can't pass in arguments both ways");
 11481   NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
 11482                   "Can't pass JS args when called via the noscript methods");
 11483   NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
 11484                   "Shouldn't have caller context when called noscript");
 11486   mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
 11488   // Calls to window.open from script should navigate.
 11489   MOZ_ASSERT(aCalledNoScript || aNavigate);
 11491   *aReturn = nullptr;
 11493   nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
 11494   if (!chrome) {
 11495     // No chrome means we don't want to go through with this open call
 11496     // -- see nsIWindowWatcher.idl
 11497     return NS_ERROR_NOT_AVAILABLE;
 11500   NS_ASSERTION(mDocShell, "Must have docshell here");
 11502   // Popups from apps are never blocked.
 11503   bool isApp = false;
 11504   if (mDoc) {
 11505     isApp = mDoc->NodePrincipal()->GetAppStatus() >=
 11506               nsIPrincipal::APP_STATUS_INSTALLED;
 11509   const bool checkForPopup = !nsContentUtils::IsCallerChrome() &&
 11510     !isApp && !aDialog && !WindowExists(aName, !aCalledNoScript);
 11512   // Note: it's very important that this be an nsXPIDLCString, since we want
 11513   // .get() on it to return nullptr until we write stuff to it.  The window
 11514   // watcher expects a null URL string if there is no URL to load.
 11515   nsXPIDLCString url;
 11516   nsresult rv = NS_OK;
 11518   // It's important to do this security check before determining whether this
 11519   // window opening should be blocked, to ensure that we don't FireAbuseEvents
 11520   // for a window opening that wouldn't have succeeded in the first place.
 11521   if (!aUrl.IsEmpty()) {
 11522     AppendUTF16toUTF8(aUrl, url);
 11524     // It's safe to skip the security check below if we're not a dialog
 11525     // because window.openDialog is not callable from content script.  See bug
 11526     // 56851.
 11527     //
 11528     // If we're not navigating, we assume that whoever *does* navigate the
 11529     // window will do a security check of their own.
 11530     if (url.get() && !aDialog && aNavigate)
 11531       rv = SecurityCheckURL(url.get());
 11534   if (NS_FAILED(rv))
 11535     return rv;
 11537   PopupControlState abuseLevel = gPopupControlState;
 11538   if (checkForPopup) {
 11539     abuseLevel = RevisePopupAbuseLevel(abuseLevel);
 11540     if (abuseLevel >= openAbused) {
 11541       if (aJSCallerContext) {
 11542         // If script in some other window is doing a window.open on us and
 11543         // it's being blocked, then it's OK to close us afterwards, probably.
 11544         // But if we're doing a window.open on ourselves and block the popup,
 11545         // prevent this window from closing until after this script terminates
 11546         // so that whatever popup blocker UI the app has will be visible.
 11547         if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
 11548           mBlockScriptedClosingFlag = true;
 11549           closeUnblocker.construct(this);
 11553       FireAbuseEvents(true, false, aUrl, aName, aOptions);
 11554       return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
 11558   nsCOMPtr<nsIDOMWindow> domReturn;
 11560   nsCOMPtr<nsIWindowWatcher> wwatch =
 11561     do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
 11562   NS_ENSURE_TRUE(wwatch, rv);
 11564   NS_ConvertUTF16toUTF8 options(aOptions);
 11565   NS_ConvertUTF16toUTF8 name(aName);
 11567   const char *options_ptr = aOptions.IsEmpty() ? nullptr : options.get();
 11568   const char *name_ptr = aName.IsEmpty() ? nullptr : name.get();
 11570   nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
 11571   NS_ENSURE_STATE(pwwatch);
 11574     // Reset popup state while opening a window to prevent the
 11575     // current state from being active the whole time a modal
 11576     // dialog is open.
 11577     nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 11579     if (!aCalledNoScript) {
 11580       // We asserted at the top of this function that aNavigate is true for
 11581       // !aCalledNoScript.
 11582       rv = pwwatch->OpenWindow2(this, url.get(), name_ptr, options_ptr,
 11583                                 /* aCalledFromScript = */ true,
 11584                                 aDialog, aNavigate, argv,
 11585                                 getter_AddRefs(domReturn));
 11586     } else {
 11587       // Force a system caller here so that the window watcher won't screw us
 11588       // up.  We do NOT want this case looking at the JS context on the stack
 11589       // when searching.  Compare comments on
 11590       // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
 11592       // Note: Because nsWindowWatcher is so broken, it's actually important
 11593       // that we don't force a system caller here, because that screws it up
 11594       // when it tries to compute the caller principal to associate with dialog
 11595       // arguments. That whole setup just really needs to be rewritten. :-(
 11596       Maybe<AutoNoJSAPI> nojsapi;
 11597       if (!aContentModal) {
 11598         nojsapi.construct();
 11602       rv = pwwatch->OpenWindow2(this, url.get(), name_ptr, options_ptr,
 11603                                 /* aCalledFromScript = */ false,
 11604                                 aDialog, aNavigate, aExtraArgument,
 11605                                 getter_AddRefs(domReturn));
 11610   NS_ENSURE_SUCCESS(rv, rv);
 11612   // success!
 11614   NS_ENSURE_TRUE(domReturn, NS_OK);
 11615   domReturn.swap(*aReturn);
 11617   if (aDoJSFixups) {
 11618     nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
 11619     if (!chrome_win) {
 11620       // A new non-chrome window was created from a call to
 11621       // window.open() from JavaScript, make sure there's a document in
 11622       // the new window. We do this by simply asking the new window for
 11623       // its document, this will synchronously create an empty document
 11624       // if there is no document in the window.
 11625       // XXXbz should this just use EnsureInnerWindow()?
 11626 #ifdef DEBUG_jst
 11628         nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
 11629         NS_ASSERTION(pidomwin->GetExtantDoc(), "No document in new window!!!");
 11631 #endif
 11633       nsCOMPtr<nsIDOMDocument> doc;
 11634       (*aReturn)->GetDocument(getter_AddRefs(doc));
 11638   if (checkForPopup) {
 11639     if (abuseLevel >= openControlled) {
 11640       nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
 11641       if (!opened->IsPopupSpamWindow()) {
 11642         opened->SetPopupSpamWindow(true);
 11643         ++gOpenPopupSpamCount;
 11646     if (abuseLevel >= openAbused)
 11647       FireAbuseEvents(false, true, aUrl, aName, aOptions);
 11650   return rv;
 11653 //*****************************************************************************
 11654 // nsGlobalWindow: Timeout Functions
 11655 //*****************************************************************************
 11657 uint32_t sNestingLevel;
 11659 nsGlobalWindow*
 11660 nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult& aError)
 11662   nsGlobalWindow* currentInner;
 11663   nsGlobalWindow* forwardTo;
 11664   if (IsInnerWindow()) {
 11665     nsGlobalWindow* outer = GetOuterWindowInternal();
 11666     currentInner = outer ? outer->GetCurrentInnerWindowInternal() : this;
 11668     forwardTo = this;
 11669   } else {
 11670     currentInner = GetCurrentInnerWindowInternal();
 11672     // This needs to forward to the inner window, but since the current
 11673     // inner may not be the inner in the calling scope, we need to treat
 11674     // this specially here as we don't want timeouts registered in a
 11675     // dying inner window to get registered and run on the current inner
 11676     // window. To get this right, we need to forward this call to the
 11677     // inner window that's calling window.setTimeout().
 11679     forwardTo = CallerInnerWindow();
 11680     if (!forwardTo) {
 11681       aError.Throw(NS_ERROR_NOT_AVAILABLE);
 11682       return nullptr;
 11685     // If the caller and the callee share the same outer window, forward to the
 11686     // caller inner. Else, we forward to the current inner (e.g. someone is
 11687     // calling setTimeout() on a reference to some other window).
 11688     if (forwardTo->GetOuterWindow() != this || !forwardTo->IsInnerWindow()) {
 11689       if (!currentInner) {
 11690         NS_WARNING("No inner window available!");
 11691         aError.Throw(NS_ERROR_NOT_INITIALIZED);
 11692         return nullptr;
 11695       return currentInner;
 11699   // If forwardTo is not the window with an active document then we want the
 11700   // call to setTimeout/Interval to be a noop, so return null but don't set an
 11701   // error.
 11702   return forwardTo->HasActiveDocument() ? currentInner : nullptr;
 11705 int32_t
 11706 nsGlobalWindow::SetTimeout(JSContext* aCx, Function& aFunction,
 11707                            int32_t aTimeout,
 11708                            const Sequence<JS::Value>& aArguments,
 11709                            ErrorResult& aError)
 11711   return SetTimeoutOrInterval(aFunction, aTimeout, aArguments, false, aError);
 11714 int32_t
 11715 nsGlobalWindow::SetTimeout(JSContext* aCx, const nsAString& aHandler,
 11716                            int32_t aTimeout,
 11717                            const Sequence<JS::Value>& /* unused */,
 11718                            ErrorResult& aError)
 11720   return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError);
 11723 static bool
 11724 IsInterval(const Optional<int32_t>& aTimeout, int32_t& aResultTimeout)
 11726   if (aTimeout.WasPassed()) {
 11727     aResultTimeout = aTimeout.Value();
 11728     return true;
 11731   // If no interval was specified, treat this like a timeout, to avoid setting
 11732   // an interval of 0 milliseconds.
 11733   aResultTimeout = 0;
 11734   return false;
 11737 int32_t
 11738 nsGlobalWindow::SetInterval(JSContext* aCx, Function& aFunction,
 11739                             const Optional<int32_t>& aTimeout,
 11740                             const Sequence<JS::Value>& aArguments,
 11741                             ErrorResult& aError)
 11743   int32_t timeout;
 11744   bool isInterval = IsInterval(aTimeout, timeout);
 11745   return SetTimeoutOrInterval(aFunction, timeout, aArguments, isInterval,
 11746                               aError);
 11749 int32_t
 11750 nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler,
 11751                             const Optional<int32_t>& aTimeout,
 11752                             const Sequence<JS::Value>& /* unused */,
 11753                             ErrorResult& aError)
 11755   int32_t timeout;
 11756   bool isInterval = IsInterval(aTimeout, timeout);
 11757   return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError);
 11760 nsresult
 11761 nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
 11762                                      int32_t interval,
 11763                                      bool aIsInterval, int32_t *aReturn)
 11765   MOZ_ASSERT(IsInnerWindow());
 11767   // If we don't have a document (we could have been unloaded since
 11768   // the call to setTimeout was made), do nothing.
 11769   if (!mDoc) {
 11770     return NS_OK;
 11773   // Disallow negative intervals.  If aIsInterval also disallow 0,
 11774   // because we use that as a "don't repeat" flag.
 11775   interval = std::max(aIsInterval ? 1 : 0, interval);
 11777   // Make sure we don't proceed with an interval larger than our timer
 11778   // code can handle. (Note: we already forced |interval| to be non-negative,
 11779   // so the uint32_t cast (to avoid compiler warnings) is ok.)
 11780   uint32_t maxTimeoutMs = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
 11781   if (static_cast<uint32_t>(interval) > maxTimeoutMs) {
 11782     interval = maxTimeoutMs;
 11785   nsRefPtr<nsTimeout> timeout = new nsTimeout();
 11786   timeout->mIsInterval = aIsInterval;
 11787   timeout->mInterval = interval;
 11788   timeout->mScriptHandler = aHandler;
 11790   // Now clamp the actual interval we will use for the timer based on
 11791   uint32_t nestingLevel = sNestingLevel + 1;
 11792   uint32_t realInterval = interval;
 11793   if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
 11794     // Don't allow timeouts less than DOMMinTimeoutValue() from
 11795     // now...
 11796     realInterval = std::max(realInterval, uint32_t(DOMMinTimeoutValue()));
 11799   // Get principal of currently executing code, save for execution of timeout.
 11800   // If our principals subsume the subject principal then use the subject
 11801   // principal. Otherwise, use our principal to avoid running script in
 11802   // elevated principals.
 11804   nsCOMPtr<nsIPrincipal> subjectPrincipal;
 11805   nsresult rv;
 11806   rv = nsContentUtils::GetSecurityManager()->
 11807     GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
 11808   if (NS_FAILED(rv)) {
 11809     return NS_ERROR_FAILURE;
 11812   bool subsumes = false;
 11813   nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
 11815   // Note the direction of this test: We don't allow setTimeouts running with
 11816   // chrome privileges on content windows, but we do allow setTimeouts running
 11817   // with content privileges on chrome windows (where they can't do very much,
 11818   // of course).
 11819   rv = ourPrincipal->Subsumes(subjectPrincipal, &subsumes);
 11820   if (NS_FAILED(rv)) {
 11821     return NS_ERROR_FAILURE;
 11824   if (subsumes) {
 11825     timeout->mPrincipal = subjectPrincipal;
 11826   } else {
 11827     timeout->mPrincipal = ourPrincipal;
 11830   ++gTimeoutsRecentlySet;
 11831   TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
 11833   if (!IsFrozen() && !mTimeoutsSuspendDepth) {
 11834     // If we're not currently frozen, then we set timeout->mWhen to be the
 11835     // actual firing time of the timer (i.e., now + delta). We also actually
 11836     // create a timer and fire it off.
 11838     timeout->mWhen = TimeStamp::Now() + delta;
 11840     timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
 11841     if (NS_FAILED(rv)) {
 11842       return rv;
 11845     nsRefPtr<nsTimeout> copy = timeout;
 11847     rv = timeout->InitTimer(TimerCallback, realInterval);
 11848     if (NS_FAILED(rv)) {
 11849       return rv;
 11852     // The timeout is now also held in the timer's closure.
 11853     unused << copy.forget();
 11854   } else {
 11855     // If we are frozen, however, then we instead simply set
 11856     // timeout->mTimeRemaining to be the "time remaining" in the timeout (i.e.,
 11857     // the interval itself). We don't create a timer for it, since that will
 11858     // happen when we are thawed and the timeout will then get a timer and run
 11859     // to completion.
 11861     timeout->mTimeRemaining = delta;
 11864   timeout->mWindow = this;
 11866   if (!aIsInterval) {
 11867     timeout->mNestingLevel = nestingLevel;
 11870   // No popups from timeouts by default
 11871   timeout->mPopupState = openAbused;
 11873   if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
 11874     // This timeout is *not* set from another timeout and it's set
 11875     // while popups are enabled. Propagate the state to the timeout if
 11876     // its delay (interval) is equal to or less than what
 11877     // "dom.disable_open_click_delay" is set to (in ms).
 11879     int32_t delay =
 11880       Preferences::GetInt("dom.disable_open_click_delay");
 11882     // This is checking |interval|, not realInterval, on purpose,
 11883     // because our lower bound for |realInterval| could be pretty high
 11884     // in some cases.
 11885     if (interval <= delay) {
 11886       timeout->mPopupState = gPopupControlState;
 11890   InsertTimeoutIntoList(timeout);
 11892   timeout->mPublicId = ++mTimeoutPublicIdCounter;
 11893   *aReturn = timeout->mPublicId;
 11895   return NS_OK;
 11899 nsresult
 11900 nsGlobalWindow::SetTimeoutOrInterval(bool aIsInterval, int32_t *aReturn)
 11902   // This needs to forward to the inner window, but since the current
 11903   // inner may not be the inner in the calling scope, we need to treat
 11904   // this specially here as we don't want timeouts registered in a
 11905   // dying inner window to get registered and run on the current inner
 11906   // window. To get this right, we need to forward this call to the
 11907   // inner window that's calling window.setTimeout().
 11909   if (IsOuterWindow()) {
 11910     nsGlobalWindow* callerInner = CallerInnerWindow();
 11911     NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
 11913     // If the caller and the callee share the same outer window,
 11914     // forward to the callee inner. Else, we forward to the current
 11915     // inner (e.g. someone is calling setTimeout() on a reference to
 11916     // some other window).
 11918     if (callerInner->GetOuterWindow() == this &&
 11919         callerInner->IsInnerWindow()) {
 11920       return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
 11923     FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
 11924                      NS_ERROR_NOT_INITIALIZED);
 11927   int32_t interval = 0;
 11928   bool isInterval = aIsInterval;
 11929   nsCOMPtr<nsIScriptTimeoutHandler> handler;
 11930   nsresult rv = NS_CreateJSTimeoutHandler(this,
 11931                                           &isInterval,
 11932                                           &interval,
 11933                                           getter_AddRefs(handler));
 11934   if (!handler) {
 11935     *aReturn = 0;
 11936     return rv;
 11939   return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
 11942 int32_t
 11943 nsGlobalWindow::SetTimeoutOrInterval(Function& aFunction, int32_t aTimeout,
 11944                                      const Sequence<JS::Value>& aArguments,
 11945                                      bool aIsInterval, ErrorResult& aError)
 11947   nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
 11948   if (!inner) {
 11949     return -1;
 11952   if (inner != this) {
 11953     return inner->SetTimeoutOrInterval(aFunction, aTimeout, aArguments,
 11954                                        aIsInterval, aError);
 11957   nsCOMPtr<nsIScriptTimeoutHandler> handler =
 11958     NS_CreateJSTimeoutHandler(this, aFunction, aArguments, aError);
 11959   if (!handler) {
 11960     return 0;
 11963   int32_t result;
 11964   aError = SetTimeoutOrInterval(handler, aTimeout, aIsInterval, &result);
 11965   return result;
 11968 int32_t
 11969 nsGlobalWindow::SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
 11970                                      int32_t aTimeout, bool aIsInterval,
 11971                                      ErrorResult& aError)
 11973   nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
 11974   if (!inner) {
 11975     return -1;
 11978   if (inner != this) {
 11979     return inner->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
 11980                                        aError);
 11983   nsCOMPtr<nsIScriptTimeoutHandler> handler =
 11984     NS_CreateJSTimeoutHandler(aCx, this, aHandler, aError);
 11985   if (!handler) {
 11986     return 0;
 11989   int32_t result;
 11990   aError = SetTimeoutOrInterval(handler, aTimeout, aIsInterval, &result);
 11991   return result;
 11994 bool
 11995 nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
 11996                                   nsIScriptContext* aScx)
 11998   // Hold on to the timeout in case mExpr or mFunObj releases its
 11999   // doc.
 12000   nsRefPtr<nsTimeout> timeout = aTimeout;
 12001   nsTimeout* last_running_timeout = mRunningTimeout;
 12002   mRunningTimeout = timeout;
 12003   timeout->mRunning = true;
 12005   // Push this timeout's popup control state, which should only be
 12006   // eabled the first time a timeout fires that was created while
 12007   // popups were enabled and with a delay less than
 12008   // "dom.disable_open_click_delay".
 12009   nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
 12011   // Clear the timeout's popup state, if any, to prevent interval
 12012   // timeouts from repeatedly opening poups.
 12013   timeout->mPopupState = openAbused;
 12015   ++gRunningTimeoutDepth;
 12016   ++mTimeoutFiringDepth;
 12018   bool trackNestingLevel = !timeout->mIsInterval;
 12019   uint32_t nestingLevel;
 12020   if (trackNestingLevel) {
 12021     nestingLevel = sNestingLevel;
 12022     sNestingLevel = timeout->mNestingLevel;
 12025   nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
 12026   nsRefPtr<Function> callback = handler->GetCallback();
 12027   if (!callback) {
 12028     // Evaluate the timeout expression.
 12029     const char16_t* script = handler->GetHandlerText();
 12030     NS_ASSERTION(script, "timeout has no script nor handler text!");
 12032     const char* filename = nullptr;
 12033     uint32_t lineNo = 0;
 12034     handler->GetLocation(&filename, &lineNo);
 12036     // New script entry point required, due to the "Create a script" sub-step of
 12037     // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialization-steps
 12038     AutoEntryScript entryScript(this, true, aScx->GetNativeContext());
 12039     JS::CompileOptions options(entryScript.cx());
 12040     options.setFileAndLine(filename, lineNo)
 12041            .setVersion(JSVERSION_DEFAULT);
 12042     JS::Rooted<JSObject*> global(entryScript.cx(), FastGetGlobalJSObject());
 12043     nsJSUtils::EvaluateString(entryScript.cx(), nsDependentString(script),
 12044                               global, options);
 12045   } else {
 12046     // Hold strong ref to ourselves while we call the callback.
 12047     nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
 12048     ErrorResult ignored;
 12049     JS::Rooted<JS::Value> ignoredVal(CycleCollectedJSRuntime::Get()->Runtime());
 12050     callback->Call(me, handler->GetArgs(), &ignoredVal, ignored);
 12053   // We ignore any failures from calling EvaluateString() on the context or
 12054   // Call() on a Function here since we're in a loop
 12055   // where we're likely to be running timeouts whose OS timers
 12056   // didn't fire in time and we don't want to not fire those timers
 12057   // now just because execution of one timer failed. We can't
 12058   // propagate the error to anyone who cares about it from this
 12059   // point anyway, and the script context should have already reported
 12060   // the script error in the usual way - so we just drop it.
 12062   if (trackNestingLevel) {
 12063     sNestingLevel = nestingLevel;
 12066   --mTimeoutFiringDepth;
 12067   --gRunningTimeoutDepth;
 12069   mRunningTimeout = last_running_timeout;
 12070   timeout->mRunning = false;
 12071   return timeout->mCleared;
 12074 bool
 12075 nsGlobalWindow::RescheduleTimeout(nsTimeout* aTimeout, const TimeStamp& now,
 12076                                   bool aRunningPendingTimeouts)
 12078   if (!aTimeout->mIsInterval) {
 12079     if (aTimeout->mTimer) {
 12080       // The timeout still has an OS timer, and it's not an interval,
 12081       // that means that the OS timer could still fire; cancel the OS
 12082       // timer and release its reference to the timeout.
 12083       aTimeout->mTimer->Cancel();
 12084       aTimeout->mTimer = nullptr;
 12085       aTimeout->Release();
 12087     return false;
 12090   // Compute time to next timeout for interval timer.
 12091   // Make sure nextInterval is at least DOMMinTimeoutValue().
 12092   TimeDuration nextInterval =
 12093     TimeDuration::FromMilliseconds(std::max(aTimeout->mInterval,
 12094                                           uint32_t(DOMMinTimeoutValue())));
 12096   // If we're running pending timeouts, set the next interval to be
 12097   // relative to "now", and not to when the timeout that was pending
 12098   // should have fired.
 12099   TimeStamp firingTime;
 12100   if (aRunningPendingTimeouts) {
 12101     firingTime = now + nextInterval;
 12102   } else {
 12103     firingTime = aTimeout->mWhen + nextInterval;
 12106   TimeStamp currentNow = TimeStamp::Now();
 12107   TimeDuration delay = firingTime - currentNow;
 12109   // And make sure delay is nonnegative; that might happen if the timer
 12110   // thread is firing our timers somewhat early or if they're taking a long
 12111   // time to run the callback.
 12112   if (delay < TimeDuration(0)) {
 12113     delay = TimeDuration(0);
 12116   if (!aTimeout->mTimer) {
 12117     NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
 12118                  "How'd our timer end up null if we're not frozen or "
 12119                  "suspended?");
 12121     aTimeout->mTimeRemaining = delay;
 12122     return true;
 12125   aTimeout->mWhen = currentNow + delay;
 12127   // Reschedule the OS timer. Don't bother returning any error codes if
 12128   // this fails since the callers of this method don't care about them.
 12129   nsresult rv = aTimeout->InitTimer(TimerCallback, delay.ToMilliseconds());
 12131   if (NS_FAILED(rv)) {
 12132     NS_ERROR("Error initializing timer for DOM timeout!");
 12134     // We failed to initialize the new OS timer, this timer does
 12135     // us no good here so we just cancel it (just in case) and
 12136     // null out the pointer to the OS timer, this will release the
 12137     // OS timer. As we continue executing the code below we'll end
 12138     // up deleting the timeout since it's not an interval timeout
 12139     // any more (since timeout->mTimer == nullptr).
 12140     aTimeout->mTimer->Cancel();
 12141     aTimeout->mTimer = nullptr;
 12143     // Now that the OS timer no longer has a reference to the
 12144     // timeout we need to drop that reference.
 12145     aTimeout->Release();
 12147     return false;
 12150   return true;
 12153 void
 12154 nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
 12156   // If a modal dialog is open for this window, return early. Pending
 12157   // timeouts will run when the modal dialog is dismissed.
 12158   if (IsInModalState() || mTimeoutsSuspendDepth) {
 12159     return;
 12162   NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
 12163   NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
 12165   nsTimeout *nextTimeout;
 12166   nsTimeout *last_expired_timeout, *last_insertion_point;
 12167   uint32_t firingDepth = mTimeoutFiringDepth + 1;
 12169   // Make sure that the window and the script context don't go away as
 12170   // a result of running timeouts
 12171   nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
 12173   // A native timer has gone off. See which of our timeouts need
 12174   // servicing
 12175   TimeStamp now = TimeStamp::Now();
 12176   TimeStamp deadline;
 12178   if (aTimeout && aTimeout->mWhen > now) {
 12179     // The OS timer fired early (which can happen due to the timers
 12180     // having lower precision than TimeStamp does).  Set |deadline| to
 12181     // be the time when the OS timer *should* have fired so that any
 12182     // timers that *should* have fired before aTimeout *will* be fired
 12183     // now.
 12185     deadline = aTimeout->mWhen;
 12186   } else {
 12187     deadline = now;
 12190   // The timeout list is kept in deadline order. Discover the latest
 12191   // timeout whose deadline has expired. On some platforms, native
 12192   // timeout events fire "early", so we need to test the timer as well
 12193   // as the deadline.
 12194   last_expired_timeout = nullptr;
 12195   for (nsTimeout *timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
 12196     if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
 12197         (timeout->mFiringDepth == 0)) {
 12198       // Mark any timeouts that are on the list to be fired with the
 12199       // firing depth so that we can reentrantly run timeouts
 12200       timeout->mFiringDepth = firingDepth;
 12201       last_expired_timeout = timeout;
 12205   // Maybe the timeout that the event was fired for has been deleted
 12206   // and there are no others timeouts with deadlines that make them
 12207   // eligible for execution yet. Go away.
 12208   if (!last_expired_timeout) {
 12209     return;
 12212   // Record telemetry information about timers set recently.
 12213   TimeDuration recordingInterval = TimeDuration::FromMilliseconds(STATISTICS_INTERVAL);
 12214   if (gLastRecordedRecentTimeouts.IsNull() ||
 12215       now - gLastRecordedRecentTimeouts > recordingInterval) {
 12216     uint32_t count = gTimeoutsRecentlySet;
 12217     gTimeoutsRecentlySet = 0;
 12218     Telemetry::Accumulate(Telemetry::DOM_TIMERS_RECENTLY_SET, count);
 12219     gLastRecordedRecentTimeouts = now;
 12222   // Insert a dummy timeout into the list of timeouts between the
 12223   // portion of the list that we are about to process now and those
 12224   // timeouts that will be processed in a future call to
 12225   // win_run_timeout(). This dummy timeout serves as the head of the
 12226   // list for any timeouts inserted as a result of running a timeout.
 12227   nsRefPtr<nsTimeout> dummy_timeout = new nsTimeout();
 12228   dummy_timeout->mFiringDepth = firingDepth;
 12229   dummy_timeout->mWhen = now;
 12230   last_expired_timeout->setNext(dummy_timeout);
 12231   dummy_timeout->AddRef();
 12233   last_insertion_point = mTimeoutInsertionPoint;
 12234   // If we ever start setting mTimeoutInsertionPoint to a non-dummy timeout,
 12235   // the logic in ResetTimersForNonBackgroundWindow will need to change.
 12236   mTimeoutInsertionPoint = dummy_timeout;
 12238   Telemetry::AutoCounter<Telemetry::DOM_TIMERS_FIRED_PER_NATIVE_TIMEOUT> timeoutsRan;
 12240   for (nsTimeout *timeout = mTimeouts.getFirst();
 12241        timeout != dummy_timeout && !IsFrozen();
 12242        timeout = nextTimeout) {
 12243     nextTimeout = timeout->getNext();
 12245     if (timeout->mFiringDepth != firingDepth) {
 12246       // We skip the timeout since it's on the list to run at another
 12247       // depth.
 12249       continue;
 12252     if (mTimeoutsSuspendDepth) {
 12253       // Some timer did suspend us. Make sure the
 12254       // rest of the timers get executed later.
 12255       timeout->mFiringDepth = 0;
 12256       continue;
 12259     // The timeout is on the list to run at this depth, go ahead and
 12260     // process it.
 12262     // Get the script context (a strong ref to prevent it going away)
 12263     // for this timeout and ensure the script language is enabled.
 12264     nsCOMPtr<nsIScriptContext> scx = GetContextInternal();
 12266     if (!scx) {
 12267       // No context means this window was closed or never properly
 12268       // initialized for this language.
 12269       continue;
 12272     // This timeout is good to run
 12273     ++timeoutsRan;
 12274     bool timeout_was_cleared = RunTimeoutHandler(timeout, scx);
 12276     if (timeout_was_cleared) {
 12277       // The running timeout's window was cleared, this means that
 12278       // ClearAllTimeouts() was called from a *nested* call, possibly
 12279       // through a timeout that fired while a modal (to this window)
 12280       // dialog was open or through other non-obvious paths.
 12281       MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
 12283       mTimeoutInsertionPoint = last_insertion_point;
 12285       return;
 12288     // If we have a regular interval timer, we re-schedule the
 12289     // timeout, accounting for clock drift.
 12290     bool needsReinsertion = RescheduleTimeout(timeout, now, !aTimeout);
 12292     // Running a timeout can cause another timeout to be deleted, so
 12293     // we need to reset the pointer to the following timeout.
 12294     nextTimeout = timeout->getNext();
 12296     timeout->remove();
 12298     if (needsReinsertion) {
 12299       // Insert interval timeout onto list sorted in deadline order.
 12300       // AddRefs timeout.
 12301       InsertTimeoutIntoList(timeout);
 12304     // Release the timeout struct since it's possibly out of the list
 12305     timeout->Release();
 12308   // Take the dummy timeout off the head of the list
 12309   dummy_timeout->remove();
 12310   dummy_timeout->Release();
 12311   MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
 12313   mTimeoutInsertionPoint = last_insertion_point;
 12316 void
 12317 nsGlobalWindow::ClearTimeoutOrInterval(int32_t aTimerID, ErrorResult& aError)
 12319   FORWARD_TO_INNER_OR_THROW(ClearTimeoutOrInterval, (aTimerID, aError),
 12320                             aError, );
 12322   uint32_t public_id = (uint32_t)aTimerID;
 12323   nsTimeout *timeout;
 12325   for (timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
 12326     if (timeout->mPublicId == public_id) {
 12327       if (timeout->mRunning) {
 12328         /* We're running from inside the timeout. Mark this
 12329            timeout for deferred deletion by the code in
 12330            RunTimeout() */
 12331         timeout->mIsInterval = false;
 12333       else {
 12334         /* Delete the timeout from the pending timeout list */
 12335         timeout->remove();
 12337         if (timeout->mTimer) {
 12338           timeout->mTimer->Cancel();
 12339           timeout->mTimer = nullptr;
 12340           timeout->Release();
 12342         timeout->Release();
 12344       break;
 12349 nsresult nsGlobalWindow::ResetTimersForNonBackgroundWindow()
 12351   FORWARD_TO_INNER(ResetTimersForNonBackgroundWindow, (),
 12352                    NS_ERROR_NOT_INITIALIZED);
 12354   if (IsFrozen() || mTimeoutsSuspendDepth) {
 12355     return NS_OK;
 12358   TimeStamp now = TimeStamp::Now();
 12360   // If mTimeoutInsertionPoint is non-null, we're in the middle of firing
 12361   // timers and the timers we're planning to fire all come before
 12362   // mTimeoutInsertionPoint; mTimeoutInsertionPoint itself is a dummy timeout
 12363   // with an mWhen that may be semi-bogus.  In that case, we don't need to do
 12364   // anything with mTimeoutInsertionPoint or anything before it, so should
 12365   // start at the timer after mTimeoutInsertionPoint, if there is one.
 12366   // Otherwise, start at the beginning of the list.
 12367   for (nsTimeout *timeout = mTimeoutInsertionPoint ?
 12368          mTimeoutInsertionPoint->getNext() : mTimeouts.getFirst();
 12369        timeout; ) {
 12370     // It's important that this check be <= so that we guarantee that
 12371     // taking std::max with |now| won't make a quantity equal to
 12372     // timeout->mWhen below.
 12373     if (timeout->mWhen <= now) {
 12374       timeout = timeout->getNext();
 12375       continue;
 12378     if (timeout->mWhen - now >
 12379         TimeDuration::FromMilliseconds(gMinBackgroundTimeoutValue)) {
 12380       // No need to loop further.  Timeouts are sorted in mWhen order
 12381       // and the ones after this point were all set up for at least
 12382       // gMinBackgroundTimeoutValue ms and hence were not clamped.
 12383       break;
 12386     /* We switched from background. Re-init the timer appropriately */
 12387     // Compute the interval the timer should have had if it had not been set in a
 12388     // background window
 12389     TimeDuration interval =
 12390       TimeDuration::FromMilliseconds(std::max(timeout->mInterval,
 12391                                             uint32_t(DOMMinTimeoutValue())));
 12392     uint32_t oldIntervalMillisecs = 0;
 12393     timeout->mTimer->GetDelay(&oldIntervalMillisecs);
 12394     TimeDuration oldInterval = TimeDuration::FromMilliseconds(oldIntervalMillisecs);
 12395     if (oldInterval > interval) {
 12396       // unclamp
 12397       TimeStamp firingTime =
 12398         std::max(timeout->mWhen - oldInterval + interval, now);
 12400       NS_ASSERTION(firingTime < timeout->mWhen,
 12401                    "Our firing time should strictly decrease!");
 12403       TimeDuration delay = firingTime - now;
 12404       timeout->mWhen = firingTime;
 12406       // Since we reset mWhen we need to move |timeout| to the right
 12407       // place in the list so that it remains sorted by mWhen.
 12409       // Get the pointer to the next timeout now, before we move the
 12410       // current timeout in the list.
 12411       nsTimeout* nextTimeout = timeout->getNext();
 12413       // It is safe to remove and re-insert because mWhen is now
 12414       // strictly smaller than it used to be, so we know we'll insert
 12415       // |timeout| before nextTimeout.
 12416       NS_ASSERTION(!nextTimeout ||
 12417                    timeout->mWhen < nextTimeout->mWhen, "How did that happen?");
 12418       timeout->remove();
 12419       // InsertTimeoutIntoList will addref |timeout| and reset
 12420       // mFiringDepth.  Make sure to undo that after calling it.
 12421       uint32_t firingDepth = timeout->mFiringDepth;
 12422       InsertTimeoutIntoList(timeout);
 12423       timeout->mFiringDepth = firingDepth;
 12424       timeout->Release();
 12426       nsresult rv = timeout->InitTimer(TimerCallback, delay.ToMilliseconds());
 12428       if (NS_FAILED(rv)) {
 12429         NS_WARNING("Error resetting non background timer for DOM timeout!");
 12430         return rv;
 12433       timeout = nextTimeout;
 12434     } else {
 12435       timeout = timeout->getNext();
 12439   return NS_OK;
 12442 void
 12443 nsGlobalWindow::ClearAllTimeouts()
 12445   nsTimeout *timeout, *nextTimeout;
 12447   for (timeout = mTimeouts.getFirst(); timeout; timeout = nextTimeout) {
 12448     /* If RunTimeout() is higher up on the stack for this
 12449        window, e.g. as a result of document.write from a timeout,
 12450        then we need to reset the list insertion point for
 12451        newly-created timeouts in case the user adds a timeout,
 12452        before we pop the stack back to RunTimeout. */
 12453     if (mRunningTimeout == timeout)
 12454       mTimeoutInsertionPoint = nullptr;
 12456     nextTimeout = timeout->getNext();
 12458     if (timeout->mTimer) {
 12459       timeout->mTimer->Cancel();
 12460       timeout->mTimer = nullptr;
 12462       // Drop the count since the timer isn't going to hold on
 12463       // anymore.
 12464       timeout->Release();
 12467     // Set timeout->mCleared to true to indicate that the timeout was
 12468     // cleared and taken out of the list of timeouts
 12469     timeout->mCleared = true;
 12471     // Drop the count since we're removing it from the list.
 12472     timeout->Release();
 12475   // Clear out our list
 12476   mTimeouts.clear();
 12479 void
 12480 nsGlobalWindow::InsertTimeoutIntoList(nsTimeout *aTimeout)
 12482   NS_ASSERTION(IsInnerWindow(),
 12483                "InsertTimeoutIntoList() called on outer window!");
 12485   // Start at mLastTimeout and go backwards.  Don't go further than
 12486   // mTimeoutInsertionPoint, though.  This optimizes for the common case of
 12487   // insertion at the end.
 12488   nsTimeout* prevSibling;
 12489   for (prevSibling = mTimeouts.getLast();
 12490        prevSibling && prevSibling != mTimeoutInsertionPoint &&
 12491          // This condition needs to match the one in SetTimeoutOrInterval that
 12492          // determines whether to set mWhen or mTimeRemaining.
 12493          ((IsFrozen() || mTimeoutsSuspendDepth) ?
 12494           prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
 12495           prevSibling->mWhen > aTimeout->mWhen);
 12496        prevSibling = prevSibling->getPrevious()) {
 12497     /* Do nothing; just searching */
 12500   // Now link in aTimeout after prevSibling.
 12501   if (prevSibling) {
 12502     prevSibling->setNext(aTimeout);
 12503   } else {
 12504     mTimeouts.insertFront(aTimeout);
 12507   aTimeout->mFiringDepth = 0;
 12509   // Increment the timeout's reference count since it's now held on to
 12510   // by the list
 12511   aTimeout->AddRef();
 12514 // static
 12515 void
 12516 nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
 12518   nsRefPtr<nsTimeout> timeout = (nsTimeout *)aClosure;
 12520   timeout->mWindow->RunTimeout(timeout);
 12523 //*****************************************************************************
 12524 // nsGlobalWindow: Helper Functions
 12525 //*****************************************************************************
 12527 already_AddRefed<nsIDocShellTreeOwner>
 12528 nsGlobalWindow::GetTreeOwner()
 12530   FORWARD_TO_OUTER(GetTreeOwner, (), nullptr);
 12532   // If there's no docShellAsItem, this window must have been closed,
 12533   // in that case there is no tree owner.
 12535   if (!mDocShell) {
 12536     return nullptr;
 12539   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
 12540   mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
 12541   return treeOwner.forget();
 12544 already_AddRefed<nsIBaseWindow>
 12545 nsGlobalWindow::GetTreeOwnerWindow()
 12547   MOZ_ASSERT(IsOuterWindow());
 12549   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
 12551   // If there's no mDocShell, this window must have been closed,
 12552   // in that case there is no tree owner.
 12554   if (mDocShell) {
 12555     mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
 12558   nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
 12559   return baseWindow.forget();
 12562 already_AddRefed<nsIWebBrowserChrome>
 12563 nsGlobalWindow::GetWebBrowserChrome()
 12565   nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
 12567   nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
 12568   return browserChrome.forget();
 12571 nsIScrollableFrame *
 12572 nsGlobalWindow::GetScrollFrame()
 12574   FORWARD_TO_OUTER(GetScrollFrame, (), nullptr);
 12576   if (!mDocShell) {
 12577     return nullptr;
 12580   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
 12581   if (presShell) {
 12582     return presShell->GetRootScrollFrameAsScrollable();
 12584   return nullptr;
 12587 nsresult
 12588 nsGlobalWindow::SecurityCheckURL(const char *aURL)
 12590   nsCOMPtr<nsPIDOMWindow> sourceWindow;
 12591   JSContext* topCx = nsContentUtils::GetCurrentJSContext();
 12592   if (topCx) {
 12593     sourceWindow = do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(topCx));
 12595   if (!sourceWindow) {
 12596     sourceWindow = this;
 12598   AutoJSContext cx;
 12599   nsGlobalWindow* sourceWin = static_cast<nsGlobalWindow*>(sourceWindow.get());
 12600   JSAutoCompartment ac(cx, sourceWin->GetGlobalJSObject());
 12602   // Resolve the baseURI, which could be relative to the calling window.
 12603   //
 12604   // Note the algorithm to get the base URI should match the one
 12605   // used to actually kick off the load in nsWindowWatcher.cpp.
 12606   nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
 12607   nsIURI* baseURI = nullptr;
 12608   nsAutoCString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
 12609   if (doc) {
 12610     baseURI = doc->GetDocBaseURI();
 12611     charset = doc->GetDocumentCharacterSet();
 12613   nsCOMPtr<nsIURI> uri;
 12614   nsresult rv = NS_NewURI(getter_AddRefs(uri), nsDependentCString(aURL),
 12615                           charset.get(), baseURI);
 12616   if (NS_WARN_IF(NS_FAILED(rv))) {
 12617     return rv;
 12620   if (NS_FAILED(nsContentUtils::GetSecurityManager()->
 12621         CheckLoadURIFromScript(cx, uri))) {
 12622     return NS_ERROR_FAILURE;
 12625   return NS_OK;
 12628 void
 12629 nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
 12631   if (mDoc) {
 12632     mDoc->FlushPendingNotifications(aType);
 12636 void
 12637 nsGlobalWindow::EnsureSizeUpToDate()
 12639   MOZ_ASSERT(IsOuterWindow());
 12641   // If we're a subframe, make sure our size is up to date.  It's OK that this
 12642   // crosses the content/chrome boundary, since chrome can have pending reflows
 12643   // too.
 12644   nsGlobalWindow *parent =
 12645     static_cast<nsGlobalWindow *>(GetPrivateParent());
 12646   if (parent) {
 12647     parent->FlushPendingNotifications(Flush_Layout);
 12651 already_AddRefed<nsISupports>
 12652 nsGlobalWindow::SaveWindowState()
 12654   NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
 12656   if (!mContext || !GetWrapperPreserveColor()) {
 12657     // The window may be getting torn down; don't bother saving state.
 12658     return nullptr;
 12661   nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
 12662   NS_ASSERTION(inner, "No inner window to save");
 12664   // Don't do anything else to this inner window! After this point, all
 12665   // calls to SetTimeoutOrInterval will create entries in the timeout
 12666   // list that will only run after this window has come out of the bfcache.
 12667   // Also, while we're frozen, we won't dispatch online/offline events
 12668   // to the page.
 12669   inner->Freeze();
 12671   nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
 12673 #ifdef DEBUG_PAGE_CACHE
 12674   printf("saving window state, state = %p\n", (void*)state);
 12675 #endif
 12677   return state.forget();
 12680 nsresult
 12681 nsGlobalWindow::RestoreWindowState(nsISupports *aState)
 12683   NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
 12685   if (!mContext || !GetWrapperPreserveColor()) {
 12686     // The window may be getting torn down; don't bother restoring state.
 12687     return NS_OK;
 12690   nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
 12691   NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
 12693 #ifdef DEBUG_PAGE_CACHE
 12694   printf("restoring window state, state = %p\n", (void*)holder);
 12695 #endif
 12697   // And we're ready to go!
 12698   nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
 12700   // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
 12701   // it easy to tell which link was last clicked when going back a page.
 12702   nsIContent* focusedNode = inner->GetFocusedNode();
 12703   if (IsLink(focusedNode)) {
 12704     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
 12705     if (fm) {
 12706       nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
 12707       fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
 12708                                    nsIFocusManager::FLAG_SHOWRING);
 12712   inner->Thaw();
 12714   holder->DidRestoreWindow();
 12716   return NS_OK;
 12719 void
 12720 nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease,
 12721                                 bool aFreezeChildren)
 12723   FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren));
 12725   bool suspended = (mTimeoutsSuspendDepth != 0);
 12726   mTimeoutsSuspendDepth += aIncrease;
 12728   if (!suspended) {
 12729     nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
 12730     if (ac) {
 12731       for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
 12732         ac->RemoveWindowListener(mEnabledSensors[i], this);
 12734     DisableGamepadUpdates();
 12736     // Suspend all of the workers for this window.
 12737     mozilla::dom::workers::SuspendWorkersForWindow(this);
 12739     TimeStamp now = TimeStamp::Now();
 12740     for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
 12741       // Set mTimeRemaining to be the time remaining for this timer.
 12742       if (t->mWhen > now)
 12743         t->mTimeRemaining = t->mWhen - now;
 12744       else
 12745         t->mTimeRemaining = TimeDuration(0);
 12747       // Drop the XPCOM timer; we'll reschedule when restoring the state.
 12748       if (t->mTimer) {
 12749         t->mTimer->Cancel();
 12750         t->mTimer = nullptr;
 12752         // Drop the reference that the timer's closure had on this timeout, we'll
 12753         // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
 12754         // passing null for the context, since this shouldn't actually release this
 12755         // timeout.
 12756         t->Release();
 12760     // Suspend all of the AudioContexts for this window
 12761     for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
 12762       mAudioContexts[i]->Suspend();
 12766   // Suspend our children as well.
 12767   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
 12768   if (docShell) {
 12769     int32_t childCount = 0;
 12770     docShell->GetChildCount(&childCount);
 12772     for (int32_t i = 0; i < childCount; ++i) {
 12773       nsCOMPtr<nsIDocShellTreeItem> childShell;
 12774       docShell->GetChildAt(i, getter_AddRefs(childShell));
 12775       NS_ASSERTION(childShell, "null child shell");
 12777       nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
 12778       if (pWin) {
 12779         nsGlobalWindow *win =
 12780           static_cast<nsGlobalWindow*>
 12781                      (static_cast<nsPIDOMWindow*>(pWin));
 12782         NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
 12783         nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
 12785         // This is a bit hackish. Only freeze/suspend windows which are truly our
 12786         // subwindows.
 12787         nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
 12788         if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
 12789           continue;
 12792         win->SuspendTimeouts(aIncrease, aFreezeChildren);
 12794         if (inner && aFreezeChildren) {
 12795           inner->Freeze();
 12802 nsresult
 12803 nsGlobalWindow::ResumeTimeouts(bool aThawChildren)
 12805   FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
 12807   NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
 12808   --mTimeoutsSuspendDepth;
 12809   bool shouldResume = (mTimeoutsSuspendDepth == 0) && !mInnerObjectsFreed;
 12810   nsresult rv;
 12812   if (shouldResume) {
 12813     nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
 12814     if (ac) {
 12815       for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
 12816         ac->AddWindowListener(mEnabledSensors[i], this);
 12818     EnableGamepadUpdates();
 12820     // Resume all of the AudioContexts for this window
 12821     for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
 12822       mAudioContexts[i]->Resume();
 12825     // Resume all of the workers for this window.
 12826     mozilla::dom::workers::ResumeWorkersForWindow(this);
 12828     // Restore all of the timeouts, using the stored time remaining
 12829     // (stored in timeout->mTimeRemaining).
 12831     TimeStamp now = TimeStamp::Now();
 12833 #ifdef DEBUG
 12834     bool _seenDummyTimeout = false;
 12835 #endif
 12837     for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
 12838       // There's a chance we're being called with RunTimeout on the stack in which
 12839       // case we have a dummy timeout in the list that *must not* be resumed. It
 12840       // can be identified by a null mWindow.
 12841       if (!t->mWindow) {
 12842 #ifdef DEBUG
 12843         NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
 12844         _seenDummyTimeout = true;
 12845 #endif
 12846         continue;
 12849       // XXXbz the combination of the way |delay| and |t->mWhen| are set here
 12850       // makes no sense.  Are we trying to impose that min timeout value or
 12851       // not???
 12852       uint32_t delay =
 12853         std::max(int32_t(t->mTimeRemaining.ToMilliseconds()),
 12854                DOMMinTimeoutValue());
 12856       // Set mWhen back to the time when the timer is supposed to
 12857       // fire.
 12858       t->mWhen = now + t->mTimeRemaining;
 12860       t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
 12861       NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
 12863       rv = t->InitTimer(TimerCallback, delay);
 12864       if (NS_FAILED(rv)) {
 12865         t->mTimer = nullptr;
 12866         return rv;
 12869       // Add a reference for the new timer's closure.
 12870       t->AddRef();
 12874   // Resume our children as well.
 12875   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
 12876   if (docShell) {
 12877     int32_t childCount = 0;
 12878     docShell->GetChildCount(&childCount);
 12880     for (int32_t i = 0; i < childCount; ++i) {
 12881       nsCOMPtr<nsIDocShellTreeItem> childShell;
 12882       docShell->GetChildAt(i, getter_AddRefs(childShell));
 12883       NS_ASSERTION(childShell, "null child shell");
 12885       nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
 12886       if (pWin) {
 12887         nsGlobalWindow *win =
 12888           static_cast<nsGlobalWindow*>
 12889                      (static_cast<nsPIDOMWindow*>(pWin));
 12891         NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
 12892         nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
 12894         // This is a bit hackish. Only thaw/resume windows which are truly our
 12895         // subwindows.
 12896         nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
 12897         if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
 12898           continue;
 12901         if (inner && aThawChildren) {
 12902           inner->Thaw();
 12905         rv = win->ResumeTimeouts(aThawChildren);
 12906         NS_ENSURE_SUCCESS(rv, rv);
 12911   return NS_OK;
 12914 uint32_t
 12915 nsGlobalWindow::TimeoutSuspendCount()
 12917   FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
 12918   return mTimeoutsSuspendDepth;
 12921 void
 12922 nsGlobalWindow::EnableDeviceSensor(uint32_t aType)
 12924   MOZ_ASSERT(IsInnerWindow());
 12926   bool alreadyEnabled = false;
 12927   for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
 12928     if (mEnabledSensors[i] == aType) {
 12929       alreadyEnabled = true;
 12930       break;
 12934   mEnabledSensors.AppendElement(aType);
 12936   if (alreadyEnabled) {
 12937     return;
 12940   nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
 12941   if (ac) {
 12942     ac->AddWindowListener(aType, this);
 12946 void
 12947 nsGlobalWindow::DisableDeviceSensor(uint32_t aType)
 12949   MOZ_ASSERT(IsInnerWindow());
 12951   int32_t doomedElement = -1;
 12952   int32_t listenerCount = 0;
 12953   for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
 12954     if (mEnabledSensors[i] == aType) {
 12955       doomedElement = i;
 12956       listenerCount++;
 12960   if (doomedElement == -1) {
 12961     return;
 12964   mEnabledSensors.RemoveElementAt(doomedElement);
 12966   if (listenerCount > 1) {
 12967     return;
 12970   nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
 12971   if (ac) {
 12972     ac->RemoveWindowListener(aType, this);
 12976 void
 12977 nsGlobalWindow::SetHasGamepadEventListener(bool aHasGamepad/* = true*/)
 12979   FORWARD_TO_INNER_VOID(SetHasGamepadEventListener, (aHasGamepad));
 12980   mHasGamepad = aHasGamepad;
 12981   if (aHasGamepad) {
 12982     EnableGamepadUpdates();
 12986 void
 12987 nsGlobalWindow::EnableTimeChangeNotifications()
 12989   mozilla::time::AddWindowListener(this);
 12992 void
 12993 nsGlobalWindow::DisableTimeChangeNotifications()
 12995   mozilla::time::RemoveWindowListener(this);
 12998 static PLDHashOperator
 12999 CollectSizeAndListenerCount(
 13000   nsPtrHashKey<DOMEventTargetHelper>* aEntry,
 13001   void *arg)
 13003   nsWindowSizes* windowSizes = static_cast<nsWindowSizes*>(arg);
 13005   DOMEventTargetHelper* et = aEntry->GetKey();
 13007   if (nsCOMPtr<nsISizeOfEventTarget> iSizeOf = do_QueryObject(et)) {
 13008     windowSizes->mDOMEventTargetsSize +=
 13009       iSizeOf->SizeOfEventTargetIncludingThis(windowSizes->mMallocSizeOf);
 13012   if (EventListenerManager* elm = et->GetExistingListenerManager()) {
 13013     windowSizes->mDOMEventListenersCount += elm->ListenerCount();
 13016   return PL_DHASH_NEXT;
 13019 void
 13020 nsGlobalWindow::AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
 13022   aWindowSizes->mDOMOtherSize += aWindowSizes->mMallocSizeOf(this);
 13024   if (IsInnerWindow()) {
 13025     EventListenerManager* elm = GetExistingListenerManager();
 13026     if (elm) {
 13027       aWindowSizes->mDOMOtherSize +=
 13028         elm->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
 13029       aWindowSizes->mDOMEventListenersCount +=
 13030         elm->ListenerCount();
 13032     if (mDoc) {
 13033       mDoc->DocAddSizeOfIncludingThis(aWindowSizes);
 13037   if (mNavigator) {
 13038     aWindowSizes->mDOMOtherSize +=
 13039       mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
 13042   // The things pointed to by the entries will be measured below, so we
 13043   // use nullptr for the callback here.
 13044   aWindowSizes->mDOMEventTargetsSize +=
 13045     mEventTargetObjects.SizeOfExcludingThis(nullptr,
 13046                                             aWindowSizes->mMallocSizeOf);
 13047   aWindowSizes->mDOMEventTargetsCount +=
 13048     const_cast<nsTHashtable<nsPtrHashKey<DOMEventTargetHelper> >*>
 13049       (&mEventTargetObjects)->EnumerateEntries(CollectSizeAndListenerCount,
 13050                                                aWindowSizes);
 13054 #ifdef MOZ_GAMEPAD
 13055 void
 13056 nsGlobalWindow::AddGamepad(uint32_t aIndex, Gamepad* aGamepad)
 13058   FORWARD_TO_INNER_VOID(AddGamepad, (aIndex, aGamepad));
 13059   mGamepads.Put(aIndex, aGamepad);
 13062 void
 13063 nsGlobalWindow::RemoveGamepad(uint32_t aIndex)
 13065   FORWARD_TO_INNER_VOID(RemoveGamepad, (aIndex));
 13066   mGamepads.Remove(aIndex);
 13069 // static
 13070 PLDHashOperator
 13071 nsGlobalWindow::EnumGamepadsForGet(const uint32_t& aKey, Gamepad* aData,
 13072                                    void* aUserArg)
 13074   nsTArray<nsRefPtr<Gamepad> >* array =
 13075     static_cast<nsTArray<nsRefPtr<Gamepad> >*>(aUserArg);
 13076   array->EnsureLengthAtLeast(aKey + 1);
 13077   (*array)[aKey] = aData;
 13078   return PL_DHASH_NEXT;
 13081 void
 13082 nsGlobalWindow::GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads)
 13084   FORWARD_TO_INNER_VOID(GetGamepads, (aGamepads));
 13085   aGamepads.Clear();
 13086   // mGamepads.Count() may not be sufficient, but it's not harmful.
 13087   aGamepads.SetCapacity(mGamepads.Count());
 13088   mGamepads.EnumerateRead(EnumGamepadsForGet, &aGamepads);
 13091 already_AddRefed<Gamepad>
 13092 nsGlobalWindow::GetGamepad(uint32_t aIndex)
 13094   FORWARD_TO_INNER(GetGamepad, (aIndex), nullptr);
 13095   nsRefPtr<Gamepad> gamepad;
 13096   if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
 13097     return gamepad.forget();
 13100   return nullptr;
 13103 void
 13104 nsGlobalWindow::SetHasSeenGamepadInput(bool aHasSeen)
 13106   FORWARD_TO_INNER_VOID(SetHasSeenGamepadInput, (aHasSeen));
 13107   mHasSeenGamepadInput = aHasSeen;
 13110 bool
 13111 nsGlobalWindow::HasSeenGamepadInput()
 13113   FORWARD_TO_INNER(HasSeenGamepadInput, (), false);
 13114   return mHasSeenGamepadInput;
 13117 // static
 13118 PLDHashOperator
 13119 nsGlobalWindow::EnumGamepadsForSync(const uint32_t& aKey, Gamepad* aData,
 13120                                     void* aUserArg)
 13122   nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
 13123   gamepadsvc->SyncGamepadState(aKey, aData);
 13124   return PL_DHASH_NEXT;
 13127 void
 13128 nsGlobalWindow::SyncGamepadState()
 13130   FORWARD_TO_INNER_VOID(SyncGamepadState, ());
 13131   if (mHasSeenGamepadInput) {
 13132     mGamepads.EnumerateRead(EnumGamepadsForSync, nullptr);
 13135 #endif
 13136 // nsGlobalChromeWindow implementation
 13138 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
 13140 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
 13141                                                   nsGlobalWindow)
 13142   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserDOMWindow)
 13143   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
 13144 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 13147 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow,
 13148                                                 nsGlobalWindow)
 13149   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserDOMWindow)
 13150   if (tmp->mMessageManager) {
 13151     static_cast<nsFrameMessageManager*>(
 13152       tmp->mMessageManager.get())->Disconnect();
 13153     NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
 13155 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 13157 DOMCI_DATA(ChromeWindow, nsGlobalChromeWindow)
 13159 // QueryInterface implementation for nsGlobalChromeWindow
 13160 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
 13161   NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
 13162   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
 13163 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
 13165 NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
 13166 NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
 13168 NS_IMETHODIMP
 13169 nsGlobalChromeWindow::GetWindowState(uint16_t* aWindowState)
 13171   *aWindowState = WindowState();
 13172   return NS_OK;
 13175 uint16_t
 13176 nsGlobalWindow::WindowState()
 13178   nsCOMPtr<nsIWidget> widget = GetMainWidget();
 13180   int32_t mode = widget ? widget->SizeMode() : 0;
 13182   switch (mode) {
 13183     case nsSizeMode_Minimized:
 13184       return nsIDOMChromeWindow::STATE_MINIMIZED;
 13185     case nsSizeMode_Maximized:
 13186       return nsIDOMChromeWindow::STATE_MAXIMIZED;
 13187     case nsSizeMode_Fullscreen:
 13188       return nsIDOMChromeWindow::STATE_FULLSCREEN;
 13189     case nsSizeMode_Normal:
 13190       return nsIDOMChromeWindow::STATE_NORMAL;
 13191     default:
 13192       NS_WARNING("Illegal window state for this chrome window");
 13193       break;
 13196   return nsIDOMChromeWindow::STATE_NORMAL;
 13199 NS_IMETHODIMP
 13200 nsGlobalChromeWindow::Maximize()
 13202   ErrorResult rv;
 13203   Maximize(rv);
 13204   return rv.ErrorCode();
 13207 void
 13208 nsGlobalWindow::Maximize(ErrorResult& aError)
 13210   nsCOMPtr<nsIWidget> widget = GetMainWidget();
 13212   if (widget) {
 13213     aError = widget->SetSizeMode(nsSizeMode_Maximized);
 13217 NS_IMETHODIMP
 13218 nsGlobalChromeWindow::Minimize()
 13220   ErrorResult rv;
 13221   Minimize(rv);
 13222   return rv.ErrorCode();
 13225 void
 13226 nsGlobalWindow::Minimize(ErrorResult& aError)
 13228   nsCOMPtr<nsIWidget> widget = GetMainWidget();
 13230   if (widget) {
 13231     aError = widget->SetSizeMode(nsSizeMode_Minimized);
 13235 NS_IMETHODIMP
 13236 nsGlobalChromeWindow::Restore()
 13238   ErrorResult rv;
 13239   Restore(rv);
 13240   return rv.ErrorCode();
 13243 void
 13244 nsGlobalWindow::Restore(ErrorResult& aError)
 13246   nsCOMPtr<nsIWidget> widget = GetMainWidget();
 13248   if (widget) {
 13249     aError = widget->SetSizeMode(nsSizeMode_Normal);
 13253 NS_IMETHODIMP
 13254 nsGlobalChromeWindow::GetAttention()
 13256   ErrorResult rv;
 13257   GetAttention(rv);
 13258   return rv.ErrorCode();
 13261 void
 13262 nsGlobalWindow::GetAttention(ErrorResult& aResult)
 13264   return GetAttentionWithCycleCount(-1, aResult);
 13267 NS_IMETHODIMP
 13268 nsGlobalChromeWindow::GetAttentionWithCycleCount(int32_t aCycleCount)
 13270   ErrorResult rv;
 13271   GetAttentionWithCycleCount(aCycleCount, rv);
 13272   return rv.ErrorCode();
 13275 void
 13276 nsGlobalWindow::GetAttentionWithCycleCount(int32_t aCycleCount,
 13277                                            ErrorResult& aError)
 13279   nsCOMPtr<nsIWidget> widget = GetMainWidget();
 13281   if (widget) {
 13282     aError = widget->GetAttention(aCycleCount);
 13286 NS_IMETHODIMP
 13287 nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent, nsIDOMElement* aPanel)
 13289   NS_ENSURE_TRUE(aMouseDownEvent, NS_ERROR_FAILURE);
 13290   Event* mouseDownEvent = aMouseDownEvent->InternalDOMEvent();
 13291   NS_ENSURE_TRUE(mouseDownEvent, NS_ERROR_FAILURE);
 13293   nsCOMPtr<Element> panel = do_QueryInterface(aPanel);
 13294   NS_ENSURE_TRUE(panel || !aPanel, NS_ERROR_FAILURE);
 13296   ErrorResult rv;
 13297   BeginWindowMove(*mouseDownEvent, panel, rv);
 13298   return rv.ErrorCode();
 13301 void
 13302 nsGlobalWindow::BeginWindowMove(Event& aMouseDownEvent, Element* aPanel,
 13303                                 ErrorResult& aError)
 13305   nsCOMPtr<nsIWidget> widget;
 13307   // if a panel was supplied, use its widget instead.
 13308 #ifdef MOZ_XUL
 13309   if (aPanel) {
 13310     nsIFrame* frame = aPanel->GetPrimaryFrame();
 13311     if (!frame || frame->GetType() != nsGkAtoms::menuPopupFrame) {
 13312       return;
 13315     widget = (static_cast<nsMenuPopupFrame*>(frame))->GetWidget();
 13317   else {
 13318 #endif
 13319     widget = GetMainWidget();
 13320 #ifdef MOZ_XUL
 13322 #endif
 13324   if (!widget) {
 13325     return;
 13328   WidgetMouseEvent* mouseEvent =
 13329     aMouseDownEvent.GetInternalNSEvent()->AsMouseEvent();
 13330   if (!mouseEvent || mouseEvent->eventStructType != NS_MOUSE_EVENT) {
 13331     aError.Throw(NS_ERROR_FAILURE);
 13332     return;
 13335   aError = widget->BeginMoveDrag(mouseEvent);
 13338 //Note: This call will lock the cursor, it will not change as it moves.
 13339 //To unlock, the cursor must be set back to CURSOR_AUTO.
 13340 NS_IMETHODIMP
 13341 nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
 13343   ErrorResult rv;
 13344   SetCursor(aCursor, rv);
 13345   return rv.ErrorCode();
 13348 void
 13349 nsGlobalWindow::SetCursor(const nsAString& aCursor, ErrorResult& aError)
 13351   FORWARD_TO_OUTER_OR_THROW(SetCursor, (aCursor, aError), aError, );
 13353   int32_t cursor;
 13355   if (aCursor.EqualsLiteral("auto"))
 13356     cursor = NS_STYLE_CURSOR_AUTO;
 13357   else {
 13358     nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
 13359     if (eCSSKeyword_UNKNOWN == keyword ||
 13360         !nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
 13361       return;
 13365   nsRefPtr<nsPresContext> presContext;
 13366   if (mDocShell) {
 13367     mDocShell->GetPresContext(getter_AddRefs(presContext));
 13370   if (presContext) {
 13371     // Need root widget.
 13372     nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
 13373     if (!presShell) {
 13374       aError.Throw(NS_ERROR_FAILURE);
 13375       return;
 13378     nsViewManager* vm = presShell->GetViewManager();
 13379     if (!vm) {
 13380       aError.Throw(NS_ERROR_FAILURE);
 13381       return;
 13384     nsView* rootView = vm->GetRootView();
 13385     if (!rootView) {
 13386       aError.Throw(NS_ERROR_FAILURE);
 13387       return;
 13390     nsIWidget* widget = rootView->GetNearestWidget(nullptr);
 13391     if (!widget) {
 13392       aError.Throw(NS_ERROR_FAILURE);
 13393       return;
 13396     // Call esm and set cursor.
 13397     aError = presContext->EventStateManager()->SetCursor(cursor, nullptr,
 13398                                                          false, 0.0f, 0.0f,
 13399                                                          widget, true);
 13403 NS_IMETHODIMP
 13404 nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
 13406   ErrorResult rv;
 13407   NS_IF_ADDREF(*aBrowserWindow = GetBrowserDOMWindow(rv));
 13408   return rv.ErrorCode();
 13411 nsIBrowserDOMWindow*
 13412 nsGlobalWindow::GetBrowserDOMWindow(ErrorResult& aError)
 13414   FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindow, (aError), aError, nullptr);
 13416   MOZ_ASSERT(IsChromeWindow());
 13417   return static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow;
 13420 NS_IMETHODIMP
 13421 nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
 13423   ErrorResult rv;
 13424   SetBrowserDOMWindow(aBrowserWindow, rv);
 13425   return rv.ErrorCode();
 13428 void
 13429 nsGlobalWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow,
 13430                                     ErrorResult& aError)
 13432   FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindow, (aBrowserWindow, aError),
 13433                             aError, );
 13434   MOZ_ASSERT(IsChromeWindow());
 13435   static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow = aBrowserWindow;
 13438 NS_IMETHODIMP
 13439 nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement* aDefaultButton)
 13441   nsCOMPtr<Element> defaultButton = do_QueryInterface(aDefaultButton);
 13442   NS_ENSURE_ARG(defaultButton);
 13444   ErrorResult rv;
 13445   NotifyDefaultButtonLoaded(*defaultButton, rv);
 13446   return rv.ErrorCode();
 13449 void
 13450 nsGlobalWindow::NotifyDefaultButtonLoaded(Element& aDefaultButton,
 13451                                           ErrorResult& aError)
 13453 #ifdef MOZ_XUL
 13454   // Don't snap to a disabled button.
 13455   nsCOMPtr<nsIDOMXULControlElement> xulControl =
 13456                                       do_QueryInterface(&aDefaultButton);
 13457   if (!xulControl) {
 13458     aError.Throw(NS_ERROR_FAILURE);
 13459     return;
 13461   bool disabled;
 13462   aError = xulControl->GetDisabled(&disabled);
 13463   if (aError.Failed() || disabled) {
 13464     return;
 13467   // Get the button rect in screen coordinates.
 13468   nsIFrame *frame = aDefaultButton.GetPrimaryFrame();
 13469   if (!frame) {
 13470     aError.Throw(NS_ERROR_FAILURE);
 13471     return;
 13473   nsIntRect buttonRect = frame->GetScreenRect();
 13475   // Get the widget rect in screen coordinates.
 13476   nsIWidget *widget = GetNearestWidget();
 13477   if (!widget) {
 13478     aError.Throw(NS_ERROR_FAILURE);
 13479     return;
 13481   nsIntRect widgetRect;
 13482   aError = widget->GetScreenBounds(widgetRect);
 13483   if (aError.Failed()) {
 13484     return;
 13487   // Convert the buttonRect coordinates from screen to the widget.
 13488   buttonRect -= widgetRect.TopLeft();
 13489   nsresult rv = widget->OnDefaultButtonLoaded(buttonRect);
 13490   if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
 13491     aError.Throw(rv);
 13493 #else
 13494   aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
 13495 #endif
 13498 NS_IMETHODIMP
 13499 nsGlobalChromeWindow::GetMessageManager(nsIMessageBroadcaster** aManager)
 13501   ErrorResult rv;
 13502   NS_IF_ADDREF(*aManager = GetMessageManager(rv));
 13503   return rv.ErrorCode();
 13506 nsIMessageBroadcaster*
 13507 nsGlobalWindow::GetMessageManager(ErrorResult& aError)
 13509   FORWARD_TO_INNER_OR_THROW(GetMessageManager, (aError), aError, nullptr);
 13510   MOZ_ASSERT(IsChromeWindow());
 13511   nsGlobalChromeWindow* myself = static_cast<nsGlobalChromeWindow*>(this);
 13512   if (!myself->mMessageManager) {
 13513     nsIScriptContext* scx = GetContextInternal();
 13514     if (NS_WARN_IF(!scx || !(scx->GetNativeContext()))) {
 13515       aError.Throw(NS_ERROR_UNEXPECTED);
 13516       return nullptr;
 13519     nsCOMPtr<nsIMessageBroadcaster> globalMM =
 13520       do_GetService("@mozilla.org/globalmessagemanager;1");
 13521     myself->mMessageManager =
 13522       new nsFrameMessageManager(nullptr,
 13523                                 static_cast<nsFrameMessageManager*>(globalMM.get()),
 13524                                 MM_CHROME | MM_BROADCASTER);
 13526   return myself->mMessageManager;
 13529 // nsGlobalModalWindow implementation
 13531 // QueryInterface implementation for nsGlobalModalWindow
 13532 DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
 13534 NS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow)
 13535   NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
 13536   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
 13537 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
 13539 NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
 13540 NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
 13543 void
 13544 nsGlobalWindow::GetDialogArguments(JSContext* aCx,
 13545                                    JS::MutableHandle<JS::Value> aRetval,
 13546                                    ErrorResult& aError)
 13548   FORWARD_TO_OUTER_OR_THROW(GetDialogArguments, (aCx, aRetval, aError),
 13549                             aError, );
 13551   MOZ_ASSERT(IsModalContentWindow(),
 13552              "This should only be called on modal windows!");
 13554   // This does an internal origin check, and returns undefined if the subject
 13555   // does not subsumes the origin of the arguments.
 13556   JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
 13557   JSAutoCompartment ac(aCx, wrapper);
 13558   mDialogArguments->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
 13559                         aRetval, aError);
 13562 NS_IMETHODIMP
 13563 nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments)
 13565   FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
 13566                                         NS_ERROR_NOT_INITIALIZED);
 13568   // This does an internal origin check, and returns undefined if the subject
 13569   // does not subsumes the origin of the arguments.
 13570   return mDialogArguments->Get(nsContentUtils::GetSubjectPrincipal(), aArguments);
 13573 void
 13574 nsGlobalWindow::GetReturnValue(JSContext* aCx,
 13575                                JS::MutableHandle<JS::Value> aReturnValue,
 13576                                ErrorResult& aError)
 13578   FORWARD_TO_OUTER_OR_THROW(GetReturnValue, (aCx, aReturnValue, aError),
 13579                             aError, );
 13581   MOZ_ASSERT(IsModalContentWindow(),
 13582              "This should only be called on modal windows!");
 13584   if (mReturnValue) {
 13585     JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
 13586     JSAutoCompartment ac(aCx, wrapper);
 13587     mReturnValue->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
 13588                       aReturnValue, aError);
 13589   } else {
 13590     aReturnValue.setUndefined();
 13594 NS_IMETHODIMP
 13595 nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
 13597   FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
 13599   nsCOMPtr<nsIVariant> result;
 13600   if (!mReturnValue) {
 13601     nsCOMPtr<nsIVariant> variant = CreateVoidVariant();
 13602     variant.forget(aRetVal);
 13603     return NS_OK;
 13605   return mReturnValue->Get(nsContentUtils::GetSubjectPrincipal(), aRetVal);
 13608 void
 13609 nsGlobalWindow::SetReturnValue(JSContext* aCx,
 13610                                JS::Handle<JS::Value> aReturnValue,
 13611                                ErrorResult& aError)
 13613   FORWARD_TO_OUTER_OR_THROW(SetReturnValue, (aCx, aReturnValue, aError),
 13614                             aError, );
 13616   MOZ_ASSERT(IsModalContentWindow(),
 13617              "This should only be called on modal windows!");
 13619   nsCOMPtr<nsIVariant> returnValue;
 13620   aError =
 13621     nsContentUtils::XPConnect()->JSToVariant(aCx, aReturnValue,
 13622                                              getter_AddRefs(returnValue));
 13623   if (!aError.Failed()) {
 13624     mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
 13625                                          returnValue);
 13629 NS_IMETHODIMP
 13630 nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
 13632   FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
 13634   mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
 13635                                        aRetVal);
 13636   return NS_OK;
 13639 /* static */
 13640 bool
 13641 nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
 13643   // For now, have to deal with XPConnect objects here.
 13644   return xpc::WindowOrNull(aGlobal)->IsModalContentWindow();
 13647 NS_IMETHODIMP
 13648 nsGlobalWindow::GetConsole(JSContext* aCx,
 13649                            JS::MutableHandle<JS::Value> aConsole)
 13651   ErrorResult rv;
 13652   nsRefPtr<Console> console = GetConsole(rv);
 13653   if (rv.Failed()) {
 13654     return rv.ErrorCode();
 13657   if (!WrapNewBindingObject(aCx, console, aConsole)) {
 13658     return NS_ERROR_FAILURE;
 13661   return NS_OK;
 13664 NS_IMETHODIMP
 13665 nsGlobalWindow::SetConsole(JSContext* aCx, JS::Handle<JS::Value> aValue)
 13667   JS::Rooted<JSObject*> thisObj(aCx, GetWrapper());
 13668   if (!thisObj) {
 13669     return NS_ERROR_UNEXPECTED;
 13672   if (!JS_WrapObject(aCx, &thisObj) ||
 13673       !JS_DefineProperty(aCx, thisObj, "console", aValue,
 13674                          JSPROP_ENUMERATE, JS_PropertyStub,
 13675                          JS_StrictPropertyStub)) {
 13676     return NS_ERROR_FAILURE;
 13679   return NS_OK;
 13682 Console*
 13683 nsGlobalWindow::GetConsole(ErrorResult& aRv)
 13685   FORWARD_TO_INNER_OR_THROW(GetConsole, (aRv), aRv, nullptr);
 13687   if (!mConsole) {
 13688     mConsole = new Console(this);
 13691   return mConsole;
 13694 already_AddRefed<External>
 13695 nsGlobalWindow::GetExternal(ErrorResult& aRv)
 13697   FORWARD_TO_INNER_OR_THROW(GetExternal, (aRv), aRv, nullptr);
 13699 #ifdef HAVE_SIDEBAR
 13700   if (!mExternal) {
 13701     AutoJSContext cx;
 13702     JS::Rooted<JSObject*> jsImplObj(cx);
 13703     ConstructJSImplementation(cx, "@mozilla.org/sidebar;1",
 13704                               this, &jsImplObj, aRv);
 13705     if (aRv.Failed()) {
 13706       return nullptr;
 13708     mExternal = new External(jsImplObj, this);
 13711   nsRefPtr<External> external = static_cast<External*>(mExternal.get());
 13712   return external.forget();
 13713 #else
 13714   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 13715   return nullptr;
 13716 #endif
 13719 void
 13720 nsGlobalWindow::GetSidebar(OwningExternalOrWindowProxy& aResult,
 13721                            ErrorResult& aRv)
 13723   FORWARD_TO_INNER_OR_THROW(GetSidebar, (aResult, aRv), aRv, );
 13725 #ifdef HAVE_SIDEBAR
 13726   // First check for a named frame named "sidebar"
 13727   nsCOMPtr<nsIDOMWindow> domWindow = GetChildWindow(NS_LITERAL_STRING("sidebar"));
 13728   if (domWindow) {
 13729     aResult.SetAsWindowProxy() = domWindow.forget();
 13730     return;
 13733   nsRefPtr<External> external = GetExternal(aRv);
 13734   if (external) {
 13735     aResult.SetAsExternal() = external;
 13737 #else
 13738   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 13739 #endif
 13742 /* static */
 13743 bool
 13744 nsGlobalWindow::WindowOnWebIDL(JSContext* aCx, JSObject* aObj)
 13746   DebugOnly<nsGlobalWindow*> win;
 13747   MOZ_ASSERT_IF(IsDOMObject(aObj),
 13748                 NS_SUCCEEDED(UNWRAP_OBJECT(Window, aObj, win)));
 13750   return IsDOMObject(aObj);
 13753 #ifdef MOZ_B2G
 13754 void
 13755 nsGlobalWindow::EnableNetworkEvent(uint32_t aType)
 13757   MOZ_ASSERT(IsInnerWindow());
 13759   nsCOMPtr<nsIPermissionManager> permMgr =
 13760     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
 13761   if (!permMgr) {
 13762     NS_ERROR("No PermissionManager available!");
 13763     return;
 13766   uint32_t permission = nsIPermissionManager::DENY_ACTION;
 13767   permMgr->TestExactPermissionFromPrincipal(GetPrincipal(), "network-events",
 13768                                             &permission);
 13770   if (permission != nsIPermissionManager::ALLOW_ACTION) {
 13771     return;
 13774   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
 13775   if (!os) {
 13776     NS_ERROR("ObserverService should be available!");
 13777     return;
 13780   switch (aType) {
 13781     case NS_NETWORK_UPLOAD_EVENT:
 13782       if (!mNetworkUploadObserverEnabled) {
 13783         mNetworkUploadObserverEnabled = true;
 13784         os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC, false);
 13786       break;
 13787     case NS_NETWORK_DOWNLOAD_EVENT:
 13788       if (!mNetworkDownloadObserverEnabled) {
 13789         mNetworkDownloadObserverEnabled = true;
 13790         os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC, false);
 13792       break;
 13796 void
 13797 nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
 13799   MOZ_ASSERT(IsInnerWindow());
 13801   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
 13802   if (!os) {
 13803     return;
 13806   switch (aType) {
 13807     case NS_NETWORK_UPLOAD_EVENT:
 13808       if (mNetworkUploadObserverEnabled) {
 13809         mNetworkUploadObserverEnabled = false;
 13810         os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC);
 13812       break;
 13813     case NS_NETWORK_DOWNLOAD_EVENT:
 13814       if (mNetworkDownloadObserverEnabled) {
 13815         mNetworkDownloadObserverEnabled = false;
 13816         os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC);
 13818       break;
 13821 #endif // MOZ_B2G
 13823 #define EVENT(name_, id_, type_, struct_)                                    \
 13824   NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx,                  \
 13825                                              JS::MutableHandle<JS::Value> vp) { \
 13826     EventHandlerNonNull* h = GetOn##name_();                                 \
 13827     vp.setObjectOrNull(h ? h->Callable().get() : nullptr);                   \
 13828     return NS_OK;                                                            \
 13829   }                                                                          \
 13830   NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx,                  \
 13831                                              JS::Handle<JS::Value> v) {      \
 13832     nsRefPtr<EventHandlerNonNull> handler;                                   \
 13833     JS::Rooted<JSObject*> callable(cx);                                      \
 13834     if (v.isObject() &&                                                      \
 13835         JS_ObjectIsCallable(cx, callable = &v.toObject())) {                 \
 13836       handler = new EventHandlerNonNull(callable, GetIncumbentGlobal());     \
 13837     }                                                                        \
 13838     SetOn##name_(handler);                                                   \
 13839     return NS_OK;                                                            \
 13841 #define ERROR_EVENT(name_, id_, type_, struct_)                              \
 13842   NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx,                  \
 13843                                              JS::MutableHandle<JS::Value> vp) { \
 13844     EventListenerManager *elm = GetExistingListenerManager();                \
 13845     if (elm) {                                                               \
 13846       OnErrorEventHandlerNonNull* h = elm->GetOnErrorEventHandler();         \
 13847       if (h) {                                                               \
 13848         vp.setObject(*h->Callable());                                        \
 13849         return NS_OK;                                                        \
 13850       }                                                                      \
 13851     }                                                                        \
 13852     vp.setNull();                                                            \
 13853     return NS_OK;                                                            \
 13854   }                                                                          \
 13855   NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx,                  \
 13856                                              JS::Handle<JS::Value> v) {      \
 13857     EventListenerManager *elm = GetOrCreateListenerManager();                \
 13858     if (!elm) {                                                              \
 13859       return NS_ERROR_OUT_OF_MEMORY;                                         \
 13860     }                                                                        \
 13862     nsRefPtr<OnErrorEventHandlerNonNull> handler;                            \
 13863     JS::Rooted<JSObject*> callable(cx);                                      \
 13864     if (v.isObject() &&                                                      \
 13865         JS_ObjectIsCallable(cx, callable = &v.toObject())) {                 \
 13866       handler = new OnErrorEventHandlerNonNull(callable, GetIncumbentGlobal()); \
 13867     }                                                                        \
 13868     elm->SetEventHandler(handler);                                           \
 13869     return NS_OK;                                                            \
 13871 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                       \
 13872   NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx,                  \
 13873                                              JS::MutableHandle<JS::Value> vp) { \
 13874     EventListenerManager *elm = GetExistingListenerManager();                \
 13875     if (elm) {                                                               \
 13876       OnBeforeUnloadEventHandlerNonNull* h =                                 \
 13877         elm->GetOnBeforeUnloadEventHandler();                                \
 13878       if (h) {                                                               \
 13879         vp.setObject(*h->Callable());                                        \
 13880         return NS_OK;                                                        \
 13881       }                                                                      \
 13882     }                                                                        \
 13883     vp.setNull();                                                            \
 13884     return NS_OK;                                                            \
 13885   }                                                                          \
 13886   NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx,                  \
 13887                                              JS::Handle<JS::Value> v) {      \
 13888     EventListenerManager *elm = GetOrCreateListenerManager();                \
 13889     if (!elm) {                                                              \
 13890       return NS_ERROR_OUT_OF_MEMORY;                                         \
 13891     }                                                                        \
 13893     nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handler;                     \
 13894     JS::Rooted<JSObject*> callable(cx);                                      \
 13895     if (v.isObject() &&                                                      \
 13896         JS_ObjectIsCallable(cx, callable = &v.toObject())) {                 \
 13897       handler = new OnBeforeUnloadEventHandlerNonNull(callable, GetIncumbentGlobal()); \
 13898     }                                                                        \
 13899     elm->SetEventHandler(handler);                                           \
 13900     return NS_OK;                                                            \
 13902 #define WINDOW_ONLY_EVENT EVENT
 13903 #define TOUCH_EVENT EVENT
 13904 #include "mozilla/EventNameList.h"
 13905 #undef TOUCH_EVENT
 13906 #undef WINDOW_ONLY_EVENT
 13907 #undef BEFOREUNLOAD_EVENT
 13908 #undef ERROR_EVENT
 13909 #undef EVENT
 13911 #ifdef _WINDOWS_
 13912 #error "Never include windows.h in this file!"
 13913 #endif

mercurial