dom/base/nsGlobalWindow.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/base/nsGlobalWindow.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,13913 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "nsGlobalWindow.h"
    1.11 +
    1.12 +#include <algorithm>
    1.13 +
    1.14 +#include "mozilla/MemoryReporting.h"
    1.15 +
    1.16 +// Local Includes
    1.17 +#include "Navigator.h"
    1.18 +#include "nsScreen.h"
    1.19 +#include "nsHistory.h"
    1.20 +#include "nsPerformance.h"
    1.21 +#include "nsDOMNavigationTiming.h"
    1.22 +#include "nsIDOMStorage.h"
    1.23 +#include "nsIDOMStorageManager.h"
    1.24 +#include "DOMStorage.h"
    1.25 +#include "nsDOMOfflineResourceList.h"
    1.26 +#include "nsError.h"
    1.27 +#include "nsIIdleService.h"
    1.28 +#include "nsISizeOfEventTarget.h"
    1.29 +#include "nsDOMJSUtils.h"
    1.30 +#include "nsArrayUtils.h"
    1.31 +#include "nsIDOMWindowCollection.h"
    1.32 +#include "nsDOMWindowList.h"
    1.33 +#include "mozilla/dom/WakeLock.h"
    1.34 +#include "mozilla/dom/power/PowerManagerService.h"
    1.35 +#include "nsIDocShellTreeOwner.h"
    1.36 +#include "nsIPermissionManager.h"
    1.37 +#include "nsIScriptContext.h"
    1.38 +#include "nsIScriptTimeoutHandler.h"
    1.39 +#include "nsIController.h"
    1.40 +#include "nsScriptNameSpaceManager.h"
    1.41 +#include "nsWindowMemoryReporter.h"
    1.42 +
    1.43 +// Helper Classes
    1.44 +#include "nsJSUtils.h"
    1.45 +#include "jsapi.h"              // for JSAutoRequest
    1.46 +#include "js/OldDebugAPI.h"     // for JS_ClearWatchPointsForObject
    1.47 +#include "jswrapper.h"
    1.48 +#include "nsReadableUtils.h"
    1.49 +#include "nsDOMClassInfo.h"
    1.50 +#include "nsJSEnvironment.h"
    1.51 +#include "ScriptSettings.h"
    1.52 +#include "mozilla/Preferences.h"
    1.53 +#include "mozilla/Likely.h"
    1.54 +#include "mozilla/unused.h"
    1.55 +
    1.56 +// Other Classes
    1.57 +#include "mozilla/dom/BarProps.h"
    1.58 +#include "nsContentCID.h"
    1.59 +#include "nsLayoutStatics.h"
    1.60 +#include "nsCCUncollectableMarker.h"
    1.61 +#include "mozilla/dom/workers/Workers.h"
    1.62 +#include "mozilla/dom/MessagePortList.h"
    1.63 +#include "nsJSPrincipals.h"
    1.64 +#include "mozilla/Attributes.h"
    1.65 +#include "mozilla/Debug.h"
    1.66 +#include "mozilla/EventListenerManager.h"
    1.67 +#include "mozilla/EventStates.h"
    1.68 +#include "mozilla/MouseEvents.h"
    1.69 +#include "AudioChannelService.h"
    1.70 +#include "MessageEvent.h"
    1.71 +
    1.72 +// Interfaces Needed
    1.73 +#include "nsIFrame.h"
    1.74 +#include "nsCanvasFrame.h"
    1.75 +#include "nsIWidget.h"
    1.76 +#include "nsIWidgetListener.h"
    1.77 +#include "nsIBaseWindow.h"
    1.78 +#include "nsIDeviceSensors.h"
    1.79 +#include "nsIContent.h"
    1.80 +#include "nsIDocShell.h"
    1.81 +#include "nsIDocCharset.h"
    1.82 +#include "nsIDocument.h"
    1.83 +#include "Crypto.h"
    1.84 +#ifndef MOZ_DISABLE_CRYPTOLEGACY
    1.85 +#include "nsIDOMCryptoLegacy.h"
    1.86 +#endif
    1.87 +#include "nsIDOMDocument.h"
    1.88 +#include "nsIDOMElement.h"
    1.89 +#include "nsIDOMEvent.h"
    1.90 +#include "nsIDOMPopupBlockedEvent.h"
    1.91 +#include "nsIDOMPopStateEvent.h"
    1.92 +#include "nsIDOMHashChangeEvent.h"
    1.93 +#include "nsIDOMOfflineResourceList.h"
    1.94 +#include "nsPIDOMStorage.h"
    1.95 +#include "nsDOMString.h"
    1.96 +#include "nsIEmbeddingSiteWindow.h"
    1.97 +#include "nsThreadUtils.h"
    1.98 +#include "nsILoadContext.h"
    1.99 +#include "nsIMarkupDocumentViewer.h"
   1.100 +#include "nsIPresShell.h"
   1.101 +#include "nsIScriptSecurityManager.h"
   1.102 +#include "nsIScrollableFrame.h"
   1.103 +#include "nsView.h"
   1.104 +#include "nsViewManager.h"
   1.105 +#include "nsISelectionController.h"
   1.106 +#include "nsISelection.h"
   1.107 +#include "nsIPrompt.h"
   1.108 +#include "nsIPromptService.h"
   1.109 +#include "nsIPromptFactory.h"
   1.110 +#include "nsIWritablePropertyBag2.h"
   1.111 +#include "nsIWebNavigation.h"
   1.112 +#include "nsIWebBrowserChrome.h"
   1.113 +#include "nsIWebBrowserFind.h"  // For window.find()
   1.114 +#include "nsIWindowMediator.h"  // For window.find()
   1.115 +#include "nsComputedDOMStyle.h"
   1.116 +#include "nsIEntropyCollector.h"
   1.117 +#include "nsDOMCID.h"
   1.118 +#include "nsDOMWindowUtils.h"
   1.119 +#include "nsIWindowWatcher.h"
   1.120 +#include "nsPIWindowWatcher.h"
   1.121 +#include "nsIContentViewer.h"
   1.122 +#include "nsIScriptError.h"
   1.123 +#include "nsIControllers.h"
   1.124 +#include "nsIControllerContext.h"
   1.125 +#include "nsGlobalWindowCommands.h"
   1.126 +#include "nsAutoPtr.h"
   1.127 +#include "nsContentUtils.h"
   1.128 +#include "nsCxPusher.h"
   1.129 +#include "nsCSSProps.h"
   1.130 +#include "nsIDOMFile.h"
   1.131 +#include "nsIDOMFileList.h"
   1.132 +#include "nsIURIFixup.h"
   1.133 +#ifndef DEBUG
   1.134 +#include "nsIAppStartup.h"
   1.135 +#include "nsToolkitCompsCID.h"
   1.136 +#endif
   1.137 +#include "nsCDefaultURIFixup.h"
   1.138 +#include "mozilla/EventDispatcher.h"
   1.139 +#include "mozilla/EventStateManager.h"
   1.140 +#include "nsIObserverService.h"
   1.141 +#include "nsFocusManager.h"
   1.142 +#include "nsIXULWindow.h"
   1.143 +#include "nsITimedChannel.h"
   1.144 +#include "nsServiceManagerUtils.h"
   1.145 +#ifdef MOZ_XUL
   1.146 +#include "nsIDOMXULControlElement.h"
   1.147 +#include "nsMenuPopupFrame.h"
   1.148 +#endif
   1.149 +#include "nsIDOMCustomEvent.h"
   1.150 +#include "nsIFrameRequestCallback.h"
   1.151 +#include "nsIJARChannel.h"
   1.152 +
   1.153 +#include "xpcprivate.h"
   1.154 +
   1.155 +#ifdef NS_PRINTING
   1.156 +#include "nsIPrintSettings.h"
   1.157 +#include "nsIPrintSettingsService.h"
   1.158 +#include "nsIWebBrowserPrint.h"
   1.159 +#endif
   1.160 +
   1.161 +#include "nsWindowRoot.h"
   1.162 +#include "nsNetCID.h"
   1.163 +#include "nsIArray.h"
   1.164 +
   1.165 +// XXX An unfortunate dependency exists here (two XUL files).
   1.166 +#include "nsIDOMXULDocument.h"
   1.167 +#include "nsIDOMXULCommandDispatcher.h"
   1.168 +
   1.169 +#include "nsBindingManager.h"
   1.170 +#include "nsXBLService.h"
   1.171 +
   1.172 +// used for popup blocking, needs to be converted to something
   1.173 +// belonging to the back-end like nsIContentPolicy
   1.174 +#include "nsIPopupWindowManager.h"
   1.175 +
   1.176 +#include "nsIDragService.h"
   1.177 +#include "mozilla/dom/Element.h"
   1.178 +#include "mozilla/dom/Selection.h"
   1.179 +#include "nsFrameLoader.h"
   1.180 +#include "nsISupportsPrimitives.h"
   1.181 +#include "nsXPCOMCID.h"
   1.182 +#include "GeneratedEvents.h"
   1.183 +#include "GeneratedEventClasses.h"
   1.184 +#include "mozIThirdPartyUtil.h"
   1.185 +#ifdef MOZ_LOGGING
   1.186 +// so we can get logging even in release builds
   1.187 +#define FORCE_PR_LOG 1
   1.188 +#endif
   1.189 +#include "prlog.h"
   1.190 +#include "prenv.h"
   1.191 +#include "prprf.h"
   1.192 +
   1.193 +#include "mozilla/dom/MessageChannel.h"
   1.194 +#include "mozilla/dom/MessagePort.h"
   1.195 +#include "mozilla/dom/MessagePortBinding.h"
   1.196 +#include "mozilla/dom/indexedDB/IDBFactory.h"
   1.197 +#include "mozilla/dom/quota/QuotaManager.h"
   1.198 +
   1.199 +#include "mozilla/dom/StructuredCloneTags.h"
   1.200 +
   1.201 +#ifdef MOZ_GAMEPAD
   1.202 +#include "mozilla/dom/GamepadService.h"
   1.203 +#endif
   1.204 +
   1.205 +#include "nsRefreshDriver.h"
   1.206 +
   1.207 +#include "mozilla/Services.h"
   1.208 +#include "mozilla/Telemetry.h"
   1.209 +#include "nsLocation.h"
   1.210 +#include "nsHTMLDocument.h"
   1.211 +#include "nsWrapperCacheInlines.h"
   1.212 +#include "mozilla/DOMEventTargetHelper.h"
   1.213 +#include "prrng.h"
   1.214 +#include "nsSandboxFlags.h"
   1.215 +#include "TimeChangeObserver.h"
   1.216 +#include "mozilla/dom/AudioContext.h"
   1.217 +#include "mozilla/dom/BrowserElementDictionariesBinding.h"
   1.218 +#include "mozilla/dom/Console.h"
   1.219 +#include "mozilla/dom/FunctionBinding.h"
   1.220 +#include "mozilla/dom/WindowBinding.h"
   1.221 +#include "nsITabChild.h"
   1.222 +#include "mozilla/dom/MediaQueryList.h"
   1.223 +#include "mozilla/dom/ScriptSettings.h"
   1.224 +#ifdef HAVE_SIDEBAR
   1.225 +#include "mozilla/dom/ExternalBinding.h"
   1.226 +#endif
   1.227 +
   1.228 +#ifdef MOZ_WEBSPEECH
   1.229 +#include "mozilla/dom/SpeechSynthesis.h"
   1.230 +#endif
   1.231 +
   1.232 +#ifdef MOZ_JSDEBUGGER
   1.233 +#include "jsdIDebuggerService.h"
   1.234 +#endif
   1.235 +
   1.236 +#ifdef MOZ_B2G
   1.237 +#include "nsPISocketTransportService.h"
   1.238 +#endif
   1.239 +
   1.240 +// Apple system headers seem to have a check() macro.  <sigh>
   1.241 +#ifdef check
   1.242 +class nsIScriptTimeoutHandler;
   1.243 +#undef check
   1.244 +#endif // check
   1.245 +#include "AccessCheck.h"
   1.246 +
   1.247 +#ifdef ANDROID
   1.248 +#include <android/log.h>
   1.249 +#endif
   1.250 +
   1.251 +#ifdef PR_LOGGING
   1.252 +static PRLogModuleInfo* gDOMLeakPRLog;
   1.253 +#endif
   1.254 +
   1.255 +#ifdef XP_WIN
   1.256 +#include <process.h>
   1.257 +#define getpid _getpid
   1.258 +#else
   1.259 +#include <unistd.h> // for getpid()
   1.260 +#endif
   1.261 +
   1.262 +static const char kStorageEnabled[] = "dom.storage.enabled";
   1.263 +
   1.264 +using namespace mozilla;
   1.265 +using namespace mozilla::dom;
   1.266 +using namespace mozilla::dom::ipc;
   1.267 +using mozilla::TimeStamp;
   1.268 +using mozilla::TimeDuration;
   1.269 +
   1.270 +nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sWindowsById = nullptr;
   1.271 +bool nsGlobalWindow::sWarnedAboutWindowInternal = false;
   1.272 +bool nsGlobalWindow::sIdleObserversAPIFuzzTimeDisabled = false;
   1.273 +
   1.274 +static nsIEntropyCollector *gEntropyCollector          = nullptr;
   1.275 +static int32_t              gRefCnt                    = 0;
   1.276 +static int32_t              gOpenPopupSpamCount        = 0;
   1.277 +static PopupControlState    gPopupControlState         = openAbused;
   1.278 +static int32_t              gRunningTimeoutDepth       = 0;
   1.279 +static bool                 gMouseDown                 = false;
   1.280 +static bool                 gDragServiceDisabled       = false;
   1.281 +static FILE                *gDumpFile                  = nullptr;
   1.282 +static uint64_t             gNextWindowID              = 0;
   1.283 +static uint32_t             gSerialCounter             = 0;
   1.284 +static uint32_t             gTimeoutsRecentlySet       = 0;
   1.285 +static TimeStamp            gLastRecordedRecentTimeouts;
   1.286 +#define STATISTICS_INTERVAL (30 * PR_MSEC_PER_SEC)
   1.287 +
   1.288 +#ifdef DEBUG_jst
   1.289 +int32_t gTimeoutCnt                                    = 0;
   1.290 +#endif
   1.291 +
   1.292 +#if defined(DEBUG_bryner) || defined(DEBUG_chb)
   1.293 +#define DEBUG_PAGE_CACHE
   1.294 +#endif
   1.295 +
   1.296 +#define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
   1.297 +
   1.298 +// The default shortest interval/timeout we permit
   1.299 +#define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
   1.300 +#define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
   1.301 +static int32_t gMinTimeoutValue;
   1.302 +static int32_t gMinBackgroundTimeoutValue;
   1.303 +inline int32_t
   1.304 +nsGlobalWindow::DOMMinTimeoutValue() const {
   1.305 +  bool isBackground = !mOuterWindow || mOuterWindow->IsBackground();
   1.306 +  return
   1.307 +    std::max(isBackground ? gMinBackgroundTimeoutValue : gMinTimeoutValue, 0);
   1.308 +}
   1.309 +
   1.310 +// The number of nested timeouts before we start clamping. HTML5 says 1, WebKit
   1.311 +// uses 5.
   1.312 +#define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
   1.313 +
   1.314 +// The longest interval (as PRIntervalTime) we permit, or that our
   1.315 +// timer code can handle, really. See DELAY_INTERVAL_LIMIT in
   1.316 +// nsTimerImpl.h for details.
   1.317 +#define DOM_MAX_TIMEOUT_VALUE    DELAY_INTERVAL_LIMIT
   1.318 +
   1.319 +#define FORWARD_TO_OUTER(method, args, err_rval)                              \
   1.320 +  PR_BEGIN_MACRO                                                              \
   1.321 +  if (IsInnerWindow()) {                                                      \
   1.322 +    nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   1.323 +    if (!HasActiveDocument()) {                                                \
   1.324 +      NS_WARNING(outer ?                                                      \
   1.325 +                 "Inner window does not have active document." :              \
   1.326 +                 "No outer window available!");                               \
   1.327 +      return err_rval;                                                        \
   1.328 +    }                                                                         \
   1.329 +    return outer->method args;                                                \
   1.330 +  }                                                                           \
   1.331 +  PR_END_MACRO
   1.332 +
   1.333 +#define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval)        \
   1.334 +  PR_BEGIN_MACRO                                                              \
   1.335 +  if (IsInnerWindow()) {                                                      \
   1.336 +    nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   1.337 +    if (!HasActiveDocument()) {                                               \
   1.338 +      if (!outer) {                                                           \
   1.339 +        NS_WARNING("No outer window available!");                             \
   1.340 +        errorresult.Throw(NS_ERROR_NOT_INITIALIZED);                          \
   1.341 +      } else {                                                                \
   1.342 +        errorresult.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO);                \
   1.343 +      }                                                                       \
   1.344 +    } else {                                                                  \
   1.345 +      return outer->method args;                                              \
   1.346 +    }                                                                         \
   1.347 +    return err_rval;                                                          \
   1.348 +  }                                                                           \
   1.349 +  PR_END_MACRO
   1.350 +
   1.351 +#define FORWARD_TO_OUTER_VOID(method, args)                                   \
   1.352 +  PR_BEGIN_MACRO                                                              \
   1.353 +  if (IsInnerWindow()) {                                                      \
   1.354 +    nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   1.355 +    if (!HasActiveDocument()) {                                               \
   1.356 +      NS_WARNING(outer ?                                                      \
   1.357 +                 "Inner window does not have active document." :              \
   1.358 +                 "No outer window available!");                               \
   1.359 +      return;                                                                 \
   1.360 +    }                                                                         \
   1.361 +    outer->method args;                                                       \
   1.362 +    return;                                                                   \
   1.363 +  }                                                                           \
   1.364 +  PR_END_MACRO
   1.365 +
   1.366 +#define FORWARD_TO_OUTER_CHROME(method, args, err_rval)                       \
   1.367 +  PR_BEGIN_MACRO                                                              \
   1.368 +  if (IsInnerWindow()) {                                                      \
   1.369 +    nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   1.370 +    if (!HasActiveDocument()) {                                               \
   1.371 +      NS_WARNING(outer ?                                                      \
   1.372 +                 "Inner window does not have active document." :              \
   1.373 +                 "No outer window available!");                               \
   1.374 +      return err_rval;                                                        \
   1.375 +    }                                                                         \
   1.376 +    return ((nsGlobalChromeWindow *)outer)->method args;                      \
   1.377 +  }                                                                           \
   1.378 +  PR_END_MACRO
   1.379 +
   1.380 +#define FORWARD_TO_INNER_CHROME(method, args, err_rval)                       \
   1.381 +  PR_BEGIN_MACRO                                                              \
   1.382 +  if (IsOuterWindow()) {                                                      \
   1.383 +    if (!mInnerWindow) {                                                      \
   1.384 +      NS_WARNING("No inner window available!");                               \
   1.385 +      return err_rval;                                                        \
   1.386 +    }                                                                         \
   1.387 +    return ((nsGlobalChromeWindow *)mInnerWindow)->method args;               \
   1.388 +  }                                                                           \
   1.389 +  PR_END_MACRO
   1.390 +
   1.391 +#define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval)         \
   1.392 +  PR_BEGIN_MACRO                                                              \
   1.393 +  if (IsInnerWindow()) {                                                      \
   1.394 +    nsGlobalWindow *outer = GetOuterWindowInternal();                         \
   1.395 +    if (!HasActiveDocument()) {                                               \
   1.396 +      NS_WARNING(outer ?                                                      \
   1.397 +                 "Inner window does not have active document." :              \
   1.398 +                 "No outer window available!");                               \
   1.399 +      return err_rval;                                                        \
   1.400 +    }                                                                         \
   1.401 +    return ((nsGlobalModalWindow *)outer)->method args;                       \
   1.402 +  }                                                                           \
   1.403 +  PR_END_MACRO
   1.404 +
   1.405 +#define FORWARD_TO_INNER(method, args, err_rval)                              \
   1.406 +  PR_BEGIN_MACRO                                                              \
   1.407 +  if (IsOuterWindow()) {                                                      \
   1.408 +    if (!mInnerWindow) {                                                      \
   1.409 +      NS_WARNING("No inner window available!");                               \
   1.410 +      return err_rval;                                                        \
   1.411 +    }                                                                         \
   1.412 +    return GetCurrentInnerWindowInternal()->method args;                      \
   1.413 +  }                                                                           \
   1.414 +  PR_END_MACRO
   1.415 +
   1.416 +#define FORWARD_TO_INNER_OR_THROW(method, args, errorresult, err_rval)        \
   1.417 +  PR_BEGIN_MACRO                                                              \
   1.418 +  if (IsOuterWindow()) {                                                      \
   1.419 +    if (!mInnerWindow) {                                                      \
   1.420 +      NS_WARNING("No inner window available!");                               \
   1.421 +      errorresult.Throw(NS_ERROR_NOT_INITIALIZED);                            \
   1.422 +      return err_rval;                                                        \
   1.423 +    }                                                                         \
   1.424 +    return GetCurrentInnerWindowInternal()->method args;                      \
   1.425 +  }                                                                           \
   1.426 +  PR_END_MACRO
   1.427 +
   1.428 +#define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval)         \
   1.429 +  PR_BEGIN_MACRO                                                              \
   1.430 +  if (IsOuterWindow()) {                                                      \
   1.431 +    if (!mInnerWindow) {                                                      \
   1.432 +      NS_WARNING("No inner window available!");                               \
   1.433 +      return err_rval;                                                        \
   1.434 +    }                                                                         \
   1.435 +    return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
   1.436 +  }                                                                           \
   1.437 +  PR_END_MACRO
   1.438 +
   1.439 +#define FORWARD_TO_INNER_VOID(method, args)                                   \
   1.440 +  PR_BEGIN_MACRO                                                              \
   1.441 +  if (IsOuterWindow()) {                                                      \
   1.442 +    if (!mInnerWindow) {                                                      \
   1.443 +      NS_WARNING("No inner window available!");                               \
   1.444 +      return;                                                                 \
   1.445 +    }                                                                         \
   1.446 +    GetCurrentInnerWindowInternal()->method args;                             \
   1.447 +    return;                                                                   \
   1.448 +  }                                                                           \
   1.449 +  PR_END_MACRO
   1.450 +
   1.451 +// Same as FORWARD_TO_INNER, but this will create a fresh inner if an
   1.452 +// inner doesn't already exists.
   1.453 +#define FORWARD_TO_INNER_CREATE(method, args, err_rval)                       \
   1.454 +  PR_BEGIN_MACRO                                                              \
   1.455 +  if (IsOuterWindow()) {                                                      \
   1.456 +    if (!mInnerWindow) {                                                      \
   1.457 +      if (mIsClosed) {                                                        \
   1.458 +        return err_rval;                                                      \
   1.459 +      }                                                                       \
   1.460 +      nsCOMPtr<nsIDOMDocument> doc;                                           \
   1.461 +      nsresult fwdic_nr = GetDocument(getter_AddRefs(doc));                   \
   1.462 +      NS_ENSURE_SUCCESS(fwdic_nr, err_rval);                                  \
   1.463 +      if (!mInnerWindow) {                                                    \
   1.464 +        return err_rval;                                                      \
   1.465 +      }                                                                       \
   1.466 +    }                                                                         \
   1.467 +    return GetCurrentInnerWindowInternal()->method args;                      \
   1.468 +  }                                                                           \
   1.469 +  PR_END_MACRO
   1.470 +
   1.471 +// CIDs
   1.472 +static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
   1.473 +
   1.474 +static const char sPopStatePrefStr[] = "browser.history.allowPopState";
   1.475 +
   1.476 +#define NETWORK_UPLOAD_EVENT_NAME     NS_LITERAL_STRING("moznetworkupload")
   1.477 +#define NETWORK_DOWNLOAD_EVENT_NAME   NS_LITERAL_STRING("moznetworkdownload")
   1.478 +
   1.479 +/**
   1.480 + * An indirect observer object that means we don't have to implement nsIObserver
   1.481 + * on nsGlobalWindow, where any script could see it.
   1.482 + */
   1.483 +class nsGlobalWindowObserver MOZ_FINAL : public nsIObserver,
   1.484 +                                         public nsIInterfaceRequestor
   1.485 +{
   1.486 +public:
   1.487 +  nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
   1.488 +  NS_DECL_ISUPPORTS
   1.489 +  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
   1.490 +  {
   1.491 +    if (!mWindow)
   1.492 +      return NS_OK;
   1.493 +    return mWindow->Observe(aSubject, aTopic, aData);
   1.494 +  }
   1.495 +  void Forget() { mWindow = nullptr; }
   1.496 +  NS_IMETHODIMP GetInterface(const nsIID& aIID, void** aResult)
   1.497 +  {
   1.498 +    if (mWindow && aIID.Equals(NS_GET_IID(nsIDOMWindow)) && mWindow) {
   1.499 +      return mWindow->QueryInterface(aIID, aResult);
   1.500 +    }
   1.501 +    return NS_NOINTERFACE;
   1.502 +  }
   1.503 +
   1.504 +private:
   1.505 +  nsGlobalWindow* mWindow;
   1.506 +};
   1.507 +
   1.508 +NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)
   1.509 +
   1.510 +nsTimeout::nsTimeout()
   1.511 +  : mCleared(false),
   1.512 +    mRunning(false),
   1.513 +    mIsInterval(false),
   1.514 +    mPublicId(0),
   1.515 +    mInterval(0),
   1.516 +    mFiringDepth(0),
   1.517 +    mNestingLevel(0),
   1.518 +    mPopupState(openAllowed)
   1.519 +{
   1.520 +#ifdef DEBUG_jst
   1.521 +  {
   1.522 +    extern int gTimeoutCnt;
   1.523 +
   1.524 +    ++gTimeoutCnt;
   1.525 +  }
   1.526 +#endif
   1.527 +
   1.528 +  MOZ_COUNT_CTOR(nsTimeout);
   1.529 +}
   1.530 +
   1.531 +nsTimeout::~nsTimeout()
   1.532 +{
   1.533 +#ifdef DEBUG_jst
   1.534 +  {
   1.535 +    extern int gTimeoutCnt;
   1.536 +
   1.537 +    --gTimeoutCnt;
   1.538 +  }
   1.539 +#endif
   1.540 +
   1.541 +  if (mTimer) {
   1.542 +    mTimer->Cancel();
   1.543 +    mTimer = nullptr;
   1.544 +  }
   1.545 +
   1.546 +  MOZ_COUNT_DTOR(nsTimeout);
   1.547 +}
   1.548 +
   1.549 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
   1.550 +
   1.551 +NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsTimeout)
   1.552 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTimeout)
   1.553 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
   1.554 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
   1.555 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler)
   1.556 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1.557 +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
   1.558 +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
   1.559 +
   1.560 +// Return true if this timeout has a refcount of 1. This is used to check
   1.561 +// that dummy_timeout doesn't leak from nsGlobalWindow::RunTimeout.
   1.562 +bool
   1.563 +nsTimeout::HasRefCntOne()
   1.564 +{
   1.565 +  return mRefCnt.get() == 1;
   1.566 +}
   1.567 +
   1.568 +nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
   1.569 +: mFrameElement(nullptr), mDocShell(nullptr), mModalStateDepth(0),
   1.570 +  mRunningTimeout(nullptr), mMutationBits(0), mIsDocumentLoaded(false),
   1.571 +  mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nullptr),
   1.572 +  mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
   1.573 +  mMayHaveMouseEnterLeaveEventListener(false),
   1.574 +  mMayHavePointerEnterLeaveEventListener(false),
   1.575 +  mIsModalContentWindow(false),
   1.576 +  mIsActive(false), mIsBackground(false),
   1.577 +  mAudioMuted(false), mAudioVolume(1.0),
   1.578 +  mInnerWindow(nullptr), mOuterWindow(aOuterWindow),
   1.579 +  // Make sure no actual window ends up with mWindowID == 0
   1.580 +  mWindowID(++gNextWindowID), mHasNotifiedGlobalCreated(false),
   1.581 +  mMarkedCCGeneration(0)
   1.582 + {}
   1.583 +
   1.584 +nsPIDOMWindow::~nsPIDOMWindow() {}
   1.585 +
   1.586 +// DialogValueHolder CC goop.
   1.587 +NS_IMPL_CYCLE_COLLECTION(DialogValueHolder, mValue)
   1.588 +
   1.589 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DialogValueHolder)
   1.590 +  NS_INTERFACE_MAP_ENTRY(nsISupports)
   1.591 +NS_INTERFACE_MAP_END
   1.592 +
   1.593 +NS_IMPL_CYCLE_COLLECTING_ADDREF(DialogValueHolder)
   1.594 +NS_IMPL_CYCLE_COLLECTING_RELEASE(DialogValueHolder)
   1.595 +
   1.596 +//*****************************************************************************
   1.597 +// nsOuterWindowProxy: Outer Window Proxy
   1.598 +//*****************************************************************************
   1.599 +
   1.600 +class nsOuterWindowProxy : public js::Wrapper
   1.601 +{
   1.602 +public:
   1.603 +  nsOuterWindowProxy() : js::Wrapper(0) { }
   1.604 +
   1.605 +  virtual bool finalizeInBackground(JS::Value priv) {
   1.606 +    return false;
   1.607 +  }
   1.608 +
   1.609 +  virtual const char *className(JSContext *cx,
   1.610 +                                JS::Handle<JSObject*> wrapper) MOZ_OVERRIDE;
   1.611 +  virtual void finalize(JSFreeOp *fop, JSObject *proxy) MOZ_OVERRIDE;
   1.612 +
   1.613 +  // Fundamental traps
   1.614 +  virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
   1.615 +                           MOZ_OVERRIDE;
   1.616 +  virtual bool preventExtensions(JSContext *cx,
   1.617 +                                 JS::Handle<JSObject*> proxy) MOZ_OVERRIDE;
   1.618 +  virtual bool getPropertyDescriptor(JSContext* cx,
   1.619 +                                     JS::Handle<JSObject*> proxy,
   1.620 +                                     JS::Handle<jsid> id,
   1.621 +                                     JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.622 +  virtual bool getOwnPropertyDescriptor(JSContext* cx,
   1.623 +                                        JS::Handle<JSObject*> proxy,
   1.624 +                                        JS::Handle<jsid> id,
   1.625 +                                        JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.626 +  virtual bool defineProperty(JSContext* cx,
   1.627 +                              JS::Handle<JSObject*> proxy,
   1.628 +                              JS::Handle<jsid> id,
   1.629 +                              JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.630 +  virtual bool getOwnPropertyNames(JSContext *cx,
   1.631 +                                   JS::Handle<JSObject*> proxy,
   1.632 +                                   JS::AutoIdVector &props) MOZ_OVERRIDE;
   1.633 +  virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.634 +                       JS::Handle<jsid> id,
   1.635 +                       bool *bp) MOZ_OVERRIDE;
   1.636 +  virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.637 +                         JS::AutoIdVector &props) MOZ_OVERRIDE;
   1.638 +
   1.639 +  virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.640 +                     JS::Handle<jsid> id, JS::Handle<JSObject*> callable) MOZ_OVERRIDE;
   1.641 +  virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.642 +                       JS::Handle<jsid> id) MOZ_OVERRIDE;
   1.643 +
   1.644 +  // Derived traps
   1.645 +  virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.646 +                   JS::Handle<jsid> id, bool *bp) MOZ_OVERRIDE;
   1.647 +  virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.648 +                      JS::Handle<jsid> id, bool *bp) MOZ_OVERRIDE;
   1.649 +  virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.650 +                   JS::Handle<JSObject*> receiver,
   1.651 +                   JS::Handle<jsid> id,
   1.652 +                   JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
   1.653 +  virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.654 +                   JS::Handle<JSObject*> receiver,
   1.655 +                   JS::Handle<jsid> id,
   1.656 +                   bool strict,
   1.657 +                   JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
   1.658 +  virtual bool keys(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.659 +                    JS::AutoIdVector &props) MOZ_OVERRIDE;
   1.660 +  virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.661 +                       unsigned flags,
   1.662 +                       JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
   1.663 +
   1.664 +  static nsOuterWindowProxy singleton;
   1.665 +
   1.666 +protected:
   1.667 +  nsGlobalWindow* GetWindow(JSObject *proxy)
   1.668 +  {
   1.669 +    return nsGlobalWindow::FromSupports(
   1.670 +      static_cast<nsISupports*>(js::GetProxyExtra(proxy, 0).toPrivate()));
   1.671 +  }
   1.672 +
   1.673 +  // False return value means we threw an exception.  True return value
   1.674 +  // but false "found" means we didn't have a subframe at that index.
   1.675 +  bool GetSubframeWindow(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.676 +                         JS::Handle<jsid> id,
   1.677 +                         JS::MutableHandle<JS::Value> vp,
   1.678 +                         bool &found);
   1.679 +
   1.680 +  // Returns a non-null window only if id is an index and we have a
   1.681 +  // window at that index.
   1.682 +  already_AddRefed<nsIDOMWindow> GetSubframeWindow(JSContext *cx,
   1.683 +                                                   JS::Handle<JSObject*> proxy,
   1.684 +                                                   JS::Handle<jsid> id);
   1.685 +
   1.686 +  bool AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
   1.687 +                                  JS::AutoIdVector &props);
   1.688 +};
   1.689 +
   1.690 +const js::Class OuterWindowProxyClass =
   1.691 +    PROXY_CLASS_WITH_EXT(
   1.692 +        "Proxy",
   1.693 +        0, /* additional slots */
   1.694 +        0, /* additional class flags */
   1.695 +        nullptr, /* call */
   1.696 +        nullptr, /* construct */
   1.697 +        PROXY_MAKE_EXT(
   1.698 +            nullptr, /* outerObject */
   1.699 +            js::proxy_innerObject,
   1.700 +            nullptr, /* iteratorObject */
   1.701 +            false   /* isWrappedNative */
   1.702 +        ));
   1.703 +
   1.704 +bool
   1.705 +nsOuterWindowProxy::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.706 +                                 bool *extensible)
   1.707 +{
   1.708 +  // If [[Extensible]] could be false, then navigating a window could navigate
   1.709 +  // to a window that's [[Extensible]] after being at one that wasn't: an
   1.710 +  // invariant violation.  So always report true for this.
   1.711 +  *extensible = true;
   1.712 +  return true;
   1.713 +}
   1.714 +
   1.715 +bool
   1.716 +nsOuterWindowProxy::preventExtensions(JSContext *cx,
   1.717 +                                      JS::Handle<JSObject*> proxy)
   1.718 +{
   1.719 +  // See above.
   1.720 +  JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   1.721 +                       JSMSG_CANT_CHANGE_EXTENSIBILITY);
   1.722 +  return false;
   1.723 +}
   1.724 +
   1.725 +const char *
   1.726 +nsOuterWindowProxy::className(JSContext *cx, JS::Handle<JSObject*> proxy)
   1.727 +{
   1.728 +    MOZ_ASSERT(js::IsProxy(proxy));
   1.729 +
   1.730 +    return "Window";
   1.731 +}
   1.732 +
   1.733 +void
   1.734 +nsOuterWindowProxy::finalize(JSFreeOp *fop, JSObject *proxy)
   1.735 +{
   1.736 +  nsGlobalWindow* global = GetWindow(proxy);
   1.737 +  if (global) {
   1.738 +    global->ClearWrapper();
   1.739 +
   1.740 +    // Ideally we would use OnFinalize here, but it's possible that
   1.741 +    // EnsureScriptEnvironment will later be called on the window, and we don't
   1.742 +    // want to create a new script object in that case. Therefore, we need to
   1.743 +    // write a non-null value that will reliably crash when dereferenced.
   1.744 +    global->PoisonOuterWindowProxy(proxy);
   1.745 +  }
   1.746 +}
   1.747 +
   1.748 +bool
   1.749 +nsOuterWindowProxy::getPropertyDescriptor(JSContext* cx,
   1.750 +                                          JS::Handle<JSObject*> proxy,
   1.751 +                                          JS::Handle<jsid> id,
   1.752 +                                          JS::MutableHandle<JSPropertyDescriptor> desc)
   1.753 +{
   1.754 +  // The only thing we can do differently from js::Wrapper is shadow stuff with
   1.755 +  // our indexed properties, so we can just try getOwnPropertyDescriptor and if
   1.756 +  // that gives us nothing call on through to js::Wrapper.
   1.757 +  desc.object().set(nullptr);
   1.758 +  if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) {
   1.759 +    return false;
   1.760 +  }
   1.761 +
   1.762 +  if (desc.object()) {
   1.763 +    return true;
   1.764 +  }
   1.765 +
   1.766 +  return js::Wrapper::getPropertyDescriptor(cx, proxy, id, desc);
   1.767 +}
   1.768 +
   1.769 +bool
   1.770 +nsOuterWindowProxy::getOwnPropertyDescriptor(JSContext* cx,
   1.771 +                                             JS::Handle<JSObject*> proxy,
   1.772 +                                             JS::Handle<jsid> id,
   1.773 +                                             JS::MutableHandle<JSPropertyDescriptor> desc)
   1.774 +{
   1.775 +  bool found;
   1.776 +  if (!GetSubframeWindow(cx, proxy, id, desc.value(), found)) {
   1.777 +    return false;
   1.778 +  }
   1.779 +  if (found) {
   1.780 +    FillPropertyDescriptor(desc, proxy, true);
   1.781 +    return true;
   1.782 +  }
   1.783 +  // else fall through to js::Wrapper
   1.784 +
   1.785 +  return js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
   1.786 +}
   1.787 +
   1.788 +bool
   1.789 +nsOuterWindowProxy::defineProperty(JSContext* cx,
   1.790 +                                   JS::Handle<JSObject*> proxy,
   1.791 +                                   JS::Handle<jsid> id,
   1.792 +                                   JS::MutableHandle<JSPropertyDescriptor> desc)
   1.793 +{
   1.794 +  int32_t index = GetArrayIndexFromId(cx, id);
   1.795 +  if (IsArrayIndex(index)) {
   1.796 +    // Spec says to Reject whether this is a supported index or not,
   1.797 +    // since we have no indexed setter or indexed creator.  That means
   1.798 +    // throwing in strict mode (FIXME: Bug 828137), doing nothing in
   1.799 +    // non-strict mode.
   1.800 +    return true;
   1.801 +  }
   1.802 +
   1.803 +  return js::Wrapper::defineProperty(cx, proxy, id, desc);
   1.804 +}
   1.805 +
   1.806 +bool
   1.807 +nsOuterWindowProxy::getOwnPropertyNames(JSContext *cx,
   1.808 +                                        JS::Handle<JSObject*> proxy,
   1.809 +                                        JS::AutoIdVector &props)
   1.810 +{
   1.811 +  // Just our indexed stuff followed by our "normal" own property names.
   1.812 +  if (!AppendIndexedPropertyNames(cx, proxy, props)) {
   1.813 +    return false;
   1.814 +  }
   1.815 +
   1.816 +  JS::AutoIdVector innerProps(cx);
   1.817 +  if (!js::Wrapper::getOwnPropertyNames(cx, proxy, innerProps)) {
   1.818 +    return false;
   1.819 +  }
   1.820 +  return js::AppendUnique(cx, props, innerProps);
   1.821 +}
   1.822 +
   1.823 +bool
   1.824 +nsOuterWindowProxy::delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.825 +                            JS::Handle<jsid> id, bool *bp)
   1.826 +{
   1.827 +  if (nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id)) {
   1.828 +    // Reject (which means throw if strict, else return false) the delete.
   1.829 +    // Except we don't even know whether we're strict.  See bug 803157.
   1.830 +    *bp = false;
   1.831 +    return true;
   1.832 +  }
   1.833 +
   1.834 +  int32_t index = GetArrayIndexFromId(cx, id);
   1.835 +  if (IsArrayIndex(index)) {
   1.836 +    // Indexed, but not supported.  Spec says return true.
   1.837 +    *bp = true;
   1.838 +    return true;
   1.839 +  }
   1.840 +
   1.841 +  return js::Wrapper::delete_(cx, proxy, id, bp);
   1.842 +}
   1.843 +
   1.844 +bool
   1.845 +nsOuterWindowProxy::enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.846 +                              JS::AutoIdVector &props)
   1.847 +{
   1.848 +  // Just our indexed stuff followed by our "normal" own property names.
   1.849 +  if (!AppendIndexedPropertyNames(cx, proxy, props)) {
   1.850 +    return false;
   1.851 +  }
   1.852 +
   1.853 +  JS::AutoIdVector innerProps(cx);
   1.854 +  if (!js::Wrapper::enumerate(cx, proxy, innerProps)) {
   1.855 +    return false;
   1.856 +  }
   1.857 +  return js::AppendUnique(cx, props, innerProps);
   1.858 +}
   1.859 +
   1.860 +bool
   1.861 +nsOuterWindowProxy::has(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.862 +                        JS::Handle<jsid> id, bool *bp)
   1.863 +{
   1.864 +  if (nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id)) {
   1.865 +    *bp = true;
   1.866 +    return true;
   1.867 +  }
   1.868 +
   1.869 +  return js::Wrapper::has(cx, proxy, id, bp);
   1.870 +}
   1.871 +
   1.872 +bool
   1.873 +nsOuterWindowProxy::hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.874 +                           JS::Handle<jsid> id, bool *bp)
   1.875 +{
   1.876 +  if (nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id)) {
   1.877 +    *bp = true;
   1.878 +    return true;
   1.879 +  }
   1.880 +
   1.881 +  return js::Wrapper::hasOwn(cx, proxy, id, bp);
   1.882 +}
   1.883 +
   1.884 +bool
   1.885 +nsOuterWindowProxy::get(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.886 +                        JS::Handle<JSObject*> receiver,
   1.887 +                        JS::Handle<jsid> id,
   1.888 +                        JS::MutableHandle<JS::Value> vp)
   1.889 +{
   1.890 +  if (id == nsDOMClassInfo::sWrappedJSObject_id &&
   1.891 +      xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
   1.892 +    vp.set(JS::ObjectValue(*proxy));
   1.893 +    return true;
   1.894 +  }
   1.895 +
   1.896 +  bool found;
   1.897 +  if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
   1.898 +    return false;
   1.899 +  }
   1.900 +  if (found) {
   1.901 +    return true;
   1.902 +  }
   1.903 +  // Else fall through to js::Wrapper
   1.904 +
   1.905 +  return js::Wrapper::get(cx, proxy, receiver, id, vp);
   1.906 +}
   1.907 +
   1.908 +bool
   1.909 +nsOuterWindowProxy::set(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.910 +                        JS::Handle<JSObject*> receiver,
   1.911 +                        JS::Handle<jsid> id,
   1.912 +                        bool strict,
   1.913 +                        JS::MutableHandle<JS::Value> vp)
   1.914 +{
   1.915 +  int32_t index = GetArrayIndexFromId(cx, id);
   1.916 +  if (IsArrayIndex(index)) {
   1.917 +    // Reject (which means throw if and only if strict) the set.
   1.918 +    if (strict) {
   1.919 +      // XXXbz This needs to throw, but see bug 828137.
   1.920 +    }
   1.921 +    return true;
   1.922 +  }
   1.923 +
   1.924 +  return js::Wrapper::set(cx, proxy, receiver, id, strict, vp);
   1.925 +}
   1.926 +
   1.927 +bool
   1.928 +nsOuterWindowProxy::keys(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.929 +                         JS::AutoIdVector &props)
   1.930 +{
   1.931 +  // BaseProxyHandler::keys seems to do what we want here: call
   1.932 +  // getOwnPropertyNames and then filter out the non-enumerable properties.
   1.933 +  return js::BaseProxyHandler::keys(cx, proxy, props);
   1.934 +}
   1.935 +
   1.936 +bool
   1.937 +nsOuterWindowProxy::iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
   1.938 +                            unsigned flags, JS::MutableHandle<JS::Value> vp)
   1.939 +{
   1.940 +  // BaseProxyHandler::iterate seems to do what we want here: fall
   1.941 +  // back on the property names returned from keys() and enumerate().
   1.942 +  return js::BaseProxyHandler::iterate(cx, proxy, flags, vp);
   1.943 +}
   1.944 +
   1.945 +bool
   1.946 +nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
   1.947 +                                      JS::Handle<JSObject*> proxy,
   1.948 +                                      JS::Handle<jsid> id,
   1.949 +                                      JS::MutableHandle<JS::Value> vp,
   1.950 +                                      bool& found)
   1.951 +{
   1.952 +  nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id);
   1.953 +  if (!frame) {
   1.954 +    found = false;
   1.955 +    return true;
   1.956 +  }
   1.957 +
   1.958 +  found = true;
   1.959 +  // Just return the window's global
   1.960 +  nsGlobalWindow* global = static_cast<nsGlobalWindow*>(frame.get());
   1.961 +  global->EnsureInnerWindow();
   1.962 +  JSObject* obj = global->FastGetGlobalJSObject();
   1.963 +  // This null check fixes a hard-to-reproduce crash that occurs when we
   1.964 +  // get here when we're mid-call to nsDocShell::Destroy. See bug 640904
   1.965 +  // comment 105.
   1.966 +  if (MOZ_UNLIKELY(!obj)) {
   1.967 +    return xpc::Throw(cx, NS_ERROR_FAILURE);
   1.968 +  }
   1.969 +
   1.970 +  vp.setObject(*obj);
   1.971 +  return JS_WrapValue(cx, vp);
   1.972 +}
   1.973 +
   1.974 +already_AddRefed<nsIDOMWindow>
   1.975 +nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
   1.976 +                                      JS::Handle<JSObject*> proxy,
   1.977 +                                      JS::Handle<jsid> id)
   1.978 +{
   1.979 +  int32_t index = GetArrayIndexFromId(cx, id);
   1.980 +  if (!IsArrayIndex(index)) {
   1.981 +    return nullptr;
   1.982 +  }
   1.983 +
   1.984 +  nsGlobalWindow* win = GetWindow(proxy);
   1.985 +  bool unused;
   1.986 +  return win->IndexedGetter(index, unused);
   1.987 +}
   1.988 +
   1.989 +bool
   1.990 +nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
   1.991 +                                               JS::AutoIdVector &props)
   1.992 +{
   1.993 +  uint32_t length = GetWindow(proxy)->Length();
   1.994 +  MOZ_ASSERT(int32_t(length) >= 0);
   1.995 +  if (!props.reserve(props.length() + length)) {
   1.996 +    return false;
   1.997 +  }
   1.998 +  for (int32_t i = 0; i < int32_t(length); ++i) {
   1.999 +    props.append(INT_TO_JSID(i));
  1.1000 +  }
  1.1001 +
  1.1002 +  return true;
  1.1003 +}
  1.1004 +
  1.1005 +bool
  1.1006 +nsOuterWindowProxy::watch(JSContext *cx, JS::Handle<JSObject*> proxy,
  1.1007 +                          JS::Handle<jsid> id, JS::Handle<JSObject*> callable)
  1.1008 +{
  1.1009 +  return js::WatchGuts(cx, proxy, id, callable);
  1.1010 +}
  1.1011 +
  1.1012 +bool
  1.1013 +nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
  1.1014 +                            JS::Handle<jsid> id)
  1.1015 +{
  1.1016 +  return js::UnwatchGuts(cx, proxy, id);
  1.1017 +}
  1.1018 +
  1.1019 +nsOuterWindowProxy
  1.1020 +nsOuterWindowProxy::singleton;
  1.1021 +
  1.1022 +class nsChromeOuterWindowProxy : public nsOuterWindowProxy
  1.1023 +{
  1.1024 +public:
  1.1025 +  nsChromeOuterWindowProxy() : nsOuterWindowProxy() {}
  1.1026 +
  1.1027 +  virtual const char *className(JSContext *cx, JS::Handle<JSObject*> wrapper) MOZ_OVERRIDE;
  1.1028 +
  1.1029 +  static nsChromeOuterWindowProxy singleton;
  1.1030 +};
  1.1031 +
  1.1032 +const char *
  1.1033 +nsChromeOuterWindowProxy::className(JSContext *cx,
  1.1034 +                                    JS::Handle<JSObject*> proxy)
  1.1035 +{
  1.1036 +    MOZ_ASSERT(js::IsProxy(proxy));
  1.1037 +
  1.1038 +    return "ChromeWindow";
  1.1039 +}
  1.1040 +
  1.1041 +nsChromeOuterWindowProxy
  1.1042 +nsChromeOuterWindowProxy::singleton;
  1.1043 +
  1.1044 +static JSObject*
  1.1045 +NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> parent, bool isChrome)
  1.1046 +{
  1.1047 +  JSAutoCompartment ac(cx, parent);
  1.1048 +  js::WrapperOptions options;
  1.1049 +  options.setClass(&OuterWindowProxyClass);
  1.1050 +  options.setSingleton(true);
  1.1051 +  JSObject *obj = js::Wrapper::New(cx, parent, parent,
  1.1052 +                                   isChrome ? &nsChromeOuterWindowProxy::singleton
  1.1053 +                                            : &nsOuterWindowProxy::singleton,
  1.1054 +                                   &options);
  1.1055 +
  1.1056 +  NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
  1.1057 +  return obj;
  1.1058 +}
  1.1059 +
  1.1060 +//*****************************************************************************
  1.1061 +//***    nsGlobalWindow: Object Management
  1.1062 +//*****************************************************************************
  1.1063 +
  1.1064 +nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
  1.1065 +  : nsPIDOMWindow(aOuterWindow),
  1.1066 +    mIdleFuzzFactor(0),
  1.1067 +    mIdleCallbackIndex(-1),
  1.1068 +    mCurrentlyIdle(false),
  1.1069 +    mAddActiveEventFuzzTime(true),
  1.1070 +    mIsFrozen(false),
  1.1071 +    mFullScreen(false),
  1.1072 +    mIsClosed(false),
  1.1073 +    mInClose(false),
  1.1074 +    mHavePendingClose(false),
  1.1075 +    mHadOriginalOpener(false),
  1.1076 +    mIsPopupSpam(false),
  1.1077 +    mBlockScriptedClosingFlag(false),
  1.1078 +    mFireOfflineStatusChangeEventOnThaw(false),
  1.1079 +    mNotifyIdleObserversIdleOnThaw(false),
  1.1080 +    mNotifyIdleObserversActiveOnThaw(false),
  1.1081 +    mCreatingInnerWindow(false),
  1.1082 +    mIsChrome(false),
  1.1083 +    mCleanMessageManager(false),
  1.1084 +    mNeedsFocus(true),
  1.1085 +    mHasFocus(false),
  1.1086 +#if defined(XP_MACOSX)
  1.1087 +    mShowAccelerators(false),
  1.1088 +    mShowFocusRings(false),
  1.1089 +#else
  1.1090 +    mShowAccelerators(true),
  1.1091 +    mShowFocusRings(true),
  1.1092 +#endif
  1.1093 +    mShowFocusRingForContent(false),
  1.1094 +    mFocusByKeyOccurred(false),
  1.1095 +    mInnerObjectsFreed(false),
  1.1096 +    mHasGamepad(false),
  1.1097 +#ifdef MOZ_GAMEPAD
  1.1098 +    mHasSeenGamepadInput(false),
  1.1099 +#endif
  1.1100 +    mNotifiedIDDestroyed(false),
  1.1101 +    mAllowScriptsToClose(false),
  1.1102 +    mTimeoutInsertionPoint(nullptr),
  1.1103 +    mTimeoutPublicIdCounter(1),
  1.1104 +    mTimeoutFiringDepth(0),
  1.1105 +    mTimeoutsSuspendDepth(0),
  1.1106 +    mFocusMethod(0),
  1.1107 +    mSerial(0),
  1.1108 +#ifdef DEBUG
  1.1109 +    mSetOpenerWindowCalled(false),
  1.1110 +#endif
  1.1111 +#ifdef MOZ_B2G
  1.1112 +    mNetworkUploadObserverEnabled(false),
  1.1113 +    mNetworkDownloadObserverEnabled(false),
  1.1114 +#endif
  1.1115 +    mCleanedUp(false),
  1.1116 +    mDialogAbuseCount(0),
  1.1117 +    mAreDialogsEnabled(true)
  1.1118 +{
  1.1119 +  nsLayoutStatics::AddRef();
  1.1120 +
  1.1121 +  // Initialize the PRCList (this).
  1.1122 +  PR_INIT_CLIST(this);
  1.1123 +
  1.1124 +  if (aOuterWindow) {
  1.1125 +    // |this| is an inner window, add this inner window to the outer
  1.1126 +    // window list of inners.
  1.1127 +    PR_INSERT_AFTER(this, aOuterWindow);
  1.1128 +
  1.1129 +    mObserver = new nsGlobalWindowObserver(this);
  1.1130 +    if (mObserver) {
  1.1131 +      NS_ADDREF(mObserver);
  1.1132 +      nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
  1.1133 +      if (os) {
  1.1134 +        // Watch for online/offline status changes so we can fire events. Use
  1.1135 +        // a strong reference.
  1.1136 +        os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
  1.1137 +                        false);
  1.1138 +
  1.1139 +        // Watch for dom-storage2-changed so we can fire storage
  1.1140 +        // events. Use a strong reference.
  1.1141 +        os->AddObserver(mObserver, "dom-storage2-changed", false);
  1.1142 +      }
  1.1143 +    }
  1.1144 +  } else {
  1.1145 +    // |this| is an outer window. Outer windows start out frozen and
  1.1146 +    // remain frozen until they get an inner window, so freeze this
  1.1147 +    // outer window here.
  1.1148 +    Freeze();
  1.1149 +
  1.1150 +    mObserver = nullptr;
  1.1151 +    SetIsDOMBinding();
  1.1152 +  }
  1.1153 +
  1.1154 +  // We could have failed the first time through trying
  1.1155 +  // to create the entropy collector, so we should
  1.1156 +  // try to get one until we succeed.
  1.1157 +
  1.1158 +  gRefCnt++;
  1.1159 +
  1.1160 +  if (gRefCnt == 1) {
  1.1161 +    Preferences::AddIntVarCache(&gMinTimeoutValue,
  1.1162 +                                "dom.min_timeout_value",
  1.1163 +                                DEFAULT_MIN_TIMEOUT_VALUE);
  1.1164 +    Preferences::AddIntVarCache(&gMinBackgroundTimeoutValue,
  1.1165 +                                "dom.min_background_timeout_value",
  1.1166 +                                DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE);
  1.1167 +    Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled, 
  1.1168 +                                 "dom.idle-observers-api.fuzz_time.disabled",
  1.1169 +                                 false);
  1.1170 +  }
  1.1171 +
  1.1172 +  if (gDumpFile == nullptr) {
  1.1173 +    const nsAdoptingCString& fname =
  1.1174 +      Preferences::GetCString("browser.dom.window.dump.file");
  1.1175 +    if (!fname.IsEmpty()) {
  1.1176 +      // if this fails to open, Dump() knows to just go to stdout
  1.1177 +      // on null.
  1.1178 +      gDumpFile = fopen(fname, "wb+");
  1.1179 +    } else {
  1.1180 +      gDumpFile = stdout;
  1.1181 +    }
  1.1182 +  }
  1.1183 +
  1.1184 +  mSerial = ++gSerialCounter;
  1.1185 +
  1.1186 +#ifdef DEBUG
  1.1187 +  if (!PR_GetEnv("MOZ_QUIET")) {
  1.1188 +    printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
  1.1189 +                  gRefCnt,
  1.1190 +                  static_cast<void*>(ToCanonicalSupports(this)),
  1.1191 +                  getpid(),
  1.1192 +                  gSerialCounter,
  1.1193 +                  static_cast<void*>(ToCanonicalSupports(aOuterWindow)));
  1.1194 +  }
  1.1195 +#endif
  1.1196 +
  1.1197 +#ifdef PR_LOGGING
  1.1198 +  if (gDOMLeakPRLog)
  1.1199 +    PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
  1.1200 +           ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
  1.1201 +#endif
  1.1202 +
  1.1203 +  NS_ASSERTION(sWindowsById, "Windows hash table must be created!");
  1.1204 +  NS_ASSERTION(!sWindowsById->Get(mWindowID),
  1.1205 +               "This window shouldn't be in the hash table yet!");
  1.1206 +  // We seem to see crashes in release builds because of null |sWindowsById|.
  1.1207 +  if (sWindowsById) {
  1.1208 +    sWindowsById->Put(mWindowID, this);
  1.1209 +  }
  1.1210 +}
  1.1211 +
  1.1212 +/* static */
  1.1213 +void
  1.1214 +nsGlobalWindow::Init()
  1.1215 +{
  1.1216 +  CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
  1.1217 +  NS_ASSERTION(gEntropyCollector,
  1.1218 +               "gEntropyCollector should have been initialized!");
  1.1219 +
  1.1220 +#ifdef PR_LOGGING
  1.1221 +  gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
  1.1222 +  NS_ASSERTION(gDOMLeakPRLog, "gDOMLeakPRLog should have been initialized!");
  1.1223 +#endif
  1.1224 +
  1.1225 +  sWindowsById = new WindowByIdTable();
  1.1226 +}
  1.1227 +
  1.1228 +static PLDHashOperator
  1.1229 +DisconnectEventTargetObjects(nsPtrHashKey<DOMEventTargetHelper>* aKey,
  1.1230 +                             void* aClosure)
  1.1231 +{
  1.1232 +  nsRefPtr<DOMEventTargetHelper> target = aKey->GetKey();
  1.1233 +  target->DisconnectFromOwner();
  1.1234 +  return PL_DHASH_NEXT;
  1.1235 +}
  1.1236 +
  1.1237 +nsGlobalWindow::~nsGlobalWindow()
  1.1238 +{
  1.1239 +  mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
  1.1240 +  mEventTargetObjects.Clear();
  1.1241 +
  1.1242 +  // We have to check if sWindowsById isn't null because ::Shutdown might have
  1.1243 +  // been called.
  1.1244 +  if (sWindowsById) {
  1.1245 +    NS_ASSERTION(sWindowsById->Get(mWindowID),
  1.1246 +                 "This window should be in the hash table");
  1.1247 +    sWindowsById->Remove(mWindowID);
  1.1248 +  }
  1.1249 +
  1.1250 +  --gRefCnt;
  1.1251 +
  1.1252 +#ifdef DEBUG
  1.1253 +  if (!PR_GetEnv("MOZ_QUIET")) {
  1.1254 +    nsAutoCString url;
  1.1255 +    if (mLastOpenedURI) {
  1.1256 +      mLastOpenedURI->GetSpec(url);
  1.1257 +
  1.1258 +      // Data URLs can be very long, so truncate to avoid flooding the log.
  1.1259 +      const uint32_t maxURLLength = 1000;
  1.1260 +      if (url.Length() > maxURLLength) {
  1.1261 +        url.Truncate(maxURLLength);
  1.1262 +      }
  1.1263 +    }
  1.1264 +
  1.1265 +    nsGlobalWindow* outer = static_cast<nsGlobalWindow*>(mOuterWindow.get());
  1.1266 +    printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n",
  1.1267 +                  gRefCnt,
  1.1268 +                  static_cast<void*>(ToCanonicalSupports(this)),
  1.1269 +                  getpid(),
  1.1270 +                  mSerial,
  1.1271 +                  static_cast<void*>(ToCanonicalSupports(outer)),
  1.1272 +                  url.get());
  1.1273 +  }
  1.1274 +#endif
  1.1275 +
  1.1276 +#ifdef PR_LOGGING
  1.1277 +  if (gDOMLeakPRLog)
  1.1278 +    PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
  1.1279 +           ("DOMWINDOW %p destroyed", this));
  1.1280 +#endif
  1.1281 +
  1.1282 +  if (IsOuterWindow()) {
  1.1283 +    JSObject *proxy = GetWrapperPreserveColor();
  1.1284 +    if (proxy) {
  1.1285 +      js::SetProxyExtra(proxy, 0, js::PrivateValue(nullptr));
  1.1286 +    }
  1.1287 +
  1.1288 +    // An outer window is destroyed with inner windows still possibly
  1.1289 +    // alive, iterate through the inner windows and null out their
  1.1290 +    // back pointer to this outer, and pull them out of the list of
  1.1291 +    // inner windows.
  1.1292 +
  1.1293 +    nsGlobalWindow *w;
  1.1294 +    while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
  1.1295 +      PR_REMOVE_AND_INIT_LINK(w);
  1.1296 +    }
  1.1297 +
  1.1298 +    DropOuterWindowDocs();
  1.1299 +  } else {
  1.1300 +    Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
  1.1301 +                          mMutationBits ? 1 : 0);
  1.1302 +
  1.1303 +    if (mListenerManager) {
  1.1304 +      mListenerManager->Disconnect();
  1.1305 +      mListenerManager = nullptr;
  1.1306 +    }
  1.1307 +
  1.1308 +    // An inner window is destroyed, pull it out of the outer window's
  1.1309 +    // list if inner windows.
  1.1310 +
  1.1311 +    PR_REMOVE_LINK(this);
  1.1312 +
  1.1313 +    // If our outer window's inner window is this window, null out the
  1.1314 +    // outer window's reference to this window that's being deleted.
  1.1315 +    nsGlobalWindow *outer = GetOuterWindowInternal();
  1.1316 +    if (outer) {
  1.1317 +      outer->MaybeClearInnerWindow(this);
  1.1318 +    }
  1.1319 +  }
  1.1320 +
  1.1321 +  // Outer windows are always supposed to call CleanUp before letting themselves
  1.1322 +  // be destroyed. And while CleanUp generally seems to be intended to clean up
  1.1323 +  // outers, we've historically called it for both. Changing this would probably
  1.1324 +  // involve auditing all of the references that inners and outers can have, and
  1.1325 +  // separating the handling into CleanUp() and FreeInnerObjects.
  1.1326 +  if (IsInnerWindow()) {
  1.1327 +    CleanUp();
  1.1328 +  } else {
  1.1329 +    MOZ_ASSERT(mCleanedUp);
  1.1330 +  }
  1.1331 +
  1.1332 +  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
  1.1333 +  if (ac)
  1.1334 +    ac->RemoveWindowAsListener(this);
  1.1335 +
  1.1336 +  nsLayoutStatics::Release();
  1.1337 +}
  1.1338 +
  1.1339 +void
  1.1340 +nsGlobalWindow::AddEventTargetObject(DOMEventTargetHelper* aObject)
  1.1341 +{
  1.1342 +  mEventTargetObjects.PutEntry(aObject);
  1.1343 +}
  1.1344 +
  1.1345 +void
  1.1346 +nsGlobalWindow::RemoveEventTargetObject(DOMEventTargetHelper* aObject)
  1.1347 +{
  1.1348 +  mEventTargetObjects.RemoveEntry(aObject);
  1.1349 +}
  1.1350 +
  1.1351 +// static
  1.1352 +void
  1.1353 +nsGlobalWindow::ShutDown()
  1.1354 +{
  1.1355 +  if (gDumpFile && gDumpFile != stdout) {
  1.1356 +    fclose(gDumpFile);
  1.1357 +  }
  1.1358 +  gDumpFile = nullptr;
  1.1359 +
  1.1360 +  NS_IF_RELEASE(gEntropyCollector);
  1.1361 +
  1.1362 +  delete sWindowsById;
  1.1363 +  sWindowsById = nullptr;
  1.1364 +}
  1.1365 +
  1.1366 +// static
  1.1367 +void
  1.1368 +nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
  1.1369 +{
  1.1370 +  if (aWindow->mCachedXBLPrototypeHandlers &&
  1.1371 +      aWindow->mCachedXBLPrototypeHandlers->Count() > 0) {
  1.1372 +    aWindow->mCachedXBLPrototypeHandlers->Clear();
  1.1373 +  }
  1.1374 +}
  1.1375 +
  1.1376 +void
  1.1377 +nsGlobalWindow::MaybeForgiveSpamCount()
  1.1378 +{
  1.1379 +  if (IsOuterWindow() &&
  1.1380 +      IsPopupSpamWindow())
  1.1381 +  {
  1.1382 +    SetPopupSpamWindow(false);
  1.1383 +    --gOpenPopupSpamCount;
  1.1384 +    NS_ASSERTION(gOpenPopupSpamCount >= 0,
  1.1385 +                 "Unbalanced decrement of gOpenPopupSpamCount");
  1.1386 +  }
  1.1387 +}
  1.1388 +
  1.1389 +void
  1.1390 +nsGlobalWindow::DropOuterWindowDocs()
  1.1391 +{
  1.1392 +  MOZ_ASSERT(IsOuterWindow());
  1.1393 +  MOZ_ASSERT_IF(mDoc, !mDoc->EventHandlingSuppressed());
  1.1394 +  mDoc = nullptr;
  1.1395 +  mSuspendedDoc = nullptr;
  1.1396 +}
  1.1397 +
  1.1398 +void
  1.1399 +nsGlobalWindow::CleanUp()
  1.1400 +{
  1.1401 +  // Guarantee idempotence.
  1.1402 +  if (mCleanedUp)
  1.1403 +    return;
  1.1404 +  mCleanedUp = true;
  1.1405 +
  1.1406 +  mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
  1.1407 +  mEventTargetObjects.Clear();
  1.1408 +
  1.1409 +  if (mObserver) {
  1.1410 +    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
  1.1411 +    if (os) {
  1.1412 +      os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
  1.1413 +      os->RemoveObserver(mObserver, "dom-storage2-changed");
  1.1414 +    }
  1.1415 +
  1.1416 +#ifdef MOZ_B2G
  1.1417 +    DisableNetworkEvent(NS_NETWORK_UPLOAD_EVENT);
  1.1418 +    DisableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT);
  1.1419 +#endif // MOZ_B2G
  1.1420 +
  1.1421 +    if (mIdleService) {
  1.1422 +      mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
  1.1423 +    }
  1.1424 +
  1.1425 +    // Drop its reference to this dying window, in case for some bogus reason
  1.1426 +    // the object stays around.
  1.1427 +    mObserver->Forget();
  1.1428 +    NS_RELEASE(mObserver);
  1.1429 +  }
  1.1430 +
  1.1431 +  if (mNavigator) {
  1.1432 +    mNavigator->Invalidate();
  1.1433 +    mNavigator = nullptr;
  1.1434 +  }
  1.1435 +
  1.1436 +  mScreen = nullptr;
  1.1437 +  mMenubar = nullptr;
  1.1438 +  mToolbar = nullptr;
  1.1439 +  mLocationbar = nullptr;
  1.1440 +  mPersonalbar = nullptr;
  1.1441 +  mStatusbar = nullptr;
  1.1442 +  mScrollbars = nullptr;
  1.1443 +  mLocation = nullptr;
  1.1444 +  mHistory = nullptr;
  1.1445 +  mFrames = nullptr;
  1.1446 +  mWindowUtils = nullptr;
  1.1447 +  mApplicationCache = nullptr;
  1.1448 +  mIndexedDB = nullptr;
  1.1449 +
  1.1450 +  mConsole = nullptr;
  1.1451 +
  1.1452 +  mExternal = nullptr;
  1.1453 +
  1.1454 +  mPerformance = nullptr;
  1.1455 +
  1.1456 +#ifdef MOZ_WEBSPEECH
  1.1457 +  mSpeechSynthesis = nullptr;
  1.1458 +#endif
  1.1459 +
  1.1460 +  ClearControllers();
  1.1461 +
  1.1462 +  mOpener = nullptr;             // Forces Release
  1.1463 +  if (mContext) {
  1.1464 +    mContext = nullptr;            // Forces Release
  1.1465 +  }
  1.1466 +  mChromeEventHandler = nullptr; // Forces Release
  1.1467 +  mParentTarget = nullptr;
  1.1468 +
  1.1469 +  nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
  1.1470 +
  1.1471 +  if (inner) {
  1.1472 +    inner->CleanUp();
  1.1473 +  }
  1.1474 +
  1.1475 +  DisableGamepadUpdates();
  1.1476 +  mHasGamepad = false;
  1.1477 +
  1.1478 +  if (mCleanMessageManager) {
  1.1479 +    NS_ABORT_IF_FALSE(mIsChrome, "only chrome should have msg manager cleaned");
  1.1480 +    nsGlobalChromeWindow *asChrome = static_cast<nsGlobalChromeWindow*>(this);
  1.1481 +    if (asChrome->mMessageManager) {
  1.1482 +      static_cast<nsFrameMessageManager*>(
  1.1483 +        asChrome->mMessageManager.get())->Disconnect();
  1.1484 +    }
  1.1485 +  }
  1.1486 +
  1.1487 +  mArguments = nullptr;
  1.1488 +  mDialogArguments = nullptr;
  1.1489 +
  1.1490 +  CleanupCachedXBLHandlers(this);
  1.1491 +
  1.1492 +  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
  1.1493 +    mAudioContexts[i]->Shutdown();
  1.1494 +  }
  1.1495 +  mAudioContexts.Clear();
  1.1496 +
  1.1497 +  if (mIdleTimer) {
  1.1498 +    mIdleTimer->Cancel();
  1.1499 +    mIdleTimer = nullptr;
  1.1500 +  }
  1.1501 +
  1.1502 +  DisableTimeChangeNotifications();
  1.1503 +}
  1.1504 +
  1.1505 +void
  1.1506 +nsGlobalWindow::ClearControllers()
  1.1507 +{
  1.1508 +  if (mControllers) {
  1.1509 +    uint32_t count;
  1.1510 +    mControllers->GetControllerCount(&count);
  1.1511 +
  1.1512 +    while (count--) {
  1.1513 +      nsCOMPtr<nsIController> controller;
  1.1514 +      mControllers->GetControllerAt(count, getter_AddRefs(controller));
  1.1515 +
  1.1516 +      nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
  1.1517 +      if (context)
  1.1518 +        context->SetCommandContext(nullptr);
  1.1519 +    }
  1.1520 +
  1.1521 +    mControllers = nullptr;
  1.1522 +  }
  1.1523 +}
  1.1524 +
  1.1525 +void
  1.1526 +nsGlobalWindow::FreeInnerObjects()
  1.1527 +{
  1.1528 +  NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
  1.1529 +
  1.1530 +  // Make sure that this is called before we null out the document and
  1.1531 +  // other members that the window destroyed observers could
  1.1532 +  // re-create.
  1.1533 +  NotifyDOMWindowDestroyed(this);
  1.1534 +
  1.1535 +  mInnerObjectsFreed = true;
  1.1536 +
  1.1537 +  // Kill all of the workers for this window.
  1.1538 +  mozilla::dom::workers::CancelWorkersForWindow(this);
  1.1539 +
  1.1540 +  // Close all offline storages for this window.
  1.1541 +  quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
  1.1542 +  if (quotaManager) {
  1.1543 +    quotaManager->AbortCloseStoragesForWindow(this);
  1.1544 +  }
  1.1545 +
  1.1546 +  ClearAllTimeouts();
  1.1547 +
  1.1548 +  if (mIdleTimer) {
  1.1549 +    mIdleTimer->Cancel();
  1.1550 +    mIdleTimer = nullptr;
  1.1551 +  }
  1.1552 +
  1.1553 +  mIdleObservers.Clear();
  1.1554 +
  1.1555 +  mChromeEventHandler = nullptr;
  1.1556 +
  1.1557 +  if (mListenerManager) {
  1.1558 +    mListenerManager->Disconnect();
  1.1559 +    mListenerManager = nullptr;
  1.1560 +  }
  1.1561 +
  1.1562 +  mLocation = nullptr;
  1.1563 +  mHistory = nullptr;
  1.1564 +
  1.1565 +  if (mNavigator) {
  1.1566 +    mNavigator->OnNavigation();
  1.1567 +    mNavigator->Invalidate();
  1.1568 +    mNavigator = nullptr;
  1.1569 +  }
  1.1570 +
  1.1571 +  if (mScreen) {
  1.1572 +    mScreen = nullptr;
  1.1573 +  }
  1.1574 +
  1.1575 +  if (mDoc) {
  1.1576 +    // Remember the document's principal and URI.
  1.1577 +    mDocumentPrincipal = mDoc->NodePrincipal();
  1.1578 +    mDocumentURI = mDoc->GetDocumentURI();
  1.1579 +    mDocBaseURI = mDoc->GetDocBaseURI();
  1.1580 +
  1.1581 +    while (mDoc->EventHandlingSuppressed()) {
  1.1582 +      mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false);
  1.1583 +    }
  1.1584 +
  1.1585 +    // Note: we don't have to worry about eAnimationsOnly suppressions because
  1.1586 +    // they won't leak.
  1.1587 +  }
  1.1588 +
  1.1589 +  // Remove our reference to the document and the document principal.
  1.1590 +  mFocusedNode = nullptr;
  1.1591 +
  1.1592 +  if (mApplicationCache) {
  1.1593 +    static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
  1.1594 +    mApplicationCache = nullptr;
  1.1595 +  }
  1.1596 +
  1.1597 +  mIndexedDB = nullptr;
  1.1598 +
  1.1599 +  NotifyWindowIDDestroyed("inner-window-destroyed");
  1.1600 +
  1.1601 +  CleanupCachedXBLHandlers(this);
  1.1602 +
  1.1603 +  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
  1.1604 +    mAudioContexts[i]->Shutdown();
  1.1605 +  }
  1.1606 +  mAudioContexts.Clear();
  1.1607 +
  1.1608 +#ifdef MOZ_GAMEPAD
  1.1609 +  DisableGamepadUpdates();
  1.1610 +  mHasGamepad = false;
  1.1611 +  mGamepads.Clear();
  1.1612 +#endif
  1.1613 +}
  1.1614 +
  1.1615 +//*****************************************************************************
  1.1616 +// nsGlobalWindow::nsISupports
  1.1617 +//*****************************************************************************
  1.1618 +
  1.1619 +DOMCI_DATA(Window, nsGlobalWindow)
  1.1620 +
  1.1621 +// QueryInterface implementation for nsGlobalWindow
  1.1622 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
  1.1623 +  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  1.1624 +  // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
  1.1625 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
  1.1626 +  NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
  1.1627 +#ifdef MOZ_B2G
  1.1628 +  NS_INTERFACE_MAP_ENTRY(nsIDOMWindowB2G)
  1.1629 +#endif // MOZ_B2G
  1.1630 +#ifdef MOZ_WEBSPEECH
  1.1631 +  NS_INTERFACE_MAP_ENTRY(nsISpeechSynthesisGetter)
  1.1632 +#endif // MOZ_B2G
  1.1633 +  NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
  1.1634 +  if (aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) {
  1.1635 +    foundInterface = static_cast<nsIDOMWindowInternal*>(this);
  1.1636 +    if (!sWarnedAboutWindowInternal) {
  1.1637 +      sWarnedAboutWindowInternal = true;
  1.1638 +      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
  1.1639 +                                      NS_LITERAL_CSTRING("Extensions"), mDoc,
  1.1640 +                                      nsContentUtils::eDOM_PROPERTIES,
  1.1641 +                                      "nsIDOMWindowInternalWarning");
  1.1642 +    }
  1.1643 +  } else
  1.1644 +  NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
  1.1645 +  NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
  1.1646 +  NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
  1.1647 +  NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
  1.1648 +  NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
  1.1649 +  NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
  1.1650 +  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  1.1651 +  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
  1.1652 +  NS_INTERFACE_MAP_ENTRY(nsIDOMWindowPerformance)
  1.1653 +  NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver)
  1.1654 +  NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
  1.1655 +  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
  1.1656 +NS_INTERFACE_MAP_END
  1.1657 +
  1.1658 +
  1.1659 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
  1.1660 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
  1.1661 +
  1.1662 +static PLDHashOperator
  1.1663 +MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
  1.1664 +{
  1.1665 +  JS::ExposeObjectToActiveJS(aData);
  1.1666 +  return PL_DHASH_NEXT;
  1.1667 +}
  1.1668 +
  1.1669 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
  1.1670 +  if (tmp->IsBlackForCC(false)) {
  1.1671 +    if (tmp->mCachedXBLPrototypeHandlers) {
  1.1672 +      tmp->mCachedXBLPrototypeHandlers->Enumerate(MarkXBLHandlers, nullptr);
  1.1673 +    }
  1.1674 +    if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
  1.1675 +      elm->MarkForCC();
  1.1676 +    }
  1.1677 +    tmp->UnmarkGrayTimers();
  1.1678 +    return true;
  1.1679 +  }
  1.1680 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
  1.1681 +
  1.1682 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)
  1.1683 +  return tmp->IsBlackForCC(true);
  1.1684 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
  1.1685 +
  1.1686 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)
  1.1687 +  return tmp->IsBlackForCC(false);
  1.1688 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
  1.1689 +
  1.1690 +inline void
  1.1691 +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
  1.1692 +                            IdleObserverHolder& aField,
  1.1693 +                            const char* aName,
  1.1694 +                            unsigned aFlags)
  1.1695 +{
  1.1696 +  CycleCollectionNoteChild(aCallback, aField.mIdleObserver.get(), aName, aFlags);
  1.1697 +}
  1.1698 +
  1.1699 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
  1.1700 +
  1.1701 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
  1.1702 +  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
  1.1703 +    char name[512];
  1.1704 +    PR_snprintf(name, sizeof(name), "nsGlobalWindow #%ld", tmp->mWindowID);
  1.1705 +    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
  1.1706 +  } else {
  1.1707 +    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow, tmp->mRefCnt.get())
  1.1708 +  }
  1.1709 +
  1.1710 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
  1.1711 +
  1.1712 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
  1.1713 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
  1.1714 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments)
  1.1715 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue)
  1.1716 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
  1.1717 +
  1.1718 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
  1.1719 +
  1.1720 +#ifdef MOZ_WEBSPEECH
  1.1721 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
  1.1722 +#endif
  1.1723 +
  1.1724 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)
  1.1725 +
  1.1726 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
  1.1727 +
  1.1728 +  for (nsTimeout* timeout = tmp->mTimeouts.getFirst();
  1.1729 +       timeout;
  1.1730 +       timeout = timeout->getNext()) {
  1.1731 +    cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(nsTimeout));
  1.1732 +  }
  1.1733 +
  1.1734 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
  1.1735 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
  1.1736 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
  1.1737 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
  1.1738 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
  1.1739 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
  1.1740 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
  1.1741 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
  1.1742 +
  1.1743 +#ifdef MOZ_GAMEPAD
  1.1744 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
  1.1745 +#endif
  1.1746 +
  1.1747 +  // Traverse stuff from nsPIDOMWindow
  1.1748 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
  1.1749 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
  1.1750 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
  1.1751 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode)
  1.1752 +
  1.1753 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
  1.1754 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
  1.1755 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
  1.1756 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
  1.1757 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
  1.1758 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
  1.1759 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
  1.1760 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
  1.1761 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
  1.1762 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
  1.1763 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  1.1764 +
  1.1765 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
  1.1766 +  nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
  1.1767 +
  1.1768 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
  1.1769 +
  1.1770 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
  1.1771 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
  1.1772 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments)
  1.1773 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue)
  1.1774 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
  1.1775 +
  1.1776 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
  1.1777 +
  1.1778 +#ifdef MOZ_WEBSPEECH
  1.1779 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
  1.1780 +#endif
  1.1781 +
  1.1782 +  if (tmp->mOuterWindow) {
  1.1783 +    static_cast<nsGlobalWindow*>(tmp->mOuterWindow.get())->MaybeClearInnerWindow(tmp);
  1.1784 +    NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
  1.1785 +  }
  1.1786 +
  1.1787 +  if (tmp->mListenerManager) {
  1.1788 +    tmp->mListenerManager->Disconnect();
  1.1789 +    NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
  1.1790 +  }
  1.1791 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
  1.1792 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
  1.1793 +  if (tmp->mApplicationCache) {
  1.1794 +    static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();
  1.1795 +    NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
  1.1796 +  }
  1.1797 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
  1.1798 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
  1.1799 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
  1.1800 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
  1.1801 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
  1.1802 +
  1.1803 +#ifdef MOZ_GAMEPAD
  1.1804 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
  1.1805 +#endif
  1.1806 +
  1.1807 +  // Unlink stuff from nsPIDOMWindow
  1.1808 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
  1.1809 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
  1.1810 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
  1.1811 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode)
  1.1812 +
  1.1813 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
  1.1814 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
  1.1815 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
  1.1816 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
  1.1817 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
  1.1818 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
  1.1819 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
  1.1820 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
  1.1821 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
  1.1822 +  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  1.1823 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  1.1824 +
  1.1825 +#ifdef DEBUG
  1.1826 +void
  1.1827 +nsGlobalWindow::RiskyUnlink()
  1.1828 +{
  1.1829 +  NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);
  1.1830 +}
  1.1831 +#endif
  1.1832 +
  1.1833 +struct TraceData
  1.1834 +{
  1.1835 +  const TraceCallbacks& callbacks;
  1.1836 +  void* closure;
  1.1837 +};
  1.1838 +
  1.1839 +static PLDHashOperator
  1.1840 +TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
  1.1841 +{
  1.1842 +  TraceData* data = static_cast<TraceData*>(aClosure);
  1.1843 +  data->callbacks.Trace(&aData, "Cached XBL prototype handler", data->closure);
  1.1844 +  return PL_DHASH_NEXT;
  1.1845 +}
  1.1846 +
  1.1847 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
  1.1848 +  if (tmp->mCachedXBLPrototypeHandlers) {
  1.1849 +    TraceData data = { aCallbacks, aClosure };
  1.1850 +    tmp->mCachedXBLPrototypeHandlers->Enumerate(TraceXBLHandlers, &data);
  1.1851 +  }
  1.1852 +  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
  1.1853 +NS_IMPL_CYCLE_COLLECTION_TRACE_END
  1.1854 +
  1.1855 +bool
  1.1856 +nsGlobalWindow::IsBlackForCC(bool aTracingNeeded)
  1.1857 +{
  1.1858 +  if (!nsCCUncollectableMarker::sGeneration) {
  1.1859 +    return false;
  1.1860 +  }
  1.1861 +
  1.1862 +  return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
  1.1863 +          IsBlack()) &&
  1.1864 +         (!aTracingNeeded ||
  1.1865 +          HasNothingToTrace(static_cast<nsIDOMEventTarget*>(this)));
  1.1866 +}
  1.1867 +
  1.1868 +void
  1.1869 +nsGlobalWindow::UnmarkGrayTimers()
  1.1870 +{
  1.1871 +  for (nsTimeout* timeout = mTimeouts.getFirst();
  1.1872 +       timeout;
  1.1873 +       timeout = timeout->getNext()) {
  1.1874 +    if (timeout->mScriptHandler) {
  1.1875 +      Function* f = timeout->mScriptHandler->GetCallback();
  1.1876 +      if (f) {
  1.1877 +        // Callable() already does xpc_UnmarkGrayObject.
  1.1878 +        DebugOnly<JS::Handle<JSObject*> > o = f->Callable();
  1.1879 +        MOZ_ASSERT(!xpc_IsGrayGCThing(o.value), "Should have been unmarked");
  1.1880 +      }
  1.1881 +    }
  1.1882 +  }
  1.1883 +}
  1.1884 +
  1.1885 +//*****************************************************************************
  1.1886 +// nsGlobalWindow::nsIScriptGlobalObject
  1.1887 +//*****************************************************************************
  1.1888 +
  1.1889 +nsresult
  1.1890 +nsGlobalWindow::EnsureScriptEnvironment()
  1.1891 +{
  1.1892 +  nsGlobalWindow* outer = GetOuterWindowInternal();
  1.1893 +  if (!outer) {
  1.1894 +    NS_WARNING("No outer window available!");
  1.1895 +    return NS_ERROR_FAILURE;
  1.1896 +  }
  1.1897 +
  1.1898 +  if (outer->GetWrapperPreserveColor()) {
  1.1899 +    return NS_OK;
  1.1900 +  }
  1.1901 +
  1.1902 +  NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(),
  1.1903 +               "No cached wrapper, but we have an inner window?");
  1.1904 +
  1.1905 +  // If this window is a [i]frame, don't bother GC'ing when the frame's context
  1.1906 +  // is destroyed since a GC will happen when the frameset or host document is
  1.1907 +  // destroyed anyway.
  1.1908 +  nsCOMPtr<nsIScriptContext> context = new nsJSContext(!IsFrame(), outer);
  1.1909 +
  1.1910 +  NS_ASSERTION(!outer->mContext, "Will overwrite mContext!");
  1.1911 +
  1.1912 +  // should probably assert the context is clean???
  1.1913 +  context->WillInitializeContext();
  1.1914 +
  1.1915 +  nsresult rv = context->InitContext();
  1.1916 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1917 +
  1.1918 +  outer->mContext = context;
  1.1919 +  return NS_OK;
  1.1920 +}
  1.1921 +
  1.1922 +nsIScriptContext *
  1.1923 +nsGlobalWindow::GetScriptContext()
  1.1924 +{
  1.1925 +  nsGlobalWindow* outer = GetOuterWindowInternal();
  1.1926 +  return outer ? outer->mContext : nullptr;
  1.1927 +}
  1.1928 +
  1.1929 +JSObject *
  1.1930 +nsGlobalWindow::GetGlobalJSObject()
  1.1931 +{
  1.1932 +  return FastGetGlobalJSObject();
  1.1933 +}
  1.1934 +
  1.1935 +void
  1.1936 +nsGlobalWindow::TraceGlobalJSObject(JSTracer* aTrc)
  1.1937 +{
  1.1938 +  TraceWrapper(aTrc, "active window global");
  1.1939 +}
  1.1940 +
  1.1941 +/* static */
  1.1942 +JSObject*
  1.1943 +nsGlobalWindow::OuterObject(JSContext* aCx, JS::Handle<JSObject*> aObj)
  1.1944 +{
  1.1945 +  nsGlobalWindow* origWin;
  1.1946 +  UNWRAP_OBJECT(Window, aObj, origWin);
  1.1947 +  nsGlobalWindow* win = origWin->GetOuterWindowInternal();
  1.1948 +
  1.1949 +  if (!win) {
  1.1950 +    // If we no longer have an outer window. No code should ever be
  1.1951 +    // running on a window w/o an outer, which means this hook should
  1.1952 +    // never be called when we have no outer. But just in case, return
  1.1953 +    // null to prevent leaking an inner window to code in a different
  1.1954 +    // window.
  1.1955 +    NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
  1.1956 +    return nullptr;
  1.1957 +  }
  1.1958 +
  1.1959 +  JS::Rooted<JSObject*> winObj(aCx, win->FastGetGlobalJSObject());
  1.1960 +  MOZ_ASSERT(winObj);
  1.1961 +
  1.1962 +  // Note that while |wrapper| is same-compartment with cx, the outer window
  1.1963 +  // might not be. If we're running script in an inactive scope and evalute
  1.1964 +  // |this|, the outer window is actually a cross-compartment wrapper. So we
  1.1965 +  // need to wrap here.
  1.1966 +  if (!JS_WrapObject(aCx, &winObj)) {
  1.1967 +    NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
  1.1968 +    return nullptr;
  1.1969 +  }
  1.1970 +
  1.1971 +  return winObj;
  1.1972 +}
  1.1973 +
  1.1974 +bool
  1.1975 +nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
  1.1976 +{
  1.1977 +  // We reuse the inner window when:
  1.1978 +  // a. We are currently at our original document.
  1.1979 +  // b. At least one of the following conditions are true:
  1.1980 +  // -- The new document is the same as the old document. This means that we're
  1.1981 +  //    getting called from document.open().
  1.1982 +  // -- The new document has the same origin as what we have loaded right now.
  1.1983 +
  1.1984 +  if (!mDoc || !aNewDocument) {
  1.1985 +    return false;
  1.1986 +  }
  1.1987 +
  1.1988 +  if (!mDoc->IsInitialDocument()) {
  1.1989 +    return false;
  1.1990 +  }
  1.1991 +  
  1.1992 +  NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
  1.1993 +               "How'd this happen?");
  1.1994 +
  1.1995 +  // Great, we're the original document, check for one of the other
  1.1996 +  // conditions.
  1.1997 +
  1.1998 +  if (mDoc == aNewDocument) {
  1.1999 +    return true;
  1.2000 +  }
  1.2001 +
  1.2002 +  bool equal;
  1.2003 +  if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
  1.2004 +                                                 &equal)) &&
  1.2005 +      equal) {
  1.2006 +    // The origin is the same.
  1.2007 +    return true;
  1.2008 +  }
  1.2009 +
  1.2010 +  return false;
  1.2011 +}
  1.2012 +
  1.2013 +void
  1.2014 +nsGlobalWindow::SetInitialPrincipalToSubject()
  1.2015 +{
  1.2016 +  FORWARD_TO_OUTER_VOID(SetInitialPrincipalToSubject, ());
  1.2017 +
  1.2018 +  // First, grab the subject principal.
  1.2019 +  nsCOMPtr<nsIPrincipal> newWindowPrincipal = nsContentUtils::GetSubjectPrincipal();
  1.2020 +  if (!newWindowPrincipal) {
  1.2021 +    newWindowPrincipal = nsContentUtils::GetSystemPrincipal();
  1.2022 +  }
  1.2023 +
  1.2024 +  // Now, if we're about to use the system principal or an nsExpandedPrincipal,
  1.2025 +  // make sure we're not using it for a content docshell.
  1.2026 +  if (nsContentUtils::IsSystemOrExpandedPrincipal(newWindowPrincipal) &&
  1.2027 +      GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome) {
  1.2028 +    newWindowPrincipal = nullptr;
  1.2029 +  }
  1.2030 +
  1.2031 +  // If there's an existing document, bail if it either:
  1.2032 +  if (mDoc) {
  1.2033 +    // (a) is not an initial about:blank document, or
  1.2034 +    if (!mDoc->IsInitialDocument())
  1.2035 +      return;
  1.2036 +    // (b) already has the correct principal.
  1.2037 +    if (mDoc->NodePrincipal() == newWindowPrincipal)
  1.2038 +      return;
  1.2039 +
  1.2040 +#ifdef DEBUG
  1.2041 +    // If we have a document loaded at this point, it had better be about:blank.
  1.2042 +    // Otherwise, something is really weird.
  1.2043 +    nsCOMPtr<nsIURI> uri;
  1.2044 +    mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
  1.2045 +    NS_ASSERTION(uri && NS_IsAboutBlank(uri) &&
  1.2046 +                 NS_IsAboutBlank(mDoc->GetDocumentURI()),
  1.2047 +                 "Unexpected original document");
  1.2048 +#endif
  1.2049 +  }
  1.2050 +
  1.2051 +  GetDocShell()->CreateAboutBlankContentViewer(newWindowPrincipal);
  1.2052 +  mDoc->SetIsInitialDocument(true);
  1.2053 +
  1.2054 +  nsCOMPtr<nsIPresShell> shell = GetDocShell()->GetPresShell();
  1.2055 +
  1.2056 +  if (shell && !shell->DidInitialize()) {
  1.2057 +    // Ensure that if someone plays with this document they will get
  1.2058 +    // layout happening.
  1.2059 +    nsRect r = shell->GetPresContext()->GetVisibleArea();
  1.2060 +    shell->Initialize(r.width, r.height);
  1.2061 +  }
  1.2062 +}
  1.2063 +
  1.2064 +PopupControlState
  1.2065 +PushPopupControlState(PopupControlState aState, bool aForce)
  1.2066 +{
  1.2067 +  MOZ_ASSERT(NS_IsMainThread());
  1.2068 +
  1.2069 +  PopupControlState oldState = gPopupControlState;
  1.2070 +
  1.2071 +  if (aState < gPopupControlState || aForce) {
  1.2072 +    gPopupControlState = aState;
  1.2073 +  }
  1.2074 +
  1.2075 +  return oldState;
  1.2076 +}
  1.2077 +
  1.2078 +void
  1.2079 +PopPopupControlState(PopupControlState aState)
  1.2080 +{
  1.2081 +  MOZ_ASSERT(NS_IsMainThread());
  1.2082 +
  1.2083 +  gPopupControlState = aState;
  1.2084 +}
  1.2085 +
  1.2086 +PopupControlState
  1.2087 +nsGlobalWindow::PushPopupControlState(PopupControlState aState,
  1.2088 +                                      bool aForce) const
  1.2089 +{
  1.2090 +  return ::PushPopupControlState(aState, aForce);
  1.2091 +}
  1.2092 +
  1.2093 +void
  1.2094 +nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
  1.2095 +{
  1.2096 +  ::PopPopupControlState(aState);
  1.2097 +}
  1.2098 +
  1.2099 +PopupControlState
  1.2100 +nsGlobalWindow::GetPopupControlState() const
  1.2101 +{
  1.2102 +  MOZ_ASSERT(NS_IsMainThread());
  1.2103 +  return gPopupControlState;
  1.2104 +}
  1.2105 +
  1.2106 +#define WINDOWSTATEHOLDER_IID \
  1.2107 +{0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
  1.2108 +
  1.2109 +class WindowStateHolder MOZ_FINAL : public nsISupports
  1.2110 +{
  1.2111 +public:
  1.2112 +  NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
  1.2113 +  NS_DECL_ISUPPORTS
  1.2114 +
  1.2115 +  WindowStateHolder(nsGlobalWindow *aWindow);
  1.2116 +
  1.2117 +  nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
  1.2118 +
  1.2119 +  void DidRestoreWindow()
  1.2120 +  {
  1.2121 +    mInnerWindow = nullptr;
  1.2122 +  }
  1.2123 +
  1.2124 +protected:
  1.2125 +  ~WindowStateHolder();
  1.2126 +
  1.2127 +  nsRefPtr<nsGlobalWindow> mInnerWindow;
  1.2128 +};
  1.2129 +
  1.2130 +NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
  1.2131 +
  1.2132 +WindowStateHolder::WindowStateHolder(nsGlobalWindow* aWindow)
  1.2133 +  : mInnerWindow(aWindow)
  1.2134 +{
  1.2135 +  NS_PRECONDITION(aWindow, "null window");
  1.2136 +  NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
  1.2137 +
  1.2138 +  // We hold onto this to make sure the inner window doesn't go away. The outer
  1.2139 +  // window ends up recalculating it anyway.
  1.2140 +  mInnerWindow->PreserveWrapper(ToSupports(mInnerWindow));
  1.2141 +
  1.2142 +  aWindow->SuspendTimeouts();
  1.2143 +
  1.2144 +  // When a global goes into the bfcache, we disable script.
  1.2145 +  xpc::Scriptability::Get(aWindow->GetWrapperPreserveColor()).SetDocShellAllowsScript(false);
  1.2146 +}
  1.2147 +
  1.2148 +WindowStateHolder::~WindowStateHolder()
  1.2149 +{
  1.2150 +  if (mInnerWindow) {
  1.2151 +    // This window was left in the bfcache and is now going away. We need to
  1.2152 +    // free it up.
  1.2153 +    // Note that FreeInnerObjects may already have been called on the
  1.2154 +    // inner window if its outer has already had SetDocShell(null)
  1.2155 +    // called.
  1.2156 +    mInnerWindow->FreeInnerObjects();
  1.2157 +  }
  1.2158 +}
  1.2159 +
  1.2160 +NS_IMPL_ISUPPORTS(WindowStateHolder, WindowStateHolder)
  1.2161 +
  1.2162 +// We need certain special behavior for remote XUL whitelisted domains, but we
  1.2163 +// don't want that behavior to take effect in automation, because we whitelist
  1.2164 +// all the mochitest domains. So we need to check a pref here.
  1.2165 +static bool
  1.2166 +TreatAsRemoteXUL(nsIPrincipal* aPrincipal)
  1.2167 +{
  1.2168 +  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(aPrincipal));
  1.2169 +  return nsContentUtils::AllowXULXBLForPrincipal(aPrincipal) &&
  1.2170 +         !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
  1.2171 +}
  1.2172 +
  1.2173 +/**
  1.2174 + * Create a new global object that will be used for an inner window.
  1.2175 + * Return the native global and an nsISupports 'holder' that can be used
  1.2176 + * to manage the lifetime of it.
  1.2177 + */
  1.2178 +static nsresult
  1.2179 +CreateNativeGlobalForInner(JSContext* aCx,
  1.2180 +                           nsGlobalWindow* aNewInner,
  1.2181 +                           nsIURI* aURI,
  1.2182 +                           nsIPrincipal* aPrincipal,
  1.2183 +                           JS::MutableHandle<JSObject*> aGlobal)
  1.2184 +{
  1.2185 +  MOZ_ASSERT(aCx);
  1.2186 +  MOZ_ASSERT(aNewInner);
  1.2187 +  MOZ_ASSERT(aNewInner->IsInnerWindow());
  1.2188 +  MOZ_ASSERT(aPrincipal);
  1.2189 +
  1.2190 +  // DOMWindow with nsEP is not supported, we have to make sure
  1.2191 +  // no one creates one accidentally.
  1.2192 +  nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(aPrincipal);
  1.2193 +  MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported");
  1.2194 +
  1.2195 +  nsGlobalWindow *top = nullptr;
  1.2196 +  if (aNewInner->GetOuterWindow()) {
  1.2197 +    top = aNewInner->GetTop();
  1.2198 +  }
  1.2199 +  JS::CompartmentOptions options;
  1.2200 +  if (top) {
  1.2201 +    if (top->GetGlobalJSObject()) {
  1.2202 +      options.setSameZoneAs(top->GetGlobalJSObject());
  1.2203 +    }
  1.2204 +  }
  1.2205 +
  1.2206 +  nsIXPConnect* xpc = nsContentUtils::XPConnect();
  1.2207 +
  1.2208 +  // Determine if we need the Components object.
  1.2209 +  bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
  1.2210 +                        TreatAsRemoteXUL(aPrincipal);
  1.2211 +  uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
  1.2212 +  flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
  1.2213 +
  1.2214 +  nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
  1.2215 +  nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
  1.2216 +    aCx, ToSupports(aNewInner),
  1.2217 +    aPrincipal, flags, options, getter_AddRefs(holder));
  1.2218 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2219 +
  1.2220 +  aGlobal.set(holder->GetJSObject());
  1.2221 +
  1.2222 +  // Set the location information for the new global, so that tools like
  1.2223 +  // about:memory may use that information
  1.2224 +  MOZ_ASSERT(aGlobal);
  1.2225 +  MOZ_ASSERT(aNewInner->GetWrapperPreserveColor() == aGlobal);
  1.2226 +  xpc::SetLocationForGlobal(aGlobal, aURI);
  1.2227 +
  1.2228 +  return NS_OK;
  1.2229 +}
  1.2230 +
  1.2231 +nsresult
  1.2232 +nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
  1.2233 +                               nsISupports* aState,
  1.2234 +                               bool aForceReuseInnerWindow)
  1.2235 +{
  1.2236 +  NS_PRECONDITION(mDocumentPrincipal == nullptr,
  1.2237 +                  "mDocumentPrincipal prematurely set!");
  1.2238 +  MOZ_ASSERT(aDocument);
  1.2239 +
  1.2240 +  if (IsInnerWindow()) {
  1.2241 +    if (!mOuterWindow) {
  1.2242 +      return NS_ERROR_NOT_INITIALIZED;
  1.2243 +    }
  1.2244 +
  1.2245 +    // Refuse to set a new document if the call came from an inner
  1.2246 +    // window that's not the current inner window.
  1.2247 +    if (mOuterWindow->GetCurrentInnerWindow() != this) {
  1.2248 +      return NS_ERROR_NOT_AVAILABLE;
  1.2249 +    }
  1.2250 +
  1.2251 +    return GetOuterWindowInternal()->SetNewDocument(aDocument, aState,
  1.2252 +                                                    aForceReuseInnerWindow);
  1.2253 +  }
  1.2254 +
  1.2255 +  NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
  1.2256 +
  1.2257 +  if (IsFrozen()) {
  1.2258 +    // This outer is now getting its first inner, thaw the outer now
  1.2259 +    // that it's ready and is getting an inner window.
  1.2260 +
  1.2261 +    Thaw();
  1.2262 +  }
  1.2263 +
  1.2264 +  NS_ASSERTION(!GetCurrentInnerWindow() ||
  1.2265 +               GetCurrentInnerWindow()->GetExtantDoc() == mDoc,
  1.2266 +               "Uh, mDoc doesn't match the current inner window "
  1.2267 +               "document!");
  1.2268 +
  1.2269 +  bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
  1.2270 +  if (aForceReuseInnerWindow &&
  1.2271 +      !wouldReuseInnerWindow &&
  1.2272 +      mDoc &&
  1.2273 +      mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
  1.2274 +    NS_ERROR("Attempted forced inner window reuse while changing principal");
  1.2275 +    return NS_ERROR_UNEXPECTED;
  1.2276 +  }
  1.2277 +
  1.2278 +  nsCOMPtr<nsIDocument> oldDoc = mDoc;
  1.2279 +
  1.2280 +  nsIScriptContext *scx = GetContextInternal();
  1.2281 +  NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
  1.2282 +
  1.2283 +  JSContext *cx = scx->GetNativeContext();
  1.2284 +
  1.2285 +#ifndef MOZ_DISABLE_CRYPTOLEGACY
  1.2286 +  // clear smartcard events, our document has gone away.
  1.2287 +  if (mCrypto && XRE_GetProcessType() != GeckoProcessType_Content) {
  1.2288 +    nsresult rv = mCrypto->SetEnableSmartCardEvents(false);
  1.2289 +    NS_ENSURE_SUCCESS(rv, rv);
  1.2290 +  }
  1.2291 +#endif
  1.2292 +
  1.2293 +  if (!mDoc) {
  1.2294 +    // First document load.
  1.2295 +
  1.2296 +    // Get our private root. If it is equal to us, then we need to
  1.2297 +    // attach our global key bindings that handles browser scrolling
  1.2298 +    // and other browser commands.
  1.2299 +    nsIDOMWindow* privateRoot = nsGlobalWindow::GetPrivateRoot();
  1.2300 +
  1.2301 +    if (privateRoot == static_cast<nsIDOMWindow*>(this)) {
  1.2302 +      nsXBLService::AttachGlobalKeyHandler(mChromeEventHandler);
  1.2303 +    }
  1.2304 +  }
  1.2305 +
  1.2306 +  /* No mDocShell means we're already been partially closed down.  When that
  1.2307 +     happens, setting status isn't a big requirement, so don't. (Doesn't happen
  1.2308 +     under normal circumstances, but bug 49615 describes a case.) */
  1.2309 +
  1.2310 +  nsContentUtils::AddScriptRunner(
  1.2311 +    NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
  1.2312 +
  1.2313 +  // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
  1.2314 +  // window (see bug 776497). Be safe.
  1.2315 +  bool reUseInnerWindow = (aForceReuseInnerWindow || wouldReuseInnerWindow) &&
  1.2316 +                          GetCurrentInnerWindowInternal();
  1.2317 +
  1.2318 +  nsresult rv = NS_OK;
  1.2319 +
  1.2320 +  // Set mDoc even if this is an outer window to avoid
  1.2321 +  // having to *always* reach into the inner window to find the
  1.2322 +  // document.
  1.2323 +  mDoc = aDocument;
  1.2324 +  if (IsInnerWindow() && IsDOMBinding()) {
  1.2325 +    WindowBinding::ClearCachedDocumentValue(cx, this);
  1.2326 +  }
  1.2327 +
  1.2328 +  // Take this opportunity to clear mSuspendedDoc. Our old inner window is now
  1.2329 +  // responsible for unsuspending it.
  1.2330 +  mSuspendedDoc = nullptr;
  1.2331 +
  1.2332 +#ifdef DEBUG
  1.2333 +  mLastOpenedURI = aDocument->GetDocumentURI();
  1.2334 +#endif
  1.2335 +
  1.2336 +  mContext->WillInitializeContext();
  1.2337 +
  1.2338 +  nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
  1.2339 +
  1.2340 +  if (currentInner && currentInner->mNavigator) {
  1.2341 +    currentInner->mNavigator->OnNavigation();
  1.2342 +  }
  1.2343 +
  1.2344 +  nsRefPtr<nsGlobalWindow> newInnerWindow;
  1.2345 +  bool createdInnerWindow = false;
  1.2346 +
  1.2347 +  bool thisChrome = IsChromeWindow();
  1.2348 +
  1.2349 +  nsCxPusher cxPusher;
  1.2350 +  cxPusher.Push(cx);
  1.2351 +
  1.2352 +  // Check if we're near the stack limit before we get anywhere near the
  1.2353 +  // transplanting code.
  1.2354 +  JS_CHECK_RECURSION(cx, return NS_ERROR_FAILURE);
  1.2355 +
  1.2356 +  nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
  1.2357 +  NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
  1.2358 +
  1.2359 +  JS::Rooted<JSObject*> newInnerGlobal(cx);
  1.2360 +  if (reUseInnerWindow) {
  1.2361 +    // We're reusing the current inner window.
  1.2362 +    NS_ASSERTION(!currentInner->IsFrozen(),
  1.2363 +                 "We should never be reusing a shared inner window");
  1.2364 +    newInnerWindow = currentInner;
  1.2365 +    newInnerGlobal = currentInner->GetWrapperPreserveColor();
  1.2366 +
  1.2367 +    if (aDocument != oldDoc) {
  1.2368 +      JS::ExposeObjectToActiveJS(newInnerGlobal);
  1.2369 +    }
  1.2370 +
  1.2371 +    // We're reusing the inner window, but this still counts as a navigation,
  1.2372 +    // so all expandos and such defined on the outer window should go away. Force
  1.2373 +    // all Xray wrappers to be recomputed.
  1.2374 +    JS::Rooted<JSObject*> rootedObject(cx, GetWrapperPreserveColor());
  1.2375 +    JS::ExposeObjectToActiveJS(rootedObject);
  1.2376 +    if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
  1.2377 +      return NS_ERROR_FAILURE;
  1.2378 +    }
  1.2379 +
  1.2380 +    // Inner windows are only reused for same-origin principals, but the principals
  1.2381 +    // don't necessarily match exactly. Update the principal on the compartment to
  1.2382 +    // match the new document.
  1.2383 +    // NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
  1.2384 +    // because we haven't yet set its mDoc to aDocument.
  1.2385 +    JSCompartment *compartment = js::GetObjectCompartment(newInnerGlobal);
  1.2386 +#ifdef DEBUG
  1.2387 +    bool sameOrigin = false;
  1.2388 +    nsIPrincipal *existing =
  1.2389 +      nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment));
  1.2390 +    aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
  1.2391 +    MOZ_ASSERT(sameOrigin);
  1.2392 +#endif
  1.2393 +    JS_SetCompartmentPrincipals(compartment,
  1.2394 +                                nsJSPrincipals::get(aDocument->NodePrincipal()));
  1.2395 +  } else {
  1.2396 +    if (aState) {
  1.2397 +      newInnerWindow = wsh->GetInnerWindow();
  1.2398 +      newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
  1.2399 +    } else {
  1.2400 +      if (thisChrome) {
  1.2401 +        newInnerWindow = new nsGlobalChromeWindow(this);
  1.2402 +      } else if (mIsModalContentWindow) {
  1.2403 +        newInnerWindow = new nsGlobalModalWindow(this);
  1.2404 +      } else {
  1.2405 +        newInnerWindow = new nsGlobalWindow(this);
  1.2406 +      }
  1.2407 +
  1.2408 +      // Freeze the outer window and null out the inner window so
  1.2409 +      // that initializing classes on the new inner doesn't end up
  1.2410 +      // reaching into the old inner window for classes etc.
  1.2411 +      //
  1.2412 +      // [This happens with Object.prototype when XPConnect creates
  1.2413 +      // a temporary global while initializing classes; the reason
  1.2414 +      // being that xpconnect creates the temp global w/o a parent
  1.2415 +      // and proto, which makes the JS engine look up classes in
  1.2416 +      // cx->globalObject, i.e. this outer window].
  1.2417 +
  1.2418 +      mInnerWindow = nullptr;
  1.2419 +
  1.2420 +      Freeze();
  1.2421 +      mCreatingInnerWindow = true;
  1.2422 +      // Every script context we are initialized with must create a
  1.2423 +      // new global.
  1.2424 +      rv = CreateNativeGlobalForInner(cx, newInnerWindow,
  1.2425 +                                      aDocument->GetDocumentURI(),
  1.2426 +                                      aDocument->NodePrincipal(),
  1.2427 +                                      &newInnerGlobal);
  1.2428 +      NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
  1.2429 +                   newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
  1.2430 +                   "Failed to get script global");
  1.2431 +
  1.2432 +      mCreatingInnerWindow = false;
  1.2433 +      createdInnerWindow = true;
  1.2434 +      Thaw();
  1.2435 +
  1.2436 +      NS_ENSURE_SUCCESS(rv, rv);
  1.2437 +    }
  1.2438 +
  1.2439 +    if (currentInner && currentInner->GetWrapperPreserveColor()) {
  1.2440 +      if (oldDoc == aDocument) {
  1.2441 +        // Move the navigator from the old inner window to the new one since
  1.2442 +        // this is a document.write. This is safe from a same-origin point of
  1.2443 +        // view because document.write can only be used by the same origin.
  1.2444 +        newInnerWindow->mNavigator = currentInner->mNavigator;
  1.2445 +        currentInner->mNavigator = nullptr;
  1.2446 +        if (newInnerWindow->mNavigator) {
  1.2447 +          newInnerWindow->mNavigator->SetWindow(newInnerWindow);
  1.2448 +        }
  1.2449 +
  1.2450 +        // Make a copy of the old window's performance object on document.open.
  1.2451 +        // Note that we have to force eager creation of it here, because we need
  1.2452 +        // to grab the current document channel and whatnot before that changes.
  1.2453 +        currentInner->CreatePerformanceObjectIfNeeded();
  1.2454 +        if (currentInner->mPerformance) {
  1.2455 +          newInnerWindow->mPerformance =
  1.2456 +            new nsPerformance(newInnerWindow,
  1.2457 +                              currentInner->mPerformance->GetDOMTiming(),
  1.2458 +                              currentInner->mPerformance->GetChannel(),
  1.2459 +                              currentInner->mPerformance->GetParentPerformance());
  1.2460 +        }
  1.2461 +      }
  1.2462 +
  1.2463 +      // Don't free objects on our current inner window if it's going to be
  1.2464 +      // held in the bfcache.
  1.2465 +      if (!currentInner->IsFrozen()) {
  1.2466 +        currentInner->FreeInnerObjects();
  1.2467 +      }
  1.2468 +    }
  1.2469 +
  1.2470 +    mInnerWindow = newInnerWindow;
  1.2471 +
  1.2472 +    if (!GetWrapperPreserveColor()) {
  1.2473 +      JS::Rooted<JSObject*> outer(cx,
  1.2474 +        NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
  1.2475 +      NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
  1.2476 +
  1.2477 +      js::SetProxyExtra(outer, 0, js::PrivateValue(ToSupports(this)));
  1.2478 +
  1.2479 +      // Inform the nsJSContext, which is the canonical holder of the outer.
  1.2480 +      mContext->SetWindowProxy(outer);
  1.2481 +      mContext->DidInitializeContext();
  1.2482 +
  1.2483 +      SetWrapper(mContext->GetWindowProxy());
  1.2484 +    } else {
  1.2485 +      JS::ExposeObjectToActiveJS(newInnerGlobal);
  1.2486 +      JS::Rooted<JSObject*> outerObject(cx,
  1.2487 +        NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
  1.2488 +      if (!outerObject) {
  1.2489 +        NS_ERROR("out of memory");
  1.2490 +        return NS_ERROR_FAILURE;
  1.2491 +      }
  1.2492 +
  1.2493 +      JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
  1.2494 +
  1.2495 +      js::SetProxyExtra(obj, 0, js::PrivateValue(nullptr));
  1.2496 +
  1.2497 +      outerObject = xpc::TransplantObject(cx, obj, outerObject);
  1.2498 +      if (!outerObject) {
  1.2499 +        NS_ERROR("unable to transplant wrappers, probably OOM");
  1.2500 +        return NS_ERROR_FAILURE;
  1.2501 +      }
  1.2502 +
  1.2503 +      js::SetProxyExtra(outerObject, 0, js::PrivateValue(ToSupports(this)));
  1.2504 +
  1.2505 +      SetWrapper(outerObject);
  1.2506 +
  1.2507 +      {
  1.2508 +        JSAutoCompartment ac(cx, outerObject);
  1.2509 +
  1.2510 +        JS_SetParent(cx, outerObject, newInnerGlobal);
  1.2511 +
  1.2512 +        // Inform the nsJSContext, which is the canonical holder of the outer.
  1.2513 +        mContext->SetWindowProxy(outerObject);
  1.2514 +
  1.2515 +        NS_ASSERTION(!JS_IsExceptionPending(cx),
  1.2516 +                     "We might overwrite a pending exception!");
  1.2517 +        XPCWrappedNativeScope* scope = xpc::GetObjectScope(outerObject);
  1.2518 +        if (scope->mWaiverWrapperMap) {
  1.2519 +          scope->mWaiverWrapperMap->Reparent(cx, newInnerGlobal);
  1.2520 +        }
  1.2521 +      }
  1.2522 +    }
  1.2523 +
  1.2524 +    // Enter the new global's compartment.
  1.2525 +    JSAutoCompartment ac(cx, GetWrapperPreserveColor());
  1.2526 +
  1.2527 +    // Set scriptability based on the state of the docshell.
  1.2528 +    bool allow = GetDocShell()->GetCanExecuteScripts();
  1.2529 +    xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);
  1.2530 +
  1.2531 +    // If we created a new inner window above, we need to do the last little bit
  1.2532 +    // of initialization now that the dust has settled.
  1.2533 +    if (createdInnerWindow) {
  1.2534 +      nsIXPConnect *xpc = nsContentUtils::XPConnect();
  1.2535 +      nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
  1.2536 +      nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerGlobal,
  1.2537 +                                                    getter_AddRefs(wrapper));
  1.2538 +      NS_ENSURE_SUCCESS(rv, rv);
  1.2539 +      NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
  1.2540 +      rv = wrapper->FinishInitForWrappedGlobal();
  1.2541 +      NS_ENSURE_SUCCESS(rv, rv);
  1.2542 +    }
  1.2543 +
  1.2544 +    if (!aState) {
  1.2545 +      JS::Rooted<JSObject*> rootedWrapper(cx, GetWrapperPreserveColor());
  1.2546 +      if (!JS_DefineProperty(cx, newInnerGlobal, "window", rootedWrapper,
  1.2547 +                             JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
  1.2548 +                             JS_PropertyStub, JS_StrictPropertyStub)) {
  1.2549 +        NS_ERROR("can't create the 'window' property");
  1.2550 +        return NS_ERROR_FAILURE;
  1.2551 +      }
  1.2552 +    }
  1.2553 +  }
  1.2554 +
  1.2555 +  JSAutoCompartment ac(cx, GetWrapperPreserveColor());
  1.2556 +
  1.2557 +  if (!aState && !reUseInnerWindow) {
  1.2558 +    // Loading a new page and creating a new inner window, *not*
  1.2559 +    // restoring from session history.
  1.2560 +
  1.2561 +    // Now that both the the inner and outer windows are initialized
  1.2562 +    // let the script context do its magic to hook them together.
  1.2563 +    MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor());
  1.2564 +#ifdef DEBUG
  1.2565 +    JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
  1.2566 +    JS::Rooted<JSObject*> proto1(cx), proto2(cx);
  1.2567 +    JS_GetPrototype(cx, rootedJSObject, &proto1);
  1.2568 +    JS_GetPrototype(cx, newInnerGlobal, &proto2);
  1.2569 +    NS_ASSERTION(proto1 == proto2,
  1.2570 +                 "outer and inner globals should have the same prototype");
  1.2571 +#endif
  1.2572 +
  1.2573 +    nsCOMPtr<Element> frame = GetFrameElementInternal();
  1.2574 +    if (frame) {
  1.2575 +      nsPIDOMWindow* parentWindow = frame->OwnerDoc()->GetWindow();
  1.2576 +      if (parentWindow && parentWindow->TimeoutSuspendCount()) {
  1.2577 +        SuspendTimeouts(parentWindow->TimeoutSuspendCount());
  1.2578 +      }
  1.2579 +    }
  1.2580 +  }
  1.2581 +
  1.2582 +  // Add an extra ref in case we release mContext during GC.
  1.2583 +  nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
  1.2584 +
  1.2585 +  aDocument->SetScriptGlobalObject(newInnerWindow);
  1.2586 +
  1.2587 +  if (!aState) {
  1.2588 +    if (reUseInnerWindow) {
  1.2589 +      if (newInnerWindow->mDoc != aDocument) {
  1.2590 +        newInnerWindow->mDoc = aDocument;
  1.2591 +
  1.2592 +        if (newInnerWindow->IsDOMBinding()) {
  1.2593 +          WindowBinding::ClearCachedDocumentValue(cx, newInnerWindow);
  1.2594 +        } else {
  1.2595 +          // We're reusing the inner window for a new document. In this
  1.2596 +          // case we don't clear the inner window's scope, but we must
  1.2597 +          // make sure the cached document property gets updated.
  1.2598 +
  1.2599 +          JS::Rooted<JSObject*> obj(cx,
  1.2600 +                                    currentInner->GetWrapperPreserveColor());
  1.2601 +          ::JS_DeleteProperty(cx, obj, "document");
  1.2602 +        }
  1.2603 +      }
  1.2604 +    } else {
  1.2605 +      newInnerWindow->InnerSetNewDocument(cx, aDocument);
  1.2606 +
  1.2607 +      // Initialize DOM classes etc on the inner window.
  1.2608 +      JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
  1.2609 +      rv = mContext->InitClasses(obj);
  1.2610 +      NS_ENSURE_SUCCESS(rv, rv);
  1.2611 +    }
  1.2612 +
  1.2613 +    // If the document comes from a JAR, check if the channel was determined
  1.2614 +    // to be unsafe. If so, permanently disable script on the compartment by
  1.2615 +    // calling Block() and throwing away the key.
  1.2616 +    nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aDocument->GetChannel());
  1.2617 +    if (jarChannel && jarChannel->GetIsUnsafe()) {
  1.2618 +      xpc::Scriptability::Get(newInnerGlobal).Block();
  1.2619 +    }
  1.2620 +
  1.2621 +    if (mArguments) {
  1.2622 +      newInnerWindow->DefineArgumentsProperty(mArguments);
  1.2623 +      mArguments = nullptr;
  1.2624 +    }
  1.2625 +
  1.2626 +    // Give the new inner window our chrome event handler (since it
  1.2627 +    // doesn't have one).
  1.2628 +    newInnerWindow->mChromeEventHandler = mChromeEventHandler;
  1.2629 +  }
  1.2630 +
  1.2631 +  mContext->GC(JS::gcreason::SET_NEW_DOCUMENT);
  1.2632 +  mContext->DidInitializeContext();
  1.2633 +
  1.2634 +  // We wait to fire the debugger hook until the window is all set up and hooked
  1.2635 +  // up with the outer. See bug 969156.
  1.2636 +  if (createdInnerWindow) {
  1.2637 +    JS::Rooted<JSObject*> global(cx, newInnerWindow->GetWrapper());
  1.2638 +    JS_FireOnNewGlobalObject(cx, global);
  1.2639 +  }
  1.2640 +
  1.2641 +  if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
  1.2642 +    // We should probably notify. However if this is the, arguably bad,
  1.2643 +    // situation when we're creating a temporary non-chrome-about-blank
  1.2644 +    // document in a chrome docshell, don't notify just yet. Instead wait
  1.2645 +    // until we have a real chrome doc.
  1.2646 +    if (!mDocShell ||
  1.2647 +        mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome ||
  1.2648 +        nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
  1.2649 +      newInnerWindow->mHasNotifiedGlobalCreated = true;
  1.2650 +      nsContentUtils::AddScriptRunner(
  1.2651 +        NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated));
  1.2652 +    }
  1.2653 +  }
  1.2654 +
  1.2655 +  PreloadLocalStorage();
  1.2656 +
  1.2657 +  return NS_OK;
  1.2658 +}
  1.2659 +
  1.2660 +void
  1.2661 +nsGlobalWindow::PreloadLocalStorage()
  1.2662 +{
  1.2663 +  if (!Preferences::GetBool(kStorageEnabled)) {
  1.2664 +    return;
  1.2665 +  }
  1.2666 +
  1.2667 +  if (IsChromeWindow()) {
  1.2668 +    return;
  1.2669 +  }
  1.2670 +
  1.2671 +  nsIPrincipal* principal = GetPrincipal();
  1.2672 +  if (!principal) {
  1.2673 +    return;
  1.2674 +  }
  1.2675 +
  1.2676 +  nsresult rv;
  1.2677 +  nsCOMPtr<nsIURI> firstPartyIsolationURI;
  1.2678 +  rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
  1.2679 +  if (NS_FAILED(rv)) {
  1.2680 +    return;
  1.2681 +  }
  1.2682 +
  1.2683 +  nsCOMPtr<nsIDOMStorageManager> storageManager =
  1.2684 +    do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
  1.2685 +  if (NS_FAILED(rv)) {
  1.2686 +    return;
  1.2687 +  }
  1.2688 +
  1.2689 +  storageManager->PrecacheStorageForFirstParty(firstPartyIsolationURI, principal);
  1.2690 +}
  1.2691 +
  1.2692 +void
  1.2693 +nsGlobalWindow::DispatchDOMWindowCreated()
  1.2694 +{
  1.2695 +  if (!mDoc) {
  1.2696 +    return;
  1.2697 +  }
  1.2698 +
  1.2699 +  // Fire DOMWindowCreated at chrome event listeners
  1.2700 +  nsContentUtils::DispatchChromeEvent(mDoc, mDoc, NS_LITERAL_STRING("DOMWindowCreated"),
  1.2701 +                                      true /* bubbles */,
  1.2702 +                                      false /* not cancellable */);
  1.2703 +
  1.2704 +  nsCOMPtr<nsIObserverService> observerService =
  1.2705 +    mozilla::services::GetObserverService();
  1.2706 +  if (observerService) {
  1.2707 +    nsAutoString origin;
  1.2708 +    nsIPrincipal* principal = mDoc->NodePrincipal();
  1.2709 +    nsContentUtils::GetUTFOrigin(principal, origin);
  1.2710 +    observerService->
  1.2711 +      NotifyObservers(static_cast<nsIDOMWindow*>(this),
  1.2712 +                      nsContentUtils::IsSystemPrincipal(principal) ?
  1.2713 +                        "chrome-document-global-created" :
  1.2714 +                        "content-document-global-created",
  1.2715 +                      origin.get());
  1.2716 +  }
  1.2717 +}
  1.2718 +
  1.2719 +void
  1.2720 +nsGlobalWindow::ClearStatus()
  1.2721 +{
  1.2722 +  SetStatus(EmptyString());
  1.2723 +}
  1.2724 +
  1.2725 +void
  1.2726 +nsGlobalWindow::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument)
  1.2727 +{
  1.2728 +  NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
  1.2729 +  MOZ_ASSERT(aDocument);
  1.2730 +
  1.2731 +#ifdef PR_LOGGING
  1.2732 +  if (gDOMLeakPRLog && PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
  1.2733 +    nsIURI *uri = aDocument->GetDocumentURI();
  1.2734 +    nsAutoCString spec;
  1.2735 +    if (uri)
  1.2736 +      uri->GetSpec(spec);
  1.2737 +    PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
  1.2738 +  }
  1.2739 +#endif
  1.2740 +
  1.2741 +  mDoc = aDocument;
  1.2742 +  if (IsDOMBinding()) {
  1.2743 +    WindowBinding::ClearCachedDocumentValue(aCx, this);
  1.2744 +  }
  1.2745 +  mFocusedNode = nullptr;
  1.2746 +  mLocalStorage = nullptr;
  1.2747 +  mSessionStorage = nullptr;
  1.2748 +
  1.2749 +#ifdef DEBUG
  1.2750 +  mLastOpenedURI = aDocument->GetDocumentURI();
  1.2751 +#endif
  1.2752 +
  1.2753 +  Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
  1.2754 +                        mMutationBits ? 1 : 0);
  1.2755 +
  1.2756 +  // Clear our mutation bitfield.
  1.2757 +  mMutationBits = 0;
  1.2758 +}
  1.2759 +
  1.2760 +void
  1.2761 +nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
  1.2762 +{
  1.2763 +  NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
  1.2764 +  MOZ_ASSERT(aDocShell);
  1.2765 +
  1.2766 +  if (aDocShell == mDocShell) {
  1.2767 +    return;
  1.2768 +  }
  1.2769 +
  1.2770 +  mDocShell = aDocShell; // Weak Reference
  1.2771 +
  1.2772 +  NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
  1.2773 +
  1.2774 +  if (mFrames) {
  1.2775 +    mFrames->SetDocShell(aDocShell);
  1.2776 +  }
  1.2777 +
  1.2778 +  // Get our enclosing chrome shell and retrieve its global window impl, so
  1.2779 +  // that we can do some forwarding to the chrome document.
  1.2780 +  nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
  1.2781 +  mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
  1.2782 +  mChromeEventHandler = do_QueryInterface(chromeEventHandler);
  1.2783 +  if (!mChromeEventHandler) {
  1.2784 +    // We have no chrome event handler. If we have a parent,
  1.2785 +    // get our chrome event handler from the parent. If
  1.2786 +    // we don't have a parent, then we need to make a new
  1.2787 +    // window root object that will function as a chrome event
  1.2788 +    // handler and receive all events that occur anywhere inside
  1.2789 +    // our window.
  1.2790 +    nsCOMPtr<nsIDOMWindow> parentWindow;
  1.2791 +    GetParent(getter_AddRefs(parentWindow));
  1.2792 +    if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
  1.2793 +      nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
  1.2794 +      mChromeEventHandler = piWindow->GetChromeEventHandler();
  1.2795 +    }
  1.2796 +    else {
  1.2797 +      mChromeEventHandler = NS_NewWindowRoot(this);
  1.2798 +    }
  1.2799 +  }
  1.2800 +
  1.2801 +  bool docShellActive;
  1.2802 +  mDocShell->GetIsActive(&docShellActive);
  1.2803 +  mIsBackground = !docShellActive;
  1.2804 +}
  1.2805 +
  1.2806 +void
  1.2807 +nsGlobalWindow::DetachFromDocShell()
  1.2808 +{
  1.2809 +  NS_ASSERTION(IsOuterWindow(), "Uh, DetachFromDocShell() called on inner window!");
  1.2810 +
  1.2811 +  // DetachFromDocShell means the window is being torn down. Drop our
  1.2812 +  // reference to the script context, allowing it to be deleted
  1.2813 +  // later. Meanwhile, keep our weak reference to the script object
  1.2814 +  // so that it can be retrieved later (until it is finalized by the JS GC).
  1.2815 +
  1.2816 +  NS_ASSERTION(mTimeouts.isEmpty(), "Uh, outer window holds timeouts!");
  1.2817 +
  1.2818 +  // Call FreeInnerObjects on all inner windows, not just the current
  1.2819 +  // one, since some could be held by WindowStateHolder objects that
  1.2820 +  // are GC-owned.
  1.2821 +  for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
  1.2822 +       inner != this;
  1.2823 +       inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
  1.2824 +    NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
  1.2825 +                 "bad outer window pointer");
  1.2826 +    inner->FreeInnerObjects();
  1.2827 +  }
  1.2828 +
  1.2829 +  // Make sure that this is called before we null out the document.
  1.2830 +  NotifyDOMWindowDestroyed(this);
  1.2831 +
  1.2832 +  NotifyWindowIDDestroyed("outer-window-destroyed");
  1.2833 +
  1.2834 +  nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
  1.2835 +
  1.2836 +  if (currentInner) {
  1.2837 +    NS_ASSERTION(mDoc, "Must have doc!");
  1.2838 +
  1.2839 +    // Remember the document's principal and URI.
  1.2840 +    mDocumentPrincipal = mDoc->NodePrincipal();
  1.2841 +    mDocumentURI = mDoc->GetDocumentURI();
  1.2842 +    mDocBaseURI = mDoc->GetDocBaseURI();
  1.2843 +
  1.2844 +    // Release our document reference
  1.2845 +    DropOuterWindowDocs();
  1.2846 +    mFocusedNode = nullptr;
  1.2847 +  }
  1.2848 +
  1.2849 +  ClearControllers();
  1.2850 +
  1.2851 +  mChromeEventHandler = nullptr; // force release now
  1.2852 +
  1.2853 +  if (mContext) {
  1.2854 +    mContext->GC(JS::gcreason::SET_DOC_SHELL);
  1.2855 +    mContext = nullptr;
  1.2856 +  }
  1.2857 +
  1.2858 +  mDocShell = nullptr; // Weak Reference
  1.2859 +
  1.2860 +  NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
  1.2861 +
  1.2862 +  if (mFrames) {
  1.2863 +    mFrames->SetDocShell(nullptr);
  1.2864 +  }
  1.2865 +
  1.2866 +  MaybeForgiveSpamCount();
  1.2867 +  CleanUp();
  1.2868 +}
  1.2869 +
  1.2870 +void
  1.2871 +nsGlobalWindow::SetOpenerWindow(nsIDOMWindow* aOpener,
  1.2872 +                                bool aOriginalOpener)
  1.2873 +{
  1.2874 +  FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
  1.2875 +
  1.2876 +  NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
  1.2877 +               "aOriginalOpener is true, but not first call to "
  1.2878 +               "SetOpenerWindow!");
  1.2879 +  NS_ASSERTION(aOpener || !aOriginalOpener,
  1.2880 +               "Shouldn't set mHadOriginalOpener if aOpener is null");
  1.2881 +
  1.2882 +  mOpener = do_GetWeakReference(aOpener);
  1.2883 +  NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
  1.2884 +
  1.2885 +  if (aOriginalOpener) {
  1.2886 +    mHadOriginalOpener = true;
  1.2887 +  }
  1.2888 +
  1.2889 +#ifdef DEBUG
  1.2890 +  mSetOpenerWindowCalled = true;
  1.2891 +#endif
  1.2892 +}
  1.2893 +
  1.2894 +static
  1.2895 +already_AddRefed<EventTarget>
  1.2896 +TryGetTabChildGlobalAsEventTarget(nsISupports *aFrom)
  1.2897 +{
  1.2898 +  nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(aFrom);
  1.2899 +  if (!frameLoaderOwner) {
  1.2900 +    return nullptr;
  1.2901 +  }
  1.2902 +
  1.2903 +  nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
  1.2904 +  if (!frameLoader) {
  1.2905 +    return nullptr;
  1.2906 +  }
  1.2907 +
  1.2908 +  nsCOMPtr<EventTarget> target = frameLoader->GetTabChildGlobalAsEventTarget();
  1.2909 +  return target.forget();
  1.2910 +}
  1.2911 +
  1.2912 +void
  1.2913 +nsGlobalWindow::UpdateParentTarget()
  1.2914 +{
  1.2915 +  // Try to get our frame element's tab child global (its in-process message
  1.2916 +  // manager).  If that fails, fall back to the chrome event handler's tab
  1.2917 +  // child global, and if it doesn't have one, just use the chrome event
  1.2918 +  // handler itself.
  1.2919 +
  1.2920 +  nsCOMPtr<Element> frameElement = GetFrameElementInternal();
  1.2921 +  nsCOMPtr<EventTarget> eventTarget =
  1.2922 +    TryGetTabChildGlobalAsEventTarget(frameElement);
  1.2923 +
  1.2924 +  if (!eventTarget) {
  1.2925 +    nsGlobalWindow* topWin = GetScriptableTop();
  1.2926 +    if (topWin) {
  1.2927 +      frameElement = topWin->GetFrameElementInternal();
  1.2928 +      eventTarget = TryGetTabChildGlobalAsEventTarget(frameElement);
  1.2929 +    }
  1.2930 +  }
  1.2931 +
  1.2932 +  if (!eventTarget) {
  1.2933 +    eventTarget = TryGetTabChildGlobalAsEventTarget(mChromeEventHandler);
  1.2934 +  }
  1.2935 +
  1.2936 +  if (!eventTarget) {
  1.2937 +    eventTarget = mChromeEventHandler;
  1.2938 +  }
  1.2939 +
  1.2940 +  mParentTarget = eventTarget;
  1.2941 +}
  1.2942 +
  1.2943 +EventTarget*
  1.2944 +nsGlobalWindow::GetTargetForDOMEvent()
  1.2945 +{
  1.2946 +  return GetOuterWindowInternal();
  1.2947 +}
  1.2948 +
  1.2949 +EventTarget*
  1.2950 +nsGlobalWindow::GetTargetForEventTargetChain()
  1.2951 +{
  1.2952 +  return IsInnerWindow() ? this : GetCurrentInnerWindowInternal();
  1.2953 +}
  1.2954 +
  1.2955 +nsresult
  1.2956 +nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor)
  1.2957 +{
  1.2958 +  return NS_OK;
  1.2959 +}
  1.2960 +
  1.2961 +JSContext*
  1.2962 +nsGlobalWindow::GetJSContextForEventHandlers()
  1.2963 +{
  1.2964 +  return nullptr;
  1.2965 +}
  1.2966 +
  1.2967 +nsresult
  1.2968 +nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
  1.2969 +{
  1.2970 +  NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
  1.2971 +  static uint32_t count = 0;
  1.2972 +  uint32_t msg = aVisitor.mEvent->message;
  1.2973 +
  1.2974 +  aVisitor.mCanHandle = true;
  1.2975 +  aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
  1.2976 +  if ((msg == NS_MOUSE_MOVE) && gEntropyCollector) {
  1.2977 +    //Chances are this counter will overflow during the life of the
  1.2978 +    //process, but that's OK for our case. Means we get a little
  1.2979 +    //more entropy.
  1.2980 +    if (count++ % 100 == 0) {
  1.2981 +      //Since the high bits seem to be zero's most of the time,
  1.2982 +      //let's only take the lowest half of the point structure.
  1.2983 +      int16_t myCoord[2];
  1.2984 +
  1.2985 +      myCoord[0] = aVisitor.mEvent->refPoint.x;
  1.2986 +      myCoord[1] = aVisitor.mEvent->refPoint.y;
  1.2987 +      gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
  1.2988 +      gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
  1.2989 +                                      sizeof(uint32_t));
  1.2990 +    }
  1.2991 +  } else if (msg == NS_RESIZE_EVENT) {
  1.2992 +    mIsHandlingResizeEvent = true;
  1.2993 +  } else if (msg == NS_MOUSE_BUTTON_DOWN &&
  1.2994 +             aVisitor.mEvent->mFlags.mIsTrusted) {
  1.2995 +    gMouseDown = true;
  1.2996 +  } else if ((msg == NS_MOUSE_BUTTON_UP ||
  1.2997 +              msg == NS_DRAGDROP_END) &&
  1.2998 +             aVisitor.mEvent->mFlags.mIsTrusted) {
  1.2999 +    gMouseDown = false;
  1.3000 +    if (gDragServiceDisabled) {
  1.3001 +      nsCOMPtr<nsIDragService> ds =
  1.3002 +        do_GetService("@mozilla.org/widget/dragservice;1");
  1.3003 +      if (ds) {
  1.3004 +        gDragServiceDisabled = false;
  1.3005 +        ds->Unsuppress();
  1.3006 +      }
  1.3007 +    }
  1.3008 +  }
  1.3009 +
  1.3010 +  aVisitor.mParentTarget = GetParentTarget();
  1.3011 +
  1.3012 +  // Handle 'active' event.
  1.3013 +  if (!mIdleObservers.IsEmpty() &&
  1.3014 +      aVisitor.mEvent->mFlags.mIsTrusted &&
  1.3015 +      (aVisitor.mEvent->HasMouseEventMessage() ||
  1.3016 +       aVisitor.mEvent->HasDragEventMessage())) {
  1.3017 +    mAddActiveEventFuzzTime = false;
  1.3018 +  }
  1.3019 +
  1.3020 +  return NS_OK;
  1.3021 +}
  1.3022 +
  1.3023 +bool
  1.3024 +nsGlobalWindow::ShouldPromptToBlockDialogs()
  1.3025 +{
  1.3026 +  MOZ_ASSERT(IsOuterWindow());
  1.3027 +
  1.3028 +  nsGlobalWindow *topWindow = GetScriptableTop();
  1.3029 +  if (!topWindow) {
  1.3030 +    NS_ASSERTION(!mDocShell, "ShouldPromptToBlockDialogs() called without a top window?");
  1.3031 +    return true;
  1.3032 +  }
  1.3033 +
  1.3034 +  topWindow = topWindow->GetCurrentInnerWindowInternal();
  1.3035 +  if (!topWindow) {
  1.3036 +    return true;
  1.3037 +  }
  1.3038 +
  1.3039 +  return topWindow->DialogsAreBeingAbused();
  1.3040 +}
  1.3041 +
  1.3042 +bool
  1.3043 +nsGlobalWindow::AreDialogsEnabled()
  1.3044 +{
  1.3045 +  nsGlobalWindow *topWindow = GetScriptableTop();
  1.3046 +  if (!topWindow) {
  1.3047 +    NS_ERROR("AreDialogsEnabled() called without a top window?");
  1.3048 +    return false;
  1.3049 +  }
  1.3050 +
  1.3051 +  // TODO: Warn if no top window?
  1.3052 +  topWindow = topWindow->GetCurrentInnerWindowInternal();
  1.3053 +  if (!topWindow) {
  1.3054 +    return false;
  1.3055 +  }
  1.3056 +
  1.3057 +  // Dialogs are blocked if the content viewer is hidden
  1.3058 +  if (mDocShell) {
  1.3059 +    nsCOMPtr<nsIContentViewer> cv;
  1.3060 +    mDocShell->GetContentViewer(getter_AddRefs(cv));
  1.3061 +
  1.3062 +    bool isHidden;
  1.3063 +    cv->GetIsHidden(&isHidden);
  1.3064 +    if (isHidden) {
  1.3065 +      return false;
  1.3066 +    }
  1.3067 +  }
  1.3068 +
  1.3069 +  return topWindow->mAreDialogsEnabled;
  1.3070 +}
  1.3071 +
  1.3072 +bool
  1.3073 +nsGlobalWindow::DialogsAreBeingAbused()
  1.3074 +{
  1.3075 +  MOZ_ASSERT(IsInnerWindow());
  1.3076 +  NS_ASSERTION(GetScriptableTop() &&
  1.3077 +               GetScriptableTop()->GetCurrentInnerWindowInternal() == this,
  1.3078 +               "DialogsAreBeingAbused called with invalid window");
  1.3079 +
  1.3080 +  if (mLastDialogQuitTime.IsNull() ||
  1.3081 +      nsContentUtils::IsCallerChrome()) {
  1.3082 +    return false;
  1.3083 +  }
  1.3084 +
  1.3085 +  TimeDuration dialogInterval(TimeStamp::Now() - mLastDialogQuitTime);
  1.3086 +  if (dialogInterval.ToSeconds() <
  1.3087 +      Preferences::GetInt("dom.successive_dialog_time_limit",
  1.3088 +                          DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT)) {
  1.3089 +    mDialogAbuseCount++;
  1.3090 +
  1.3091 +    return GetPopupControlState() > openAllowed ||
  1.3092 +           mDialogAbuseCount > MAX_SUCCESSIVE_DIALOG_COUNT;
  1.3093 +  }
  1.3094 +
  1.3095 +  // Reset the abuse counter
  1.3096 +  mDialogAbuseCount = 0;
  1.3097 +
  1.3098 +  return false;
  1.3099 +}
  1.3100 +
  1.3101 +bool
  1.3102 +nsGlobalWindow::ConfirmDialogIfNeeded()
  1.3103 +{
  1.3104 +  MOZ_ASSERT(IsOuterWindow());
  1.3105 +
  1.3106 +  NS_ENSURE_TRUE(mDocShell, false);
  1.3107 +  nsCOMPtr<nsIPromptService> promptSvc =
  1.3108 +    do_GetService("@mozilla.org/embedcomp/prompt-service;1");
  1.3109 +
  1.3110 +  if (!promptSvc) {
  1.3111 +    return true;
  1.3112 +  }
  1.3113 +
  1.3114 +  // Reset popup state while opening a modal dialog, and firing events
  1.3115 +  // about the dialog, to prevent the current state from being active
  1.3116 +  // the whole time a modal dialog is open.
  1.3117 +  nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  1.3118 +
  1.3119 +  bool disableDialog = false;
  1.3120 +  nsXPIDLString label, title;
  1.3121 +  nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  1.3122 +                                     "ScriptDialogLabel", label);
  1.3123 +  nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  1.3124 +                                     "ScriptDialogPreventTitle", title);
  1.3125 +  promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
  1.3126 +  if (disableDialog) {
  1.3127 +    DisableDialogs();
  1.3128 +    return false;
  1.3129 +  }
  1.3130 +
  1.3131 +  return true;
  1.3132 +}
  1.3133 +
  1.3134 +void
  1.3135 +nsGlobalWindow::DisableDialogs()
  1.3136 +{
  1.3137 +  nsGlobalWindow *topWindow = GetScriptableTop();
  1.3138 +  if (!topWindow) {
  1.3139 +    NS_ERROR("DisableDialogs() called without a top window?");
  1.3140 +    return;
  1.3141 +  }
  1.3142 +
  1.3143 +  topWindow = topWindow->GetCurrentInnerWindowInternal();
  1.3144 +  // TODO: Warn if no top window?
  1.3145 +  if (topWindow) {
  1.3146 +    topWindow->mAreDialogsEnabled = false;
  1.3147 +  }
  1.3148 +}
  1.3149 +
  1.3150 +void
  1.3151 +nsGlobalWindow::EnableDialogs()
  1.3152 +{
  1.3153 +  nsGlobalWindow *topWindow = GetScriptableTop();
  1.3154 +  if (!topWindow) {
  1.3155 +    NS_ERROR("EnableDialogs() called without a top window?");
  1.3156 +    return;
  1.3157 +  }
  1.3158 +
  1.3159 +  // TODO: Warn if no top window?
  1.3160 +  topWindow = topWindow->GetCurrentInnerWindowInternal();
  1.3161 +  if (topWindow) {
  1.3162 +    topWindow->mAreDialogsEnabled = true;
  1.3163 +  }
  1.3164 +}
  1.3165 +
  1.3166 +nsresult
  1.3167 +nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
  1.3168 +{
  1.3169 +  NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
  1.3170 +
  1.3171 +  // Return early if there is nothing to do.
  1.3172 +  switch (aVisitor.mEvent->message) {
  1.3173 +    case NS_RESIZE_EVENT:
  1.3174 +    case NS_PAGE_UNLOAD:
  1.3175 +    case NS_LOAD:
  1.3176 +      break;
  1.3177 +    default:
  1.3178 +      return NS_OK;
  1.3179 +  }
  1.3180 +
  1.3181 +  /* mChromeEventHandler and mContext go dangling in the middle of this
  1.3182 +   function under some circumstances (events that destroy the window)
  1.3183 +   without this addref. */
  1.3184 +  nsCOMPtr<nsIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
  1.3185 +  nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
  1.3186 +
  1.3187 +  if (aVisitor.mEvent->message == NS_RESIZE_EVENT) {
  1.3188 +    mIsHandlingResizeEvent = false;
  1.3189 +  } else if (aVisitor.mEvent->message == NS_PAGE_UNLOAD &&
  1.3190 +             aVisitor.mEvent->mFlags.mIsTrusted) {
  1.3191 +    // Execute bindingdetached handlers before we tear ourselves
  1.3192 +    // down.
  1.3193 +    if (mDoc) {
  1.3194 +      mDoc->BindingManager()->ExecuteDetachedHandlers();
  1.3195 +    }
  1.3196 +    mIsDocumentLoaded = false;
  1.3197 +  } else if (aVisitor.mEvent->message == NS_LOAD &&
  1.3198 +             aVisitor.mEvent->mFlags.mIsTrusted) {
  1.3199 +    // This is page load event since load events don't propagate to |window|.
  1.3200 +    // @see nsDocument::PreHandleEvent.
  1.3201 +    mIsDocumentLoaded = true;
  1.3202 +
  1.3203 +    nsCOMPtr<Element> element = GetFrameElementInternal();
  1.3204 +    nsIDocShell* docShell = GetDocShell();
  1.3205 +    if (element && GetParentInternal() &&
  1.3206 +        docShell && docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
  1.3207 +      // If we're not in chrome, or at a chrome boundary, fire the
  1.3208 +      // onload event for the frame element.
  1.3209 +
  1.3210 +      nsEventStatus status = nsEventStatus_eIgnore;
  1.3211 +      WidgetEvent event(aVisitor.mEvent->mFlags.mIsTrusted, NS_LOAD);
  1.3212 +      event.mFlags.mBubbles = false;
  1.3213 +
  1.3214 +      // Most of the time we could get a pres context to pass in here,
  1.3215 +      // but not always (i.e. if this window is not shown there won't
  1.3216 +      // be a pres context available). Since we're not firing a GUI
  1.3217 +      // event we don't need a pres context anyway so we just pass
  1.3218 +      // null as the pres context all the time here.
  1.3219 +      EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status);
  1.3220 +    }
  1.3221 +  }
  1.3222 +
  1.3223 +  return NS_OK;
  1.3224 +}
  1.3225 +
  1.3226 +nsresult
  1.3227 +nsGlobalWindow::DispatchDOMEvent(WidgetEvent* aEvent,
  1.3228 +                                 nsIDOMEvent* aDOMEvent,
  1.3229 +                                 nsPresContext* aPresContext,
  1.3230 +                                 nsEventStatus* aEventStatus)
  1.3231 +{
  1.3232 +  return EventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),
  1.3233 +                                           aEvent, aDOMEvent, aPresContext,
  1.3234 +                                           aEventStatus);
  1.3235 +}
  1.3236 +
  1.3237 +void
  1.3238 +nsGlobalWindow::PoisonOuterWindowProxy(JSObject *aObject)
  1.3239 +{
  1.3240 +  MOZ_ASSERT(IsOuterWindow());
  1.3241 +  if (aObject == GetWrapperPreserveColor()) {
  1.3242 +    PoisonWrapper();
  1.3243 +  }
  1.3244 +}
  1.3245 +
  1.3246 +nsresult
  1.3247 +nsGlobalWindow::SetArguments(nsIArray *aArguments)
  1.3248 +{
  1.3249 +  MOZ_ASSERT(IsOuterWindow());
  1.3250 +  nsresult rv;
  1.3251 +
  1.3252 +  // Historically, we've used the same machinery to handle openDialog arguments
  1.3253 +  // (exposed via window.arguments) and showModalDialog arguments (exposed via
  1.3254 +  // window.dialogArguments), even though the former is XUL-only and uses an XPCOM
  1.3255 +  // array while the latter is web-exposed and uses an arbitrary JS value.
  1.3256 +  // Moreover, per-spec |dialogArguments| is a property of the browsing context
  1.3257 +  // (outer), whereas |arguments| lives on the inner.
  1.3258 +  //
  1.3259 +  // We've now mostly separated them, but the difference is still opaque to
  1.3260 +  // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
  1.3261 +  // embedding waltz we do here).
  1.3262 +  //
  1.3263 +  // So we need to demultiplex the two cases here.
  1.3264 +  nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
  1.3265 +  if (mIsModalContentWindow) {
  1.3266 +    // nsWindowWatcher blindly converts the original nsISupports into an array
  1.3267 +    // of length 1. We need to recover it, and then cast it back to the concrete
  1.3268 +    // object we know it to be.
  1.3269 +    nsCOMPtr<nsISupports> supports = do_QueryElementAt(aArguments, 0, &rv);
  1.3270 +    NS_ENSURE_SUCCESS(rv, rv);
  1.3271 +    mDialogArguments = static_cast<DialogValueHolder*>(supports.get());
  1.3272 +  } else {
  1.3273 +    mArguments = aArguments;
  1.3274 +    rv = currentInner->DefineArgumentsProperty(aArguments);
  1.3275 +    NS_ENSURE_SUCCESS(rv, rv);
  1.3276 +  }
  1.3277 +
  1.3278 +  return NS_OK;
  1.3279 +}
  1.3280 +
  1.3281 +nsresult
  1.3282 +nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
  1.3283 +{
  1.3284 +  MOZ_ASSERT(!mIsModalContentWindow); // Handled separately.
  1.3285 +  nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
  1.3286 +  NS_ENSURE_TRUE(aArguments && ctx, NS_ERROR_NOT_INITIALIZED);
  1.3287 +  AutoJSContext cx;
  1.3288 +
  1.3289 +  JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
  1.3290 +  return ctx->SetProperty(obj, "arguments", aArguments);
  1.3291 +}
  1.3292 +
  1.3293 +//*****************************************************************************
  1.3294 +// nsGlobalWindow::nsIScriptObjectPrincipal
  1.3295 +//*****************************************************************************
  1.3296 +
  1.3297 +nsIPrincipal*
  1.3298 +nsGlobalWindow::GetPrincipal()
  1.3299 +{
  1.3300 +  if (mDoc) {
  1.3301 +    // If we have a document, get the principal from the document
  1.3302 +    return mDoc->NodePrincipal();
  1.3303 +  }
  1.3304 +
  1.3305 +  if (mDocumentPrincipal) {
  1.3306 +    return mDocumentPrincipal;
  1.3307 +  }
  1.3308 +
  1.3309 +  // If we don't have a principal and we don't have a document we
  1.3310 +  // ask the parent window for the principal. This can happen when
  1.3311 +  // loading a frameset that has a <frame src="javascript:xxx">, in
  1.3312 +  // that case the global window is used in JS before we've loaded
  1.3313 +  // a document into the window.
  1.3314 +
  1.3315 +  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
  1.3316 +    do_QueryInterface(GetParentInternal());
  1.3317 +
  1.3318 +  if (objPrincipal) {
  1.3319 +    return objPrincipal->GetPrincipal();
  1.3320 +  }
  1.3321 +
  1.3322 +  return nullptr;
  1.3323 +}
  1.3324 +
  1.3325 +//*****************************************************************************
  1.3326 +// nsGlobalWindow::nsIDOMWindow
  1.3327 +//*****************************************************************************
  1.3328 +
  1.3329 +nsIURI*
  1.3330 +nsPIDOMWindow::GetDocumentURI() const
  1.3331 +{
  1.3332 +  return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
  1.3333 +}
  1.3334 +
  1.3335 +nsIURI*
  1.3336 +nsPIDOMWindow::GetDocBaseURI() const
  1.3337 +{
  1.3338 +  return mDoc ? mDoc->GetDocBaseURI() : mDocBaseURI.get();
  1.3339 +}
  1.3340 +
  1.3341 +void
  1.3342 +nsPIDOMWindow::MaybeCreateDoc()
  1.3343 +{
  1.3344 +  MOZ_ASSERT(!mDoc);
  1.3345 +  if (nsIDocShell* docShell = GetDocShell()) {
  1.3346 +    // Note that |document| here is the same thing as our mDoc, but we
  1.3347 +    // don't have to explicitly set the member variable because the docshell
  1.3348 +    // has already called SetNewDocument().
  1.3349 +    nsCOMPtr<nsIDocument> document = do_GetInterface(docShell);
  1.3350 +  }
  1.3351 +}
  1.3352 +
  1.3353 +Element*
  1.3354 +nsPIDOMWindow::GetFrameElementInternal() const
  1.3355 +{
  1.3356 +  if (mOuterWindow) {
  1.3357 +    return mOuterWindow->GetFrameElementInternal();
  1.3358 +  }
  1.3359 +
  1.3360 +  NS_ASSERTION(!IsInnerWindow(),
  1.3361 +               "GetFrameElementInternal() called on orphan inner window");
  1.3362 +
  1.3363 +  return mFrameElement;
  1.3364 +}
  1.3365 +
  1.3366 +void
  1.3367 +nsPIDOMWindow::SetFrameElementInternal(Element* aFrameElement)
  1.3368 +{
  1.3369 +  if (IsOuterWindow()) {
  1.3370 +    mFrameElement = aFrameElement;
  1.3371 +
  1.3372 +    return;
  1.3373 +  }
  1.3374 +
  1.3375 +  if (!mOuterWindow) {
  1.3376 +    NS_ERROR("frameElement set on inner window with no outer!");
  1.3377 +
  1.3378 +    return;
  1.3379 +  }
  1.3380 +
  1.3381 +  mOuterWindow->SetFrameElementInternal(aFrameElement);
  1.3382 +}
  1.3383 +
  1.3384 +void
  1.3385 +nsPIDOMWindow::AddAudioContext(AudioContext* aAudioContext)
  1.3386 +{
  1.3387 +  mAudioContexts.AppendElement(aAudioContext);
  1.3388 +
  1.3389 +  nsIDocShell* docShell = GetDocShell();
  1.3390 +  if (docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline()) {
  1.3391 +    aAudioContext->Mute();
  1.3392 +  }
  1.3393 +}
  1.3394 +
  1.3395 +void
  1.3396 +nsPIDOMWindow::RemoveAudioContext(AudioContext* aAudioContext)
  1.3397 +{
  1.3398 +  mAudioContexts.RemoveElement(aAudioContext);
  1.3399 +}
  1.3400 +
  1.3401 +void
  1.3402 +nsPIDOMWindow::MuteAudioContexts()
  1.3403 +{
  1.3404 +  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
  1.3405 +    if (!mAudioContexts[i]->IsOffline()) {
  1.3406 +      mAudioContexts[i]->Mute();
  1.3407 +    }
  1.3408 +  }
  1.3409 +}
  1.3410 +
  1.3411 +void
  1.3412 +nsPIDOMWindow::UnmuteAudioContexts()
  1.3413 +{
  1.3414 +  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
  1.3415 +    if (!mAudioContexts[i]->IsOffline()) {
  1.3416 +      mAudioContexts[i]->Unmute();
  1.3417 +    }
  1.3418 +  }
  1.3419 +}
  1.3420 +
  1.3421 +NS_IMETHODIMP
  1.3422 +nsGlobalWindow::GetDocument(nsIDOMDocument** aDocument)
  1.3423 +{
  1.3424 +  nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(GetDocument());
  1.3425 +  document.forget(aDocument);
  1.3426 +  return NS_OK;
  1.3427 +}
  1.3428 +
  1.3429 +nsIDOMWindow*
  1.3430 +nsGlobalWindow::GetWindow(ErrorResult& aError)
  1.3431 +{
  1.3432 +  FORWARD_TO_OUTER_OR_THROW(GetWindow, (aError), aError, nullptr);
  1.3433 +
  1.3434 +  return this;
  1.3435 +}
  1.3436 +
  1.3437 +NS_IMETHODIMP
  1.3438 +nsGlobalWindow::GetWindow(nsIDOMWindow** aWindow)
  1.3439 +{
  1.3440 +  ErrorResult rv;
  1.3441 +  nsCOMPtr<nsIDOMWindow> window = GetWindow(rv);
  1.3442 +  window.forget(aWindow);
  1.3443 +
  1.3444 +  return rv.ErrorCode();
  1.3445 +}
  1.3446 +
  1.3447 +nsIDOMWindow*
  1.3448 +nsGlobalWindow::GetSelf(ErrorResult& aError)
  1.3449 +{
  1.3450 +  FORWARD_TO_OUTER_OR_THROW(GetSelf, (aError), aError, nullptr);
  1.3451 +
  1.3452 +  return this;
  1.3453 +}
  1.3454 +
  1.3455 +NS_IMETHODIMP
  1.3456 +nsGlobalWindow::GetSelf(nsIDOMWindow** aWindow)
  1.3457 +{
  1.3458 +  ErrorResult rv;
  1.3459 +  nsCOMPtr<nsIDOMWindow> window = GetSelf(rv);
  1.3460 +  window.forget(aWindow);
  1.3461 +
  1.3462 +  return rv.ErrorCode();
  1.3463 +}
  1.3464 +
  1.3465 +Navigator*
  1.3466 +nsGlobalWindow::GetNavigator(ErrorResult& aError)
  1.3467 +{
  1.3468 +  FORWARD_TO_INNER_OR_THROW(GetNavigator, (aError), aError, nullptr);
  1.3469 +
  1.3470 +  if (!mNavigator) {
  1.3471 +    mNavigator = new Navigator(this);
  1.3472 +  }
  1.3473 +
  1.3474 +  return mNavigator;
  1.3475 +}
  1.3476 +
  1.3477 +NS_IMETHODIMP
  1.3478 +nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
  1.3479 +{
  1.3480 +  ErrorResult rv;
  1.3481 +  nsCOMPtr<nsIDOMNavigator> navigator = GetNavigator(rv);
  1.3482 +  navigator.forget(aNavigator);
  1.3483 +
  1.3484 +  return rv.ErrorCode();
  1.3485 +}
  1.3486 +
  1.3487 +nsScreen*
  1.3488 +nsGlobalWindow::GetScreen(ErrorResult& aError)
  1.3489 +{
  1.3490 +  FORWARD_TO_INNER_OR_THROW(GetScreen, (aError), aError, nullptr);
  1.3491 +
  1.3492 +  if (!mScreen) {
  1.3493 +    mScreen = nsScreen::Create(this);
  1.3494 +    if (!mScreen) {
  1.3495 +      aError.Throw(NS_ERROR_UNEXPECTED);
  1.3496 +      return nullptr;
  1.3497 +    }
  1.3498 +  }
  1.3499 +
  1.3500 +  return mScreen;
  1.3501 +}
  1.3502 +
  1.3503 +NS_IMETHODIMP
  1.3504 +nsGlobalWindow::GetScreen(nsIDOMScreen** aScreen)
  1.3505 +{
  1.3506 +  ErrorResult rv;
  1.3507 +  nsRefPtr<nsScreen> screen = GetScreen(rv);
  1.3508 +  screen.forget(aScreen);
  1.3509 +
  1.3510 +  return rv.ErrorCode();
  1.3511 +}
  1.3512 +
  1.3513 +nsHistory*
  1.3514 +nsGlobalWindow::GetHistory(ErrorResult& aError)
  1.3515 +{
  1.3516 +  FORWARD_TO_INNER_OR_THROW(GetHistory, (aError), aError, nullptr);
  1.3517 +
  1.3518 +  if (!mHistory) {
  1.3519 +    mHistory = new nsHistory(this);
  1.3520 +  }
  1.3521 +
  1.3522 +  return mHistory;
  1.3523 +}
  1.3524 +
  1.3525 +NS_IMETHODIMP
  1.3526 +nsGlobalWindow::GetHistory(nsISupports** aHistory)
  1.3527 +{
  1.3528 +  ErrorResult rv;
  1.3529 +  nsCOMPtr<nsISupports> history = GetHistory(rv);
  1.3530 +  history.forget(aHistory);
  1.3531 +
  1.3532 +  return rv.ErrorCode();
  1.3533 +}
  1.3534 +
  1.3535 +nsPerformance*
  1.3536 +nsGlobalWindow::GetPerformance(ErrorResult& aError)
  1.3537 +{
  1.3538 +  FORWARD_TO_INNER_OR_THROW(GetPerformance, (aError), aError, nullptr);
  1.3539 +
  1.3540 +  nsPerformance* p = nsPIDOMWindow::GetPerformance();
  1.3541 +  if (!p) {
  1.3542 +    aError.Throw(NS_ERROR_FAILURE);
  1.3543 +  }
  1.3544 +  return p;
  1.3545 +}
  1.3546 +
  1.3547 +NS_IMETHODIMP
  1.3548 +nsGlobalWindow::GetPerformance(nsISupports** aPerformance)
  1.3549 +{
  1.3550 +  ErrorResult rv;
  1.3551 +  nsCOMPtr<nsISupports> performance = GetPerformance(rv);
  1.3552 +  performance.forget(aPerformance);
  1.3553 +
  1.3554 +  return rv.ErrorCode();
  1.3555 +}
  1.3556 +
  1.3557 +nsPerformance*
  1.3558 +nsPIDOMWindow::GetPerformance()
  1.3559 +{
  1.3560 +  MOZ_ASSERT(IsInnerWindow());
  1.3561 +  CreatePerformanceObjectIfNeeded();
  1.3562 +  return mPerformance;
  1.3563 +}
  1.3564 +
  1.3565 +void
  1.3566 +nsPIDOMWindow::CreatePerformanceObjectIfNeeded()
  1.3567 +{
  1.3568 +  if (mPerformance || !mDoc) {
  1.3569 +    return;
  1.3570 +  }
  1.3571 +  nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
  1.3572 +  nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
  1.3573 +  bool timingEnabled = false;
  1.3574 +  if (!timedChannel ||
  1.3575 +      !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
  1.3576 +      !timingEnabled) {
  1.3577 +    timedChannel = nullptr;
  1.3578 +  }
  1.3579 +  if (timing) {
  1.3580 +    // If we are dealing with an iframe, we will need the parent's performance
  1.3581 +    // object (so we can add the iframe as a resource of that page).
  1.3582 +    nsPerformance* parentPerformance = nullptr;
  1.3583 +    nsCOMPtr<nsIDOMWindow> parentWindow;
  1.3584 +    GetScriptableParent(getter_AddRefs(parentWindow));
  1.3585 +    nsCOMPtr<nsPIDOMWindow> parentPWindow = do_GetInterface(parentWindow);
  1.3586 +    if (GetOuterWindow() != parentPWindow) {
  1.3587 +      if (parentPWindow && !parentPWindow->IsInnerWindow()) {
  1.3588 +        parentPWindow = parentPWindow->GetCurrentInnerWindow();
  1.3589 +      }
  1.3590 +      if (parentPWindow) {
  1.3591 +        parentPerformance = parentPWindow->GetPerformance();
  1.3592 +      }
  1.3593 +    }
  1.3594 +    mPerformance =
  1.3595 +      new nsPerformance(this, timing, timedChannel, parentPerformance);
  1.3596 +  }
  1.3597 +}
  1.3598 +
  1.3599 +bool
  1.3600 +nsPIDOMWindow::GetAudioMuted() const
  1.3601 +{
  1.3602 +  if (!IsInnerWindow()) {
  1.3603 +    return mInnerWindow->GetAudioMuted();
  1.3604 +  }
  1.3605 +
  1.3606 +  return mAudioMuted;
  1.3607 +}
  1.3608 +
  1.3609 +void
  1.3610 +nsPIDOMWindow::SetAudioMuted(bool aMuted)
  1.3611 +{
  1.3612 +  if (!IsInnerWindow()) {
  1.3613 +    mInnerWindow->SetAudioMuted(aMuted);
  1.3614 +    return;
  1.3615 +  }
  1.3616 +
  1.3617 +  if (mAudioMuted == aMuted) {
  1.3618 +    return;
  1.3619 +  }
  1.3620 +
  1.3621 +  mAudioMuted = aMuted;
  1.3622 +  RefreshMediaElements();
  1.3623 +}
  1.3624 +
  1.3625 +float
  1.3626 +nsPIDOMWindow::GetAudioVolume() const
  1.3627 +{
  1.3628 +  if (!IsInnerWindow()) {
  1.3629 +    return mInnerWindow->GetAudioVolume();
  1.3630 +  }
  1.3631 +
  1.3632 +  return mAudioVolume;
  1.3633 +}
  1.3634 +
  1.3635 +nsresult
  1.3636 +nsPIDOMWindow::SetAudioVolume(float aVolume)
  1.3637 +{
  1.3638 +  if (!IsInnerWindow()) {
  1.3639 +    return mInnerWindow->SetAudioVolume(aVolume);
  1.3640 +  }
  1.3641 +
  1.3642 +  if (aVolume < 0.0) {
  1.3643 +    return NS_ERROR_DOM_INDEX_SIZE_ERR;
  1.3644 +  }
  1.3645 +
  1.3646 +  if (mAudioVolume == aVolume) {
  1.3647 +    return NS_OK;
  1.3648 +  }
  1.3649 +
  1.3650 +  mAudioVolume = aVolume;
  1.3651 +  RefreshMediaElements();
  1.3652 +  return NS_OK;
  1.3653 +}
  1.3654 +
  1.3655 +float
  1.3656 +nsPIDOMWindow::GetAudioGlobalVolume()
  1.3657 +{
  1.3658 +  float globalVolume = 1.0;
  1.3659 +  nsCOMPtr<nsPIDOMWindow> window = this;
  1.3660 +
  1.3661 +  do {
  1.3662 +    if (window->GetAudioMuted()) {
  1.3663 +      return 0;
  1.3664 +    }
  1.3665 +
  1.3666 +    globalVolume *= window->GetAudioVolume();
  1.3667 +
  1.3668 +    nsCOMPtr<nsIDOMWindow> win;
  1.3669 +    window->GetParent(getter_AddRefs(win));
  1.3670 +    if (window == win) {
  1.3671 +      break;
  1.3672 +    }
  1.3673 +
  1.3674 +    window = do_QueryInterface(win);
  1.3675 +
  1.3676 +    // If there is not parent, or we are the toplevel or the volume is
  1.3677 +    // already 0.0, we don't continue.
  1.3678 +  } while (window && window != this && globalVolume);
  1.3679 +
  1.3680 +  return globalVolume;
  1.3681 +}
  1.3682 +
  1.3683 +void
  1.3684 +nsPIDOMWindow::RefreshMediaElements()
  1.3685 +{
  1.3686 +  nsRefPtr<AudioChannelService> service =
  1.3687 +    AudioChannelService::GetAudioChannelService();
  1.3688 +  if (service) {
  1.3689 +    service->RefreshAgentsVolume(this);
  1.3690 +  }
  1.3691 +}
  1.3692 +
  1.3693 +// nsISpeechSynthesisGetter
  1.3694 +
  1.3695 +#ifdef MOZ_WEBSPEECH
  1.3696 +SpeechSynthesis*
  1.3697 +nsGlobalWindow::GetSpeechSynthesis(ErrorResult& aError)
  1.3698 +{
  1.3699 +  FORWARD_TO_INNER_OR_THROW(GetSpeechSynthesis, (aError), aError, nullptr);
  1.3700 +
  1.3701 +  if (!mSpeechSynthesis) {
  1.3702 +    mSpeechSynthesis = new SpeechSynthesis(this);
  1.3703 +  }
  1.3704 +
  1.3705 +  return mSpeechSynthesis;
  1.3706 +}
  1.3707 +
  1.3708 +NS_IMETHODIMP
  1.3709 +nsGlobalWindow::GetSpeechSynthesis(nsISupports** aSpeechSynthesis)
  1.3710 +{
  1.3711 +  ErrorResult rv;
  1.3712 +  nsCOMPtr<nsISupports> speechSynthesis;
  1.3713 +  if (Preferences::GetBool("media.webspeech.synth.enabled")) {
  1.3714 +    speechSynthesis = GetSpeechSynthesis(rv);
  1.3715 +  }
  1.3716 +  speechSynthesis.forget(aSpeechSynthesis);
  1.3717 +
  1.3718 +  return rv.ErrorCode();
  1.3719 +}
  1.3720 +#endif
  1.3721 +
  1.3722 +already_AddRefed<nsIDOMWindow>
  1.3723 +nsGlobalWindow::GetParent(ErrorResult& aError)
  1.3724 +{
  1.3725 +  FORWARD_TO_OUTER_OR_THROW(GetParent, (aError), aError, nullptr);
  1.3726 +
  1.3727 +  if (!mDocShell) {
  1.3728 +    return nullptr;
  1.3729 +  }
  1.3730 +
  1.3731 +  nsCOMPtr<nsIDOMWindow> parent;
  1.3732 +  if (mDocShell->GetIsBrowserOrApp()) {
  1.3733 +    parent = this;
  1.3734 +  } else {
  1.3735 +    aError = GetRealParent(getter_AddRefs(parent));
  1.3736 +  }
  1.3737 +
  1.3738 +  return parent.forget();
  1.3739 +}
  1.3740 +
  1.3741 +/**
  1.3742 + * GetScriptableParent is called when script reads window.parent.
  1.3743 + *
  1.3744 + * In contrast to GetRealParent, GetScriptableParent respects <iframe
  1.3745 + * mozbrowser> boundaries, so if |this| is contained by an <iframe
  1.3746 + * mozbrowser>, we will return |this| as its own parent.
  1.3747 + */
  1.3748 +NS_IMETHODIMP
  1.3749 +nsGlobalWindow::GetScriptableParent(nsIDOMWindow** aParent)
  1.3750 +{
  1.3751 +  ErrorResult rv;
  1.3752 +  nsCOMPtr<nsIDOMWindow> parent = GetParent(rv);
  1.3753 +  parent.forget(aParent);
  1.3754 +
  1.3755 +  return rv.ErrorCode();
  1.3756 +}
  1.3757 +
  1.3758 +/**
  1.3759 + * nsIDOMWindow::GetParent (when called from C++) is just a wrapper around
  1.3760 + * GetRealParent.
  1.3761 + */
  1.3762 +NS_IMETHODIMP
  1.3763 +nsGlobalWindow::GetRealParent(nsIDOMWindow** aParent)
  1.3764 +{
  1.3765 +  FORWARD_TO_OUTER(GetRealParent, (aParent), NS_ERROR_NOT_INITIALIZED);
  1.3766 +
  1.3767 +  *aParent = nullptr;
  1.3768 +  if (!mDocShell) {
  1.3769 +    return NS_OK;
  1.3770 +  }
  1.3771 +
  1.3772 +  nsCOMPtr<nsIDocShell> parent;
  1.3773 +  mDocShell->GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
  1.3774 +
  1.3775 +  if (parent) {
  1.3776 +    nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(parent));
  1.3777 +    NS_ENSURE_SUCCESS(CallQueryInterface(globalObject.get(), aParent),
  1.3778 +                      NS_ERROR_FAILURE);
  1.3779 +  }
  1.3780 +  else {
  1.3781 +    *aParent = static_cast<nsIDOMWindow*>(this);
  1.3782 +    NS_ADDREF(*aParent);
  1.3783 +  }
  1.3784 +  return NS_OK;
  1.3785 +}
  1.3786 +
  1.3787 +static nsresult
  1.3788 +GetTopImpl(nsGlobalWindow* aWin, nsIDOMWindow** aTop, bool aScriptable)
  1.3789 +{
  1.3790 +  *aTop = nullptr;
  1.3791 +
  1.3792 +  // Walk up the parent chain.
  1.3793 +
  1.3794 +  nsCOMPtr<nsIDOMWindow> prevParent = aWin;
  1.3795 +  nsCOMPtr<nsIDOMWindow> parent = aWin;
  1.3796 +  do {
  1.3797 +    if (!parent) {
  1.3798 +      break;
  1.3799 +    }
  1.3800 +
  1.3801 +    prevParent = parent;
  1.3802 +
  1.3803 +    nsCOMPtr<nsIDOMWindow> newParent;
  1.3804 +    nsresult rv;
  1.3805 +    if (aScriptable) {
  1.3806 +      rv = parent->GetScriptableParent(getter_AddRefs(newParent));
  1.3807 +    }
  1.3808 +    else {
  1.3809 +      rv = parent->GetParent(getter_AddRefs(newParent));
  1.3810 +    }
  1.3811 +    NS_ENSURE_SUCCESS(rv, rv);
  1.3812 +
  1.3813 +    parent = newParent;
  1.3814 +
  1.3815 +  } while (parent != prevParent);
  1.3816 +
  1.3817 +  if (parent) {
  1.3818 +    parent.swap(*aTop);
  1.3819 +  }
  1.3820 +
  1.3821 +  return NS_OK;
  1.3822 +}
  1.3823 +
  1.3824 +/**
  1.3825 + * GetScriptableTop is called when script reads window.top.
  1.3826 + *
  1.3827 + * In contrast to GetRealTop, GetScriptableTop respects <iframe mozbrowser>
  1.3828 + * boundaries.  If we encounter a window owned by an <iframe mozbrowser> while
  1.3829 + * walking up the window hierarchy, we'll stop and return that window.
  1.3830 + */
  1.3831 +NS_IMETHODIMP
  1.3832 +nsGlobalWindow::GetScriptableTop(nsIDOMWindow **aTop)
  1.3833 +{
  1.3834 +  FORWARD_TO_OUTER(GetScriptableTop, (aTop), NS_ERROR_NOT_INITIALIZED);
  1.3835 +  return GetTopImpl(this, aTop, /* aScriptable = */ true);
  1.3836 +}
  1.3837 +
  1.3838 +/**
  1.3839 + * nsIDOMWindow::GetTop (when called from C++) is just a wrapper around
  1.3840 + * GetRealTop.
  1.3841 + */
  1.3842 +NS_IMETHODIMP
  1.3843 +nsGlobalWindow::GetRealTop(nsIDOMWindow** aTop)
  1.3844 +{
  1.3845 +  nsGlobalWindow* outer;
  1.3846 +  if (IsInnerWindow()) {
  1.3847 +    outer = GetOuterWindowInternal();
  1.3848 +    if (!outer) {
  1.3849 +      NS_WARNING("No outer window available!");
  1.3850 +      return NS_ERROR_NOT_INITIALIZED;
  1.3851 +    }
  1.3852 +  } else {
  1.3853 +    outer = this;
  1.3854 +  }
  1.3855 +  return GetTopImpl(outer, aTop, /* aScriptable = */ false);
  1.3856 +}
  1.3857 +
  1.3858 +void
  1.3859 +nsGlobalWindow::GetContent(JSContext* aCx,
  1.3860 +                           JS::MutableHandle<JSObject*> aRetval,
  1.3861 +                           ErrorResult& aError)
  1.3862 +{
  1.3863 +  FORWARD_TO_OUTER_OR_THROW(GetContent, (aCx, aRetval, aError), aError, );
  1.3864 +
  1.3865 +  nsCOMPtr<nsIDOMWindow> content = GetContentInternal(aError);
  1.3866 +  if (aError.Failed()) {
  1.3867 +    return;
  1.3868 +  }
  1.3869 +
  1.3870 +  if (content) {
  1.3871 +    JS::Rooted<JS::Value> val(aCx);
  1.3872 +    aError = nsContentUtils::WrapNative(aCx, content, &val);
  1.3873 +    if (aError.Failed()) {
  1.3874 +      return;
  1.3875 +    }
  1.3876 +
  1.3877 +    aRetval.set(&val.toObject());
  1.3878 +    return;
  1.3879 +  }
  1.3880 +
  1.3881 +  if (!nsContentUtils::IsCallerChrome() || !IsChromeWindow()) {
  1.3882 +    aError.Throw(NS_ERROR_FAILURE);
  1.3883 +    return;
  1.3884 +  }
  1.3885 +
  1.3886 +  // Something tries to get .content on a ChromeWindow, try to fetch the CPOW.
  1.3887 +  nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  1.3888 +  if (!treeOwner) {
  1.3889 +    aError.Throw(NS_ERROR_FAILURE);
  1.3890 +    return;
  1.3891 +  }
  1.3892 +
  1.3893 +  JS::Rooted<JS::Value> val(aCx, JS::NullValue());
  1.3894 +  aError = treeOwner->GetContentWindow(aCx, &val);
  1.3895 +  if (aError.Failed()) {
  1.3896 +    return;
  1.3897 +  }
  1.3898 +
  1.3899 +  aRetval.set(val.toObjectOrNull());
  1.3900 +}
  1.3901 +
  1.3902 +already_AddRefed<nsIDOMWindow>
  1.3903 +nsGlobalWindow::GetContentInternal(ErrorResult& aError)
  1.3904 +{
  1.3905 +  // First check for a named frame named "content"
  1.3906 +  nsCOMPtr<nsIDOMWindow> domWindow =
  1.3907 +    GetChildWindow(NS_LITERAL_STRING("content"));
  1.3908 +  if (domWindow) {
  1.3909 +    return domWindow.forget();
  1.3910 +  }
  1.3911 +
  1.3912 +  // If we're contained in <iframe mozbrowser> or <iframe mozapp>, then
  1.3913 +  // GetContent is the same as window.top.
  1.3914 +  if (mDocShell && mDocShell->GetIsInBrowserOrApp()) {
  1.3915 +    return GetTop(aError);
  1.3916 +  }
  1.3917 +
  1.3918 +  nsCOMPtr<nsIDocShellTreeItem> primaryContent;
  1.3919 +  if (!nsContentUtils::IsCallerChrome()) {
  1.3920 +    // If we're called by non-chrome code, make sure we don't return
  1.3921 +    // the primary content window if the calling tab is hidden. In
  1.3922 +    // such a case we return the same-type root in the hidden tab,
  1.3923 +    // which is "good enough", for now.
  1.3924 +    nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
  1.3925 +
  1.3926 +    if (baseWin) {
  1.3927 +      bool visible = false;
  1.3928 +      baseWin->GetVisibility(&visible);
  1.3929 +
  1.3930 +      if (!visible) {
  1.3931 +        mDocShell->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
  1.3932 +      }
  1.3933 +    }
  1.3934 +  }
  1.3935 +
  1.3936 +  if (!primaryContent) {
  1.3937 +    nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  1.3938 +    if (!treeOwner) {
  1.3939 +      aError.Throw(NS_ERROR_FAILURE);
  1.3940 +      return nullptr;
  1.3941 +    }
  1.3942 +
  1.3943 +    treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
  1.3944 +  }
  1.3945 +
  1.3946 +  domWindow = do_GetInterface(primaryContent);
  1.3947 +  return domWindow.forget();
  1.3948 +}
  1.3949 +
  1.3950 +NS_IMETHODIMP
  1.3951 +nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
  1.3952 +{
  1.3953 +  ErrorResult rv;
  1.3954 +  *aContent = GetContentInternal(rv).take();
  1.3955 +
  1.3956 +  return rv.ErrorCode();
  1.3957 +}
  1.3958 +
  1.3959 +NS_IMETHODIMP
  1.3960 +nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
  1.3961 +{
  1.3962 +  ErrorResult rv;
  1.3963 +  JS::Rooted<JSObject*> content(aCx);
  1.3964 +  GetContent(aCx, &content, rv);
  1.3965 +  if (!rv.Failed()) {
  1.3966 +    aVal.setObjectOrNull(content);
  1.3967 +  }
  1.3968 +
  1.3969 +  return rv.ErrorCode();
  1.3970 +}
  1.3971 +
  1.3972 +NS_IMETHODIMP
  1.3973 +nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
  1.3974 +{
  1.3975 +  if (IsInnerWindow()) {
  1.3976 +    nsGlobalWindow* outer = GetOuterWindowInternal();
  1.3977 +    if (!outer) {
  1.3978 +      NS_WARNING("No outer window available!");
  1.3979 +      return NS_ERROR_NOT_INITIALIZED;
  1.3980 +    }
  1.3981 +    return outer->GetPrompter(aPrompt);
  1.3982 +  }
  1.3983 +
  1.3984 +  if (!mDocShell)
  1.3985 +    return NS_ERROR_FAILURE;
  1.3986 +
  1.3987 +  nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
  1.3988 +  NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
  1.3989 +
  1.3990 +  NS_ADDREF(*aPrompt = prompter);
  1.3991 +  return NS_OK;
  1.3992 +}
  1.3993 +
  1.3994 +BarProp*
  1.3995 +nsGlobalWindow::GetMenubar(ErrorResult& aError)
  1.3996 +{
  1.3997 +  FORWARD_TO_INNER_OR_THROW(GetMenubar, (aError), aError, nullptr);
  1.3998 +
  1.3999 +  if (!mMenubar) {
  1.4000 +    mMenubar = new MenubarProp(this);
  1.4001 +  }
  1.4002 +
  1.4003 +  return mMenubar;
  1.4004 +}
  1.4005 +
  1.4006 +NS_IMETHODIMP
  1.4007 +nsGlobalWindow::GetMenubar(nsISupports** aMenubar)
  1.4008 +{
  1.4009 +  ErrorResult rv;
  1.4010 +  nsCOMPtr<nsISupports> menubar = GetMenubar(rv);
  1.4011 +  menubar.forget(aMenubar);
  1.4012 +
  1.4013 +  return rv.ErrorCode();
  1.4014 +}
  1.4015 +
  1.4016 +BarProp*
  1.4017 +nsGlobalWindow::GetToolbar(ErrorResult& aError)
  1.4018 +{
  1.4019 +  FORWARD_TO_INNER_OR_THROW(GetToolbar, (aError), aError, nullptr);
  1.4020 +
  1.4021 +  if (!mToolbar) {
  1.4022 +    mToolbar = new ToolbarProp(this);
  1.4023 +  }
  1.4024 +
  1.4025 +  return mToolbar;
  1.4026 +}
  1.4027 +
  1.4028 +NS_IMETHODIMP
  1.4029 +nsGlobalWindow::GetToolbar(nsISupports** aToolbar)
  1.4030 +{
  1.4031 +  ErrorResult rv;
  1.4032 +  nsCOMPtr<nsISupports> toolbar = GetToolbar(rv);
  1.4033 +  toolbar.forget(aToolbar);
  1.4034 +
  1.4035 +  return rv.ErrorCode();
  1.4036 +}
  1.4037 +
  1.4038 +BarProp*
  1.4039 +nsGlobalWindow::GetLocationbar(ErrorResult& aError)
  1.4040 +{
  1.4041 +  FORWARD_TO_INNER_OR_THROW(GetLocationbar, (aError), aError, nullptr);
  1.4042 +
  1.4043 +  if (!mLocationbar) {
  1.4044 +    mLocationbar = new LocationbarProp(this);
  1.4045 +  }
  1.4046 +  return mLocationbar;
  1.4047 +}
  1.4048 +
  1.4049 +NS_IMETHODIMP
  1.4050 +nsGlobalWindow::GetLocationbar(nsISupports** aLocationbar)
  1.4051 +{
  1.4052 +  ErrorResult rv;
  1.4053 +  nsCOMPtr<nsISupports> locationbar = GetLocationbar(rv);
  1.4054 +  locationbar.forget(aLocationbar);
  1.4055 +
  1.4056 +  return rv.ErrorCode();
  1.4057 +}
  1.4058 +
  1.4059 +BarProp*
  1.4060 +nsGlobalWindow::GetPersonalbar(ErrorResult& aError)
  1.4061 +{
  1.4062 +  FORWARD_TO_INNER_OR_THROW(GetPersonalbar, (aError), aError, nullptr);
  1.4063 +
  1.4064 +  if (!mPersonalbar) {
  1.4065 +    mPersonalbar = new PersonalbarProp(this);
  1.4066 +  }
  1.4067 +  return mPersonalbar;
  1.4068 +}
  1.4069 +
  1.4070 +NS_IMETHODIMP
  1.4071 +nsGlobalWindow::GetPersonalbar(nsISupports** aPersonalbar)
  1.4072 +{
  1.4073 +  ErrorResult rv;
  1.4074 +  nsCOMPtr<nsISupports> personalbar = GetPersonalbar(rv);
  1.4075 +  personalbar.forget(aPersonalbar);
  1.4076 +
  1.4077 +  return rv.ErrorCode();
  1.4078 +}
  1.4079 +
  1.4080 +BarProp*
  1.4081 +nsGlobalWindow::GetStatusbar(ErrorResult& aError)
  1.4082 +{
  1.4083 +  FORWARD_TO_INNER_OR_THROW(GetStatusbar, (aError), aError, nullptr);
  1.4084 +
  1.4085 +  if (!mStatusbar) {
  1.4086 +    mStatusbar = new StatusbarProp(this);
  1.4087 +  }
  1.4088 +  return mStatusbar;
  1.4089 +}
  1.4090 +
  1.4091 +NS_IMETHODIMP
  1.4092 +nsGlobalWindow::GetStatusbar(nsISupports** aStatusbar)
  1.4093 +{
  1.4094 +  ErrorResult rv;
  1.4095 +  nsCOMPtr<nsISupports> statusbar = GetStatusbar(rv);
  1.4096 +  statusbar.forget(aStatusbar);
  1.4097 +
  1.4098 +  return rv.ErrorCode();
  1.4099 +}
  1.4100 +
  1.4101 +BarProp*
  1.4102 +nsGlobalWindow::GetScrollbars(ErrorResult& aError)
  1.4103 +{
  1.4104 +  FORWARD_TO_INNER_OR_THROW(GetScrollbars, (aError), aError, nullptr);
  1.4105 +
  1.4106 +  if (!mScrollbars) {
  1.4107 +    mScrollbars = new ScrollbarsProp(this);
  1.4108 +  }
  1.4109 +
  1.4110 +  return mScrollbars;
  1.4111 +}
  1.4112 +
  1.4113 +NS_IMETHODIMP
  1.4114 +nsGlobalWindow::GetScrollbars(nsISupports** aScrollbars)
  1.4115 +{
  1.4116 +  ErrorResult rv;
  1.4117 +  nsCOMPtr<nsISupports> scrollbars = GetScrollbars(rv);
  1.4118 +  scrollbars.forget(aScrollbars);
  1.4119 +
  1.4120 +  return rv.ErrorCode();
  1.4121 +}
  1.4122 +
  1.4123 +bool
  1.4124 +nsGlobalWindow::GetClosed(ErrorResult& aError)
  1.4125 +{
  1.4126 +  FORWARD_TO_OUTER_OR_THROW(GetClosed, (aError), aError, false);
  1.4127 +
  1.4128 +  // If someone called close(), or if we don't have a docshell, we're closed.
  1.4129 +  return mIsClosed || !mDocShell;
  1.4130 +}
  1.4131 +
  1.4132 +NS_IMETHODIMP
  1.4133 +nsGlobalWindow::GetClosed(bool* aClosed)
  1.4134 +{
  1.4135 +  ErrorResult rv;
  1.4136 +  *aClosed = GetClosed(rv);
  1.4137 +
  1.4138 +  return rv.ErrorCode();
  1.4139 +}
  1.4140 +
  1.4141 +nsDOMWindowList*
  1.4142 +nsGlobalWindow::GetWindowList()
  1.4143 +{
  1.4144 +  MOZ_ASSERT(IsOuterWindow());
  1.4145 +
  1.4146 +  if (!mFrames && mDocShell) {
  1.4147 +    mFrames = new nsDOMWindowList(mDocShell);
  1.4148 +  }
  1.4149 +
  1.4150 +  return mFrames;
  1.4151 +}
  1.4152 +
  1.4153 +NS_IMETHODIMP
  1.4154 +nsGlobalWindow::GetFrames(nsIDOMWindowCollection** aFrames)
  1.4155 +{
  1.4156 +  FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
  1.4157 +
  1.4158 +  *aFrames = GetWindowList();
  1.4159 +  NS_IF_ADDREF(*aFrames);
  1.4160 +  return NS_OK;
  1.4161 +}
  1.4162 +
  1.4163 +already_AddRefed<nsIDOMWindow>
  1.4164 +nsGlobalWindow::IndexedGetter(uint32_t aIndex, bool& aFound)
  1.4165 +{
  1.4166 +  aFound = false;
  1.4167 +
  1.4168 +  FORWARD_TO_OUTER(IndexedGetter, (aIndex, aFound), nullptr);
  1.4169 +
  1.4170 +  nsDOMWindowList* windows = GetWindowList();
  1.4171 +  NS_ENSURE_TRUE(windows, nullptr);
  1.4172 +
  1.4173 +  return windows->IndexedGetter(aIndex, aFound);
  1.4174 +}
  1.4175 +
  1.4176 +void
  1.4177 +nsGlobalWindow::GetSupportedNames(nsTArray<nsString>& aNames)
  1.4178 +{
  1.4179 +  FORWARD_TO_OUTER_VOID(GetSupportedNames, (aNames));
  1.4180 +
  1.4181 +  nsDOMWindowList* windows = GetWindowList();
  1.4182 +  if (windows) {
  1.4183 +    uint32_t length = windows->GetLength();
  1.4184 +    nsString* name = aNames.AppendElements(length);
  1.4185 +    for (uint32_t i = 0; i < length; ++i, ++name) {
  1.4186 +      nsCOMPtr<nsIDocShellTreeItem> item =
  1.4187 +        windows->GetDocShellTreeItemAt(i);
  1.4188 +      item->GetName(*name);
  1.4189 +    }
  1.4190 +  }
  1.4191 +}
  1.4192 +
  1.4193 +bool
  1.4194 +nsGlobalWindow::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
  1.4195 +                             JS::Handle<jsid> aId,
  1.4196 +                             JS::MutableHandle<JSPropertyDescriptor> aDesc)
  1.4197 +{
  1.4198 +  MOZ_ASSERT(IsInnerWindow());
  1.4199 +
  1.4200 +  if (!JSID_IS_STRING(aId)) {
  1.4201 +    return true;
  1.4202 +  }
  1.4203 +
  1.4204 +  nsresult rv = nsWindowSH::GlobalResolve(this, aCx, aObj, aId, aDesc);
  1.4205 +  if (NS_FAILED(rv)) {
  1.4206 +    return Throw(aCx, rv);
  1.4207 +  }
  1.4208 +
  1.4209 +  return true;
  1.4210 +}
  1.4211 +
  1.4212 +struct GlobalNameEnumeratorClosure
  1.4213 +{
  1.4214 +  GlobalNameEnumeratorClosure(JSContext* aCx, nsGlobalWindow* aWindow,
  1.4215 +                              nsTArray<nsString>& aNames)
  1.4216 +    : mCx(aCx),
  1.4217 +      mWindow(aWindow),
  1.4218 +      mWrapper(aCx, aWindow->GetWrapper()),
  1.4219 +      mNames(aNames)
  1.4220 +  {
  1.4221 +  }
  1.4222 +
  1.4223 +  JSContext* mCx;
  1.4224 +  nsGlobalWindow* mWindow;
  1.4225 +  JS::Rooted<JSObject*> mWrapper;
  1.4226 +  nsTArray<nsString>& mNames;
  1.4227 +};
  1.4228 +
  1.4229 +static PLDHashOperator
  1.4230 +EnumerateGlobalName(const nsAString& aName,
  1.4231 +                    const nsGlobalNameStruct& aNameStruct,
  1.4232 +                    void* aClosure)
  1.4233 +{
  1.4234 +  GlobalNameEnumeratorClosure* closure =
  1.4235 +    static_cast<GlobalNameEnumeratorClosure*>(aClosure);
  1.4236 +
  1.4237 +  if (aNameStruct.mType == nsGlobalNameStruct::eTypeStaticNameSet) {
  1.4238 +    // We have no idea what names this might install.
  1.4239 +    return PL_DHASH_NEXT;
  1.4240 +  }
  1.4241 +
  1.4242 +  if (nsWindowSH::NameStructEnabled(closure->mCx, closure->mWindow, aName,
  1.4243 +                                    aNameStruct) &&
  1.4244 +      (!aNameStruct.mConstructorEnabled ||
  1.4245 +       aNameStruct.mConstructorEnabled(closure->mCx, closure->mWrapper))) {
  1.4246 +    closure->mNames.AppendElement(aName);
  1.4247 +  }
  1.4248 +  return PL_DHASH_NEXT;
  1.4249 +}
  1.4250 +
  1.4251 +void
  1.4252 +nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
  1.4253 +                                    ErrorResult& aRv)
  1.4254 +{
  1.4255 +  // "Components" is marked as enumerable but only resolved on demand :-/.
  1.4256 +  //aNames.AppendElement(NS_LITERAL_STRING("Components"));
  1.4257 +
  1.4258 +  nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
  1.4259 +  if (nameSpaceManager) {
  1.4260 +    GlobalNameEnumeratorClosure closure(aCx, this, aNames);
  1.4261 +    nameSpaceManager->EnumerateGlobalNames(EnumerateGlobalName, &closure);
  1.4262 +  }
  1.4263 +}
  1.4264 +
  1.4265 +/* static */ bool
  1.4266 +nsGlobalWindow::IsChromeWindow(JSContext* aCx, JSObject* aObj)
  1.4267 +{
  1.4268 +  // For now, have to deal with XPConnect objects here.
  1.4269 +  return xpc::WindowOrNull(aObj)->IsChromeWindow();
  1.4270 +}
  1.4271 +
  1.4272 +nsIDOMOfflineResourceList*
  1.4273 +nsGlobalWindow::GetApplicationCache(ErrorResult& aError)
  1.4274 +{
  1.4275 +  FORWARD_TO_INNER_OR_THROW(GetApplicationCache, (aError), aError, nullptr);
  1.4276 +
  1.4277 +  if (!mApplicationCache) {
  1.4278 +    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
  1.4279 +    if (!webNav) {
  1.4280 +      aError.Throw(NS_ERROR_FAILURE);
  1.4281 +      return nullptr;
  1.4282 +    }
  1.4283 +
  1.4284 +    nsCOMPtr<nsIURI> uri;
  1.4285 +    aError = webNav->GetCurrentURI(getter_AddRefs(uri));
  1.4286 +    if (aError.Failed()) {
  1.4287 +      return nullptr;
  1.4288 +    }
  1.4289 +
  1.4290 +    nsCOMPtr<nsIURI> manifestURI;
  1.4291 +    nsContentUtils::GetOfflineAppManifest(mDoc, getter_AddRefs(manifestURI));
  1.4292 +
  1.4293 +    nsRefPtr<nsDOMOfflineResourceList> applicationCache =
  1.4294 +      new nsDOMOfflineResourceList(manifestURI, uri, this);
  1.4295 +
  1.4296 +    applicationCache->Init();
  1.4297 +
  1.4298 +    mApplicationCache = applicationCache;
  1.4299 +  }
  1.4300 +
  1.4301 +  return mApplicationCache;
  1.4302 +}
  1.4303 +
  1.4304 +NS_IMETHODIMP
  1.4305 +nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
  1.4306 +{
  1.4307 +  ErrorResult rv;
  1.4308 +  nsCOMPtr<nsIDOMOfflineResourceList> applicationCache =
  1.4309 +    GetApplicationCache(rv);
  1.4310 +  applicationCache.forget(aApplicationCache);
  1.4311 +
  1.4312 +  return rv.ErrorCode();
  1.4313 +}
  1.4314 +
  1.4315 +nsIDOMCrypto*
  1.4316 +nsGlobalWindow::GetCrypto(ErrorResult& aError)
  1.4317 +{
  1.4318 +  FORWARD_TO_INNER_OR_THROW(GetCrypto, (aError), aError, nullptr);
  1.4319 +
  1.4320 +  if (!mCrypto) {
  1.4321 +#ifndef MOZ_DISABLE_CRYPTOLEGACY
  1.4322 +    if (XRE_GetProcessType() != GeckoProcessType_Content) {
  1.4323 +      nsresult rv;
  1.4324 +      mCrypto = do_CreateInstance(NS_CRYPTO_CONTRACTID, &rv);
  1.4325 +      if (NS_FAILED(rv)) {
  1.4326 +        aError.Throw(rv);
  1.4327 +        return nullptr;
  1.4328 +      }
  1.4329 +    } else
  1.4330 +#endif
  1.4331 +    {
  1.4332 +      mCrypto = new Crypto();
  1.4333 +    }
  1.4334 +
  1.4335 +    mCrypto->Init(this);
  1.4336 +  }
  1.4337 +  return mCrypto;
  1.4338 +}
  1.4339 +
  1.4340 +NS_IMETHODIMP
  1.4341 +nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
  1.4342 +{
  1.4343 +  ErrorResult rv;
  1.4344 +  nsCOMPtr<nsIDOMCrypto> crypto = GetCrypto(rv);
  1.4345 +  crypto.forget(aCrypto);
  1.4346 +
  1.4347 +  return rv.ErrorCode();
  1.4348 +}
  1.4349 +
  1.4350 +nsIControllers*
  1.4351 +nsGlobalWindow::GetControllers(ErrorResult& aError)
  1.4352 +{
  1.4353 +  FORWARD_TO_OUTER_OR_THROW(GetControllers, (aError), aError, nullptr);
  1.4354 +
  1.4355 +  if (!mControllers) {
  1.4356 +    nsresult rv;
  1.4357 +    mControllers = do_CreateInstance(kXULControllersCID, &rv);
  1.4358 +    if (NS_FAILED(rv)) {
  1.4359 +      aError.Throw(rv);
  1.4360 +      return nullptr;
  1.4361 +    }
  1.4362 +
  1.4363 +    // Add in the default controller
  1.4364 +    nsCOMPtr<nsIController> controller = do_CreateInstance(
  1.4365 +                               NS_WINDOWCONTROLLER_CONTRACTID, &rv);
  1.4366 +    if (NS_FAILED(rv)) {
  1.4367 +      aError.Throw(rv);
  1.4368 +      return nullptr;
  1.4369 +    }
  1.4370 +    
  1.4371 +    mControllers->InsertControllerAt(0, controller);
  1.4372 +    nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
  1.4373 +    if (!controllerContext) {
  1.4374 +      aError.Throw(NS_ERROR_FAILURE);
  1.4375 +      return nullptr;
  1.4376 +    }
  1.4377 +
  1.4378 +    controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
  1.4379 +  }
  1.4380 +
  1.4381 +  return mControllers;
  1.4382 +}
  1.4383 +
  1.4384 +NS_IMETHODIMP
  1.4385 +nsGlobalWindow::GetControllers(nsIControllers** aResult)
  1.4386 +{
  1.4387 +  ErrorResult rv;
  1.4388 +  nsCOMPtr<nsIControllers> controllers = GetControllers(rv);
  1.4389 +  controllers.forget(aResult);
  1.4390 +
  1.4391 +  return rv.ErrorCode();
  1.4392 +}
  1.4393 +
  1.4394 +nsIDOMWindow*
  1.4395 +nsGlobalWindow::GetOpenerWindow(ErrorResult& aError)
  1.4396 +{
  1.4397 +  FORWARD_TO_OUTER_OR_THROW(GetOpenerWindow, (aError), aError, nullptr);
  1.4398 +
  1.4399 +  nsCOMPtr<nsPIDOMWindow> opener = do_QueryReferent(mOpener);
  1.4400 +  if (!opener) {
  1.4401 +    return nullptr;
  1.4402 +  }
  1.4403 +
  1.4404 +  // First, check if we were called from a privileged chrome script
  1.4405 +  if (nsContentUtils::IsCallerChrome()) {
  1.4406 +    return opener;
  1.4407 +  }
  1.4408 +
  1.4409 +  // First, ensure that we're not handing back a chrome window.
  1.4410 +  nsGlobalWindow *win = static_cast<nsGlobalWindow *>(opener.get());
  1.4411 +  if (win->IsChromeWindow()) {
  1.4412 +    return nullptr;
  1.4413 +  }
  1.4414 +
  1.4415 +  // We don't want to reveal the opener if the opener is a mail window,
  1.4416 +  // because opener can be used to spoof the contents of a message (bug 105050).
  1.4417 +  // So, we look in the opener's root docshell to see if it's a mail window.
  1.4418 +  nsCOMPtr<nsIDocShell> openerDocShell = opener->GetDocShell();
  1.4419 +
  1.4420 +  if (openerDocShell) {
  1.4421 +    nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
  1.4422 +    openerDocShell->GetRootTreeItem(getter_AddRefs(openerRootItem));
  1.4423 +    nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
  1.4424 +    if (openerRootDocShell) {
  1.4425 +      uint32_t appType;
  1.4426 +      nsresult rv = openerRootDocShell->GetAppType(&appType);
  1.4427 +      if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
  1.4428 +        return opener;
  1.4429 +      }
  1.4430 +    }
  1.4431 +  }
  1.4432 +
  1.4433 +  return nullptr;
  1.4434 +}
  1.4435 +
  1.4436 +void
  1.4437 +nsGlobalWindow::GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
  1.4438 +                          ErrorResult& aError)
  1.4439 +{
  1.4440 +  nsCOMPtr<nsIDOMWindow> opener = GetOpenerWindow(aError);
  1.4441 +  if (aError.Failed() || !opener) {
  1.4442 +    aRetval.setNull();
  1.4443 +    return;
  1.4444 +  }
  1.4445 +
  1.4446 +  aError = nsContentUtils::WrapNative(aCx, opener, aRetval);
  1.4447 +}
  1.4448 +
  1.4449 +NS_IMETHODIMP
  1.4450 +nsGlobalWindow::GetScriptableOpener(JSContext* aCx,
  1.4451 +                                    JS::MutableHandle<JS::Value> aOpener)
  1.4452 +{
  1.4453 +  ErrorResult rv;
  1.4454 +  GetOpener(aCx, aOpener, rv);
  1.4455 +
  1.4456 +  return rv.ErrorCode();
  1.4457 +}
  1.4458 +
  1.4459 +NS_IMETHODIMP
  1.4460 +nsGlobalWindow::GetOpener(nsIDOMWindow** aOpener)
  1.4461 +{
  1.4462 +  ErrorResult rv;
  1.4463 +  nsCOMPtr<nsIDOMWindow> opener = GetOpenerWindow(rv);
  1.4464 +  opener.forget(aOpener);
  1.4465 +  return rv.ErrorCode();
  1.4466 +}
  1.4467 +
  1.4468 +void
  1.4469 +nsGlobalWindow::SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
  1.4470 +                          ErrorResult& aError)
  1.4471 +{
  1.4472 +  // Check if we were called from a privileged chrome script.  If not, and if
  1.4473 +  // aOpener is not null, just define aOpener on our inner window's JS object,
  1.4474 +  // wrapped into the current compartment so that for Xrays we define on the
  1.4475 +  // Xray expando object, but don't set it on the outer window, so that it'll
  1.4476 +  // get reset on navigation.  This is just like replaceable properties, but
  1.4477 +  // we're not quite readonly.
  1.4478 +  if (!aOpener.isNull() && !nsContentUtils::IsCallerChrome()) {
  1.4479 +    JS::Rooted<JSObject*> thisObj(aCx, GetWrapperPreserveColor());
  1.4480 +    if (!thisObj) {
  1.4481 +      aError.Throw(NS_ERROR_UNEXPECTED);
  1.4482 +      return;
  1.4483 +    }
  1.4484 +
  1.4485 +    if (!JS_WrapObject(aCx, &thisObj) ||
  1.4486 +        !JS_DefineProperty(aCx, thisObj, "opener", aOpener, JSPROP_ENUMERATE,
  1.4487 +                           JS_PropertyStub, JS_StrictPropertyStub)) {
  1.4488 +      aError.Throw(NS_ERROR_FAILURE);
  1.4489 +    }
  1.4490 +
  1.4491 +    return;
  1.4492 +  }
  1.4493 +
  1.4494 +  if (!aOpener.isObjectOrNull()) {
  1.4495 +    // Chrome code trying to set some random value as opener
  1.4496 +    aError.Throw(NS_ERROR_INVALID_ARG);
  1.4497 +    return;
  1.4498 +  }
  1.4499 +
  1.4500 +  nsGlobalWindow* win = nullptr;
  1.4501 +  if (aOpener.isObject()) {
  1.4502 +    JSObject* unwrapped = js::CheckedUnwrap(&aOpener.toObject(),
  1.4503 +                                            /* stopAtOuter = */ false);
  1.4504 +    if (!unwrapped) {
  1.4505 +      aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.4506 +      return;
  1.4507 +    }
  1.4508 +
  1.4509 +    win = xpc::WindowOrNull(unwrapped);
  1.4510 +    if (!win) {
  1.4511 +      // Wasn't a window
  1.4512 +      aError.Throw(NS_ERROR_INVALID_ARG);
  1.4513 +      return;
  1.4514 +    }
  1.4515 +  }
  1.4516 +
  1.4517 +  SetOpenerWindow(win, false);
  1.4518 +}
  1.4519 +
  1.4520 +NS_IMETHODIMP
  1.4521 +nsGlobalWindow::SetScriptableOpener(JSContext* aCx,
  1.4522 +                                    JS::Handle<JS::Value> aOpener)
  1.4523 +{
  1.4524 +  ErrorResult rv;
  1.4525 +  SetOpener(aCx, aOpener, rv);
  1.4526 +
  1.4527 +  return rv.ErrorCode();
  1.4528 +}
  1.4529 +
  1.4530 +NS_IMETHODIMP
  1.4531 +nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener)
  1.4532 +{
  1.4533 +  SetOpenerWindow(aOpener, false);
  1.4534 +  return NS_OK;
  1.4535 +}
  1.4536 +
  1.4537 +void
  1.4538 +nsGlobalWindow::GetStatus(nsAString& aStatus, ErrorResult& aError)
  1.4539 +{
  1.4540 +  FORWARD_TO_OUTER_OR_THROW(GetStatus, (aStatus, aError), aError, );
  1.4541 +
  1.4542 +  aStatus = mStatus;
  1.4543 +}
  1.4544 +
  1.4545 +NS_IMETHODIMP
  1.4546 +nsGlobalWindow::GetStatus(nsAString& aStatus)
  1.4547 +{
  1.4548 +  ErrorResult rv;
  1.4549 +  GetStatus(aStatus, rv);
  1.4550 +
  1.4551 +  return rv.ErrorCode();
  1.4552 +}
  1.4553 +
  1.4554 +void
  1.4555 +nsGlobalWindow::SetStatus(const nsAString& aStatus, ErrorResult& aError)
  1.4556 +{
  1.4557 +  FORWARD_TO_OUTER_OR_THROW(SetStatus, (aStatus, aError), aError, );
  1.4558 +
  1.4559 +  mStatus = aStatus;
  1.4560 +
  1.4561 +  /*
  1.4562 +   * If caller is not chrome and dom.disable_window_status_change is true,
  1.4563 +   * prevent propagating window.status to the UI by exiting early
  1.4564 +   */
  1.4565 +
  1.4566 +  if (!CanSetProperty("dom.disable_window_status_change")) {
  1.4567 +    return;
  1.4568 +  }
  1.4569 +
  1.4570 +  nsCOMPtr<nsIWebBrowserChrome> browserChrome = GetWebBrowserChrome();
  1.4571 +  if (browserChrome) {
  1.4572 +    browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
  1.4573 +                             PromiseFlatString(aStatus).get());
  1.4574 +  }
  1.4575 +}
  1.4576 +
  1.4577 +NS_IMETHODIMP
  1.4578 +nsGlobalWindow::SetStatus(const nsAString& aStatus)
  1.4579 +{
  1.4580 +  ErrorResult rv;
  1.4581 +  SetStatus(aStatus, rv);
  1.4582 +
  1.4583 +  return rv.ErrorCode();
  1.4584 +}
  1.4585 +
  1.4586 +void
  1.4587 +nsGlobalWindow::GetName(nsAString& aName, ErrorResult& aError)
  1.4588 +{
  1.4589 +  FORWARD_TO_OUTER_OR_THROW(GetName, (aName, aError), aError, );
  1.4590 +
  1.4591 +  if (mDocShell) {
  1.4592 +    mDocShell->GetName(aName);
  1.4593 +  }
  1.4594 +}
  1.4595 +
  1.4596 +NS_IMETHODIMP
  1.4597 +nsGlobalWindow::GetName(nsAString& aName)
  1.4598 +{
  1.4599 +  ErrorResult rv;
  1.4600 +  GetName(aName, rv);
  1.4601 +
  1.4602 +  return rv.ErrorCode();
  1.4603 +}
  1.4604 +
  1.4605 +void
  1.4606 +nsGlobalWindow::SetName(const nsAString& aName, mozilla::ErrorResult& aError)
  1.4607 +{
  1.4608 +  FORWARD_TO_OUTER_OR_THROW(SetName, (aName, aError), aError, );
  1.4609 +
  1.4610 +  if (mDocShell) {
  1.4611 +    aError = mDocShell->SetName(aName);
  1.4612 +  }
  1.4613 +}
  1.4614 +
  1.4615 +NS_IMETHODIMP
  1.4616 +nsGlobalWindow::SetName(const nsAString& aName)
  1.4617 +{
  1.4618 +  ErrorResult rv;
  1.4619 +  SetName(aName, rv);
  1.4620 +
  1.4621 +  return rv.ErrorCode();
  1.4622 +}
  1.4623 +
  1.4624 +// Helper functions used by many methods below.
  1.4625 +int32_t
  1.4626 +nsGlobalWindow::DevToCSSIntPixels(int32_t px)
  1.4627 +{
  1.4628 +  if (!mDocShell)
  1.4629 +    return px; // assume 1:1
  1.4630 +
  1.4631 +  nsRefPtr<nsPresContext> presContext;
  1.4632 +  mDocShell->GetPresContext(getter_AddRefs(presContext));
  1.4633 +  if (!presContext)
  1.4634 +    return px;
  1.4635 +
  1.4636 +  return presContext->DevPixelsToIntCSSPixels(px);
  1.4637 +}
  1.4638 +
  1.4639 +int32_t
  1.4640 +nsGlobalWindow::CSSToDevIntPixels(int32_t px)
  1.4641 +{
  1.4642 +  if (!mDocShell)
  1.4643 +    return px; // assume 1:1
  1.4644 +
  1.4645 +  nsRefPtr<nsPresContext> presContext;
  1.4646 +  mDocShell->GetPresContext(getter_AddRefs(presContext));
  1.4647 +  if (!presContext)
  1.4648 +    return px;
  1.4649 +
  1.4650 +  return presContext->CSSPixelsToDevPixels(px);
  1.4651 +}
  1.4652 +
  1.4653 +nsIntSize
  1.4654 +nsGlobalWindow::DevToCSSIntPixels(nsIntSize px)
  1.4655 +{
  1.4656 +  if (!mDocShell)
  1.4657 +    return px; // assume 1:1
  1.4658 +
  1.4659 +  nsRefPtr<nsPresContext> presContext;
  1.4660 +  mDocShell->GetPresContext(getter_AddRefs(presContext));
  1.4661 +  if (!presContext)
  1.4662 +    return px;
  1.4663 +
  1.4664 +  return nsIntSize(
  1.4665 +      presContext->DevPixelsToIntCSSPixels(px.width),
  1.4666 +      presContext->DevPixelsToIntCSSPixels(px.height));
  1.4667 +}
  1.4668 +
  1.4669 +nsIntSize
  1.4670 +nsGlobalWindow::CSSToDevIntPixels(nsIntSize px)
  1.4671 +{
  1.4672 +  if (!mDocShell)
  1.4673 +    return px; // assume 1:1
  1.4674 +
  1.4675 +  nsRefPtr<nsPresContext> presContext;
  1.4676 +  mDocShell->GetPresContext(getter_AddRefs(presContext));
  1.4677 +  if (!presContext)
  1.4678 +    return px;
  1.4679 +
  1.4680 +  return nsIntSize(
  1.4681 +    presContext->CSSPixelsToDevPixels(px.width),
  1.4682 +    presContext->CSSPixelsToDevPixels(px.height));
  1.4683 +}
  1.4684 +
  1.4685 +nsresult
  1.4686 +nsGlobalWindow::GetInnerSize(CSSIntSize& aSize)
  1.4687 +{
  1.4688 +  MOZ_ASSERT(IsOuterWindow());
  1.4689 +
  1.4690 +  EnsureSizeUpToDate();
  1.4691 +
  1.4692 +  NS_ENSURE_STATE(mDocShell);
  1.4693 +
  1.4694 +  nsRefPtr<nsPresContext> presContext;
  1.4695 +  mDocShell->GetPresContext(getter_AddRefs(presContext));
  1.4696 +  nsRefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  1.4697 +
  1.4698 +  if (!presContext || !presShell) {
  1.4699 +    aSize = CSSIntSize(0, 0);
  1.4700 +    return NS_OK;
  1.4701 +  }
  1.4702 +
  1.4703 +  /*
  1.4704 +   * On platforms with resolution-based zooming, the CSS viewport
  1.4705 +   * and visual viewport may not be the same. The inner size should
  1.4706 +   * be the visual viewport, but we fall back to the CSS viewport
  1.4707 +   * if it is not set.
  1.4708 +   */
  1.4709 +  if (presShell->IsScrollPositionClampingScrollPortSizeSet()) {
  1.4710 +    aSize = CSSIntRect::FromAppUnitsRounded(
  1.4711 +      presShell->GetScrollPositionClampingScrollPortSize());
  1.4712 +  } else {
  1.4713 +    nsRefPtr<nsViewManager> viewManager = presShell->GetViewManager();
  1.4714 +    if (viewManager) {
  1.4715 +      viewManager->FlushDelayedResize(false);
  1.4716 +    }
  1.4717 +
  1.4718 +    aSize = CSSIntRect::FromAppUnitsRounded(
  1.4719 +      presContext->GetVisibleArea().Size());
  1.4720 +  }
  1.4721 +  return NS_OK;
  1.4722 +}
  1.4723 +
  1.4724 +int32_t
  1.4725 +nsGlobalWindow::GetInnerWidth(ErrorResult& aError)
  1.4726 +{
  1.4727 +  FORWARD_TO_OUTER_OR_THROW(GetInnerWidth, (aError), aError, 0);
  1.4728 +
  1.4729 +  CSSIntSize size;
  1.4730 +  aError = GetInnerSize(size);
  1.4731 +  return size.width;
  1.4732 +}
  1.4733 +
  1.4734 +NS_IMETHODIMP
  1.4735 +nsGlobalWindow::GetInnerWidth(int32_t* aInnerWidth)
  1.4736 +{
  1.4737 +  ErrorResult rv;
  1.4738 +  *aInnerWidth = GetInnerWidth(rv);
  1.4739 +
  1.4740 +  return rv.ErrorCode();
  1.4741 +}
  1.4742 +
  1.4743 +void
  1.4744 +nsGlobalWindow::SetInnerWidth(int32_t aInnerWidth, ErrorResult& aError)
  1.4745 +{
  1.4746 +  FORWARD_TO_OUTER_OR_THROW(SetInnerWidth, (aInnerWidth, aError), aError, );
  1.4747 +
  1.4748 +  if (!mDocShell) {
  1.4749 +    aError.Throw(NS_ERROR_UNEXPECTED);
  1.4750 +    return;
  1.4751 +  }
  1.4752 +
  1.4753 +  /*
  1.4754 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.4755 +   * prevent setting window.innerWidth by exiting early
  1.4756 +   */
  1.4757 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.4758 +    return;
  1.4759 +  }
  1.4760 +
  1.4761 +  CheckSecurityWidthAndHeight(&aInnerWidth, nullptr);
  1.4762 +
  1.4763 +  nsRefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  1.4764 +
  1.4765 +  if (presShell && presShell->GetIsViewportOverridden())
  1.4766 +  {
  1.4767 +    nscoord height = 0;
  1.4768 +
  1.4769 +    nsRefPtr<nsPresContext> presContext;
  1.4770 +    presContext = presShell->GetPresContext();
  1.4771 +
  1.4772 +    nsRect shellArea = presContext->GetVisibleArea();
  1.4773 +    height = shellArea.height;
  1.4774 +    SetCSSViewportWidthAndHeight(nsPresContext::CSSPixelsToAppUnits(aInnerWidth),
  1.4775 +                                 height);
  1.4776 +    return;
  1.4777 +  }
  1.4778 +
  1.4779 +  int32_t height = 0;
  1.4780 +  int32_t unused  = 0;
  1.4781 +
  1.4782 +  nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
  1.4783 +  docShellAsWin->GetSize(&unused, &height);
  1.4784 +  aError = SetDocShellWidthAndHeight(CSSToDevIntPixels(aInnerWidth), height);
  1.4785 +}
  1.4786 +
  1.4787 +NS_IMETHODIMP
  1.4788 +nsGlobalWindow::SetInnerWidth(int32_t aInnerWidth)
  1.4789 +{
  1.4790 +  ErrorResult rv;
  1.4791 +  SetInnerWidth(aInnerWidth, rv);
  1.4792 +
  1.4793 +  return rv.ErrorCode();
  1.4794 +}
  1.4795 +
  1.4796 +int32_t
  1.4797 +nsGlobalWindow::GetInnerHeight(ErrorResult& aError)
  1.4798 +{
  1.4799 +  FORWARD_TO_OUTER_OR_THROW(GetInnerHeight, (aError), aError, 0);
  1.4800 +
  1.4801 +  CSSIntSize size;
  1.4802 +  aError = GetInnerSize(size);
  1.4803 +  return size.height;
  1.4804 +}
  1.4805 +
  1.4806 +NS_IMETHODIMP
  1.4807 +nsGlobalWindow::GetInnerHeight(int32_t* aInnerHeight)
  1.4808 +{
  1.4809 +  ErrorResult rv;
  1.4810 +  *aInnerHeight = GetInnerHeight(rv);
  1.4811 +
  1.4812 +  return rv.ErrorCode();
  1.4813 +}
  1.4814 +
  1.4815 +void
  1.4816 +nsGlobalWindow::SetInnerHeight(int32_t aInnerHeight, ErrorResult& aError)
  1.4817 +{
  1.4818 +  FORWARD_TO_OUTER_OR_THROW(SetInnerHeight, (aInnerHeight, aError), aError, );
  1.4819 +
  1.4820 +  if (!mDocShell) {
  1.4821 +    aError.Throw(NS_ERROR_UNEXPECTED);
  1.4822 +    return;
  1.4823 +  }
  1.4824 +
  1.4825 +  /*
  1.4826 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.4827 +   * prevent setting window.innerHeight by exiting early
  1.4828 +   */
  1.4829 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.4830 +    return;
  1.4831 +  }
  1.4832 +
  1.4833 +  nsRefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  1.4834 +
  1.4835 +  if (presShell && presShell->GetIsViewportOverridden())
  1.4836 +  {
  1.4837 +    nsRefPtr<nsPresContext> presContext;
  1.4838 +    presContext = presShell->GetPresContext();
  1.4839 +
  1.4840 +    nsRect shellArea = presContext->GetVisibleArea();
  1.4841 +    nscoord height = aInnerHeight;
  1.4842 +    nscoord width = shellArea.width;
  1.4843 +    CheckSecurityWidthAndHeight(nullptr, &height);
  1.4844 +    SetCSSViewportWidthAndHeight(width,
  1.4845 +                                 nsPresContext::CSSPixelsToAppUnits(height));
  1.4846 +    return;
  1.4847 +  }
  1.4848 +
  1.4849 +  int32_t height = 0;
  1.4850 +  int32_t width  = 0;
  1.4851 +
  1.4852 +  nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
  1.4853 +  docShellAsWin->GetSize(&width, &height);
  1.4854 +  CheckSecurityWidthAndHeight(nullptr, &aInnerHeight);
  1.4855 +  aError = SetDocShellWidthAndHeight(width, CSSToDevIntPixels(aInnerHeight));
  1.4856 +}
  1.4857 +
  1.4858 +NS_IMETHODIMP
  1.4859 +nsGlobalWindow::SetInnerHeight(int32_t aInnerHeight)
  1.4860 +{
  1.4861 +  ErrorResult rv;
  1.4862 +  SetInnerHeight(aInnerHeight, rv);
  1.4863 +
  1.4864 +  return rv.ErrorCode();
  1.4865 +}
  1.4866 +
  1.4867 +nsIntSize
  1.4868 +nsGlobalWindow::GetOuterSize(ErrorResult& aError)
  1.4869 +{
  1.4870 +  MOZ_ASSERT(IsOuterWindow());
  1.4871 +
  1.4872 +  if (!IsChrome()) {
  1.4873 +    CSSIntSize size;                                                                                                                                                                                       
  1.4874 +    aError = GetInnerSize(size);                                                                                                                                                                           
  1.4875 +    return nsIntSize(size.width, size.height);  
  1.4876 +  }
  1.4877 +
  1.4878 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.4879 +  if (!treeOwnerAsWin) {
  1.4880 +    aError.Throw(NS_ERROR_FAILURE);
  1.4881 +    return nsIntSize(0, 0);
  1.4882 +  }
  1.4883 +
  1.4884 +  nsGlobalWindow* rootWindow =
  1.4885 +    static_cast<nsGlobalWindow *>(GetPrivateRoot());
  1.4886 +  if (rootWindow) {
  1.4887 +    rootWindow->FlushPendingNotifications(Flush_Layout);
  1.4888 +  }
  1.4889 +
  1.4890 +  nsIntSize sizeDevPixels;
  1.4891 +  aError = treeOwnerAsWin->GetSize(&sizeDevPixels.width, &sizeDevPixels.height);
  1.4892 +  if (aError.Failed()) {
  1.4893 +    return nsIntSize();
  1.4894 +  }
  1.4895 +
  1.4896 +  return DevToCSSIntPixels(sizeDevPixels);
  1.4897 +}
  1.4898 +
  1.4899 +int32_t
  1.4900 +nsGlobalWindow::GetOuterWidth(ErrorResult& aError)
  1.4901 +{
  1.4902 +  FORWARD_TO_OUTER_OR_THROW(GetOuterWidth, (aError), aError, 0);
  1.4903 +  return GetOuterSize(aError).width;
  1.4904 +}
  1.4905 +
  1.4906 +NS_IMETHODIMP
  1.4907 +nsGlobalWindow::GetOuterWidth(int32_t* aOuterWidth)
  1.4908 +{
  1.4909 +  ErrorResult rv;
  1.4910 +  *aOuterWidth = GetOuterWidth(rv);
  1.4911 +
  1.4912 +  return rv.ErrorCode();
  1.4913 +}
  1.4914 +
  1.4915 +int32_t
  1.4916 +nsGlobalWindow::GetOuterHeight(ErrorResult& aError)
  1.4917 +{
  1.4918 +  FORWARD_TO_OUTER_OR_THROW(GetOuterHeight, (aError), aError, 0);
  1.4919 +  return GetOuterSize(aError).height;
  1.4920 +}
  1.4921 +
  1.4922 +NS_IMETHODIMP
  1.4923 +nsGlobalWindow::GetOuterHeight(int32_t* aOuterHeight)
  1.4924 +{
  1.4925 +  ErrorResult rv;
  1.4926 +  *aOuterHeight = GetOuterHeight(rv);
  1.4927 +
  1.4928 +  return rv.ErrorCode();
  1.4929 +}
  1.4930 +
  1.4931 +void
  1.4932 +nsGlobalWindow::SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth,
  1.4933 +                             ErrorResult& aError)
  1.4934 +{
  1.4935 +  MOZ_ASSERT(IsOuterWindow());
  1.4936 +
  1.4937 +  /*
  1.4938 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.4939 +   * prevent setting window.outerWidth by exiting early
  1.4940 +   */
  1.4941 +
  1.4942 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.4943 +    return;
  1.4944 +  }
  1.4945 +
  1.4946 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.4947 +  if (!treeOwnerAsWin) {
  1.4948 +    aError.Throw(NS_ERROR_FAILURE);
  1.4949 +    return;
  1.4950 +  }
  1.4951 +
  1.4952 +  CheckSecurityWidthAndHeight(aIsWidth ? &aLengthCSSPixels : nullptr,
  1.4953 +                              aIsWidth ? nullptr : &aLengthCSSPixels);
  1.4954 +
  1.4955 +  int32_t width, height;
  1.4956 +  aError = treeOwnerAsWin->GetSize(&width, &height);
  1.4957 +  if (aError.Failed()) {
  1.4958 +    return;
  1.4959 +  }
  1.4960 +
  1.4961 +  int32_t lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
  1.4962 +  if (aIsWidth) {
  1.4963 +    width = lengthDevPixels;
  1.4964 +  } else {
  1.4965 +    height = lengthDevPixels;
  1.4966 +  }
  1.4967 +  aError = treeOwnerAsWin->SetSize(width, height, true);    
  1.4968 +}
  1.4969 +
  1.4970 +void
  1.4971 +nsGlobalWindow::SetOuterWidth(int32_t aOuterWidth, ErrorResult& aError)
  1.4972 +{
  1.4973 +  FORWARD_TO_OUTER_OR_THROW(SetOuterWidth, (aOuterWidth, aError), aError, );
  1.4974 +
  1.4975 +  SetOuterSize(aOuterWidth, true, aError);
  1.4976 +}
  1.4977 +
  1.4978 +NS_IMETHODIMP
  1.4979 +nsGlobalWindow::SetOuterWidth(int32_t aOuterWidth)
  1.4980 +{
  1.4981 +  ErrorResult rv;
  1.4982 +  SetOuterWidth(aOuterWidth, rv);
  1.4983 +
  1.4984 +  return rv.ErrorCode();
  1.4985 +}
  1.4986 +
  1.4987 +void
  1.4988 +nsGlobalWindow::SetOuterHeight(int32_t aOuterHeight, ErrorResult& aError)
  1.4989 +{
  1.4990 +  FORWARD_TO_OUTER_OR_THROW(SetOuterHeight, (aOuterHeight, aError), aError, );
  1.4991 +
  1.4992 +  SetOuterSize(aOuterHeight, false, aError);
  1.4993 +}
  1.4994 +
  1.4995 +NS_IMETHODIMP
  1.4996 +nsGlobalWindow::SetOuterHeight(int32_t aOuterHeight)
  1.4997 +{
  1.4998 +  ErrorResult rv;
  1.4999 +  SetOuterHeight(aOuterHeight, rv);
  1.5000 +
  1.5001 +  return rv.ErrorCode();
  1.5002 +}
  1.5003 +
  1.5004 +nsIntPoint
  1.5005 +nsGlobalWindow::GetScreenXY(ErrorResult& aError)
  1.5006 +{
  1.5007 +  MOZ_ASSERT(IsOuterWindow());
  1.5008 +
  1.5009 +  // For non-chrome callers, always return (0,0) to prevent fingerprinting.
  1.5010 +  if (!IsChrome()) {
  1.5011 +    return nsIntPoint(0, 0);
  1.5012 +  }
  1.5013 +
  1.5014 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.5015 +  if (!treeOwnerAsWin) {
  1.5016 +    aError.Throw(NS_ERROR_FAILURE);
  1.5017 +    return nsIntPoint(0, 0);
  1.5018 +  }
  1.5019 +
  1.5020 +  int32_t x = 0, y = 0;
  1.5021 +  aError = treeOwnerAsWin->GetPosition(&x, &y);
  1.5022 +  return nsIntPoint(x, y);
  1.5023 +}
  1.5024 +
  1.5025 +int32_t
  1.5026 +nsGlobalWindow::GetScreenX(ErrorResult& aError)
  1.5027 +{
  1.5028 +  FORWARD_TO_OUTER_OR_THROW(GetScreenX, (aError), aError, 0);
  1.5029 +
  1.5030 +  return DevToCSSIntPixels(GetScreenXY(aError).x);
  1.5031 +}
  1.5032 +
  1.5033 +NS_IMETHODIMP
  1.5034 +nsGlobalWindow::GetScreenX(int32_t* aScreenX)
  1.5035 +{
  1.5036 +  ErrorResult rv;
  1.5037 +  *aScreenX = GetScreenX(rv);
  1.5038 +
  1.5039 +  return rv.ErrorCode();
  1.5040 +}
  1.5041 +
  1.5042 +nsRect
  1.5043 +nsGlobalWindow::GetInnerScreenRect()
  1.5044 +{
  1.5045 +  MOZ_ASSERT(IsOuterWindow());
  1.5046 +
  1.5047 +  if (!mDocShell) {
  1.5048 +    return nsRect();
  1.5049 +  }
  1.5050 +
  1.5051 +  nsGlobalWindow* rootWindow =
  1.5052 +    static_cast<nsGlobalWindow*>(GetPrivateRoot());
  1.5053 +  if (rootWindow) {
  1.5054 +    rootWindow->FlushPendingNotifications(Flush_Layout);
  1.5055 +  }
  1.5056 +
  1.5057 +  if (!mDocShell) {
  1.5058 +    return nsRect();
  1.5059 +  }
  1.5060 +
  1.5061 +  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  1.5062 +  if (!presShell) {
  1.5063 +    return nsRect();
  1.5064 +  }
  1.5065 +  nsIFrame* rootFrame = presShell->GetRootFrame();
  1.5066 +  if (!rootFrame) {
  1.5067 +    return nsRect();
  1.5068 +  }
  1.5069 +
  1.5070 +  return rootFrame->GetScreenRectInAppUnits();
  1.5071 +}
  1.5072 +
  1.5073 +float
  1.5074 +nsGlobalWindow::GetMozInnerScreenX(ErrorResult& aError)
  1.5075 +{
  1.5076 +  FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenX, (aError), aError, 0);
  1.5077 +
  1.5078 +  // For non-chrome callers, always return 0 to prevent fingerprinting.
  1.5079 +  if (!IsChrome()) return 0.0;
  1.5080 +
  1.5081 +  nsRect r = GetInnerScreenRect();
  1.5082 +  return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
  1.5083 +}
  1.5084 +
  1.5085 +NS_IMETHODIMP
  1.5086 +nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
  1.5087 +{
  1.5088 +  ErrorResult rv;
  1.5089 +  *aScreenX = GetMozInnerScreenX(rv);
  1.5090 +
  1.5091 +  return rv.ErrorCode();
  1.5092 +}
  1.5093 +
  1.5094 +float
  1.5095 +nsGlobalWindow::GetMozInnerScreenY(ErrorResult& aError)
  1.5096 +{
  1.5097 +  FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenY, (aError), aError, 0);
  1.5098 +
  1.5099 +  // For non-chrome callers, always return 0 to prevent fingerprinting.
  1.5100 +  if (!IsChrome()) return 0.0;
  1.5101 +
  1.5102 +  nsRect r = GetInnerScreenRect();
  1.5103 +  return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
  1.5104 +}
  1.5105 +
  1.5106 +NS_IMETHODIMP
  1.5107 +nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
  1.5108 +{
  1.5109 +  ErrorResult rv;
  1.5110 +  *aScreenY = GetMozInnerScreenY(rv);
  1.5111 +
  1.5112 +  return rv.ErrorCode();
  1.5113 +}
  1.5114 +
  1.5115 +float
  1.5116 +nsGlobalWindow::GetDevicePixelRatio(ErrorResult& aError)
  1.5117 +{
  1.5118 +  FORWARD_TO_OUTER_OR_THROW(GetDevicePixelRatio, (aError), aError, 0.0);
  1.5119 +
  1.5120 +  if (!mDocShell) {
  1.5121 +    return 1.0;
  1.5122 +  }
  1.5123 +
  1.5124 +  nsRefPtr<nsPresContext> presContext;
  1.5125 +  mDocShell->GetPresContext(getter_AddRefs(presContext));
  1.5126 +  if (!presContext) {
  1.5127 +    return 1.0;
  1.5128 +  }
  1.5129 +
  1.5130 +  return float(nsPresContext::AppUnitsPerCSSPixel())/
  1.5131 +      presContext->AppUnitsPerDevPixel();
  1.5132 +}
  1.5133 +
  1.5134 +NS_IMETHODIMP
  1.5135 +nsGlobalWindow::GetDevicePixelRatio(float* aRatio)
  1.5136 +{
  1.5137 +  ErrorResult rv;
  1.5138 +  *aRatio = GetDevicePixelRatio(rv);
  1.5139 +
  1.5140 +  return rv.ErrorCode();
  1.5141 +}
  1.5142 +
  1.5143 +uint64_t
  1.5144 +nsGlobalWindow::GetMozPaintCount(ErrorResult& aError)
  1.5145 +{
  1.5146 +  FORWARD_TO_OUTER_OR_THROW(GetMozPaintCount, (aError), aError, 0);
  1.5147 +
  1.5148 +  if (!mDocShell) {
  1.5149 +    return 0;
  1.5150 +  }
  1.5151 +
  1.5152 +  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  1.5153 +  return presShell ? presShell->GetPaintCount() : 0;
  1.5154 +}
  1.5155 +
  1.5156 +NS_IMETHODIMP
  1.5157 +nsGlobalWindow::GetMozPaintCount(uint64_t* aResult)
  1.5158 +{
  1.5159 +  ErrorResult rv;
  1.5160 +  *aResult = GetMozPaintCount(rv);
  1.5161 +
  1.5162 +  return rv.ErrorCode();
  1.5163 +}
  1.5164 +
  1.5165 +NS_IMETHODIMP
  1.5166 +nsGlobalWindow::MozRequestAnimationFrame(nsIFrameRequestCallback* aCallback,
  1.5167 +                                         int32_t *aHandle)
  1.5168 +{
  1.5169 +  if (!aCallback) {
  1.5170 +    if (mDoc) {
  1.5171 +      mDoc->WarnOnceAbout(nsIDocument::eMozBeforePaint);
  1.5172 +    }
  1.5173 +    return NS_ERROR_XPC_BAD_CONVERT_JS;
  1.5174 +  }
  1.5175 +
  1.5176 +  ErrorResult rv;
  1.5177 +  nsIDocument::FrameRequestCallbackHolder holder(aCallback);
  1.5178 +  *aHandle = RequestAnimationFrame(holder, rv);
  1.5179 +
  1.5180 +  return rv.ErrorCode();
  1.5181 +}
  1.5182 +
  1.5183 +int32_t
  1.5184 +nsGlobalWindow::RequestAnimationFrame(FrameRequestCallback& aCallback,
  1.5185 +                                      ErrorResult& aError)
  1.5186 +{
  1.5187 +  nsIDocument::FrameRequestCallbackHolder holder(&aCallback);
  1.5188 +  return RequestAnimationFrame(holder, aError);
  1.5189 +}
  1.5190 +
  1.5191 +int32_t
  1.5192 +nsGlobalWindow::MozRequestAnimationFrame(nsIFrameRequestCallback* aCallback,
  1.5193 +                                         ErrorResult& aError)
  1.5194 +{
  1.5195 +  nsIDocument::FrameRequestCallbackHolder holder(aCallback);
  1.5196 +  return RequestAnimationFrame(holder, aError);
  1.5197 +}
  1.5198 +
  1.5199 +int32_t
  1.5200 +nsGlobalWindow::RequestAnimationFrame(const nsIDocument::FrameRequestCallbackHolder& aCallback,
  1.5201 +                                      ErrorResult& aError)
  1.5202 +{
  1.5203 +  FORWARD_TO_INNER_OR_THROW(RequestAnimationFrame, (aCallback, aError), aError,
  1.5204 +                            0);
  1.5205 +
  1.5206 +  if (!mDoc) {
  1.5207 +    return 0;
  1.5208 +  }
  1.5209 +
  1.5210 +  if (GetWrapperPreserveColor()) {
  1.5211 +    js::NotifyAnimationActivity(GetWrapperPreserveColor());
  1.5212 +  }
  1.5213 +
  1.5214 +  int32_t handle;
  1.5215 +  aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle);
  1.5216 +  return handle;
  1.5217 +}
  1.5218 +
  1.5219 +NS_IMETHODIMP
  1.5220 +nsGlobalWindow::RequestAnimationFrame(JS::Handle<JS::Value> aCallback,
  1.5221 +                                      JSContext* cx,
  1.5222 +                                      int32_t* aHandle)
  1.5223 +{
  1.5224 +  if (!aCallback.isObject() || !JS_ObjectIsCallable(cx, &aCallback.toObject())) {
  1.5225 +    return NS_ERROR_INVALID_ARG;
  1.5226 +  }
  1.5227 +
  1.5228 +  JS::Rooted<JSObject*> callbackObj(cx, &aCallback.toObject());
  1.5229 +  nsRefPtr<FrameRequestCallback> callback =
  1.5230 +    new FrameRequestCallback(callbackObj, GetIncumbentGlobal());
  1.5231 +
  1.5232 +  ErrorResult rv;
  1.5233 +  *aHandle = RequestAnimationFrame(*callback, rv);
  1.5234 +
  1.5235 +  return rv.ErrorCode();
  1.5236 +}
  1.5237 +
  1.5238 +NS_IMETHODIMP
  1.5239 +nsGlobalWindow::MozCancelRequestAnimationFrame(int32_t aHandle)
  1.5240 +{
  1.5241 +  return CancelAnimationFrame(aHandle);
  1.5242 +}
  1.5243 +
  1.5244 +NS_IMETHODIMP
  1.5245 +nsGlobalWindow::MozCancelAnimationFrame(int32_t aHandle)
  1.5246 +{
  1.5247 +  return CancelAnimationFrame(aHandle);
  1.5248 +}
  1.5249 +
  1.5250 +void
  1.5251 +nsGlobalWindow::CancelAnimationFrame(int32_t aHandle, ErrorResult& aError)
  1.5252 +{
  1.5253 +  FORWARD_TO_INNER_OR_THROW(CancelAnimationFrame, (aHandle, aError), aError, );
  1.5254 +
  1.5255 +  if (!mDoc) {
  1.5256 +    return;
  1.5257 +  }
  1.5258 +
  1.5259 +  mDoc->CancelFrameRequestCallback(aHandle);
  1.5260 +}
  1.5261 +
  1.5262 +NS_IMETHODIMP
  1.5263 +nsGlobalWindow::CancelAnimationFrame(int32_t aHandle)
  1.5264 +{
  1.5265 +  ErrorResult rv;
  1.5266 +  CancelAnimationFrame(aHandle, rv);
  1.5267 +
  1.5268 +  return rv.ErrorCode();
  1.5269 +}
  1.5270 +
  1.5271 +int64_t
  1.5272 +nsGlobalWindow::GetMozAnimationStartTime(ErrorResult& aError)
  1.5273 +{
  1.5274 +  FORWARD_TO_INNER_OR_THROW(GetMozAnimationStartTime, (aError), aError, 0);
  1.5275 +
  1.5276 +  if (mDoc) {
  1.5277 +    nsIPresShell* presShell = mDoc->GetShell();
  1.5278 +    if (presShell) {
  1.5279 +      return presShell->GetPresContext()->RefreshDriver()->
  1.5280 +        MostRecentRefreshEpochTime() / PR_USEC_PER_MSEC;
  1.5281 +    }
  1.5282 +  }
  1.5283 +
  1.5284 +  // If all else fails, just be compatible with Date.now()
  1.5285 +  return JS_Now() / PR_USEC_PER_MSEC;
  1.5286 +}
  1.5287 +
  1.5288 +NS_IMETHODIMP
  1.5289 +nsGlobalWindow::GetMozAnimationStartTime(int64_t *aTime)
  1.5290 +{
  1.5291 +  ErrorResult rv;
  1.5292 +  *aTime = GetMozAnimationStartTime(rv);
  1.5293 +
  1.5294 +  return rv.ErrorCode();
  1.5295 +}
  1.5296 +
  1.5297 +already_AddRefed<MediaQueryList>
  1.5298 +nsGlobalWindow::MatchMedia(const nsAString& aMediaQueryList,
  1.5299 +                           ErrorResult& aError)
  1.5300 +{
  1.5301 +  // FIXME: This whole forward-to-outer and then get a pres
  1.5302 +  // shell/context off the docshell dance is sort of silly; it'd make
  1.5303 +  // more sense to forward to the inner, but it's what everyone else
  1.5304 +  // (GetSelection, GetScrollXY, etc.) does around here.
  1.5305 +  FORWARD_TO_OUTER_OR_THROW(MatchMedia, (aMediaQueryList, aError), aError,
  1.5306 +                            nullptr);
  1.5307 +
  1.5308 +  // We need this now to ensure that we have a non-null |presContext|
  1.5309 +  // when we ought to.
  1.5310 +  // This is similar to EnsureSizeUpToDate, but only flushes frames.
  1.5311 +  nsGlobalWindow *parent = static_cast<nsGlobalWindow*>(GetPrivateParent());
  1.5312 +  if (parent) {
  1.5313 +    parent->FlushPendingNotifications(Flush_Frames);
  1.5314 +  }
  1.5315 +
  1.5316 +  if (!mDocShell) {
  1.5317 +    return nullptr;
  1.5318 +  }
  1.5319 +
  1.5320 +  nsRefPtr<nsPresContext> presContext;
  1.5321 +  mDocShell->GetPresContext(getter_AddRefs(presContext));
  1.5322 +
  1.5323 +  if (!presContext) {
  1.5324 +    return nullptr;
  1.5325 +  }
  1.5326 +
  1.5327 +  return presContext->MatchMedia(aMediaQueryList);
  1.5328 +}
  1.5329 +
  1.5330 +NS_IMETHODIMP
  1.5331 +nsGlobalWindow::MatchMedia(const nsAString& aMediaQueryList,
  1.5332 +                           nsISupports** aResult)
  1.5333 +{
  1.5334 +  ErrorResult rv;
  1.5335 +  nsRefPtr<MediaQueryList> mediaQueryList = MatchMedia(aMediaQueryList, rv);
  1.5336 +  mediaQueryList.forget(aResult);
  1.5337 +
  1.5338 +  return rv.ErrorCode();
  1.5339 +}
  1.5340 +
  1.5341 +void
  1.5342 +nsGlobalWindow::SetScreenX(int32_t aScreenX, ErrorResult& aError)
  1.5343 +{
  1.5344 +  FORWARD_TO_OUTER_OR_THROW(SetScreenX, (aScreenX, aError), aError, );
  1.5345 +
  1.5346 +  /*
  1.5347 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.5348 +   * prevent setting window.screenX by exiting early
  1.5349 +   */
  1.5350 +
  1.5351 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.5352 +    return;
  1.5353 +  }
  1.5354 +
  1.5355 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.5356 +  if (!treeOwnerAsWin) {
  1.5357 +    aError.Throw(NS_ERROR_FAILURE);
  1.5358 +    return;
  1.5359 +  }
  1.5360 +
  1.5361 +  int32_t x, y;
  1.5362 +  aError = treeOwnerAsWin->GetPosition(&x, &y);
  1.5363 +  if (aError.Failed()) {
  1.5364 +    return;
  1.5365 +  }
  1.5366 +
  1.5367 +  CheckSecurityLeftAndTop(&aScreenX, nullptr);
  1.5368 +  x = CSSToDevIntPixels(aScreenX);
  1.5369 +
  1.5370 +  aError = treeOwnerAsWin->SetPosition(x, y);
  1.5371 +}
  1.5372 +
  1.5373 +NS_IMETHODIMP
  1.5374 +nsGlobalWindow::SetScreenX(int32_t aScreenX)
  1.5375 +{
  1.5376 +  ErrorResult rv;
  1.5377 +  SetScreenX(aScreenX, rv);
  1.5378 +
  1.5379 +  return rv.ErrorCode();
  1.5380 +}
  1.5381 +
  1.5382 +int32_t
  1.5383 +nsGlobalWindow::GetScreenY(ErrorResult& aError)
  1.5384 +{
  1.5385 +  FORWARD_TO_OUTER_OR_THROW(GetScreenY, (aError), aError, 0);
  1.5386 +
  1.5387 +  return DevToCSSIntPixels(GetScreenXY(aError).y);
  1.5388 +}
  1.5389 +
  1.5390 +NS_IMETHODIMP
  1.5391 +nsGlobalWindow::GetScreenY(int32_t* aScreenY)
  1.5392 +{
  1.5393 +  ErrorResult rv;
  1.5394 +  *aScreenY = GetScreenY(rv);
  1.5395 +
  1.5396 +  return rv.ErrorCode();
  1.5397 +}
  1.5398 +
  1.5399 +void
  1.5400 +nsGlobalWindow::SetScreenY(int32_t aScreenY, ErrorResult& aError)
  1.5401 +{
  1.5402 +  FORWARD_TO_OUTER_OR_THROW(SetScreenY, (aScreenY, aError), aError, );
  1.5403 +
  1.5404 +  /*
  1.5405 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.5406 +   * prevent setting window.screenY by exiting early
  1.5407 +   */
  1.5408 +
  1.5409 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.5410 +    return;
  1.5411 +  }
  1.5412 +
  1.5413 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.5414 +  if (!treeOwnerAsWin) {
  1.5415 +    aError.Throw(NS_ERROR_FAILURE);
  1.5416 +    return;
  1.5417 +  }
  1.5418 +
  1.5419 +  int32_t x, y;
  1.5420 +  aError = treeOwnerAsWin->GetPosition(&x, &y);
  1.5421 +  if (aError.Failed()) {
  1.5422 +    return;
  1.5423 +  }
  1.5424 +
  1.5425 +  CheckSecurityLeftAndTop(nullptr, &aScreenY);
  1.5426 +  y = CSSToDevIntPixels(aScreenY);
  1.5427 +
  1.5428 +  aError = treeOwnerAsWin->SetPosition(x, y);
  1.5429 +}
  1.5430 +
  1.5431 +NS_IMETHODIMP
  1.5432 +nsGlobalWindow::SetScreenY(int32_t aScreenY)
  1.5433 +{
  1.5434 +  ErrorResult rv;
  1.5435 +  SetScreenY(aScreenY, rv);
  1.5436 +
  1.5437 +  return rv.ErrorCode();
  1.5438 +}
  1.5439 +
  1.5440 +bool
  1.5441 +nsGlobalWindow::IsChrome() const
  1.5442 +{
  1.5443 +  bool isChrome = false;
  1.5444 +
  1.5445 +  if (mDocShell) {
  1.5446 +    nsRefPtr<nsPresContext> presContext;
  1.5447 +    mDocShell->GetPresContext(getter_AddRefs(presContext));
  1.5448 +    isChrome = (presContext && presContext->IsChrome());
  1.5449 +  }
  1.5450 +
  1.5451 +  return isChrome;
  1.5452 +}
  1.5453 +
  1.5454 +// NOTE: Arguments to this function should have values scaled to
  1.5455 +// CSS pixels, not device pixels.
  1.5456 +void
  1.5457 +nsGlobalWindow::CheckSecurityWidthAndHeight(int32_t* aWidth, int32_t* aHeight)
  1.5458 +{
  1.5459 +  MOZ_ASSERT(IsOuterWindow());
  1.5460 +
  1.5461 +#ifdef MOZ_XUL
  1.5462 +  if (!nsContentUtils::IsCallerChrome()) {
  1.5463 +    // if attempting to resize the window, hide any open popups
  1.5464 +    nsContentUtils::HidePopupsInDocument(mDoc);
  1.5465 +  }
  1.5466 +#endif
  1.5467 +
  1.5468 +  // This one is easy. Just ensure the variable is greater than 100;
  1.5469 +  if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
  1.5470 +    // Check security state for use in determing window dimensions
  1.5471 +
  1.5472 +    if (!nsContentUtils::IsCallerChrome()) {
  1.5473 +      //sec check failed
  1.5474 +      if (aWidth && *aWidth < 100) {
  1.5475 +        *aWidth = 100;
  1.5476 +      }
  1.5477 +      if (aHeight && *aHeight < 100) {
  1.5478 +        *aHeight = 100;
  1.5479 +      }
  1.5480 +    }
  1.5481 +  }
  1.5482 +}
  1.5483 +
  1.5484 +// NOTE: Arguments to this function should have values in device pixels
  1.5485 +nsresult
  1.5486 +nsGlobalWindow::SetDocShellWidthAndHeight(int32_t aInnerWidth, int32_t aInnerHeight)
  1.5487 +{
  1.5488 +  MOZ_ASSERT(IsOuterWindow());
  1.5489 +
  1.5490 +  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
  1.5491 +
  1.5492 +  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
  1.5493 +  mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
  1.5494 +  NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
  1.5495 +
  1.5496 +  NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(mDocShell, aInnerWidth, aInnerHeight),
  1.5497 +                    NS_ERROR_FAILURE);
  1.5498 +
  1.5499 +  return NS_OK;
  1.5500 +}
  1.5501 +
  1.5502 +// NOTE: Arguments to this function should have values in app units
  1.5503 +void
  1.5504 +nsGlobalWindow::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
  1.5505 +{
  1.5506 +  MOZ_ASSERT(IsOuterWindow());
  1.5507 +
  1.5508 +  nsRefPtr<nsPresContext> presContext;
  1.5509 +  mDocShell->GetPresContext(getter_AddRefs(presContext));
  1.5510 +
  1.5511 +  nsRect shellArea = presContext->GetVisibleArea();
  1.5512 +  shellArea.height = aInnerHeight;
  1.5513 +  shellArea.width = aInnerWidth;
  1.5514 +
  1.5515 +  presContext->SetVisibleArea(shellArea);
  1.5516 +}
  1.5517 +
  1.5518 +// NOTE: Arguments to this function should have values scaled to
  1.5519 +// CSS pixels, not device pixels.
  1.5520 +void
  1.5521 +nsGlobalWindow::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop)
  1.5522 +{
  1.5523 +  MOZ_ASSERT(IsOuterWindow());
  1.5524 +
  1.5525 +  // This one is harder. We have to get the screen size and window dimensions.
  1.5526 +
  1.5527 +  // Check security state for use in determing window dimensions
  1.5528 +
  1.5529 +  if (!nsContentUtils::IsCallerChrome()) {
  1.5530 +#ifdef MOZ_XUL
  1.5531 +    // if attempting to move the window, hide any open popups
  1.5532 +    nsContentUtils::HidePopupsInDocument(mDoc);
  1.5533 +#endif
  1.5534 +
  1.5535 +    nsGlobalWindow* rootWindow =
  1.5536 +      static_cast<nsGlobalWindow*>(GetPrivateRoot());
  1.5537 +    if (rootWindow) {
  1.5538 +      rootWindow->FlushPendingNotifications(Flush_Layout);
  1.5539 +    }
  1.5540 +
  1.5541 +    nsCOMPtr<nsIBaseWindow> treeOwner = GetTreeOwnerWindow();
  1.5542 +
  1.5543 +    nsCOMPtr<nsIDOMScreen> screen;
  1.5544 +    GetScreen(getter_AddRefs(screen));
  1.5545 +
  1.5546 +    if (treeOwner && screen) {
  1.5547 +      int32_t screenLeft, screenTop, screenWidth, screenHeight;
  1.5548 +      int32_t winLeft, winTop, winWidth, winHeight;
  1.5549 +
  1.5550 +      // Get the window size
  1.5551 +      treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
  1.5552 +
  1.5553 +      // convert those values to CSS pixels
  1.5554 +      // XXX four separate retrievals of the prescontext
  1.5555 +      winLeft   = DevToCSSIntPixels(winLeft);
  1.5556 +      winTop    = DevToCSSIntPixels(winTop);
  1.5557 +      winWidth  = DevToCSSIntPixels(winWidth);
  1.5558 +      winHeight = DevToCSSIntPixels(winHeight);
  1.5559 +
  1.5560 +      // Get the screen dimensions
  1.5561 +      // XXX This should use nsIScreenManager once it's fully fleshed out.
  1.5562 +      screen->GetAvailLeft(&screenLeft);
  1.5563 +      screen->GetAvailWidth(&screenWidth);
  1.5564 +      screen->GetAvailHeight(&screenHeight);
  1.5565 +#if defined(XP_MACOSX)
  1.5566 +      /* The mac's coordinate system is different from the assumed Windows'
  1.5567 +         system. It offsets by the height of the menubar so that a window
  1.5568 +         placed at (0,0) will be entirely visible. Unfortunately that
  1.5569 +         correction is made elsewhere (in Widget) and the meaning of
  1.5570 +         the Avail... coordinates is overloaded. Here we allow a window
  1.5571 +         to be placed at (0,0) because it does make sense to do so.
  1.5572 +      */
  1.5573 +      screen->GetTop(&screenTop);
  1.5574 +#else
  1.5575 +      screen->GetAvailTop(&screenTop);
  1.5576 +#endif
  1.5577 +
  1.5578 +      if (aLeft) {
  1.5579 +        if (screenLeft+screenWidth < *aLeft+winWidth)
  1.5580 +          *aLeft = screenLeft+screenWidth - winWidth;
  1.5581 +        if (screenLeft > *aLeft)
  1.5582 +          *aLeft = screenLeft;
  1.5583 +      }
  1.5584 +      if (aTop) {
  1.5585 +        if (screenTop+screenHeight < *aTop+winHeight)
  1.5586 +          *aTop = screenTop+screenHeight - winHeight;
  1.5587 +        if (screenTop > *aTop)
  1.5588 +          *aTop = screenTop;
  1.5589 +      }
  1.5590 +    } else {
  1.5591 +      if (aLeft)
  1.5592 +        *aLeft = 0;
  1.5593 +      if (aTop)
  1.5594 +        *aTop = 0;
  1.5595 +    }
  1.5596 +  }
  1.5597 +}
  1.5598 +
  1.5599 +NS_IMETHODIMP
  1.5600 +nsGlobalWindow::GetPageXOffset(int32_t* aPageXOffset)
  1.5601 +{
  1.5602 +  return GetScrollX(aPageXOffset);
  1.5603 +}
  1.5604 +
  1.5605 +NS_IMETHODIMP
  1.5606 +nsGlobalWindow::GetPageYOffset(int32_t* aPageYOffset)
  1.5607 +{
  1.5608 +  return GetScrollY(aPageYOffset);
  1.5609 +}
  1.5610 +
  1.5611 +void
  1.5612 +nsGlobalWindow::GetScrollMaxXY(int32_t* aScrollMaxX, int32_t* aScrollMaxY,
  1.5613 +                               ErrorResult& aError)
  1.5614 +{
  1.5615 +  FORWARD_TO_OUTER_OR_THROW(GetScrollMaxXY, (aScrollMaxX, aScrollMaxY, aError),
  1.5616 +                            aError, );
  1.5617 +
  1.5618 +  FlushPendingNotifications(Flush_Layout);
  1.5619 +  nsIScrollableFrame *sf = GetScrollFrame();
  1.5620 +  if (!sf) {
  1.5621 +    return;
  1.5622 +  }
  1.5623 +
  1.5624 +  nsRect scrollRange = sf->GetScrollRange();
  1.5625 +
  1.5626 +  if (aScrollMaxX) {
  1.5627 +    *aScrollMaxX = std::max(0,
  1.5628 +      (int32_t)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.XMost())));
  1.5629 +  }
  1.5630 +  if (aScrollMaxY) {
  1.5631 +    *aScrollMaxY = std::max(0,
  1.5632 +      (int32_t)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.YMost())));
  1.5633 +  }
  1.5634 +}
  1.5635 +
  1.5636 +int32_t
  1.5637 +nsGlobalWindow::GetScrollMaxX(ErrorResult& aError)
  1.5638 +{
  1.5639 +  int32_t scrollMaxX = 0;
  1.5640 +  GetScrollMaxXY(&scrollMaxX, nullptr, aError);
  1.5641 +  return scrollMaxX;
  1.5642 +}
  1.5643 +
  1.5644 +NS_IMETHODIMP
  1.5645 +nsGlobalWindow::GetScrollMaxX(int32_t* aScrollMaxX)
  1.5646 +{
  1.5647 +  NS_ENSURE_ARG_POINTER(aScrollMaxX);
  1.5648 +  ErrorResult rv;
  1.5649 +  *aScrollMaxX = GetScrollMaxX(rv);
  1.5650 +
  1.5651 +  return rv.ErrorCode();
  1.5652 +}
  1.5653 +
  1.5654 +int32_t
  1.5655 +nsGlobalWindow::GetScrollMaxY(ErrorResult& aError)
  1.5656 +{
  1.5657 +  int32_t scrollMaxY = 0;
  1.5658 +  GetScrollMaxXY(nullptr, &scrollMaxY, aError);
  1.5659 +  return scrollMaxY;
  1.5660 +}
  1.5661 +
  1.5662 +NS_IMETHODIMP
  1.5663 +nsGlobalWindow::GetScrollMaxY(int32_t* aScrollMaxY)
  1.5664 +{
  1.5665 +  NS_ENSURE_ARG_POINTER(aScrollMaxY);
  1.5666 +  ErrorResult rv;
  1.5667 +  *aScrollMaxY = GetScrollMaxY(rv);
  1.5668 +
  1.5669 +  return rv.ErrorCode();
  1.5670 +}
  1.5671 +
  1.5672 +CSSIntPoint
  1.5673 +nsGlobalWindow::GetScrollXY(bool aDoFlush, ErrorResult& aError)
  1.5674 +{
  1.5675 +  FORWARD_TO_OUTER_OR_THROW(GetScrollXY, (aDoFlush, aError), aError,
  1.5676 +                            CSSIntPoint(0, 0));
  1.5677 +
  1.5678 +  if (aDoFlush) {
  1.5679 +    FlushPendingNotifications(Flush_Layout);
  1.5680 +  } else {
  1.5681 +    EnsureSizeUpToDate();
  1.5682 +  }
  1.5683 +
  1.5684 +  nsIScrollableFrame *sf = GetScrollFrame();
  1.5685 +  if (!sf) {
  1.5686 +    return CSSIntPoint(0, 0);
  1.5687 +  }
  1.5688 +
  1.5689 +  nsPoint scrollPos = sf->GetScrollPosition();
  1.5690 +  if (scrollPos != nsPoint(0,0) && !aDoFlush) {
  1.5691 +    // Oh, well.  This is the expensive case -- the window is scrolled and we
  1.5692 +    // didn't actually flush yet.  Repeat, but with a flush, since the content
  1.5693 +    // may get shorter and hence our scroll position may decrease.
  1.5694 +    return GetScrollXY(true, aError);
  1.5695 +  }
  1.5696 +
  1.5697 +  return sf->GetScrollPositionCSSPixels();
  1.5698 +}
  1.5699 +
  1.5700 +int32_t
  1.5701 +nsGlobalWindow::GetScrollX(ErrorResult& aError)
  1.5702 +{
  1.5703 +  return GetScrollXY(false, aError).x;
  1.5704 +}
  1.5705 +
  1.5706 +NS_IMETHODIMP
  1.5707 +nsGlobalWindow::GetScrollX(int32_t* aScrollX)
  1.5708 +{
  1.5709 +  NS_ENSURE_ARG_POINTER(aScrollX);
  1.5710 +  ErrorResult rv;
  1.5711 +  *aScrollX = GetScrollXY(false, rv).x;
  1.5712 +  return rv.ErrorCode();
  1.5713 +}
  1.5714 +
  1.5715 +int32_t
  1.5716 +nsGlobalWindow::GetScrollY(ErrorResult& aError)
  1.5717 +{
  1.5718 +  return GetScrollXY(false, aError).y;
  1.5719 +}
  1.5720 +
  1.5721 +NS_IMETHODIMP
  1.5722 +nsGlobalWindow::GetScrollY(int32_t* aScrollY)
  1.5723 +{
  1.5724 +  NS_ENSURE_ARG_POINTER(aScrollY);
  1.5725 +  ErrorResult rv;
  1.5726 +  *aScrollY = GetScrollXY(false, rv).y;
  1.5727 +  return rv.ErrorCode();
  1.5728 +}
  1.5729 +
  1.5730 +uint32_t
  1.5731 +nsGlobalWindow::Length()
  1.5732 +{
  1.5733 +  FORWARD_TO_OUTER(Length, (), 0);
  1.5734 +
  1.5735 +  nsDOMWindowList* windows = GetWindowList();
  1.5736 +
  1.5737 +  return windows ? windows->GetLength() : 0;
  1.5738 +}
  1.5739 +
  1.5740 +NS_IMETHODIMP
  1.5741 +nsGlobalWindow::GetLength(uint32_t* aLength)
  1.5742 +{
  1.5743 +  *aLength = Length();
  1.5744 +  return NS_OK;
  1.5745 +}
  1.5746 +
  1.5747 +already_AddRefed<nsIDOMWindow>
  1.5748 +nsGlobalWindow::GetChildWindow(const nsAString& aName)
  1.5749 +{
  1.5750 +  nsCOMPtr<nsIDocShell> docShell(GetDocShell());
  1.5751 +  NS_ENSURE_TRUE(docShell, nullptr);
  1.5752 +
  1.5753 +  nsCOMPtr<nsIDocShellTreeItem> child;
  1.5754 +  docShell->FindChildWithName(PromiseFlatString(aName).get(),
  1.5755 +                              false, true, nullptr, nullptr,
  1.5756 +                              getter_AddRefs(child));
  1.5757 +
  1.5758 +  nsCOMPtr<nsIDOMWindow> child_win(do_GetInterface(child));
  1.5759 +  return child_win.forget();
  1.5760 +}
  1.5761 +
  1.5762 +bool
  1.5763 +nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
  1.5764 +{
  1.5765 +  bool defaultActionEnabled = true;
  1.5766 +  nsContentUtils::DispatchTrustedEvent(mDoc,
  1.5767 +                                       GetOuterWindow(),
  1.5768 +                                       NS_ConvertASCIItoUTF16(aEventName),
  1.5769 +                                       true, true, &defaultActionEnabled);
  1.5770 +
  1.5771 +  return defaultActionEnabled;
  1.5772 +}
  1.5773 +
  1.5774 +// NOTE: Arguments to this function should be CSS pixels, not device pixels.
  1.5775 +bool
  1.5776 +nsGlobalWindow::DispatchResizeEvent(const nsIntSize& aSize)
  1.5777 +{
  1.5778 +  ErrorResult res;
  1.5779 +  nsRefPtr<Event> domEvent =
  1.5780 +    mDoc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), res);
  1.5781 +  if (res.Failed()) {
  1.5782 +    return false;
  1.5783 +  }
  1.5784 +
  1.5785 +  AutoSafeJSContext cx;
  1.5786 +  JSAutoCompartment ac(cx, GetWrapperPreserveColor());
  1.5787 +  DOMWindowResizeEventDetail detail;
  1.5788 +  detail.mWidth = aSize.width;
  1.5789 +  detail.mHeight = aSize.height;
  1.5790 +  JS::Rooted<JS::Value> detailValue(cx);
  1.5791 +  if (!detail.ToObject(cx, &detailValue)) {
  1.5792 +    return false;
  1.5793 +  }
  1.5794 +
  1.5795 +  CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
  1.5796 +  customEvent->InitCustomEvent(cx,
  1.5797 +                               NS_LITERAL_STRING("DOMWindowResize"),
  1.5798 +                               /* bubbles = */ true,
  1.5799 +                               /* cancelable = */ true,
  1.5800 +                               detailValue,
  1.5801 +                               res);
  1.5802 +  if (res.Failed()) {
  1.5803 +    return false;
  1.5804 +  }
  1.5805 +
  1.5806 +  domEvent->SetTrusted(true);
  1.5807 +  domEvent->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
  1.5808 +
  1.5809 +  nsCOMPtr<EventTarget> target = do_QueryInterface(GetOuterWindow());
  1.5810 +  domEvent->SetTarget(target);
  1.5811 +
  1.5812 +  bool defaultActionEnabled = true;
  1.5813 +  target->DispatchEvent(domEvent, &defaultActionEnabled);
  1.5814 +
  1.5815 +  return defaultActionEnabled;
  1.5816 +}
  1.5817 +
  1.5818 +void
  1.5819 +nsGlobalWindow::RefreshCompartmentPrincipal()
  1.5820 +{
  1.5821 +  FORWARD_TO_INNER(RefreshCompartmentPrincipal, (), /* void */ );
  1.5822 +
  1.5823 +  JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),
  1.5824 +                              nsJSPrincipals::get(mDoc->NodePrincipal()));
  1.5825 +}
  1.5826 +
  1.5827 +static already_AddRefed<nsIDocShellTreeItem>
  1.5828 +GetCallerDocShellTreeItem()
  1.5829 +{
  1.5830 +  JSContext *cx = nsContentUtils::GetCurrentJSContext();
  1.5831 +  nsCOMPtr<nsIDocShellTreeItem> callerItem;
  1.5832 +
  1.5833 +  if (cx) {
  1.5834 +    nsCOMPtr<nsIWebNavigation> callerWebNav =
  1.5835 +      do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
  1.5836 +
  1.5837 +    callerItem = do_QueryInterface(callerWebNav);
  1.5838 +  }
  1.5839 +
  1.5840 +  return callerItem.forget();
  1.5841 +}
  1.5842 +
  1.5843 +bool
  1.5844 +nsGlobalWindow::WindowExists(const nsAString& aName,
  1.5845 +                             bool aLookForCallerOnJSStack)
  1.5846 +{
  1.5847 +  NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
  1.5848 +  NS_PRECONDITION(mDocShell, "Must have docshell");
  1.5849 +
  1.5850 +  nsCOMPtr<nsIDocShellTreeItem> caller;
  1.5851 +  if (aLookForCallerOnJSStack) {
  1.5852 +    caller = GetCallerDocShellTreeItem();
  1.5853 +  }
  1.5854 +
  1.5855 +  if (!caller) {
  1.5856 +    caller = mDocShell;
  1.5857 +  }
  1.5858 +
  1.5859 +  nsCOMPtr<nsIDocShellTreeItem> namedItem;
  1.5860 +  mDocShell->FindItemWithName(PromiseFlatString(aName).get(), nullptr, caller,
  1.5861 +                              getter_AddRefs(namedItem));
  1.5862 +  return namedItem != nullptr;
  1.5863 +}
  1.5864 +
  1.5865 +already_AddRefed<nsIWidget>
  1.5866 +nsGlobalWindow::GetMainWidget()
  1.5867 +{
  1.5868 +  FORWARD_TO_OUTER(GetMainWidget, (), nullptr);
  1.5869 +
  1.5870 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.5871 +
  1.5872 +  nsCOMPtr<nsIWidget> widget;
  1.5873 +
  1.5874 +  if (treeOwnerAsWin) {
  1.5875 +    treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
  1.5876 +  }
  1.5877 +
  1.5878 +  return widget.forget();
  1.5879 +}
  1.5880 +
  1.5881 +nsIWidget*
  1.5882 +nsGlobalWindow::GetNearestWidget()
  1.5883 +{
  1.5884 +  nsIDocShell* docShell = GetDocShell();
  1.5885 +  NS_ENSURE_TRUE(docShell, nullptr);
  1.5886 +  nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
  1.5887 +  NS_ENSURE_TRUE(presShell, nullptr);
  1.5888 +  nsIFrame* rootFrame = presShell->GetRootFrame();
  1.5889 +  NS_ENSURE_TRUE(rootFrame, nullptr);
  1.5890 +  return rootFrame->GetView()->GetNearestWidget(nullptr);
  1.5891 +}
  1.5892 +
  1.5893 +void
  1.5894 +nsGlobalWindow::SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError)
  1.5895 +{
  1.5896 +  aError = SetFullScreenInternal(aFullScreen, true);
  1.5897 +}
  1.5898 +
  1.5899 +NS_IMETHODIMP
  1.5900 +nsGlobalWindow::SetFullScreen(bool aFullScreen)
  1.5901 +{
  1.5902 +  return SetFullScreenInternal(aFullScreen, true);
  1.5903 +}
  1.5904 +
  1.5905 +nsresult
  1.5906 +nsGlobalWindow::SetFullScreenInternal(bool aFullScreen, bool aRequireTrust)
  1.5907 +{
  1.5908 +  FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
  1.5909 +
  1.5910 +  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
  1.5911 +
  1.5912 +  bool rootWinFullScreen;
  1.5913 +  GetFullScreen(&rootWinFullScreen);
  1.5914 +  // Only chrome can change our fullScreen mode, unless we're running in
  1.5915 +  // untrusted mode.
  1.5916 +  if (aFullScreen == rootWinFullScreen ||
  1.5917 +      (aRequireTrust && !nsContentUtils::IsCallerChrome())) {
  1.5918 +    return NS_OK;
  1.5919 +  }
  1.5920 +
  1.5921 +  // SetFullScreen needs to be called on the root window, so get that
  1.5922 +  // via the DocShell tree, and if we are not already the root,
  1.5923 +  // call SetFullScreen on that window instead.
  1.5924 +  nsCOMPtr<nsIDocShellTreeItem> rootItem;
  1.5925 +  mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
  1.5926 +  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(rootItem);
  1.5927 +  if (!window)
  1.5928 +    return NS_ERROR_FAILURE;
  1.5929 +  if (rootItem != mDocShell)
  1.5930 +    return window->SetFullScreenInternal(aFullScreen, aRequireTrust);
  1.5931 +
  1.5932 +  // make sure we don't try to set full screen on a non-chrome window,
  1.5933 +  // which might happen in embedding world
  1.5934 +  if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
  1.5935 +    return NS_ERROR_FAILURE;
  1.5936 +
  1.5937 +  // If we are already in full screen mode, just return.
  1.5938 +  if (mFullScreen == aFullScreen)
  1.5939 +    return NS_OK;
  1.5940 +
  1.5941 +  // dispatch a "fullscreen" DOM event so that XUL apps can
  1.5942 +  // respond visually if we are kicked into full screen mode
  1.5943 +  if (!DispatchCustomEvent("fullscreen")) {
  1.5944 +    return NS_OK;
  1.5945 +  }
  1.5946 +
  1.5947 +  // Prevent chrome documents which are still loading from resizing
  1.5948 +  // the window after we set fullscreen mode.
  1.5949 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.5950 +  nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
  1.5951 +  if (aFullScreen && xulWin) {
  1.5952 +    xulWin->SetIntrinsicallySized(false);
  1.5953 +  }
  1.5954 +
  1.5955 +  // Set this before so if widget sends an event indicating its
  1.5956 +  // gone full screen, the state trap above works.
  1.5957 +  mFullScreen = aFullScreen;
  1.5958 +
  1.5959 +  // Sometimes we don't want the top-level widget to actually go fullscreen,
  1.5960 +  // for example in the B2G desktop client, we don't want the emulated screen
  1.5961 +  // dimensions to appear to increase when entering fullscreen mode; we just
  1.5962 +  // want the content to fill the entire client area of the emulator window.
  1.5963 +  if (!Preferences::GetBool("full-screen-api.ignore-widgets", false)) {
  1.5964 +    nsCOMPtr<nsIWidget> widget = GetMainWidget();
  1.5965 +    if (widget)
  1.5966 +      widget->MakeFullScreen(aFullScreen);
  1.5967 +  }
  1.5968 +
  1.5969 +  if (!mFullScreen) {
  1.5970 +    // Force exit from DOM full-screen mode. This is so that if we're in
  1.5971 +    // DOM full-screen mode and the user exits full-screen mode with
  1.5972 +    // the browser full-screen mode toggle keyboard-shortcut, we'll detect
  1.5973 +    // that and leave DOM API full-screen mode too.
  1.5974 +    nsIDocument::ExitFullscreen(mDoc, /* async */ false);
  1.5975 +  }
  1.5976 +
  1.5977 +  if (!mWakeLock && mFullScreen) {
  1.5978 +    nsRefPtr<power::PowerManagerService> pmService =
  1.5979 +      power::PowerManagerService::GetInstance();
  1.5980 +    NS_ENSURE_TRUE(pmService, NS_OK);
  1.5981 +
  1.5982 +    ErrorResult rv;
  1.5983 +    mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"),
  1.5984 +                                       this, rv);
  1.5985 +    if (rv.Failed()) {
  1.5986 +      return rv.ErrorCode();
  1.5987 +    }
  1.5988 +
  1.5989 +  } else if (mWakeLock && !mFullScreen) {
  1.5990 +    ErrorResult rv;
  1.5991 +    mWakeLock->Unlock(rv);
  1.5992 +    NS_WARN_IF_FALSE(!rv.Failed(), "Failed to unlock the wakelock.");
  1.5993 +    mWakeLock = nullptr;
  1.5994 +  }
  1.5995 +
  1.5996 +  return NS_OK;
  1.5997 +}
  1.5998 +
  1.5999 +bool
  1.6000 +nsGlobalWindow::GetFullScreen(ErrorResult& aError)
  1.6001 +{
  1.6002 +  FORWARD_TO_OUTER_OR_THROW(GetFullScreen, (aError), aError, false);
  1.6003 +
  1.6004 +  // Get the fullscreen value of the root window, to always have the value
  1.6005 +  // accurate, even when called from content.
  1.6006 +  if (mDocShell) {
  1.6007 +    nsCOMPtr<nsIDocShellTreeItem> rootItem;
  1.6008 +    mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
  1.6009 +    if (rootItem != mDocShell) {
  1.6010 +      nsCOMPtr<nsIDOMWindow> window = do_GetInterface(rootItem);
  1.6011 +      if (window) {
  1.6012 +        bool fullScreen = false;
  1.6013 +        aError = window->GetFullScreen(&fullScreen);
  1.6014 +        return fullScreen;
  1.6015 +      }
  1.6016 +    }
  1.6017 +  }
  1.6018 +
  1.6019 +  // We are the root window, or something went wrong. Return our internal value.
  1.6020 +  return mFullScreen;
  1.6021 +}
  1.6022 +
  1.6023 +NS_IMETHODIMP
  1.6024 +nsGlobalWindow::GetFullScreen(bool* aFullScreen)
  1.6025 +{
  1.6026 +  ErrorResult rv;
  1.6027 +  *aFullScreen = GetFullScreen(rv);
  1.6028 +
  1.6029 +  return rv.ErrorCode();
  1.6030 +}
  1.6031 +
  1.6032 +NS_IMETHODIMP
  1.6033 +nsGlobalWindow::Dump(const nsAString& aStr)
  1.6034 +{
  1.6035 +  if (!nsContentUtils::DOMWindowDumpEnabled()) {
  1.6036 +    return NS_OK;
  1.6037 +  }
  1.6038 +
  1.6039 +  char *cstr = ToNewUTF8String(aStr);
  1.6040 +
  1.6041 +#if defined(XP_MACOSX)
  1.6042 +  // have to convert \r to \n so that printing to the console works
  1.6043 +  char *c = cstr, *cEnd = cstr + strlen(cstr);
  1.6044 +  while (c < cEnd) {
  1.6045 +    if (*c == '\r')
  1.6046 +      *c = '\n';
  1.6047 +    c++;
  1.6048 +  }
  1.6049 +#endif
  1.6050 +
  1.6051 +  if (cstr) {
  1.6052 +#ifdef XP_WIN
  1.6053 +    PrintToDebugger(cstr);
  1.6054 +#endif
  1.6055 +#ifdef ANDROID
  1.6056 +    __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
  1.6057 +#endif
  1.6058 +    FILE *fp = gDumpFile ? gDumpFile : stdout;
  1.6059 +    fputs(cstr, fp);
  1.6060 +    fflush(fp);
  1.6061 +    nsMemory::Free(cstr);
  1.6062 +  }
  1.6063 +
  1.6064 +  return NS_OK;
  1.6065 +}
  1.6066 +
  1.6067 +void
  1.6068 +nsGlobalWindow::EnsureReflowFlushAndPaint()
  1.6069 +{
  1.6070 +  MOZ_ASSERT(IsOuterWindow());
  1.6071 +  NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
  1.6072 +               "docshell!");
  1.6073 +
  1.6074 +  if (!mDocShell)
  1.6075 +    return;
  1.6076 +
  1.6077 +  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  1.6078 +
  1.6079 +  if (!presShell)
  1.6080 +    return;
  1.6081 +
  1.6082 +  // Flush pending reflows.
  1.6083 +  if (mDoc) {
  1.6084 +    mDoc->FlushPendingNotifications(Flush_Layout);
  1.6085 +  }
  1.6086 +
  1.6087 +  // Unsuppress painting.
  1.6088 +  presShell->UnsuppressPainting();
  1.6089 +}
  1.6090 +
  1.6091 +NS_IMETHODIMP
  1.6092 +nsGlobalWindow::GetTextZoom(float *aZoom)
  1.6093 +{
  1.6094 +  FORWARD_TO_OUTER(GetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
  1.6095 +
  1.6096 +  if (mDocShell) {
  1.6097 +    nsCOMPtr<nsIContentViewer> contentViewer;
  1.6098 +    mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
  1.6099 +    nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
  1.6100 +
  1.6101 +    if (markupViewer) {
  1.6102 +      return markupViewer->GetTextZoom(aZoom);
  1.6103 +    }
  1.6104 +  }
  1.6105 +  return NS_ERROR_FAILURE;
  1.6106 +}
  1.6107 +
  1.6108 +NS_IMETHODIMP
  1.6109 +nsGlobalWindow::SetTextZoom(float aZoom)
  1.6110 +{
  1.6111 +  FORWARD_TO_OUTER(SetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
  1.6112 +
  1.6113 +  if (mDocShell) {
  1.6114 +    nsCOMPtr<nsIContentViewer> contentViewer;
  1.6115 +    mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
  1.6116 +    nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
  1.6117 +
  1.6118 +    if (markupViewer)
  1.6119 +      return markupViewer->SetTextZoom(aZoom);
  1.6120 +  }
  1.6121 +  return NS_ERROR_FAILURE;
  1.6122 +}
  1.6123 +
  1.6124 +// static
  1.6125 +void
  1.6126 +nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
  1.6127 +{
  1.6128 +  aOutTitle.Truncate();
  1.6129 +
  1.6130 +  // Try to get a host from the running principal -- this will do the
  1.6131 +  // right thing for javascript: and data: documents.
  1.6132 +
  1.6133 +  nsresult rv = NS_OK;
  1.6134 +  NS_ASSERTION(nsContentUtils::GetSecurityManager(),
  1.6135 +    "Global Window has no security manager!");
  1.6136 +  if (nsContentUtils::GetSecurityManager()) {
  1.6137 +    nsCOMPtr<nsIPrincipal> principal;
  1.6138 +    rv = nsContentUtils::GetSecurityManager()->
  1.6139 +      GetSubjectPrincipal(getter_AddRefs(principal));
  1.6140 +
  1.6141 +    if (NS_SUCCEEDED(rv) && principal) {
  1.6142 +      nsCOMPtr<nsIURI> uri;
  1.6143 +      rv = principal->GetURI(getter_AddRefs(uri));
  1.6144 +
  1.6145 +      if (NS_SUCCEEDED(rv) && uri) {
  1.6146 +        // remove user:pass for privacy and spoof prevention
  1.6147 +
  1.6148 +        nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
  1.6149 +        if (fixup) {
  1.6150 +          nsCOMPtr<nsIURI> fixedURI;
  1.6151 +          rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
  1.6152 +          if (NS_SUCCEEDED(rv) && fixedURI) {
  1.6153 +            nsAutoCString host;
  1.6154 +            fixedURI->GetHost(host);
  1.6155 +
  1.6156 +            if (!host.IsEmpty()) {
  1.6157 +              // if this URI has a host we'll show it. For other
  1.6158 +              // schemes (e.g. file:) we fall back to the localized
  1.6159 +              // generic string
  1.6160 +
  1.6161 +              nsAutoCString prepath;
  1.6162 +              fixedURI->GetPrePath(prepath);
  1.6163 +
  1.6164 +              NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
  1.6165 +              const char16_t *formatStrings[] = { ucsPrePath.get() };
  1.6166 +              nsXPIDLString tempString;
  1.6167 +              nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  1.6168 +                                                    "ScriptDlgHeading",
  1.6169 +                                                    formatStrings,
  1.6170 +                                                    tempString);
  1.6171 +              aOutTitle = tempString;
  1.6172 +            }
  1.6173 +          }
  1.6174 +        }
  1.6175 +      }
  1.6176 +    }
  1.6177 +    else { // failed to get subject principal
  1.6178 +      NS_WARNING("No script principal? Who is calling alert/confirm/prompt?!");
  1.6179 +    }
  1.6180 +  }
  1.6181 +
  1.6182 +  if (aOutTitle.IsEmpty()) {
  1.6183 +    // We didn't find a host so use the generic heading
  1.6184 +    nsXPIDLString tempString;
  1.6185 +    nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  1.6186 +                                       "ScriptDlgGenericHeading",
  1.6187 +                                       tempString);
  1.6188 +    aOutTitle = tempString;
  1.6189 +  }
  1.6190 +
  1.6191 +  // Just in case
  1.6192 +  if (aOutTitle.IsEmpty()) {
  1.6193 +    NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
  1.6194 +    aOutTitle.AssignLiteral("[Script]");
  1.6195 +  }
  1.6196 +}
  1.6197 +
  1.6198 +bool
  1.6199 +nsGlobalWindow::CanMoveResizeWindows()
  1.6200 +{
  1.6201 +  MOZ_ASSERT(IsOuterWindow());
  1.6202 +
  1.6203 +  // When called from chrome, we can avoid the following checks.
  1.6204 +  if (!nsContentUtils::IsCallerChrome()) {
  1.6205 +    // Don't allow scripts to move or resize windows that were not opened by a
  1.6206 +    // script.
  1.6207 +    if (!mHadOriginalOpener) {
  1.6208 +      return false;
  1.6209 +    }
  1.6210 +
  1.6211 +    if (!CanSetProperty("dom.disable_window_move_resize")) {
  1.6212 +      return false;
  1.6213 +    }
  1.6214 +
  1.6215 +    // Ignore the request if we have more than one tab in the window.
  1.6216 +    nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  1.6217 +    if (treeOwner) {
  1.6218 +      uint32_t itemCount;
  1.6219 +      if (NS_SUCCEEDED(treeOwner->GetTargetableShellCount(&itemCount)) &&
  1.6220 +          itemCount > 1) {
  1.6221 +        return false;
  1.6222 +      }
  1.6223 +    }
  1.6224 +  }
  1.6225 +
  1.6226 +  // The preference is useful for the webapp runtime. Webapps should be able
  1.6227 +  // to resize or move their window.
  1.6228 +  if (mDocShell && !Preferences::GetBool("dom.always_allow_move_resize_window",
  1.6229 +                                         false)) {
  1.6230 +    bool allow;
  1.6231 +    nsresult rv = mDocShell->GetAllowWindowControl(&allow);
  1.6232 +    if (NS_SUCCEEDED(rv) && !allow)
  1.6233 +      return false;
  1.6234 +  }
  1.6235 +
  1.6236 +  if (gMouseDown && !gDragServiceDisabled) {
  1.6237 +    nsCOMPtr<nsIDragService> ds =
  1.6238 +      do_GetService("@mozilla.org/widget/dragservice;1");
  1.6239 +    if (ds) {
  1.6240 +      gDragServiceDisabled = true;
  1.6241 +      ds->Suppress();
  1.6242 +    }
  1.6243 +  }
  1.6244 +  return true;
  1.6245 +}
  1.6246 +
  1.6247 +bool
  1.6248 +nsGlobalWindow::AlertOrConfirm(bool aAlert,
  1.6249 +                               const nsAString& aMessage,
  1.6250 +                               mozilla::ErrorResult& aError)
  1.6251 +{
  1.6252 +  // XXX This method is very similar to nsGlobalWindow::Prompt, make
  1.6253 +  // sure any modifications here don't need to happen over there!
  1.6254 +  MOZ_ASSERT(IsOuterWindow());
  1.6255 +
  1.6256 +  if (!AreDialogsEnabled()) {
  1.6257 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.6258 +    return false;
  1.6259 +  }
  1.6260 +
  1.6261 +  // Reset popup state while opening a modal dialog, and firing events
  1.6262 +  // about the dialog, to prevent the current state from being active
  1.6263 +  // the whole time a modal dialog is open.
  1.6264 +  nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  1.6265 +
  1.6266 +  // Before bringing up the window, unsuppress painting and flush
  1.6267 +  // pending reflows.
  1.6268 +  EnsureReflowFlushAndPaint();
  1.6269 +
  1.6270 +  nsAutoString title;
  1.6271 +  MakeScriptDialogTitle(title);
  1.6272 +
  1.6273 +  // Remove non-terminating null characters from the 
  1.6274 +  // string. See bug #310037. 
  1.6275 +  nsAutoString final;
  1.6276 +  nsContentUtils::StripNullChars(aMessage, final);
  1.6277 +
  1.6278 +  nsresult rv;
  1.6279 +  nsCOMPtr<nsIPromptFactory> promptFac =
  1.6280 +    do_GetService("@mozilla.org/prompter;1", &rv);
  1.6281 +  if (NS_FAILED(rv)) {
  1.6282 +    aError.Throw(rv);
  1.6283 +    return false;
  1.6284 +  }
  1.6285 +
  1.6286 +  nsCOMPtr<nsIPrompt> prompt;
  1.6287 +  aError = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
  1.6288 +                                getter_AddRefs(prompt));
  1.6289 +  if (aError.Failed()) {
  1.6290 +    return false;
  1.6291 +  }
  1.6292 +
  1.6293 +  // Always allow tab modal prompts for alert and confirm.
  1.6294 +  if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
  1.6295 +    promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
  1.6296 +  }
  1.6297 +
  1.6298 +  bool result = false;
  1.6299 +  nsAutoSyncOperation sync(mDoc);
  1.6300 +  if (ShouldPromptToBlockDialogs()) {
  1.6301 +    bool disallowDialog = false;
  1.6302 +    nsXPIDLString label;
  1.6303 +    nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  1.6304 +                                       "ScriptDialogLabel", label);
  1.6305 +
  1.6306 +    aError = aAlert ?
  1.6307 +               prompt->AlertCheck(title.get(), final.get(), label.get(),
  1.6308 +                                  &disallowDialog) :
  1.6309 +               prompt->ConfirmCheck(title.get(), final.get(), label.get(),
  1.6310 +                                    &disallowDialog, &result);
  1.6311 +
  1.6312 +    if (disallowDialog)
  1.6313 +      DisableDialogs();
  1.6314 +  } else {
  1.6315 +    aError = aAlert ?
  1.6316 +               prompt->Alert(title.get(), final.get()) :
  1.6317 +               prompt->Confirm(title.get(), final.get(), &result);
  1.6318 +  }
  1.6319 +
  1.6320 +  return result;
  1.6321 +}
  1.6322 +
  1.6323 +void
  1.6324 +nsGlobalWindow::Alert(const nsAString& aMessage, mozilla::ErrorResult& aError)
  1.6325 +{
  1.6326 +  FORWARD_TO_OUTER_OR_THROW(Alert, (aMessage, aError), aError, );
  1.6327 +  AlertOrConfirm(/* aAlert = */ true, aMessage, aError);
  1.6328 +}
  1.6329 +
  1.6330 +NS_IMETHODIMP
  1.6331 +nsGlobalWindow::Alert(const nsAString& aString)
  1.6332 +{
  1.6333 +  ErrorResult rv;
  1.6334 +  Alert(aString, rv);
  1.6335 +
  1.6336 +  return rv.ErrorCode();
  1.6337 +}
  1.6338 +
  1.6339 +bool
  1.6340 +nsGlobalWindow::Confirm(const nsAString& aMessage, ErrorResult& aError)
  1.6341 +{
  1.6342 +  FORWARD_TO_OUTER_OR_THROW(Confirm, (aMessage, aError), aError, false);
  1.6343 +
  1.6344 +  return AlertOrConfirm(/* aAlert = */ false, aMessage, aError);
  1.6345 +}
  1.6346 +
  1.6347 +NS_IMETHODIMP
  1.6348 +nsGlobalWindow::Confirm(const nsAString& aString, bool* aReturn)
  1.6349 +{
  1.6350 +  ErrorResult rv;
  1.6351 +  *aReturn = Confirm(aString, rv);
  1.6352 +
  1.6353 +  return rv.ErrorCode();
  1.6354 +}
  1.6355 +
  1.6356 +void
  1.6357 +nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
  1.6358 +                       nsAString& aReturn, ErrorResult& aError)
  1.6359 +{
  1.6360 +  // XXX This method is very similar to nsGlobalWindow::AlertOrConfirm, make
  1.6361 +  // sure any modifications here don't need to happen over there!
  1.6362 +  FORWARD_TO_OUTER_OR_THROW(Prompt, (aMessage, aInitial, aReturn, aError),
  1.6363 +                            aError, );
  1.6364 +
  1.6365 +  SetDOMStringToNull(aReturn);
  1.6366 +
  1.6367 +  if (!AreDialogsEnabled()) {
  1.6368 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.6369 +    return;
  1.6370 +  }
  1.6371 +
  1.6372 +  // Reset popup state while opening a modal dialog, and firing events
  1.6373 +  // about the dialog, to prevent the current state from being active
  1.6374 +  // the whole time a modal dialog is open.
  1.6375 +  nsAutoPopupStatePusher popupStatePusher(openAbused, true);
  1.6376 +
  1.6377 +  // Before bringing up the window, unsuppress painting and flush
  1.6378 +  // pending reflows.
  1.6379 +  EnsureReflowFlushAndPaint();
  1.6380 +
  1.6381 +  nsAutoString title;
  1.6382 +  MakeScriptDialogTitle(title);
  1.6383 +  
  1.6384 +  // Remove non-terminating null characters from the 
  1.6385 +  // string. See bug #310037. 
  1.6386 +  nsAutoString fixedMessage, fixedInitial;
  1.6387 +  nsContentUtils::StripNullChars(aMessage, fixedMessage);
  1.6388 +  nsContentUtils::StripNullChars(aInitial, fixedInitial);
  1.6389 +
  1.6390 +  nsresult rv;
  1.6391 +  nsCOMPtr<nsIPromptFactory> promptFac =
  1.6392 +    do_GetService("@mozilla.org/prompter;1", &rv);
  1.6393 +  if (NS_FAILED(rv)) {
  1.6394 +    aError.Throw(rv);
  1.6395 +    return;
  1.6396 +  }
  1.6397 +
  1.6398 +  nsCOMPtr<nsIPrompt> prompt;
  1.6399 +  aError = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
  1.6400 +                                getter_AddRefs(prompt));
  1.6401 +  if (aError.Failed()) {
  1.6402 +    return;
  1.6403 +  }
  1.6404 +
  1.6405 +  // Always allow tab modal prompts for prompt.
  1.6406 +  if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
  1.6407 +    promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
  1.6408 +  }
  1.6409 +
  1.6410 +  // Pass in the default value, if any.
  1.6411 +  char16_t *inoutValue = ToNewUnicode(fixedInitial);
  1.6412 +  bool disallowDialog = false;
  1.6413 +
  1.6414 +  nsXPIDLString label;
  1.6415 +  if (ShouldPromptToBlockDialogs()) {
  1.6416 +    nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
  1.6417 +                                       "ScriptDialogLabel", label);
  1.6418 +  }
  1.6419 +
  1.6420 +  nsAutoSyncOperation sync(mDoc);
  1.6421 +  bool ok;
  1.6422 +  aError = prompt->Prompt(title.get(), fixedMessage.get(),
  1.6423 +                          &inoutValue, label.get(), &disallowDialog, &ok);
  1.6424 +
  1.6425 +  if (disallowDialog) {
  1.6426 +    DisableDialogs();
  1.6427 +  }
  1.6428 +
  1.6429 +  if (aError.Failed()) {
  1.6430 +    return;
  1.6431 +  }
  1.6432 +
  1.6433 +  nsAdoptingString outValue(inoutValue);
  1.6434 +
  1.6435 +  if (ok && outValue) {
  1.6436 +    aReturn.Assign(outValue);
  1.6437 +  }
  1.6438 +}
  1.6439 +
  1.6440 +NS_IMETHODIMP
  1.6441 +nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
  1.6442 +                       nsAString& aReturn)
  1.6443 +{
  1.6444 +  ErrorResult rv;
  1.6445 +  Prompt(aMessage, aInitial, aReturn, rv);
  1.6446 +
  1.6447 +  return rv.ErrorCode();
  1.6448 +}
  1.6449 +
  1.6450 +void
  1.6451 +nsGlobalWindow::Focus(ErrorResult& aError)
  1.6452 +{
  1.6453 +  FORWARD_TO_OUTER_OR_THROW(Focus, (aError), aError, );
  1.6454 +
  1.6455 +  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.6456 +  if (!fm) {
  1.6457 +    return;
  1.6458 +  }
  1.6459 +
  1.6460 +  nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
  1.6461 +
  1.6462 +  bool isVisible = false;
  1.6463 +  if (baseWin) {
  1.6464 +    baseWin->GetVisibility(&isVisible);
  1.6465 +  }
  1.6466 +
  1.6467 +  if (!isVisible) {
  1.6468 +    // A hidden tab is being focused, ignore this call.
  1.6469 +    return;
  1.6470 +  }
  1.6471 +
  1.6472 +  nsIDOMWindow *caller = nsContentUtils::GetWindowFromCaller();
  1.6473 +  nsCOMPtr<nsIDOMWindow> opener;
  1.6474 +  GetOpener(getter_AddRefs(opener));
  1.6475 +
  1.6476 +  // Enforce dom.disable_window_flip (for non-chrome), but still allow the
  1.6477 +  // window which opened us to raise us at times when popups are allowed
  1.6478 +  // (bugs 355482 and 369306).
  1.6479 +  bool canFocus = CanSetProperty("dom.disable_window_flip") ||
  1.6480 +                    (opener == caller &&
  1.6481 +                     RevisePopupAbuseLevel(gPopupControlState) < openAbused);
  1.6482 +
  1.6483 +  nsCOMPtr<nsIDOMWindow> activeWindow;
  1.6484 +  fm->GetActiveWindow(getter_AddRefs(activeWindow));
  1.6485 +
  1.6486 +  nsCOMPtr<nsIDocShellTreeItem> rootItem;
  1.6487 +  mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
  1.6488 +  nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
  1.6489 +  bool isActive = (rootWin == activeWindow);
  1.6490 +
  1.6491 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.6492 +  if (treeOwnerAsWin && (canFocus || isActive)) {
  1.6493 +    bool isEnabled = true;
  1.6494 +    if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
  1.6495 +      NS_WARNING( "Should not try to set the focus on a disabled window" );
  1.6496 +      return;
  1.6497 +    }
  1.6498 +
  1.6499 +    // XXXndeakin not sure what this is for or if it should go somewhere else
  1.6500 +    nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
  1.6501 +    if (embeddingWin)
  1.6502 +      embeddingWin->SetFocus();
  1.6503 +  }
  1.6504 +
  1.6505 +  if (!mDocShell) {
  1.6506 +    return;
  1.6507 +  }
  1.6508 +
  1.6509 +  nsCOMPtr<nsIPresShell> presShell;
  1.6510 +  // Don't look for a presshell if we're a root chrome window that's got
  1.6511 +  // about:blank loaded.  We don't want to focus our widget in that case.
  1.6512 +  // XXXbz should we really be checking for IsInitialDocument() instead?
  1.6513 +  bool lookForPresShell = true;
  1.6514 +  if (mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome &&
  1.6515 +      GetPrivateRoot() == static_cast<nsIDOMWindow*>(this) &&
  1.6516 +      mDoc) {
  1.6517 +    nsIURI* ourURI = mDoc->GetDocumentURI();
  1.6518 +    if (ourURI) {
  1.6519 +      lookForPresShell = !NS_IsAboutBlank(ourURI);
  1.6520 +    }
  1.6521 +  }
  1.6522 +
  1.6523 +  if (lookForPresShell) {
  1.6524 +    mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
  1.6525 +  }
  1.6526 +
  1.6527 +  nsCOMPtr<nsIDocShellTreeItem> parentDsti;
  1.6528 +  mDocShell->GetParent(getter_AddRefs(parentDsti));
  1.6529 +
  1.6530 +  // set the parent's current focus to the frame containing this window.
  1.6531 +  nsCOMPtr<nsPIDOMWindow> parent = do_GetInterface(parentDsti);
  1.6532 +  if (parent) {
  1.6533 +    nsCOMPtr<nsIDocument> parentdoc = parent->GetDoc();
  1.6534 +    if (!parentdoc) {
  1.6535 +      return;
  1.6536 +    }
  1.6537 +
  1.6538 +    nsIContent* frame = parentdoc->FindContentForSubDocument(mDoc);
  1.6539 +    nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
  1.6540 +    if (frameElement) {
  1.6541 +      uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
  1.6542 +      if (canFocus)
  1.6543 +        flags |= nsIFocusManager::FLAG_RAISE;
  1.6544 +      aError = fm->SetFocus(frameElement, flags);
  1.6545 +    }
  1.6546 +    return;
  1.6547 +  }
  1.6548 +  if (nsCOMPtr<nsITabChild> child = do_GetInterface(mDocShell)) {
  1.6549 +    child->SendRequestFocus(canFocus);
  1.6550 +    return;
  1.6551 +  }
  1.6552 +  if (canFocus) {
  1.6553 +    // if there is no parent, this must be a toplevel window, so raise the
  1.6554 +    // window if canFocus is true
  1.6555 +    aError = fm->SetActiveWindow(this);
  1.6556 +  }
  1.6557 +}
  1.6558 +
  1.6559 +NS_IMETHODIMP
  1.6560 +nsGlobalWindow::Focus()
  1.6561 +{
  1.6562 +  ErrorResult rv;
  1.6563 +  Focus(rv);
  1.6564 +
  1.6565 +  return rv.ErrorCode();
  1.6566 +}
  1.6567 +
  1.6568 +void
  1.6569 +nsGlobalWindow::Blur(ErrorResult& aError)
  1.6570 +{
  1.6571 +  FORWARD_TO_OUTER_OR_THROW(Blur, (aError), aError, );
  1.6572 +
  1.6573 +  // If dom.disable_window_flip == true, then content should not be allowed
  1.6574 +  // to call this function (this would allow popunders, bug 369306)
  1.6575 +  if (!CanSetProperty("dom.disable_window_flip")) {
  1.6576 +    return;
  1.6577 +  }
  1.6578 +
  1.6579 +  // If embedding apps don't implement nsIEmbeddingSiteWindow, we
  1.6580 +  // shouldn't throw exceptions to web content.
  1.6581 +
  1.6582 +  nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  1.6583 +  nsCOMPtr<nsIEmbeddingSiteWindow> siteWindow(do_GetInterface(treeOwner));
  1.6584 +  if (siteWindow) {
  1.6585 +    // This method call may cause mDocShell to become nullptr.
  1.6586 +    siteWindow->Blur();
  1.6587 +
  1.6588 +    // if the root is focused, clear the focus
  1.6589 +    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.6590 +    if (fm && mDoc) {
  1.6591 +      nsCOMPtr<nsIDOMElement> element;
  1.6592 +      fm->GetFocusedElementForWindow(this, false, nullptr, getter_AddRefs(element));
  1.6593 +      nsCOMPtr<nsIContent> content = do_QueryInterface(element);
  1.6594 +      if (content == mDoc->GetRootElement())
  1.6595 +        fm->ClearFocus(this);
  1.6596 +    }
  1.6597 +  }
  1.6598 +}
  1.6599 +
  1.6600 +NS_IMETHODIMP
  1.6601 +nsGlobalWindow::Blur()
  1.6602 +{
  1.6603 +  ErrorResult rv;
  1.6604 +  Blur(rv);
  1.6605 +
  1.6606 +  return rv.ErrorCode();
  1.6607 +}
  1.6608 +
  1.6609 +void
  1.6610 +nsGlobalWindow::Back(ErrorResult& aError)
  1.6611 +{
  1.6612 +  FORWARD_TO_OUTER_OR_THROW(Back, (aError), aError, );
  1.6613 +
  1.6614 +  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  1.6615 +  if (!webNav) {
  1.6616 +    aError.Throw(NS_ERROR_FAILURE);
  1.6617 +    return;
  1.6618 +  }
  1.6619 +
  1.6620 +  aError = webNav->GoBack();
  1.6621 +}
  1.6622 +
  1.6623 +NS_IMETHODIMP
  1.6624 +nsGlobalWindow::Back()
  1.6625 +{
  1.6626 +  ErrorResult rv;
  1.6627 +  Back(rv);
  1.6628 +
  1.6629 +  return rv.ErrorCode();
  1.6630 +}
  1.6631 +
  1.6632 +void
  1.6633 +nsGlobalWindow::Forward(ErrorResult& aError)
  1.6634 +{
  1.6635 +  FORWARD_TO_OUTER_OR_THROW(Forward, (aError), aError, );
  1.6636 +
  1.6637 +  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  1.6638 +  if (!webNav) {
  1.6639 +    aError.Throw(NS_ERROR_FAILURE);
  1.6640 +    return;
  1.6641 +  }
  1.6642 +
  1.6643 +  aError = webNav->GoForward();
  1.6644 +}
  1.6645 +
  1.6646 +NS_IMETHODIMP
  1.6647 +nsGlobalWindow::Forward()
  1.6648 +{
  1.6649 +  ErrorResult rv;
  1.6650 +  Forward(rv);
  1.6651 +
  1.6652 +  return rv.ErrorCode();
  1.6653 +}
  1.6654 +
  1.6655 +void
  1.6656 +nsGlobalWindow::Home(ErrorResult& aError)
  1.6657 +{
  1.6658 +  FORWARD_TO_OUTER_OR_THROW(Home, (aError), aError, );
  1.6659 +
  1.6660 +  if (!mDocShell) {
  1.6661 +    return;
  1.6662 +  }
  1.6663 +
  1.6664 +  nsAdoptingString homeURL =
  1.6665 +    Preferences::GetLocalizedString(PREF_BROWSER_STARTUP_HOMEPAGE);
  1.6666 +
  1.6667 +  if (homeURL.IsEmpty()) {
  1.6668 +    // if all else fails, use this
  1.6669 +#ifdef DEBUG_seth
  1.6670 +    printf("all else failed.  using %s as the home page\n", DEFAULT_HOME_PAGE);
  1.6671 +#endif
  1.6672 +    CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
  1.6673 +  }
  1.6674 +
  1.6675 +#ifdef MOZ_PHOENIX
  1.6676 +  {
  1.6677 +    // Firefox lets the user specify multiple home pages to open in
  1.6678 +    // individual tabs by separating them with '|'. Since we don't
  1.6679 +    // have the machinery in place to easily open new tabs from here,
  1.6680 +    // simply truncate the homeURL at the first '|' character to
  1.6681 +    // prevent any possibilities of leaking the users list of home
  1.6682 +    // pages to the first home page.
  1.6683 +    //
  1.6684 +    // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
  1.6685 +    // fixed we can revisit this.
  1.6686 +    int32_t firstPipe = homeURL.FindChar('|');
  1.6687 +
  1.6688 +    if (firstPipe > 0) {
  1.6689 +      homeURL.Truncate(firstPipe);
  1.6690 +    }
  1.6691 +  }
  1.6692 +#endif
  1.6693 +
  1.6694 +  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  1.6695 +  if (!webNav) {
  1.6696 +    aError.Throw(NS_ERROR_FAILURE);
  1.6697 +    return;
  1.6698 +  }
  1.6699 +
  1.6700 +  aError = webNav->LoadURI(homeURL.get(),
  1.6701 +                           nsIWebNavigation::LOAD_FLAGS_NONE,
  1.6702 +                           nullptr,
  1.6703 +                           nullptr,
  1.6704 +                           nullptr);
  1.6705 +}
  1.6706 +
  1.6707 +NS_IMETHODIMP
  1.6708 +nsGlobalWindow::Home()
  1.6709 +{
  1.6710 +  ErrorResult rv;
  1.6711 +  Home(rv);
  1.6712 +
  1.6713 +  return rv.ErrorCode();
  1.6714 +}
  1.6715 +
  1.6716 +void
  1.6717 +nsGlobalWindow::Stop(ErrorResult& aError)
  1.6718 +{
  1.6719 +  FORWARD_TO_OUTER_OR_THROW(Stop, (aError), aError, );
  1.6720 +
  1.6721 +  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  1.6722 +  if (webNav) {
  1.6723 +    aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
  1.6724 +  }
  1.6725 +}
  1.6726 +
  1.6727 +NS_IMETHODIMP
  1.6728 +nsGlobalWindow::Stop()
  1.6729 +{
  1.6730 +  ErrorResult rv;
  1.6731 +  Stop(rv);
  1.6732 +
  1.6733 +  return rv.ErrorCode();
  1.6734 +}
  1.6735 +
  1.6736 +void
  1.6737 +nsGlobalWindow::Print(ErrorResult& aError)
  1.6738 +{
  1.6739 +#ifdef NS_PRINTING
  1.6740 +  FORWARD_TO_OUTER_OR_THROW(Print, (aError), aError, );
  1.6741 +
  1.6742 +  if (Preferences::GetBool("dom.disable_window_print", false)) {
  1.6743 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.6744 +    return;
  1.6745 +  }
  1.6746 +
  1.6747 +  if (!AreDialogsEnabled()) {
  1.6748 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.6749 +    return;
  1.6750 +  }
  1.6751 +
  1.6752 +  if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
  1.6753 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.6754 +    return;
  1.6755 +  }
  1.6756 +
  1.6757 +  nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
  1.6758 +  if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
  1.6759 +                                getter_AddRefs(webBrowserPrint)))) {
  1.6760 +    nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
  1.6761 +                               GetCurrentInnerWindowInternal()->mDoc :
  1.6762 +                               nullptr);
  1.6763 +
  1.6764 +    nsCOMPtr<nsIPrintSettingsService> printSettingsService = 
  1.6765 +      do_GetService("@mozilla.org/gfx/printsettings-service;1");
  1.6766 +
  1.6767 +    nsCOMPtr<nsIPrintSettings> printSettings;
  1.6768 +    if (printSettingsService) {
  1.6769 +      bool printSettingsAreGlobal =
  1.6770 +        Preferences::GetBool("print.use_global_printsettings", false);
  1.6771 +
  1.6772 +      if (printSettingsAreGlobal) {
  1.6773 +        printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
  1.6774 +
  1.6775 +        nsXPIDLString printerName;
  1.6776 +        printSettings->GetPrinterName(getter_Copies(printerName));
  1.6777 +        if (printerName.IsEmpty()) {
  1.6778 +          printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
  1.6779 +          printSettings->SetPrinterName(printerName);
  1.6780 +        }
  1.6781 +        printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
  1.6782 +        printSettingsService->InitPrintSettingsFromPrefs(printSettings, 
  1.6783 +                                                         true, 
  1.6784 +                                                         nsIPrintSettings::kInitSaveAll);
  1.6785 +      } else {
  1.6786 +        printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
  1.6787 +      }
  1.6788 +
  1.6789 +      EnterModalState();
  1.6790 +      webBrowserPrint->Print(printSettings, nullptr);
  1.6791 +      LeaveModalState();
  1.6792 +
  1.6793 +      bool savePrintSettings =
  1.6794 +        Preferences::GetBool("print.save_print_settings", false);
  1.6795 +      if (printSettingsAreGlobal && savePrintSettings) {
  1.6796 +        printSettingsService->
  1.6797 +          SavePrintSettingsToPrefs(printSettings,
  1.6798 +                                   true,
  1.6799 +                                   nsIPrintSettings::kInitSaveAll);
  1.6800 +        printSettingsService->
  1.6801 +          SavePrintSettingsToPrefs(printSettings,
  1.6802 +                                   false,
  1.6803 +                                   nsIPrintSettings::kInitSavePrinterName);
  1.6804 +      }
  1.6805 +    } else {
  1.6806 +      webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
  1.6807 +      webBrowserPrint->Print(printSettings, nullptr);
  1.6808 +    }
  1.6809 +  }
  1.6810 +#endif //NS_PRINTING
  1.6811 +}
  1.6812 +
  1.6813 +NS_IMETHODIMP
  1.6814 +nsGlobalWindow::Print()
  1.6815 +{
  1.6816 +  ErrorResult rv;
  1.6817 +  Print(rv);
  1.6818 +
  1.6819 +  return rv.ErrorCode();
  1.6820 +}
  1.6821 +
  1.6822 +void
  1.6823 +nsGlobalWindow::MoveTo(int32_t aXPos, int32_t aYPos, ErrorResult& aError)
  1.6824 +{
  1.6825 +  FORWARD_TO_OUTER_OR_THROW(MoveTo, (aXPos, aYPos, aError), aError, );
  1.6826 +
  1.6827 +  /*
  1.6828 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.6829 +   * prevent window.moveTo() by exiting early
  1.6830 +   */
  1.6831 +
  1.6832 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.6833 +    return;
  1.6834 +  }
  1.6835 +
  1.6836 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.6837 +  if (!treeOwnerAsWin) {
  1.6838 +    aError.Throw(NS_ERROR_FAILURE);
  1.6839 +    return;
  1.6840 +  }
  1.6841 +
  1.6842 +  // Mild abuse of a "size" object so we don't need more helper functions.
  1.6843 +  nsIntSize cssPos(aXPos, aYPos);
  1.6844 +  CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height);
  1.6845 +
  1.6846 +  nsIntSize devPos = CSSToDevIntPixels(cssPos);
  1.6847 +
  1.6848 +  aError = treeOwnerAsWin->SetPosition(devPos.width, devPos.height);
  1.6849 +}
  1.6850 +
  1.6851 +NS_IMETHODIMP
  1.6852 +nsGlobalWindow::MoveTo(int32_t aXPos, int32_t aYPos)
  1.6853 +{
  1.6854 +  ErrorResult rv;
  1.6855 +  MoveTo(aXPos, aYPos, rv);
  1.6856 +
  1.6857 +  return rv.ErrorCode();
  1.6858 +}
  1.6859 +
  1.6860 +void
  1.6861 +nsGlobalWindow::MoveBy(int32_t aXDif, int32_t aYDif, ErrorResult& aError)
  1.6862 +{
  1.6863 +  FORWARD_TO_OUTER_OR_THROW(MoveBy, (aXDif, aYDif, aError), aError, );
  1.6864 +
  1.6865 +  /*
  1.6866 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.6867 +   * prevent window.moveBy() by exiting early
  1.6868 +   */
  1.6869 +
  1.6870 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.6871 +    return;
  1.6872 +  }
  1.6873 +
  1.6874 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.6875 +  if (!treeOwnerAsWin) {
  1.6876 +    aError.Throw(NS_ERROR_FAILURE);
  1.6877 +    return;
  1.6878 +  }
  1.6879 +
  1.6880 +  // To do this correctly we have to convert what we get from GetPosition
  1.6881 +  // into CSS pixels, add the arguments, do the security check, and
  1.6882 +  // then convert back to device pixels for the call to SetPosition.
  1.6883 +
  1.6884 +  int32_t x, y;
  1.6885 +  aError = treeOwnerAsWin->GetPosition(&x, &y);
  1.6886 +  if (aError.Failed()) {
  1.6887 +    return;
  1.6888 +  }
  1.6889 +
  1.6890 +  // mild abuse of a "size" object so we don't need more helper functions
  1.6891 +  nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
  1.6892 +
  1.6893 +  cssPos.width += aXDif;
  1.6894 +  cssPos.height += aYDif;
  1.6895 +  
  1.6896 +  CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height);
  1.6897 +
  1.6898 +  nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
  1.6899 +
  1.6900 +  aError = treeOwnerAsWin->SetPosition(newDevPos.width, newDevPos.height);
  1.6901 +}
  1.6902 +
  1.6903 +NS_IMETHODIMP
  1.6904 +nsGlobalWindow::MoveBy(int32_t aXDif, int32_t aYDif)
  1.6905 +{
  1.6906 +  ErrorResult rv;
  1.6907 +  MoveBy(aXDif, aYDif, rv);
  1.6908 +
  1.6909 +  return rv.ErrorCode();
  1.6910 +}
  1.6911 +
  1.6912 +void
  1.6913 +nsGlobalWindow::ResizeTo(int32_t aWidth, int32_t aHeight, ErrorResult& aError)
  1.6914 +{
  1.6915 +  FORWARD_TO_OUTER_OR_THROW(ResizeTo, (aWidth, aHeight, aError), aError, );
  1.6916 +
  1.6917 +  /*
  1.6918 +   * If caller is a browser-element then dispatch a resize event to
  1.6919 +   * the embedder.
  1.6920 +   */
  1.6921 +  if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
  1.6922 +    nsIntSize size(aWidth, aHeight);
  1.6923 +    if (!DispatchResizeEvent(size)) {
  1.6924 +      // The embedder chose to prevent the default action for this
  1.6925 +      // event, so let's not resize this window after all...
  1.6926 +      return;
  1.6927 +    }
  1.6928 +  }
  1.6929 +
  1.6930 +  /*
  1.6931 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.6932 +   * prevent window.resizeTo() by exiting early
  1.6933 +   */
  1.6934 +
  1.6935 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.6936 +    return;
  1.6937 +  }
  1.6938 +
  1.6939 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.6940 +  if (!treeOwnerAsWin) {
  1.6941 +    aError.Throw(NS_ERROR_FAILURE);
  1.6942 +    return;
  1.6943 +  }
  1.6944 +  
  1.6945 +  nsIntSize cssSize(aWidth, aHeight);
  1.6946 +  CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height);
  1.6947 +
  1.6948 +  nsIntSize devSz(CSSToDevIntPixels(cssSize));
  1.6949 +
  1.6950 +  aError = treeOwnerAsWin->SetSize(devSz.width, devSz.height, true);
  1.6951 +}
  1.6952 +
  1.6953 +NS_IMETHODIMP
  1.6954 +nsGlobalWindow::ResizeTo(int32_t aWidth, int32_t aHeight)
  1.6955 +{
  1.6956 +  ErrorResult rv;
  1.6957 +  ResizeTo(aWidth, aHeight, rv);
  1.6958 +
  1.6959 +  return rv.ErrorCode();
  1.6960 +}
  1.6961 +
  1.6962 +void
  1.6963 +nsGlobalWindow::ResizeBy(int32_t aWidthDif, int32_t aHeightDif,
  1.6964 +                         ErrorResult& aError)
  1.6965 +{
  1.6966 +  FORWARD_TO_OUTER_OR_THROW(ResizeBy, (aWidthDif, aHeightDif, aError), aError, );
  1.6967 +
  1.6968 +  /*
  1.6969 +   * If caller is a browser-element then dispatch a resize event to
  1.6970 +   * parent.
  1.6971 +   */
  1.6972 +  if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
  1.6973 +    CSSIntSize size;
  1.6974 +    if (NS_FAILED(GetInnerSize(size))) {
  1.6975 +      return;
  1.6976 +    }
  1.6977 +
  1.6978 +    size.width += aWidthDif;
  1.6979 +    size.height += aHeightDif;
  1.6980 +
  1.6981 +    if (!DispatchResizeEvent(nsIntSize(size.width, size.height))) {
  1.6982 +      // The embedder chose to prevent the default action for this
  1.6983 +      // event, so let's not resize this window after all...
  1.6984 +      return;
  1.6985 +    }
  1.6986 +  }
  1.6987 +
  1.6988 +  /*
  1.6989 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.6990 +   * prevent window.resizeBy() by exiting early
  1.6991 +   */
  1.6992 +
  1.6993 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.6994 +    return;
  1.6995 +  }
  1.6996 +
  1.6997 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.6998 +  if (!treeOwnerAsWin) {
  1.6999 +    aError.Throw(NS_ERROR_FAILURE);
  1.7000 +    return;
  1.7001 +  }
  1.7002 +
  1.7003 +  int32_t width, height;
  1.7004 +  aError = treeOwnerAsWin->GetSize(&width, &height);
  1.7005 +  if (aError.Failed()) {
  1.7006 +    return;
  1.7007 +  }
  1.7008 +
  1.7009 +  // To do this correctly we have to convert what we got from GetSize
  1.7010 +  // into CSS pixels, add the arguments, do the security check, and
  1.7011 +  // then convert back to device pixels for the call to SetSize.
  1.7012 +
  1.7013 +  nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
  1.7014 +
  1.7015 +  cssSize.width += aWidthDif;
  1.7016 +  cssSize.height += aHeightDif;
  1.7017 +
  1.7018 +  CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height);
  1.7019 +
  1.7020 +  nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
  1.7021 +
  1.7022 +  aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
  1.7023 +}
  1.7024 +
  1.7025 +NS_IMETHODIMP
  1.7026 +nsGlobalWindow::ResizeBy(int32_t aWidthDif, int32_t aHeightDif)
  1.7027 +{
  1.7028 +  ErrorResult rv;
  1.7029 +  ResizeBy(aWidthDif, aHeightDif, rv);
  1.7030 +
  1.7031 +  return rv.ErrorCode();
  1.7032 +}
  1.7033 +
  1.7034 +void
  1.7035 +nsGlobalWindow::SizeToContent(ErrorResult& aError)
  1.7036 +{
  1.7037 +  FORWARD_TO_OUTER_OR_THROW(SizeToContent, (aError), aError, );
  1.7038 +
  1.7039 +  if (!mDocShell) {
  1.7040 +    return;
  1.7041 +  }
  1.7042 +
  1.7043 +  /*
  1.7044 +   * If caller is not chrome and the user has not explicitly exempted the site,
  1.7045 +   * prevent window.sizeToContent() by exiting early
  1.7046 +   */
  1.7047 +
  1.7048 +  if (!CanMoveResizeWindows() || IsFrame()) {
  1.7049 +    return;
  1.7050 +  }
  1.7051 +
  1.7052 +  // The content viewer does a check to make sure that it's a content
  1.7053 +  // viewer for a toplevel docshell.
  1.7054 +  nsCOMPtr<nsIContentViewer> cv;
  1.7055 +  mDocShell->GetContentViewer(getter_AddRefs(cv));
  1.7056 +  nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
  1.7057 +  if (!markupViewer) {
  1.7058 +    aError.Throw(NS_ERROR_FAILURE);
  1.7059 +    return;
  1.7060 +  }
  1.7061 +
  1.7062 +  int32_t width, height;
  1.7063 +  aError = markupViewer->GetContentSize(&width, &height);
  1.7064 +  if (aError.Failed()) {
  1.7065 +    return;
  1.7066 +  }
  1.7067 +
  1.7068 +  // Make sure the new size is following the CheckSecurityWidthAndHeight
  1.7069 +  // rules.
  1.7070 +  nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
  1.7071 +  if (!treeOwner) {
  1.7072 +    aError.Throw(NS_ERROR_FAILURE);
  1.7073 +    return;
  1.7074 +  }
  1.7075 +
  1.7076 +  nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
  1.7077 +  CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height);
  1.7078 +
  1.7079 +  nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
  1.7080 +
  1.7081 +  aError = treeOwner->SizeShellTo(mDocShell, newDevSize.width,
  1.7082 +                                  newDevSize.height);
  1.7083 +}
  1.7084 +
  1.7085 +NS_IMETHODIMP
  1.7086 +nsGlobalWindow::SizeToContent()
  1.7087 +{
  1.7088 +  ErrorResult rv;
  1.7089 +  SizeToContent(rv);
  1.7090 +
  1.7091 +  return rv.ErrorCode();
  1.7092 +}
  1.7093 +
  1.7094 +NS_IMETHODIMP
  1.7095 +nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
  1.7096 +{
  1.7097 +  nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
  1.7098 +  return CallQueryInterface(root, aWindowRoot);
  1.7099 +}
  1.7100 +
  1.7101 +already_AddRefed<nsPIWindowRoot>
  1.7102 +nsGlobalWindow::GetTopWindowRoot()
  1.7103 +{
  1.7104 +  nsPIDOMWindow* piWin = GetPrivateRoot();
  1.7105 +  if (!piWin) {
  1.7106 +    return nullptr;
  1.7107 +  }
  1.7108 +
  1.7109 +  nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
  1.7110 +  return window.forget();
  1.7111 +}
  1.7112 +
  1.7113 +NS_IMETHODIMP
  1.7114 +nsGlobalWindow::Scroll(int32_t aXScroll, int32_t aYScroll)
  1.7115 +{
  1.7116 +  ScrollTo(CSSIntPoint(aXScroll, aYScroll));
  1.7117 +  return NS_OK;
  1.7118 +}
  1.7119 +
  1.7120 +NS_IMETHODIMP
  1.7121 +nsGlobalWindow::ScrollTo(int32_t aXScroll, int32_t aYScroll)
  1.7122 +{
  1.7123 +  ScrollTo(CSSIntPoint(aXScroll, aYScroll));
  1.7124 +  return NS_OK;
  1.7125 +}
  1.7126 +
  1.7127 +void
  1.7128 +nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll)
  1.7129 +{
  1.7130 +  FlushPendingNotifications(Flush_Layout);
  1.7131 +  nsIScrollableFrame *sf = GetScrollFrame();
  1.7132 +
  1.7133 +  if (sf) {
  1.7134 +    // Here we calculate what the max pixel value is that we can
  1.7135 +    // scroll to, we do this by dividing maxint with the pixel to
  1.7136 +    // twips conversion factor, and subtracting 4, the 4 comes from
  1.7137 +    // experimenting with this value, anything less makes the view
  1.7138 +    // code not scroll correctly, I have no idea why. -- jst
  1.7139 +    const int32_t maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
  1.7140 +
  1.7141 +    CSSIntPoint scroll(aScroll);
  1.7142 +    if (scroll.x > maxpx) {
  1.7143 +      scroll.x = maxpx;
  1.7144 +    }
  1.7145 +
  1.7146 +    if (scroll.y > maxpx) {
  1.7147 +      scroll.y = maxpx;
  1.7148 +    }
  1.7149 +    sf->ScrollToCSSPixels(scroll);
  1.7150 +  }
  1.7151 +}
  1.7152 +
  1.7153 +NS_IMETHODIMP
  1.7154 +nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif)
  1.7155 +{
  1.7156 +  FlushPendingNotifications(Flush_Layout);
  1.7157 +  nsIScrollableFrame *sf = GetScrollFrame();
  1.7158 +
  1.7159 +  if (sf) {
  1.7160 +    CSSIntPoint scrollPos =
  1.7161 +      sf->GetScrollPositionCSSPixels() + CSSIntPoint(aXScrollDif, aYScrollDif);
  1.7162 +    // It seems like it would make more sense for ScrollBy to use
  1.7163 +    // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
  1.7164 +    // Perhaps Web content does too.
  1.7165 +    ScrollTo(scrollPos);
  1.7166 +  }
  1.7167 +
  1.7168 +  return NS_OK;
  1.7169 +}
  1.7170 +
  1.7171 +NS_IMETHODIMP
  1.7172 +nsGlobalWindow::ScrollByLines(int32_t numLines)
  1.7173 +{
  1.7174 +  FlushPendingNotifications(Flush_Layout);
  1.7175 +  nsIScrollableFrame *sf = GetScrollFrame();
  1.7176 +  if (sf) {
  1.7177 +    // It seems like it would make more sense for ScrollByLines to use
  1.7178 +    // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
  1.7179 +    // Perhaps Web content does too.
  1.7180 +    sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
  1.7181 +                 nsIScrollableFrame::INSTANT);
  1.7182 +  }
  1.7183 +
  1.7184 +  return NS_OK;
  1.7185 +}
  1.7186 +
  1.7187 +NS_IMETHODIMP
  1.7188 +nsGlobalWindow::ScrollByPages(int32_t numPages)
  1.7189 +{
  1.7190 +  FlushPendingNotifications(Flush_Layout);
  1.7191 +  nsIScrollableFrame *sf = GetScrollFrame();
  1.7192 +  if (sf) {
  1.7193 +    // It seems like it would make more sense for ScrollByPages to use
  1.7194 +    // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
  1.7195 +    // Perhaps Web content does too.
  1.7196 +    sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
  1.7197 +                 nsIScrollableFrame::INSTANT);
  1.7198 +  }
  1.7199 +
  1.7200 +  return NS_OK;
  1.7201 +}
  1.7202 +
  1.7203 +void
  1.7204 +nsGlobalWindow::ClearTimeout(int32_t aHandle, ErrorResult& aError)
  1.7205 +{
  1.7206 +  if (aHandle > 0) {
  1.7207 +    ClearTimeoutOrInterval(aHandle, aError);
  1.7208 +  }
  1.7209 +}
  1.7210 +
  1.7211 +NS_IMETHODIMP
  1.7212 +nsGlobalWindow::ClearTimeout(int32_t aHandle)
  1.7213 +{
  1.7214 +  ErrorResult rv;
  1.7215 +  ClearTimeout(aHandle, rv);
  1.7216 +
  1.7217 +  return rv.ErrorCode();
  1.7218 +}
  1.7219 +
  1.7220 +void
  1.7221 +nsGlobalWindow::ClearInterval(int32_t aHandle, ErrorResult& aError)
  1.7222 +{
  1.7223 +  if (aHandle > 0) {
  1.7224 +    ClearTimeoutOrInterval(aHandle, aError);
  1.7225 +  }
  1.7226 +}
  1.7227 +
  1.7228 +NS_IMETHODIMP
  1.7229 +nsGlobalWindow::ClearInterval(int32_t aHandle)
  1.7230 +{
  1.7231 +  ErrorResult rv;
  1.7232 +  ClearInterval(aHandle, rv);
  1.7233 +
  1.7234 +  return rv.ErrorCode();
  1.7235 +}
  1.7236 +
  1.7237 +NS_IMETHODIMP
  1.7238 +nsGlobalWindow::SetTimeout(int32_t *_retval)
  1.7239 +{
  1.7240 +  return SetTimeoutOrInterval(false, _retval);
  1.7241 +}
  1.7242 +
  1.7243 +NS_IMETHODIMP
  1.7244 +nsGlobalWindow::SetInterval(int32_t *_retval)
  1.7245 +{
  1.7246 +  return SetTimeoutOrInterval(true, _retval);
  1.7247 +}
  1.7248 +
  1.7249 +NS_IMETHODIMP
  1.7250 +nsGlobalWindow::SetResizable(bool aResizable)
  1.7251 +{
  1.7252 +  // nop
  1.7253 +
  1.7254 +  return NS_OK;
  1.7255 +}
  1.7256 +
  1.7257 +NS_IMETHODIMP
  1.7258 +nsGlobalWindow::CaptureEvents()
  1.7259 +{
  1.7260 +  if (mDoc) {
  1.7261 +    mDoc->WarnOnceAbout(nsIDocument::eUseOfCaptureEvents);
  1.7262 +  }
  1.7263 +
  1.7264 +  return NS_OK;
  1.7265 +}
  1.7266 +
  1.7267 +NS_IMETHODIMP
  1.7268 +nsGlobalWindow::ReleaseEvents()
  1.7269 +{
  1.7270 +  if (mDoc) {
  1.7271 +    mDoc->WarnOnceAbout(nsIDocument::eUseOfReleaseEvents);
  1.7272 +  }
  1.7273 +
  1.7274 +  return NS_OK;
  1.7275 +}
  1.7276 +
  1.7277 +static
  1.7278 +bool IsPopupBlocked(nsIDocument* aDoc)
  1.7279 +{
  1.7280 +  nsCOMPtr<nsIPopupWindowManager> pm =
  1.7281 +    do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
  1.7282 +
  1.7283 +  if (!pm) {
  1.7284 +    return false;
  1.7285 +  }
  1.7286 +
  1.7287 +  if (!aDoc) {
  1.7288 +    return true;
  1.7289 +  }
  1.7290 +
  1.7291 +  uint32_t permission = nsIPopupWindowManager::ALLOW_POPUP;
  1.7292 +  pm->TestPermission(aDoc->NodePrincipal(), &permission);
  1.7293 +  return permission == nsIPopupWindowManager::DENY_POPUP;
  1.7294 +}
  1.7295 +
  1.7296 +/* static */
  1.7297 +void
  1.7298 +nsGlobalWindow::FirePopupBlockedEvent(nsIDocument* aDoc,
  1.7299 +                                      nsIDOMWindow *aRequestingWindow, nsIURI *aPopupURI,
  1.7300 +                                      const nsAString &aPopupWindowName,
  1.7301 +                                      const nsAString &aPopupWindowFeatures)
  1.7302 +{
  1.7303 +  if (aDoc) {
  1.7304 +    // Fire a "DOMPopupBlocked" event so that the UI can hear about
  1.7305 +    // blocked popups.
  1.7306 +    nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDoc);
  1.7307 +    nsCOMPtr<nsIDOMEvent> event;
  1.7308 +    doc->CreateEvent(NS_LITERAL_STRING("PopupBlockedEvents"), getter_AddRefs(event));
  1.7309 +    if (event) {
  1.7310 +      nsCOMPtr<nsIDOMPopupBlockedEvent> pbev(do_QueryInterface(event));
  1.7311 +      pbev->InitPopupBlockedEvent(NS_LITERAL_STRING("DOMPopupBlocked"),
  1.7312 +                                  true, true, aRequestingWindow,
  1.7313 +                                  aPopupURI, aPopupWindowName,
  1.7314 +                                  aPopupWindowFeatures);
  1.7315 +      event->SetTrusted(true);
  1.7316 +
  1.7317 +      bool defaultActionEnabled;
  1.7318 +      aDoc->DispatchEvent(event, &defaultActionEnabled);
  1.7319 +    }
  1.7320 +  }
  1.7321 +}
  1.7322 +
  1.7323 +static void FirePopupWindowEvent(nsIDocument* aDoc)
  1.7324 +{
  1.7325 +  // Fire a "PopupWindow" event
  1.7326 +  nsContentUtils::DispatchTrustedEvent(aDoc, aDoc,
  1.7327 +                                       NS_LITERAL_STRING("PopupWindow"),
  1.7328 +                                       true, true);
  1.7329 +}
  1.7330 +
  1.7331 +// static
  1.7332 +bool
  1.7333 +nsGlobalWindow::CanSetProperty(const char *aPrefName)
  1.7334 +{
  1.7335 +  // Chrome can set any property.
  1.7336 +  if (nsContentUtils::IsCallerChrome()) {
  1.7337 +    return true;
  1.7338 +  }
  1.7339 +
  1.7340 +  // If the pref is set to true, we can not set the property
  1.7341 +  // and vice versa.
  1.7342 +  return !Preferences::GetBool(aPrefName, true);
  1.7343 +}
  1.7344 +
  1.7345 +bool
  1.7346 +nsGlobalWindow::PopupWhitelisted()
  1.7347 +{
  1.7348 +  if (!IsPopupBlocked(mDoc))
  1.7349 +    return true;
  1.7350 +
  1.7351 +  nsCOMPtr<nsIDOMWindow> parent;
  1.7352 +
  1.7353 +  if (NS_FAILED(GetParent(getter_AddRefs(parent))) ||
  1.7354 +      parent == static_cast<nsIDOMWindow*>(this))
  1.7355 +  {
  1.7356 +    return false;
  1.7357 +  }
  1.7358 +
  1.7359 +  return static_cast<nsGlobalWindow*>
  1.7360 +                    (static_cast<nsIDOMWindow*>
  1.7361 +                                (parent.get()))->PopupWhitelisted();
  1.7362 +}
  1.7363 +
  1.7364 +/*
  1.7365 + * Examine the current document state to see if we're in a way that is
  1.7366 + * typically abused by web designers. The window.open code uses this
  1.7367 + * routine to determine whether to allow the new window.
  1.7368 + * Returns a value from the PopupControlState enum.
  1.7369 + */
  1.7370 +PopupControlState
  1.7371 +nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
  1.7372 +{
  1.7373 +  MOZ_ASSERT(IsOuterWindow());
  1.7374 +
  1.7375 +  NS_ASSERTION(mDocShell, "Must have docshell");
  1.7376 +  
  1.7377 +  if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
  1.7378 +    return openAllowed;
  1.7379 +  }
  1.7380 +
  1.7381 +  PopupControlState abuse = aControl;
  1.7382 +  switch (abuse) {
  1.7383 +  case openControlled:
  1.7384 +  case openAbused:
  1.7385 +  case openOverridden:
  1.7386 +    if (PopupWhitelisted())
  1.7387 +      abuse = PopupControlState(abuse - 1);
  1.7388 +  case openAllowed: break;
  1.7389 +  default:
  1.7390 +    NS_WARNING("Strange PopupControlState!");
  1.7391 +  }
  1.7392 +
  1.7393 +  // limit the number of simultaneously open popups
  1.7394 +  if (abuse == openAbused || abuse == openControlled) {
  1.7395 +    int32_t popupMax = Preferences::GetInt("dom.popup_maximum", -1);
  1.7396 +    if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
  1.7397 +      abuse = openOverridden;
  1.7398 +  }
  1.7399 +
  1.7400 +  return abuse;
  1.7401 +}
  1.7402 +
  1.7403 +/* If a window open is blocked, fire the appropriate DOM events.
  1.7404 +   aBlocked signifies we just blocked a popup.
  1.7405 +   aWindow signifies we just opened what is probably a popup.
  1.7406 +*/
  1.7407 +void
  1.7408 +nsGlobalWindow::FireAbuseEvents(bool aBlocked, bool aWindow,
  1.7409 +                                const nsAString &aPopupURL,
  1.7410 +                                const nsAString &aPopupWindowName,
  1.7411 +                                const nsAString &aPopupWindowFeatures)
  1.7412 +{
  1.7413 +  // fetch the URI of the window requesting the opened window
  1.7414 +
  1.7415 +  nsCOMPtr<nsIDOMWindow> topWindow;
  1.7416 +  GetTop(getter_AddRefs(topWindow));
  1.7417 +  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(topWindow);
  1.7418 +  if (!window) {
  1.7419 +    return;
  1.7420 +  }
  1.7421 +
  1.7422 +  nsCOMPtr<nsIDocument> topDoc = window->GetDoc();
  1.7423 +  nsCOMPtr<nsIURI> popupURI;
  1.7424 +
  1.7425 +  // build the URI of the would-have-been popup window
  1.7426 +  // (see nsWindowWatcher::URIfromURL)
  1.7427 +
  1.7428 +  // first, fetch the opener's base URI
  1.7429 +
  1.7430 +  nsIURI *baseURL = nullptr;
  1.7431 +
  1.7432 +  JSContext *cx = nsContentUtils::GetCurrentJSContext();
  1.7433 +  nsCOMPtr<nsPIDOMWindow> contextWindow;
  1.7434 +
  1.7435 +  if (cx) {
  1.7436 +    nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
  1.7437 +    if (currentCX) {
  1.7438 +      contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
  1.7439 +    }
  1.7440 +  }
  1.7441 +  if (!contextWindow) {
  1.7442 +    contextWindow = this;
  1.7443 +  }
  1.7444 +
  1.7445 +  nsCOMPtr<nsIDocument> doc = contextWindow->GetDoc();
  1.7446 +  if (doc)
  1.7447 +    baseURL = doc->GetDocBaseURI();
  1.7448 +
  1.7449 +  // use the base URI to build what would have been the popup's URI
  1.7450 +  nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
  1.7451 +  if (ios)
  1.7452 +    ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
  1.7453 +                getter_AddRefs(popupURI));
  1.7454 +
  1.7455 +  // fire an event chock full of informative URIs
  1.7456 +  if (aBlocked) {
  1.7457 +    FirePopupBlockedEvent(topDoc, this, popupURI, aPopupWindowName,
  1.7458 +                          aPopupWindowFeatures);
  1.7459 +  }
  1.7460 +  if (aWindow)
  1.7461 +    FirePopupWindowEvent(topDoc);
  1.7462 +}
  1.7463 +
  1.7464 +already_AddRefed<nsIDOMWindow>
  1.7465 +nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
  1.7466 +                     const nsAString& aOptions, ErrorResult& aError)
  1.7467 +{
  1.7468 +  nsCOMPtr<nsIDOMWindow> window;
  1.7469 +  aError = OpenJS(aUrl, aName, aOptions, getter_AddRefs(window));
  1.7470 +  return window.forget();
  1.7471 +}
  1.7472 +
  1.7473 +NS_IMETHODIMP
  1.7474 +nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
  1.7475 +                     const nsAString& aOptions, nsIDOMWindow **_retval)
  1.7476 +{
  1.7477 +  return OpenInternal(aUrl, aName, aOptions,
  1.7478 +                      false,          // aDialog
  1.7479 +                      false,          // aContentModal
  1.7480 +                      true,           // aCalledNoScript
  1.7481 +                      false,          // aDoJSFixups
  1.7482 +                      true,           // aNavigate
  1.7483 +                      nullptr, nullptr,  // No args
  1.7484 +                      GetPrincipal(),    // aCalleePrincipal
  1.7485 +                      nullptr,           // aJSCallerContext
  1.7486 +                      _retval);
  1.7487 +}
  1.7488 +
  1.7489 +NS_IMETHODIMP
  1.7490 +nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
  1.7491 +                       const nsAString& aOptions, nsIDOMWindow **_retval)
  1.7492 +{
  1.7493 +  return OpenInternal(aUrl, aName, aOptions,
  1.7494 +                      false,          // aDialog
  1.7495 +                      false,          // aContentModal
  1.7496 +                      false,          // aCalledNoScript
  1.7497 +                      true,           // aDoJSFixups
  1.7498 +                      true,           // aNavigate
  1.7499 +                      nullptr, nullptr,  // No args
  1.7500 +                      GetPrincipal(),    // aCalleePrincipal
  1.7501 +                      nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
  1.7502 +                      _retval);
  1.7503 +}
  1.7504 +
  1.7505 +// like Open, but attaches to the new window any extra parameters past
  1.7506 +// [features] as a JS property named "arguments"
  1.7507 +NS_IMETHODIMP
  1.7508 +nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
  1.7509 +                           const nsAString& aOptions,
  1.7510 +                           nsISupports* aExtraArgument, nsIDOMWindow** _retval)
  1.7511 +{
  1.7512 +  return OpenInternal(aUrl, aName, aOptions,
  1.7513 +                      true,                    // aDialog
  1.7514 +                      false,                   // aContentModal
  1.7515 +                      true,                    // aCalledNoScript
  1.7516 +                      false,                   // aDoJSFixups
  1.7517 +                      true,                    // aNavigate
  1.7518 +                      nullptr, aExtraArgument,    // Arguments
  1.7519 +                      GetPrincipal(),             // aCalleePrincipal
  1.7520 +                      nullptr,                    // aJSCallerContext
  1.7521 +                      _retval);
  1.7522 +}
  1.7523 +
  1.7524 +// Like Open, but passes aNavigate=false.
  1.7525 +/* virtual */ nsresult
  1.7526 +nsGlobalWindow::OpenNoNavigate(const nsAString& aUrl,
  1.7527 +                               const nsAString& aName,
  1.7528 +                               const nsAString& aOptions,
  1.7529 +                               nsIDOMWindow **_retval)
  1.7530 +{
  1.7531 +  return OpenInternal(aUrl, aName, aOptions,
  1.7532 +                      false,          // aDialog
  1.7533 +                      false,          // aContentModal
  1.7534 +                      true,           // aCalledNoScript
  1.7535 +                      false,          // aDoJSFixups
  1.7536 +                      false,          // aNavigate
  1.7537 +                      nullptr, nullptr,  // No args
  1.7538 +                      GetPrincipal(),    // aCalleePrincipal
  1.7539 +                      nullptr,           // aJSCallerContext
  1.7540 +                      _retval);
  1.7541 +
  1.7542 +}
  1.7543 +
  1.7544 +already_AddRefed<nsIDOMWindow>
  1.7545 +nsGlobalWindow::OpenDialog(JSContext* aCx, const nsAString& aUrl,
  1.7546 +                           const nsAString& aName, const nsAString& aOptions,
  1.7547 +                           const Sequence<JS::Value>& aExtraArgument,
  1.7548 +                           ErrorResult& aError)
  1.7549 +{
  1.7550 +  nsCOMPtr<nsIJSArgArray> argvArray;
  1.7551 +  aError = NS_CreateJSArgv(aCx, aExtraArgument.Length(),
  1.7552 +                           const_cast<JS::Value*>(aExtraArgument.Elements()),
  1.7553 +                           getter_AddRefs(argvArray));
  1.7554 +  if (aError.Failed()) {
  1.7555 +    return nullptr;
  1.7556 +  }
  1.7557 +
  1.7558 +  nsCOMPtr<nsIDOMWindow> dialog;
  1.7559 +  aError = OpenInternal(aUrl, aName, aOptions,
  1.7560 +                        true,             // aDialog
  1.7561 +                        false,            // aContentModal
  1.7562 +                        false,            // aCalledNoScript
  1.7563 +                        false,            // aDoJSFixups
  1.7564 +                        true,                // aNavigate
  1.7565 +                        argvArray, nullptr,  // Arguments
  1.7566 +                        GetPrincipal(),      // aCalleePrincipal
  1.7567 +                        aCx,                 // aJSCallerContext
  1.7568 +                        getter_AddRefs(dialog));
  1.7569 +  return dialog.forget();
  1.7570 +}
  1.7571 +
  1.7572 +NS_IMETHODIMP
  1.7573 +nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
  1.7574 +                           const nsAString& aOptions, nsIDOMWindow** _retval)
  1.7575 +{
  1.7576 +  if (!nsContentUtils::IsCallerChrome()) {
  1.7577 +    return NS_ERROR_DOM_SECURITY_ERR;
  1.7578 +  }
  1.7579 +
  1.7580 +  nsAXPCNativeCallContext *ncc = nullptr;
  1.7581 +  nsresult rv = nsContentUtils::XPConnect()->
  1.7582 +    GetCurrentNativeCallContext(&ncc);
  1.7583 +  NS_ENSURE_SUCCESS(rv, rv);
  1.7584 +
  1.7585 +  if (!ncc)
  1.7586 +    return NS_ERROR_NOT_AVAILABLE;
  1.7587 +
  1.7588 +  JSContext *cx = nullptr;
  1.7589 +
  1.7590 +  rv = ncc->GetJSContext(&cx);
  1.7591 +  NS_ENSURE_SUCCESS(rv, rv);
  1.7592 +
  1.7593 +  uint32_t argc;
  1.7594 +  JS::Value *argv = nullptr;
  1.7595 +
  1.7596 +  // XXX - need to get this as nsISupports?
  1.7597 +  ncc->GetArgc(&argc);
  1.7598 +  ncc->GetArgvPtr(&argv);
  1.7599 +
  1.7600 +  // Strip the url, name and options from the args seen by scripts.
  1.7601 +  uint32_t argOffset = argc < 3 ? argc : 3;
  1.7602 +  nsCOMPtr<nsIJSArgArray> argvArray;
  1.7603 +  rv = NS_CreateJSArgv(cx, argc - argOffset, argv + argOffset,
  1.7604 +                       getter_AddRefs(argvArray));
  1.7605 +  NS_ENSURE_SUCCESS(rv, rv);
  1.7606 +
  1.7607 +  return OpenInternal(aUrl, aName, aOptions,
  1.7608 +                      true,             // aDialog
  1.7609 +                      false,            // aContentModal
  1.7610 +                      false,            // aCalledNoScript
  1.7611 +                      false,            // aDoJSFixups
  1.7612 +                      true,                // aNavigate
  1.7613 +                      argvArray, nullptr,  // Arguments
  1.7614 +                      GetPrincipal(),      // aCalleePrincipal
  1.7615 +                      cx,                  // aJSCallerContext
  1.7616 +                      _retval);
  1.7617 +}
  1.7618 +
  1.7619 +already_AddRefed<nsIDOMWindow>
  1.7620 +nsGlobalWindow::GetFrames(ErrorResult& aError)
  1.7621 +{
  1.7622 +  FORWARD_TO_OUTER_OR_THROW(GetFrames, (aError), aError, nullptr);
  1.7623 +
  1.7624 +  nsRefPtr<nsGlobalWindow> frames(this);
  1.7625 +  FlushPendingNotifications(Flush_ContentAndNotify);
  1.7626 +  return frames.forget();
  1.7627 +}
  1.7628 +
  1.7629 +NS_IMETHODIMP
  1.7630 +nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
  1.7631 +{
  1.7632 +  ErrorResult rv;
  1.7633 +  nsCOMPtr<nsIDOMWindow> frames = GetFrames(rv);
  1.7634 +  frames.forget(aFrames);
  1.7635 +
  1.7636 +  return rv.ErrorCode();
  1.7637 +}
  1.7638 +
  1.7639 +JSObject* nsGlobalWindow::CallerGlobal()
  1.7640 +{
  1.7641 +  JSContext *cx = nsContentUtils::GetCurrentJSContext();
  1.7642 +  if (!cx) {
  1.7643 +    NS_ERROR("Please don't call this method from C++!");
  1.7644 +
  1.7645 +    return nullptr;
  1.7646 +  }
  1.7647 +
  1.7648 +  // If somebody does sameOriginIframeWindow.postMessage(...), they probably
  1.7649 +  // expect the .source attribute of the resulting message event to be |window|
  1.7650 +  // rather than |sameOriginIframeWindow|, even though the transparent wrapper
  1.7651 +  // semantics of same-origin access will cause us to be in the iframe's
  1.7652 +  // compartment at the time of the call. This means that we want the incumbent
  1.7653 +  // global here, rather than the global of the current compartment.
  1.7654 +  //
  1.7655 +  // There are various edge cases in which the incumbent global and the current
  1.7656 +  // global would not be same-origin. They include:
  1.7657 +  // * A privileged caller (System Principal or Expanded Principal) manipulating
  1.7658 +  //   less-privileged content via Xray Waivers.
  1.7659 +  // * An unprivileged caller invoking a cross-origin function that was exposed
  1.7660 +  //   to it by privileged code (i.e. Sandbox.importFunction).
  1.7661 +  //
  1.7662 +  // In these cases, we probably don't want the privileged global appearing in the
  1.7663 +  // .source attribute. So we fall back to the compartment global there.
  1.7664 +  JS::Rooted<JSObject*> incumbentGlobal(cx, &IncumbentJSGlobal());
  1.7665 +  JS::Rooted<JSObject*> compartmentGlobal(cx, JS::CurrentGlobalOrNull(cx));
  1.7666 +  nsIPrincipal* incumbentPrin = nsContentUtils::GetObjectPrincipal(incumbentGlobal);
  1.7667 +  nsIPrincipal* compartmentPrin = nsContentUtils::GetObjectPrincipal(compartmentGlobal);
  1.7668 +  return incumbentPrin->EqualsConsideringDomain(compartmentPrin) ? incumbentGlobal
  1.7669 +                                                                 : compartmentGlobal;
  1.7670 +}
  1.7671 +
  1.7672 +
  1.7673 +nsGlobalWindow*
  1.7674 +nsGlobalWindow::CallerInnerWindow()
  1.7675 +{
  1.7676 +  JSContext *cx = nsContentUtils::GetCurrentJSContext();
  1.7677 +  NS_ENSURE_TRUE(cx, nullptr);
  1.7678 +  JS::Rooted<JSObject*> scope(cx, CallerGlobal());
  1.7679 +
  1.7680 +  // When Jetpack runs content scripts inside a sandbox, it uses
  1.7681 +  // sandboxPrototype to make them appear as though they're running in the
  1.7682 +  // scope of the page. So when a content script invokes postMessage, it expects
  1.7683 +  // the |source| of the received message to be the window set as the
  1.7684 +  // sandboxPrototype. This used to work incidentally for unrelated reasons, but
  1.7685 +  // now we need to do some special handling to support it.
  1.7686 +  {
  1.7687 +    JSAutoCompartment ac(cx, scope);
  1.7688 +    JS::Rooted<JSObject*> scopeProto(cx);
  1.7689 +    bool ok = JS_GetPrototype(cx, scope, &scopeProto);
  1.7690 +    NS_ENSURE_TRUE(ok, nullptr);
  1.7691 +    if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
  1.7692 +        (scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtOuter = */ false)))
  1.7693 +    {
  1.7694 +      scope = scopeProto;
  1.7695 +    }
  1.7696 +  }
  1.7697 +  JSAutoCompartment ac(cx, scope);
  1.7698 +
  1.7699 +  // We don't use xpc::WindowOrNull here because we want to be able to tell
  1.7700 +  // apart the cases of "scope is not an nsISupports at all" and "scope is an
  1.7701 +  // nsISupports that's not a window". It's not clear whether that's desirable,
  1.7702 +  // see bug 984467.
  1.7703 +  nsISupports* native =
  1.7704 +    nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, scope);
  1.7705 +  if (!native)
  1.7706 +    return nullptr;
  1.7707 +
  1.7708 +  // The calling window must be holding a reference, so we can just return a
  1.7709 +  // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
  1.7710 +  // destructor's release.
  1.7711 +  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(native);
  1.7712 +  if (!win)
  1.7713 +    return GetCurrentInnerWindowInternal();
  1.7714 +  return static_cast<nsGlobalWindow*>(win.get());
  1.7715 +}
  1.7716 +
  1.7717 +nsresult
  1.7718 +nsGlobalWindow::GetFirstPartyIsolationURI(nsIURI** aFirstPartyIsolationURI)
  1.7719 +{
  1.7720 +  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
  1.7721 +                               do_GetService(THIRDPARTYUTIL_CONTRACTID);
  1.7722 +  if (!thirdPartyUtil)
  1.7723 +    return NS_ERROR_FAILURE;
  1.7724 +
  1.7725 +  nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDoc);
  1.7726 +  return thirdPartyUtil->GetFirstPartyIsolationURI(NULL, doc, aFirstPartyIsolationURI);
  1.7727 +}
  1.7728 +
  1.7729 +
  1.7730 +/**
  1.7731 + * Class used to represent events generated by calls to Window.postMessage,
  1.7732 + * which asynchronously creates and dispatches events.
  1.7733 + */
  1.7734 +class PostMessageEvent : public nsRunnable
  1.7735 +{
  1.7736 +  public:
  1.7737 +    NS_DECL_NSIRUNNABLE
  1.7738 +
  1.7739 +    PostMessageEvent(nsGlobalWindow* aSource,
  1.7740 +                     const nsAString& aCallerOrigin,
  1.7741 +                     nsGlobalWindow* aTargetWindow,
  1.7742 +                     nsIPrincipal* aProvidedPrincipal,
  1.7743 +                     bool aTrustedCaller)
  1.7744 +    : mSource(aSource),
  1.7745 +      mCallerOrigin(aCallerOrigin),
  1.7746 +      mTargetWindow(aTargetWindow),
  1.7747 +      mProvidedPrincipal(aProvidedPrincipal),
  1.7748 +      mTrustedCaller(aTrustedCaller)
  1.7749 +    {
  1.7750 +      MOZ_COUNT_CTOR(PostMessageEvent);
  1.7751 +    }
  1.7752 +    
  1.7753 +    ~PostMessageEvent()
  1.7754 +    {
  1.7755 +      MOZ_COUNT_DTOR(PostMessageEvent);
  1.7756 +    }
  1.7757 +
  1.7758 +    JSAutoStructuredCloneBuffer& Buffer()
  1.7759 +    {
  1.7760 +      return mBuffer;
  1.7761 +    }
  1.7762 +
  1.7763 +    bool StoreISupports(nsISupports* aSupports)
  1.7764 +    {
  1.7765 +      mSupportsArray.AppendElement(aSupports);
  1.7766 +      return true;
  1.7767 +    }
  1.7768 +
  1.7769 +  private:
  1.7770 +    JSAutoStructuredCloneBuffer mBuffer;
  1.7771 +    nsRefPtr<nsGlobalWindow> mSource;
  1.7772 +    nsString mCallerOrigin;
  1.7773 +    nsRefPtr<nsGlobalWindow> mTargetWindow;
  1.7774 +    nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
  1.7775 +    bool mTrustedCaller;
  1.7776 +    nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
  1.7777 +};
  1.7778 +
  1.7779 +namespace {
  1.7780 +
  1.7781 +struct StructuredCloneInfo {
  1.7782 +  PostMessageEvent* event;
  1.7783 +  bool subsumes;
  1.7784 +  nsPIDOMWindow* window;
  1.7785 +  nsRefPtrHashtable<nsRefPtrHashKey<MessagePortBase>, MessagePortBase> ports;
  1.7786 +};
  1.7787 +
  1.7788 +static JSObject*
  1.7789 +PostMessageReadStructuredClone(JSContext* cx,
  1.7790 +                               JSStructuredCloneReader* reader,
  1.7791 +                               uint32_t tag,
  1.7792 +                               uint32_t data,
  1.7793 +                               void* closure)
  1.7794 +{
  1.7795 +  if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
  1.7796 +    NS_ASSERTION(!data, "Data should be empty");
  1.7797 +
  1.7798 +    nsISupports* supports;
  1.7799 +    if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
  1.7800 +      JS::Rooted<JS::Value> val(cx);
  1.7801 +      if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
  1.7802 +        return val.toObjectOrNull();
  1.7803 +      }
  1.7804 +    }
  1.7805 +  }
  1.7806 +
  1.7807 +  const JSStructuredCloneCallbacks* runtimeCallbacks =
  1.7808 +    js::GetContextStructuredCloneCallbacks(cx);
  1.7809 +
  1.7810 +  if (runtimeCallbacks) {
  1.7811 +    return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
  1.7812 +  }
  1.7813 +
  1.7814 +  return nullptr;
  1.7815 +}
  1.7816 +
  1.7817 +static bool
  1.7818 +PostMessageWriteStructuredClone(JSContext* cx,
  1.7819 +                                JSStructuredCloneWriter* writer,
  1.7820 +                                JS::Handle<JSObject*> obj,
  1.7821 +                                void *closure)
  1.7822 +{
  1.7823 +  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
  1.7824 +  NS_ASSERTION(scInfo, "Must have scInfo!");
  1.7825 +
  1.7826 +  nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
  1.7827 +  nsContentUtils::XPConnect()->
  1.7828 +    GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
  1.7829 +  if (wrappedNative) {
  1.7830 +    uint32_t scTag = 0;
  1.7831 +    nsISupports* supports = wrappedNative->Native();
  1.7832 +
  1.7833 +    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
  1.7834 +    if (blob && scInfo->subsumes)
  1.7835 +      scTag = SCTAG_DOM_BLOB;
  1.7836 +
  1.7837 +    nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
  1.7838 +    if (list && scInfo->subsumes)
  1.7839 +      scTag = SCTAG_DOM_FILELIST;
  1.7840 +
  1.7841 +    if (scTag)
  1.7842 +      return JS_WriteUint32Pair(writer, scTag, 0) &&
  1.7843 +             JS_WriteBytes(writer, &supports, sizeof(supports)) &&
  1.7844 +             scInfo->event->StoreISupports(supports);
  1.7845 +  }
  1.7846 +
  1.7847 +  const JSStructuredCloneCallbacks* runtimeCallbacks =
  1.7848 +    js::GetContextStructuredCloneCallbacks(cx);
  1.7849 +
  1.7850 +  if (runtimeCallbacks) {
  1.7851 +    return runtimeCallbacks->write(cx, writer, obj, nullptr);
  1.7852 +  }
  1.7853 +
  1.7854 +  return false;
  1.7855 +}
  1.7856 +
  1.7857 +static bool
  1.7858 +PostMessageReadTransferStructuredClone(JSContext* aCx,
  1.7859 +                                       JSStructuredCloneReader* reader,
  1.7860 +                                       uint32_t tag, void* aData,
  1.7861 +                                       uint64_t aExtraData,
  1.7862 +                                       void* aClosure,
  1.7863 +                                       JS::MutableHandle<JSObject*> returnObject)
  1.7864 +{
  1.7865 +  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
  1.7866 +  NS_ASSERTION(scInfo, "Must have scInfo!");
  1.7867 +
  1.7868 +  if (MessageChannel::PrefEnabled() && tag == SCTAG_DOM_MAP_MESSAGEPORT) {
  1.7869 +    MessagePort* port = static_cast<MessagePort*>(aData);
  1.7870 +    port->BindToOwner(scInfo->window);
  1.7871 +    scInfo->ports.Put(port, nullptr);
  1.7872 +
  1.7873 +    JS::Rooted<JSObject*> obj(aCx, port->WrapObject(aCx));
  1.7874 +    if (JS_WrapObject(aCx, &obj)) {
  1.7875 +      MOZ_ASSERT(port->GetOwner() == scInfo->window);
  1.7876 +      returnObject.set(obj);
  1.7877 +    }
  1.7878 +
  1.7879 +    return true;
  1.7880 +  }
  1.7881 +
  1.7882 +  return false;
  1.7883 +}
  1.7884 +
  1.7885 +static bool
  1.7886 +PostMessageTransferStructuredClone(JSContext* aCx,
  1.7887 +                                   JS::Handle<JSObject*> aObj,
  1.7888 +                                   void* aClosure,
  1.7889 +                                   uint32_t* aTag,
  1.7890 +                                   JS::TransferableOwnership* aOwnership,
  1.7891 +                                   void** aContent,
  1.7892 +                                   uint64_t* aExtraData)
  1.7893 +{
  1.7894 +  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
  1.7895 +  NS_ASSERTION(scInfo, "Must have scInfo!");
  1.7896 +
  1.7897 +  if (MessageChannel::PrefEnabled()) {
  1.7898 +    MessagePortBase* port = nullptr;
  1.7899 +    nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
  1.7900 +    if (NS_SUCCEEDED(rv)) {
  1.7901 +      nsRefPtr<MessagePortBase> newPort;
  1.7902 +      if (scInfo->ports.Get(port, getter_AddRefs(newPort))) {
  1.7903 +        // No duplicate.
  1.7904 +        return false;
  1.7905 +      }
  1.7906 +
  1.7907 +      newPort = port->Clone();
  1.7908 +      scInfo->ports.Put(port, newPort);
  1.7909 +
  1.7910 +      *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
  1.7911 +      *aOwnership = JS::SCTAG_TMO_CUSTOM;
  1.7912 +      *aContent = newPort;
  1.7913 +      *aExtraData = 0;
  1.7914 +
  1.7915 +      return true;
  1.7916 +    }
  1.7917 +  }
  1.7918 +
  1.7919 +  return false;
  1.7920 +}
  1.7921 +
  1.7922 +void
  1.7923 +PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership,
  1.7924 +                                       void *aContent, uint64_t aExtraData, void* aClosure)
  1.7925 +{
  1.7926 +  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
  1.7927 +  NS_ASSERTION(scInfo, "Must have scInfo!");
  1.7928 +
  1.7929 +  if (MessageChannel::PrefEnabled() && aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
  1.7930 +    nsRefPtr<MessagePortBase> port(static_cast<MessagePort*>(aContent));
  1.7931 +    scInfo->ports.Remove(port);
  1.7932 +  }
  1.7933 +}
  1.7934 +
  1.7935 +JSStructuredCloneCallbacks kPostMessageCallbacks = {
  1.7936 +  PostMessageReadStructuredClone,
  1.7937 +  PostMessageWriteStructuredClone,
  1.7938 +  nullptr,
  1.7939 +  PostMessageReadTransferStructuredClone,
  1.7940 +  PostMessageTransferStructuredClone,
  1.7941 +  PostMessageFreeTransferStructuredClone
  1.7942 +};
  1.7943 +
  1.7944 +} // anonymous namespace
  1.7945 +
  1.7946 +static PLDHashOperator
  1.7947 +PopulateMessagePortList(MessagePortBase* aKey, MessagePortBase* aValue, void* aClosure)
  1.7948 +{
  1.7949 +  nsTArray<nsRefPtr<MessagePortBase> > *array =
  1.7950 +    static_cast<nsTArray<nsRefPtr<MessagePortBase> > *>(aClosure);
  1.7951 +
  1.7952 +  array->AppendElement(aKey);
  1.7953 +  return PL_DHASH_NEXT;
  1.7954 +}
  1.7955 +
  1.7956 +NS_IMETHODIMP
  1.7957 +PostMessageEvent::Run()
  1.7958 +{
  1.7959 +  NS_ABORT_IF_FALSE(mTargetWindow->IsOuterWindow(),
  1.7960 +                    "should have been passed an outer window!");
  1.7961 +  NS_ABORT_IF_FALSE(!mSource || mSource->IsOuterWindow(),
  1.7962 +                    "should have been passed an outer window!");
  1.7963 +
  1.7964 +  AutoJSAPI jsapi;
  1.7965 +  JSContext* cx = jsapi.cx();
  1.7966 +
  1.7967 +  // If we bailed before this point we're going to leak mMessage, but
  1.7968 +  // that's probably better than crashing.
  1.7969 +
  1.7970 +  nsRefPtr<nsGlobalWindow> targetWindow;
  1.7971 +  if (mTargetWindow->IsClosedOrClosing() ||
  1.7972 +      !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
  1.7973 +      targetWindow->IsClosedOrClosing())
  1.7974 +    return NS_OK;
  1.7975 +
  1.7976 +  NS_ABORT_IF_FALSE(targetWindow->IsInnerWindow(),
  1.7977 +                    "we ordered an inner window!");
  1.7978 +  JSAutoCompartment ac(cx, targetWindow->GetWrapperPreserveColor());
  1.7979 +
  1.7980 +  // Ensure that any origin which might have been provided is the origin of this
  1.7981 +  // window's document.  Note that we do this *now* instead of when postMessage
  1.7982 +  // is called because the target window might have been navigated to a
  1.7983 +  // different location between then and now.  If this check happened when
  1.7984 +  // postMessage was called, it would be fairly easy for a malicious webpage to
  1.7985 +  // intercept messages intended for another site by carefully timing navigation
  1.7986 +  // of the target window so it changed location after postMessage but before
  1.7987 +  // now.
  1.7988 +  if (mProvidedPrincipal) {
  1.7989 +    // Get the target's origin either from its principal or, in the case the
  1.7990 +    // principal doesn't carry a URI (e.g. the system principal), the target's
  1.7991 +    // document.
  1.7992 +    nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
  1.7993 +    if (NS_WARN_IF(!targetPrin))
  1.7994 +      return NS_OK;
  1.7995 +
  1.7996 +    // Note: This is contrary to the spec with respect to file: URLs, which
  1.7997 +    //       the spec groups into a single origin, but given we intentionally
  1.7998 +    //       don't do that in other places it seems better to hold the line for
  1.7999 +    //       now.  Long-term, we want HTML5 to address this so that we can
  1.8000 +    //       be compliant while being safer.
  1.8001 +    if (!targetPrin->Equals(mProvidedPrincipal)) {
  1.8002 +      return NS_OK;
  1.8003 +    }
  1.8004 +  }
  1.8005 +
  1.8006 +  // Deserialize the structured clone data
  1.8007 +  JS::Rooted<JS::Value> messageData(cx);
  1.8008 +  StructuredCloneInfo scInfo;
  1.8009 +  scInfo.event = this;
  1.8010 +  scInfo.window = targetWindow;
  1.8011 +
  1.8012 +  if (!mBuffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo)) {
  1.8013 +    return NS_ERROR_DOM_DATA_CLONE_ERR;
  1.8014 +  }
  1.8015 +
  1.8016 +  // Create the event
  1.8017 +  nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
  1.8018 +    do_QueryInterface(static_cast<nsPIDOMWindow*>(targetWindow.get()));
  1.8019 +  nsRefPtr<MessageEvent> event =
  1.8020 +    new MessageEvent(eventTarget, nullptr, nullptr);
  1.8021 +
  1.8022 +  event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */,
  1.8023 +                          false /*cancelable */, messageData, mCallerOrigin,
  1.8024 +                          EmptyString(), mSource);
  1.8025 +
  1.8026 +  nsTArray<nsRefPtr<MessagePortBase> > ports;
  1.8027 +  scInfo.ports.EnumerateRead(PopulateMessagePortList, &ports);
  1.8028 +  event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()), ports));
  1.8029 +
  1.8030 +  // We can't simply call dispatchEvent on the window because doing so ends
  1.8031 +  // up flipping the trusted bit on the event, and we don't want that to
  1.8032 +  // happen because then untrusted content can call postMessage on a chrome
  1.8033 +  // window if it can get a reference to it.
  1.8034 +
  1.8035 +  nsIPresShell *shell = targetWindow->mDoc->GetShell();
  1.8036 +  nsRefPtr<nsPresContext> presContext;
  1.8037 +  if (shell)
  1.8038 +    presContext = shell->GetPresContext();
  1.8039 +
  1.8040 +  event->SetTrusted(mTrustedCaller);
  1.8041 +  WidgetEvent* internalEvent = event->GetInternalNSEvent();
  1.8042 +
  1.8043 +  nsEventStatus status = nsEventStatus_eIgnore;
  1.8044 +  EventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
  1.8045 +                            presContext,
  1.8046 +                            internalEvent,
  1.8047 +                            static_cast<dom::Event*>(event.get()),
  1.8048 +                            &status);
  1.8049 +  return NS_OK;
  1.8050 +}
  1.8051 +
  1.8052 +void
  1.8053 +nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
  1.8054 +                               const nsAString& aTargetOrigin,
  1.8055 +                               JS::Handle<JS::Value> aTransfer,
  1.8056 +                               ErrorResult& aError)
  1.8057 +{
  1.8058 +  FORWARD_TO_OUTER_OR_THROW(PostMessageMoz,
  1.8059 +                            (aCx, aMessage, aTargetOrigin, aTransfer, aError),
  1.8060 +                            aError, );
  1.8061 +
  1.8062 +  //
  1.8063 +  // Window.postMessage is an intentional subversion of the same-origin policy.
  1.8064 +  // As such, this code must be particularly careful in the information it
  1.8065 +  // exposes to calling code.
  1.8066 +  //
  1.8067 +  // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
  1.8068 +  //
  1.8069 +
  1.8070 +  // First, get the caller's window
  1.8071 +  nsRefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
  1.8072 +  nsIPrincipal* callerPrin;
  1.8073 +  if (callerInnerWin) {
  1.8074 +    NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(),
  1.8075 +                      "should have gotten an inner window here");
  1.8076 +
  1.8077 +    // Compute the caller's origin either from its principal or, in the case the
  1.8078 +    // principal doesn't carry a URI (e.g. the system principal), the caller's
  1.8079 +    // document.  We must get this now instead of when the event is created and
  1.8080 +    // dispatched, because ultimately it is the identity of the calling window
  1.8081 +    // *now* that determines who sent the message (and not an identity which might
  1.8082 +    // have changed due to intervening navigations).
  1.8083 +    callerPrin = callerInnerWin->GetPrincipal();
  1.8084 +  }
  1.8085 +  else {
  1.8086 +    // In case the global is not a window, it can be a sandbox, and the sandbox's
  1.8087 +    // principal can be used for the security check.
  1.8088 +    JSObject *global = CallerGlobal();
  1.8089 +    NS_ASSERTION(global, "Why is there no global object?");
  1.8090 +    JSCompartment *compartment = js::GetObjectCompartment(global);
  1.8091 +    callerPrin = xpc::GetCompartmentPrincipal(compartment);
  1.8092 +  }
  1.8093 +  if (!callerPrin) {
  1.8094 +    return;
  1.8095 +  }
  1.8096 +
  1.8097 +  nsCOMPtr<nsIURI> callerOuterURI;
  1.8098 +  if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI)))) {
  1.8099 +    return;
  1.8100 +  }
  1.8101 +
  1.8102 +  nsAutoString origin;
  1.8103 +  if (callerOuterURI) {
  1.8104 +    // if the principal has a URI, use that to generate the origin
  1.8105 +    nsContentUtils::GetUTFOrigin(callerPrin, origin);
  1.8106 +  }
  1.8107 +  else if (callerInnerWin) {
  1.8108 +    // otherwise use the URI of the document to generate origin
  1.8109 +    nsCOMPtr<nsIDocument> doc = callerInnerWin->GetExtantDoc();
  1.8110 +    if (!doc) {
  1.8111 +      return;
  1.8112 +    }
  1.8113 +    callerOuterURI = doc->GetDocumentURI();
  1.8114 +    // if the principal has a URI, use that to generate the origin
  1.8115 +    nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
  1.8116 +  }
  1.8117 +  else {
  1.8118 +    // in case of a sandbox with a system principal origin can be empty
  1.8119 +    if (!nsContentUtils::IsSystemPrincipal(callerPrin)) {
  1.8120 +      return;
  1.8121 +    }
  1.8122 +  }
  1.8123 +
  1.8124 +  // Convert the provided origin string into a URI for comparison purposes.
  1.8125 +  nsCOMPtr<nsIPrincipal> providedPrincipal;
  1.8126 +
  1.8127 +  if (aTargetOrigin.EqualsASCII("/")) {
  1.8128 +    providedPrincipal = BrokenGetEntryGlobal()->PrincipalOrNull();
  1.8129 +    if (NS_WARN_IF(!providedPrincipal))
  1.8130 +      return;
  1.8131 +  }
  1.8132 +
  1.8133 +  // "*" indicates no specific origin is required.
  1.8134 +  else if (!aTargetOrigin.EqualsASCII("*")) {
  1.8135 +    nsCOMPtr<nsIURI> originURI;
  1.8136 +    if (NS_FAILED(NS_NewURI(getter_AddRefs(originURI), aTargetOrigin))) {
  1.8137 +      aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  1.8138 +      return;
  1.8139 +    }
  1.8140 +
  1.8141 +    if (NS_FAILED(originURI->SetUserPass(EmptyCString())) ||
  1.8142 +        NS_FAILED(originURI->SetPath(EmptyCString()))) {
  1.8143 +      return;
  1.8144 +    }
  1.8145 +
  1.8146 +    nsCOMPtr<nsIScriptSecurityManager> ssm =
  1.8147 +      nsContentUtils::GetSecurityManager();
  1.8148 +    MOZ_ASSERT(ssm);
  1.8149 +
  1.8150 +    nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetSubjectPrincipal();
  1.8151 +    MOZ_ASSERT(principal);
  1.8152 +
  1.8153 +    uint32_t appId;
  1.8154 +    if (NS_WARN_IF(NS_FAILED(principal->GetAppId(&appId))))
  1.8155 +      return;
  1.8156 +
  1.8157 +    bool isInBrowser;
  1.8158 +    if (NS_WARN_IF(NS_FAILED(principal->GetIsInBrowserElement(&isInBrowser))))
  1.8159 +      return;
  1.8160 +
  1.8161 +    // Create a nsIPrincipal inheriting the app/browser attributes from the
  1.8162 +    // caller.
  1.8163 +    nsresult rv = ssm->GetAppCodebasePrincipal(originURI, appId, isInBrowser,
  1.8164 +                                             getter_AddRefs(providedPrincipal));
  1.8165 +    if (NS_WARN_IF(NS_FAILED(rv))) {
  1.8166 +      return;
  1.8167 +    }
  1.8168 +  }
  1.8169 +
  1.8170 +  // Create and asynchronously dispatch a runnable which will handle actual DOM
  1.8171 +  // event creation and dispatch.
  1.8172 +  nsRefPtr<PostMessageEvent> event =
  1.8173 +    new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin
  1.8174 +                         ? nullptr
  1.8175 +                         : callerInnerWin->GetOuterWindowInternal(),
  1.8176 +                         origin,
  1.8177 +                         this,
  1.8178 +                         providedPrincipal,
  1.8179 +                         nsContentUtils::IsCallerChrome());
  1.8180 +
  1.8181 +  // We *must* clone the data here, or the JS::Value could be modified
  1.8182 +  // by script
  1.8183 +  StructuredCloneInfo scInfo;
  1.8184 +  scInfo.event = event;
  1.8185 +  scInfo.window = this;
  1.8186 +
  1.8187 +  nsIPrincipal* principal = GetPrincipal();
  1.8188 +  JS::Rooted<JS::Value> message(aCx, aMessage);
  1.8189 +  JS::Rooted<JS::Value> transfer(aCx, aTransfer);
  1.8190 +  if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)) ||
  1.8191 +      !event->Buffer().write(aCx, message, transfer, &kPostMessageCallbacks,
  1.8192 +                             &scInfo)) {
  1.8193 +    aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
  1.8194 +    return;
  1.8195 +  }
  1.8196 +
  1.8197 +  aError = NS_DispatchToCurrentThread(event);
  1.8198 +}
  1.8199 +
  1.8200 +void
  1.8201 +nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
  1.8202 +                               const nsAString& aTargetOrigin,
  1.8203 +                               const Optional<Sequence<JS::Value > >& aTransfer,
  1.8204 +                               ErrorResult& aError)
  1.8205 +{
  1.8206 +  JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
  1.8207 +  if (aTransfer.WasPassed()) {
  1.8208 +    const Sequence<JS::Value >& values = aTransfer.Value();
  1.8209 +
  1.8210 +    // The input sequence only comes from the generated bindings code, which
  1.8211 +    // ensures it is rooted.
  1.8212 +    JS::HandleValueArray elements =
  1.8213 +      JS::HandleValueArray::fromMarkedLocation(values.Length(), values.Elements());
  1.8214 +
  1.8215 +    transferArray = JS::ObjectOrNullValue(JS_NewArrayObject(aCx, elements));
  1.8216 +    if (transferArray.isNull()) {
  1.8217 +      aError.Throw(NS_ERROR_OUT_OF_MEMORY);
  1.8218 +      return;
  1.8219 +    }
  1.8220 +  }
  1.8221 +
  1.8222 +  PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray, aError);
  1.8223 +}
  1.8224 +
  1.8225 +NS_IMETHODIMP
  1.8226 +nsGlobalWindow::PostMessageMoz(JS::Handle<JS::Value> aMessage,
  1.8227 +                               const nsAString& aOrigin,
  1.8228 +                               JS::Handle<JS::Value> aTransfer,
  1.8229 +                               JSContext* aCx)
  1.8230 +{
  1.8231 +  ErrorResult rv;
  1.8232 +  PostMessageMoz(aCx, aMessage, aOrigin, aTransfer, rv);
  1.8233 +
  1.8234 +  return rv.ErrorCode();
  1.8235 +}
  1.8236 +
  1.8237 +class nsCloseEvent : public nsRunnable {
  1.8238 +
  1.8239 +  nsRefPtr<nsGlobalWindow> mWindow;
  1.8240 +  bool mIndirect;
  1.8241 +
  1.8242 +  nsCloseEvent(nsGlobalWindow *aWindow, bool aIndirect)
  1.8243 +    : mWindow(aWindow)
  1.8244 +    , mIndirect(aIndirect)
  1.8245 +  {}
  1.8246 +
  1.8247 +public:
  1.8248 +
  1.8249 +  static nsresult
  1.8250 +  PostCloseEvent(nsGlobalWindow* aWindow, bool aIndirect) {
  1.8251 +    nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
  1.8252 +    nsresult rv = NS_DispatchToCurrentThread(ev);
  1.8253 +    if (NS_SUCCEEDED(rv))
  1.8254 +      aWindow->MaybeForgiveSpamCount();
  1.8255 +    return rv;
  1.8256 +  }
  1.8257 +
  1.8258 +  NS_IMETHOD Run() {
  1.8259 +    if (mWindow) {
  1.8260 +      if (mIndirect) {
  1.8261 +        return PostCloseEvent(mWindow, false);
  1.8262 +      }
  1.8263 +      mWindow->ReallyCloseWindow();
  1.8264 +    }
  1.8265 +    return NS_OK;
  1.8266 +  }
  1.8267 +
  1.8268 +};
  1.8269 +
  1.8270 +bool
  1.8271 +nsGlobalWindow::CanClose()
  1.8272 +{
  1.8273 +  if (!mDocShell)
  1.8274 +    return true;
  1.8275 +
  1.8276 +  // Ask the content viewer whether the toplevel window can close.
  1.8277 +  // If the content viewer returns false, it is responsible for calling
  1.8278 +  // Close() as soon as it is possible for the window to close.
  1.8279 +  // This allows us to not close the window while printing is happening.
  1.8280 +
  1.8281 +  nsCOMPtr<nsIContentViewer> cv;
  1.8282 +  mDocShell->GetContentViewer(getter_AddRefs(cv));
  1.8283 +  if (cv) {
  1.8284 +    bool canClose;
  1.8285 +    nsresult rv = cv->PermitUnload(false, &canClose);
  1.8286 +    if (NS_SUCCEEDED(rv) && !canClose)
  1.8287 +      return false;
  1.8288 +
  1.8289 +    rv = cv->RequestWindowClose(&canClose);
  1.8290 +    if (NS_SUCCEEDED(rv) && !canClose)
  1.8291 +      return false;
  1.8292 +  }
  1.8293 +
  1.8294 +  return true;
  1.8295 +}
  1.8296 +
  1.8297 +void
  1.8298 +nsGlobalWindow::Close(ErrorResult& aError)
  1.8299 +{
  1.8300 +  FORWARD_TO_OUTER_OR_THROW(Close, (aError), aError, );
  1.8301 +
  1.8302 +  if (!mDocShell || IsInModalState() ||
  1.8303 +      (IsFrame() && !mDocShell->GetIsBrowserOrApp())) {
  1.8304 +    // window.close() is called on a frame in a frameset, on a window
  1.8305 +    // that's already closed, or on a window for which there's
  1.8306 +    // currently a modal dialog open. Ignore such calls.
  1.8307 +    return;
  1.8308 +  }
  1.8309 +
  1.8310 +  if (mHavePendingClose) {
  1.8311 +    // We're going to be closed anyway; do nothing since we don't want
  1.8312 +    // to double-close
  1.8313 +    return;
  1.8314 +  }
  1.8315 +
  1.8316 +  if (mBlockScriptedClosingFlag)
  1.8317 +  {
  1.8318 +    // A script's popup has been blocked and we don't want
  1.8319 +    // the window to be closed directly after this event,
  1.8320 +    // so the user can see that there was a blocked popup.
  1.8321 +    return;
  1.8322 +  }
  1.8323 +
  1.8324 +  // Don't allow scripts from content to close non-app or non-neterror
  1.8325 +  // windows that were not opened by script.
  1.8326 +  nsAutoString url;
  1.8327 +  mDoc->GetURL(url);
  1.8328 +  if (!mDocShell->GetIsApp() &&
  1.8329 +      !StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
  1.8330 +      !mHadOriginalOpener && !nsContentUtils::IsCallerChrome()) {
  1.8331 +    bool allowClose = mAllowScriptsToClose ||
  1.8332 +      Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
  1.8333 +    if (!allowClose) {
  1.8334 +      // We're blocking the close operation
  1.8335 +      // report localized error msg in JS console
  1.8336 +      nsContentUtils::ReportToConsole(
  1.8337 +          nsIScriptError::warningFlag,
  1.8338 +          NS_LITERAL_CSTRING("DOM Window"), mDoc,  // Better name for the category?
  1.8339 +          nsContentUtils::eDOM_PROPERTIES,
  1.8340 +          "WindowCloseBlockedWarning");
  1.8341 +
  1.8342 +      return;
  1.8343 +    }
  1.8344 +  }
  1.8345 +
  1.8346 +  if (!mInClose && !mIsClosed && !CanClose()) {
  1.8347 +    return;
  1.8348 +  }
  1.8349 +
  1.8350 +  // Fire a DOM event notifying listeners that this window is about to
  1.8351 +  // be closed. The tab UI code may choose to cancel the default
  1.8352 +  // action for this event, if so, we won't actually close the window
  1.8353 +  // (since the tab UI code will close the tab in stead). Sure, this
  1.8354 +  // could be abused by content code, but do we care? I don't think
  1.8355 +  // so...
  1.8356 +
  1.8357 +  bool wasInClose = mInClose;
  1.8358 +  mInClose = true;
  1.8359 +
  1.8360 +  if (!DispatchCustomEvent("DOMWindowClose")) {
  1.8361 +    // Someone chose to prevent the default action for this event, if
  1.8362 +    // so, let's not close this window after all...
  1.8363 +
  1.8364 +    mInClose = wasInClose;
  1.8365 +    return;
  1.8366 +  }
  1.8367 +
  1.8368 +  aError = FinalClose();
  1.8369 +}
  1.8370 +
  1.8371 +NS_IMETHODIMP
  1.8372 +nsGlobalWindow::Close()
  1.8373 +{
  1.8374 +  ErrorResult rv;
  1.8375 +  Close(rv);
  1.8376 +
  1.8377 +  return rv.ErrorCode();
  1.8378 +}
  1.8379 +
  1.8380 +nsresult
  1.8381 +nsGlobalWindow::ForceClose()
  1.8382 +{
  1.8383 +  if (IsFrame() || !mDocShell) {
  1.8384 +    // This may be a frame in a frameset, or a window that's already closed.
  1.8385 +    // Ignore such calls.
  1.8386 +
  1.8387 +    return NS_OK;
  1.8388 +  }
  1.8389 +
  1.8390 +  if (mHavePendingClose) {
  1.8391 +    // We're going to be closed anyway; do nothing since we don't want
  1.8392 +    // to double-close
  1.8393 +    return NS_OK;
  1.8394 +  }
  1.8395 +
  1.8396 +  mInClose = true;
  1.8397 +
  1.8398 +  DispatchCustomEvent("DOMWindowClose");
  1.8399 +
  1.8400 +  return FinalClose();
  1.8401 +}
  1.8402 +
  1.8403 +nsresult
  1.8404 +nsGlobalWindow::FinalClose()
  1.8405 +{
  1.8406 +  // Flag that we were closed.
  1.8407 +  mIsClosed = true;
  1.8408 +
  1.8409 +  // This stuff is non-sensical but incredibly fragile. The reasons for the
  1.8410 +  // behavior here don't make sense today and may not have ever made sense,
  1.8411 +  // but various bits of frontend code break when you change them. If you need
  1.8412 +  // to fix up this behavior, feel free to. It's a righteous task, but involves
  1.8413 +  // wrestling with various download manager tests, frontend code, and possible
  1.8414 +  // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
  1.8415 +  // testing ground.
  1.8416 +  //
  1.8417 +  // In particular, if |win|'s JSContext is at the top of the stack, we must
  1.8418 +  // complete _two_ round-trips to the event loop before the call to
  1.8419 +  // ReallyCloseWindow. This allows setTimeout handlers that are set after
  1.8420 +  // FinalClose() is called to run before the window is torn down.
  1.8421 +  bool indirect = GetContextInternal() && // Occasionally null. See bug 877390.
  1.8422 +                  (nsContentUtils::GetCurrentJSContext() ==
  1.8423 +                   GetContextInternal()->GetNativeContext());
  1.8424 +  if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))) {
  1.8425 +    ReallyCloseWindow();
  1.8426 +  } else {
  1.8427 +    mHavePendingClose = true;
  1.8428 +  }
  1.8429 +
  1.8430 +  return NS_OK;
  1.8431 +}
  1.8432 +
  1.8433 +
  1.8434 +void
  1.8435 +nsGlobalWindow::ReallyCloseWindow()
  1.8436 +{
  1.8437 +  FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
  1.8438 +
  1.8439 +  // Make sure we never reenter this method.
  1.8440 +  mHavePendingClose = true;
  1.8441 +
  1.8442 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
  1.8443 +
  1.8444 +  // If there's no treeOwnerAsWin, this window must already be closed.
  1.8445 +
  1.8446 +  if (treeOwnerAsWin) {
  1.8447 +
  1.8448 +    // but if we're a browser window we could be in some nasty
  1.8449 +    // self-destroying cascade that we should mostly ignore
  1.8450 +
  1.8451 +    if (mDocShell) {
  1.8452 +      nsCOMPtr<nsIBrowserDOMWindow> bwin;
  1.8453 +      nsCOMPtr<nsIDocShellTreeItem> rootItem;
  1.8454 +      mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
  1.8455 +      nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
  1.8456 +      nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
  1.8457 +      if (chromeWin)
  1.8458 +        chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
  1.8459 +
  1.8460 +      if (rootWin) {
  1.8461 +        /* Normally we destroy the entire window, but not if
  1.8462 +           this DOM window belongs to a tabbed browser and doesn't
  1.8463 +           correspond to a tab. This allows a well-behaved tab
  1.8464 +           to destroy the container as it should but is a final measure
  1.8465 +           to prevent an errant tab from doing so when it shouldn't.
  1.8466 +           This works because we reach this code when we shouldn't only
  1.8467 +           in the particular circumstance that we belong to a tab
  1.8468 +           that has just been closed (and is therefore already missing
  1.8469 +           from the list of browsers) (and has an unload handler
  1.8470 +           that closes the window). */
  1.8471 +        // XXXbz now that we have mHavePendingClose, is this needed?
  1.8472 +        bool isTab = false;
  1.8473 +        if (rootWin == this ||
  1.8474 +            !bwin || (bwin->IsTabContentWindow(GetOuterWindowInternal(),
  1.8475 +                                               &isTab), isTab))
  1.8476 +          treeOwnerAsWin->Destroy();
  1.8477 +      }
  1.8478 +    }
  1.8479 +
  1.8480 +    CleanUp();
  1.8481 +  }
  1.8482 +}
  1.8483 +
  1.8484 +void
  1.8485 +nsGlobalWindow::EnterModalState()
  1.8486 +{
  1.8487 +  MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
  1.8488 +
  1.8489 +  // GetScriptableTop, not GetTop, so that EnterModalState works properly with
  1.8490 +  // <iframe mozbrowser>.
  1.8491 +  nsGlobalWindow* topWin = GetScriptableTop();
  1.8492 +
  1.8493 +  if (!topWin) {
  1.8494 +    NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
  1.8495 +    return;
  1.8496 +  }
  1.8497 +
  1.8498 +  // If there is an active ESM in this window, clear it. Otherwise, this can
  1.8499 +  // cause a problem if a modal state is entered during a mouseup event.
  1.8500 +  EventStateManager* activeESM =
  1.8501 +    static_cast<EventStateManager*>(
  1.8502 +      EventStateManager::GetActiveEventStateManager());
  1.8503 +  if (activeESM && activeESM->GetPresContext()) {
  1.8504 +    nsIPresShell* activeShell = activeESM->GetPresContext()->GetPresShell();
  1.8505 +    if (activeShell && (
  1.8506 +        nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(), mDoc) ||
  1.8507 +        nsContentUtils::ContentIsCrossDocDescendantOf(mDoc, activeShell->GetDocument()))) {
  1.8508 +      EventStateManager::ClearGlobalActiveContent(activeESM);
  1.8509 +
  1.8510 +      activeShell->SetCapturingContent(nullptr, 0);
  1.8511 +
  1.8512 +      if (activeShell) {
  1.8513 +        nsRefPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
  1.8514 +        frameSelection->SetMouseDownState(false);
  1.8515 +      }
  1.8516 +    }
  1.8517 +  }
  1.8518 +
  1.8519 +  // If there are any drag and drop operations in flight, try to end them.
  1.8520 +  nsCOMPtr<nsIDragService> ds =
  1.8521 +    do_GetService("@mozilla.org/widget/dragservice;1");
  1.8522 +  if (ds) {
  1.8523 +    ds->EndDragSession(true);
  1.8524 +  }
  1.8525 +
  1.8526 +  // Clear the capturing content if it is under topDoc.
  1.8527 +  // Usually the activeESM check above does that, but there are cases when
  1.8528 +  // we don't have activeESM, or it is for different document.
  1.8529 +  nsIDocument* topDoc = topWin->GetExtantDoc();
  1.8530 +  nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
  1.8531 +  if (capturingContent && topDoc &&
  1.8532 +      nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
  1.8533 +    nsIPresShell::SetCapturingContent(nullptr, 0);
  1.8534 +  }
  1.8535 +
  1.8536 +  if (topWin->mModalStateDepth == 0) {
  1.8537 +    NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
  1.8538 +
  1.8539 +    mSuspendedDoc = topDoc;
  1.8540 +    if (mSuspendedDoc) {
  1.8541 +      mSuspendedDoc->SuppressEventHandling(nsIDocument::eAnimationsOnly);
  1.8542 +    }
  1.8543 +  }
  1.8544 +  topWin->mModalStateDepth++;
  1.8545 +}
  1.8546 +
  1.8547 +// static
  1.8548 +void
  1.8549 +nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
  1.8550 +                                            nsGlobalWindow *aWindow)
  1.8551 +{
  1.8552 +  nsGlobalWindow *inner;
  1.8553 +
  1.8554 +  // Return early if we're frozen or have no inner window.
  1.8555 +  if (!(inner = aWindow->GetCurrentInnerWindowInternal()) ||
  1.8556 +      inner->IsFrozen()) {
  1.8557 +    return;
  1.8558 +  }
  1.8559 +
  1.8560 +  inner->RunTimeout(nullptr);
  1.8561 +
  1.8562 +  // Check again if we're frozen since running pending timeouts
  1.8563 +  // could've frozen us.
  1.8564 +  if (inner->IsFrozen()) {
  1.8565 +    return;
  1.8566 +  }
  1.8567 +
  1.8568 +  nsCOMPtr<nsIDOMWindowCollection> frames;
  1.8569 +  aWindow->GetFrames(getter_AddRefs(frames));
  1.8570 +
  1.8571 +  if (!frames) {
  1.8572 +    return;
  1.8573 +  }
  1.8574 +
  1.8575 +  uint32_t i, length;
  1.8576 +  if (NS_FAILED(frames->GetLength(&length)) || !length) {
  1.8577 +    return;
  1.8578 +  }
  1.8579 +
  1.8580 +  for (i = 0; i < length && aTopWindow->mModalStateDepth == 0; i++) {
  1.8581 +    nsCOMPtr<nsIDOMWindow> child;
  1.8582 +    frames->Item(i, getter_AddRefs(child));
  1.8583 +
  1.8584 +    if (!child) {
  1.8585 +      return;
  1.8586 +    }
  1.8587 +
  1.8588 +    nsGlobalWindow *childWin =
  1.8589 +      static_cast<nsGlobalWindow *>
  1.8590 +                 (static_cast<nsIDOMWindow *>
  1.8591 +                             (child.get()));
  1.8592 +
  1.8593 +    RunPendingTimeoutsRecursive(aTopWindow, childWin);
  1.8594 +  }
  1.8595 +}
  1.8596 +
  1.8597 +class nsPendingTimeoutRunner : public nsRunnable
  1.8598 +{
  1.8599 +public:
  1.8600 +  nsPendingTimeoutRunner(nsGlobalWindow *aWindow)
  1.8601 +    : mWindow(aWindow)
  1.8602 +  {
  1.8603 +    NS_ASSERTION(mWindow, "mWindow is null.");
  1.8604 +  }
  1.8605 +
  1.8606 +  NS_IMETHOD Run()
  1.8607 +  {
  1.8608 +    nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow, mWindow);
  1.8609 +
  1.8610 +    return NS_OK;
  1.8611 +  }
  1.8612 +
  1.8613 +private:
  1.8614 +  nsRefPtr<nsGlobalWindow> mWindow;
  1.8615 +};
  1.8616 +
  1.8617 +void
  1.8618 +nsGlobalWindow::LeaveModalState()
  1.8619 +{
  1.8620 +  MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
  1.8621 +
  1.8622 +  nsGlobalWindow* topWin = GetScriptableTop();
  1.8623 +
  1.8624 +  if (!topWin) {
  1.8625 +    NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
  1.8626 +    return;
  1.8627 +  }
  1.8628 +
  1.8629 +  topWin->mModalStateDepth--;
  1.8630 +
  1.8631 +  if (topWin->mModalStateDepth == 0) {
  1.8632 +    nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
  1.8633 +    if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
  1.8634 +      NS_WARNING("failed to dispatch pending timeout runnable");
  1.8635 +
  1.8636 +    if (mSuspendedDoc) {
  1.8637 +      nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
  1.8638 +      mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly,
  1.8639 +                                                          currentDoc == mSuspendedDoc);
  1.8640 +      mSuspendedDoc = nullptr;
  1.8641 +    }
  1.8642 +  }
  1.8643 +
  1.8644 +  // Remember the time of the last dialog quit.
  1.8645 +  nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
  1.8646 +  if (inner)
  1.8647 +    inner->mLastDialogQuitTime = TimeStamp::Now();
  1.8648 +}
  1.8649 +
  1.8650 +bool
  1.8651 +nsGlobalWindow::IsInModalState()
  1.8652 +{
  1.8653 +  nsGlobalWindow *topWin = GetScriptableTop();
  1.8654 +
  1.8655 +  if (!topWin) {
  1.8656 +    NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
  1.8657 +
  1.8658 +    return false;
  1.8659 +  }
  1.8660 +
  1.8661 +  return topWin->mModalStateDepth != 0;
  1.8662 +}
  1.8663 +
  1.8664 +// static
  1.8665 +void
  1.8666 +nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
  1.8667 +  nsCOMPtr<nsIObserverService> observerService =
  1.8668 +    services::GetObserverService();
  1.8669 +  if (observerService) {
  1.8670 +    observerService->
  1.8671 +      NotifyObservers(ToSupports(aWindow),
  1.8672 +                      DOM_WINDOW_DESTROYED_TOPIC, nullptr);
  1.8673 +  }
  1.8674 +}
  1.8675 +
  1.8676 +class WindowDestroyedEvent : public nsRunnable
  1.8677 +{
  1.8678 +public:
  1.8679 +  WindowDestroyedEvent(nsPIDOMWindow* aWindow, uint64_t aID,
  1.8680 +                       const char* aTopic) :
  1.8681 +    mID(aID), mTopic(aTopic)
  1.8682 +  {
  1.8683 +    mWindow = do_GetWeakReference(aWindow);
  1.8684 +  }
  1.8685 +
  1.8686 +  NS_IMETHOD Run()
  1.8687 +  {
  1.8688 +    nsCOMPtr<nsIObserverService> observerService =
  1.8689 +      do_GetService("@mozilla.org/observer-service;1");
  1.8690 +    if (observerService) {
  1.8691 +      nsCOMPtr<nsISupportsPRUint64> wrapper =
  1.8692 +        do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
  1.8693 +      if (wrapper) {
  1.8694 +        wrapper->SetData(mID);
  1.8695 +        observerService->NotifyObservers(wrapper, mTopic.get(), nullptr);
  1.8696 +      }
  1.8697 +    }
  1.8698 +
  1.8699 +    bool skipNukeCrossCompartment = false;
  1.8700 +#ifndef DEBUG
  1.8701 +    nsCOMPtr<nsIAppStartup> appStartup =
  1.8702 +      do_GetService(NS_APPSTARTUP_CONTRACTID);
  1.8703 +
  1.8704 +    if (appStartup) {
  1.8705 +      appStartup->GetShuttingDown(&skipNukeCrossCompartment);
  1.8706 +    }
  1.8707 +#endif
  1.8708 +
  1.8709 +    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
  1.8710 +    if (!skipNukeCrossCompartment && window) {
  1.8711 +      nsGlobalWindow* currentInner =
  1.8712 +        window->IsInnerWindow() ? static_cast<nsGlobalWindow*>(window.get()) :
  1.8713 +                                  static_cast<nsGlobalWindow*>(window->GetCurrentInnerWindow());
  1.8714 +      NS_ENSURE_TRUE(currentInner, NS_OK);
  1.8715 +
  1.8716 +      AutoSafeJSContext cx;
  1.8717 +      JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
  1.8718 +      // We only want to nuke wrappers for the chrome->content case
  1.8719 +      if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
  1.8720 +        js::NukeCrossCompartmentWrappers(cx,
  1.8721 +                                         js::ChromeCompartmentsOnly(),
  1.8722 +                                         js::SingleCompartment(js::GetObjectCompartment(obj)),
  1.8723 +                                         window->IsInnerWindow() ? js::DontNukeWindowReferences :
  1.8724 +                                                                   js::NukeWindowReferences);
  1.8725 +      }
  1.8726 +    }
  1.8727 +
  1.8728 +    return NS_OK;
  1.8729 +  }
  1.8730 +
  1.8731 +private:
  1.8732 +  uint64_t mID;
  1.8733 +  nsCString mTopic;
  1.8734 +  nsWeakPtr mWindow;
  1.8735 +};
  1.8736 +
  1.8737 +void
  1.8738 +nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
  1.8739 +{
  1.8740 +  nsRefPtr<nsIRunnable> runnable = new WindowDestroyedEvent(this, mWindowID, aTopic);
  1.8741 +  nsresult rv = NS_DispatchToCurrentThread(runnable);
  1.8742 +  if (NS_SUCCEEDED(rv)) {
  1.8743 +    mNotifiedIDDestroyed = true;
  1.8744 +  }
  1.8745 +}
  1.8746 +
  1.8747 +// static
  1.8748 +void
  1.8749 +nsGlobalWindow::NotifyDOMWindowFrozen(nsGlobalWindow* aWindow) {
  1.8750 +  if (aWindow && aWindow->IsInnerWindow()) {
  1.8751 +    nsCOMPtr<nsIObserverService> observerService =
  1.8752 +      services::GetObserverService();
  1.8753 +    if (observerService) {
  1.8754 +      observerService->
  1.8755 +        NotifyObservers(ToSupports(aWindow),
  1.8756 +                        DOM_WINDOW_FROZEN_TOPIC, nullptr);
  1.8757 +    }
  1.8758 +  }
  1.8759 +}
  1.8760 +
  1.8761 +// static
  1.8762 +void
  1.8763 +nsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindow* aWindow) {
  1.8764 +  if (aWindow && aWindow->IsInnerWindow()) {
  1.8765 +    nsCOMPtr<nsIObserverService> observerService =
  1.8766 +      services::GetObserverService();
  1.8767 +    if (observerService) {
  1.8768 +      observerService->
  1.8769 +        NotifyObservers(ToSupports(aWindow),
  1.8770 +                        DOM_WINDOW_THAWED_TOPIC, nullptr);
  1.8771 +    }
  1.8772 +  }
  1.8773 +}
  1.8774 +
  1.8775 +JSObject*
  1.8776 +nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
  1.8777 +{
  1.8778 +  AutoSafeJSContext cx;
  1.8779 +  JS::Rooted<JSObject*> handler(cx);
  1.8780 +  if (mCachedXBLPrototypeHandlers) {
  1.8781 +    mCachedXBLPrototypeHandlers->Get(aKey, handler.address());
  1.8782 +  }
  1.8783 +  return handler;
  1.8784 +}
  1.8785 +
  1.8786 +void
  1.8787 +nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
  1.8788 +                                         JS::Handle<JSObject*> aHandler)
  1.8789 +{
  1.8790 +  if (!mCachedXBLPrototypeHandlers) {
  1.8791 +    mCachedXBLPrototypeHandlers = new nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>();
  1.8792 +    PreserveWrapper(ToSupports(this));
  1.8793 +  }
  1.8794 +
  1.8795 +  mCachedXBLPrototypeHandlers->Put(aKey, aHandler);
  1.8796 +}
  1.8797 +
  1.8798 +/**
  1.8799 + * GetScriptableFrameElement is called when script reads
  1.8800 + * nsIGlobalWindow::frameElement.
  1.8801 + *
  1.8802 + * In contrast to GetRealFrameElement, GetScriptableFrameElement says that the
  1.8803 + * window contained by an <iframe mozbrowser> or <iframe mozapp> has no frame
  1.8804 + * element (effectively treating a mozbrowser the same as a content/chrome
  1.8805 + * boundary).
  1.8806 + */
  1.8807 +NS_IMETHODIMP
  1.8808 +nsGlobalWindow::GetScriptableFrameElement(nsIDOMElement** aFrameElement)
  1.8809 +{
  1.8810 +  ErrorResult rv;
  1.8811 +  nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(GetFrameElement(rv));
  1.8812 +  if (rv.Failed()) {
  1.8813 +    return rv.ErrorCode();
  1.8814 +  }
  1.8815 +
  1.8816 +  frameElement.forget(aFrameElement);
  1.8817 +
  1.8818 +  return NS_OK;
  1.8819 +}
  1.8820 +
  1.8821 +Element*
  1.8822 +nsGlobalWindow::GetFrameElement(ErrorResult& aError)
  1.8823 +{
  1.8824 +  FORWARD_TO_OUTER_OR_THROW(GetFrameElement, (aError), aError, nullptr);
  1.8825 +
  1.8826 +  if (!mDocShell || mDocShell->GetIsBrowserOrApp()) {
  1.8827 +    return nullptr;
  1.8828 +  }
  1.8829 +
  1.8830 +  // Per HTML5, the frameElement getter returns null in cross-origin situations.
  1.8831 +  Element* element = GetRealFrameElement(aError);
  1.8832 +  if (aError.Failed() || !element) {
  1.8833 +    return nullptr;
  1.8834 +  }
  1.8835 +  if (!nsContentUtils::GetSubjectPrincipal()->
  1.8836 +         SubsumesConsideringDomain(element->NodePrincipal())) {
  1.8837 +    return nullptr;
  1.8838 +  }
  1.8839 +  return element;
  1.8840 +}
  1.8841 +
  1.8842 +Element*
  1.8843 +nsGlobalWindow::GetRealFrameElement(ErrorResult& aError)
  1.8844 +{
  1.8845 +  FORWARD_TO_OUTER_OR_THROW(GetRealFrameElement, (aError), aError, nullptr);
  1.8846 +
  1.8847 +  if (!mDocShell) {
  1.8848 +    return nullptr;
  1.8849 +  }
  1.8850 +
  1.8851 +  nsCOMPtr<nsIDocShell> parent;
  1.8852 +  mDocShell->GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
  1.8853 +
  1.8854 +  if (!parent || parent == mDocShell) {
  1.8855 +    // We're at a chrome boundary, don't expose the chrome iframe
  1.8856 +    // element to content code.
  1.8857 +    return nullptr;
  1.8858 +  }
  1.8859 +
  1.8860 +  return mFrameElement;
  1.8861 +}
  1.8862 +
  1.8863 +/**
  1.8864 + * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper
  1.8865 + * around GetRealFrameElement.
  1.8866 + */
  1.8867 +NS_IMETHODIMP
  1.8868 +nsGlobalWindow::GetRealFrameElement(nsIDOMElement** aFrameElement)
  1.8869 +{
  1.8870 +  ErrorResult rv;
  1.8871 +  nsCOMPtr<nsIDOMElement> frameElement =
  1.8872 +    do_QueryInterface(GetRealFrameElement(rv));
  1.8873 +  frameElement.forget(aFrameElement);
  1.8874 +
  1.8875 +  return rv.ErrorCode();
  1.8876 +}
  1.8877 +
  1.8878 +// Helper for converting window.showModalDialog() options (list of ';'
  1.8879 +// separated name (:|=) value pairs) to a format that's parsable by
  1.8880 +// our normal window opening code.
  1.8881 +
  1.8882 +void
  1.8883 +ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult)
  1.8884 +{
  1.8885 +  nsAString::const_iterator end;
  1.8886 +  aOptions.EndReading(end);
  1.8887 +
  1.8888 +  nsAString::const_iterator iter;
  1.8889 +  aOptions.BeginReading(iter);
  1.8890 +
  1.8891 +  while (iter != end) {
  1.8892 +    // Skip whitespace.
  1.8893 +    while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
  1.8894 +      ++iter;
  1.8895 +    }
  1.8896 +
  1.8897 +    nsAString::const_iterator name_start = iter;
  1.8898 +
  1.8899 +    // Skip characters until we find whitespace, ';', ':', or '='
  1.8900 +    while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
  1.8901 +           *iter != ';' &&
  1.8902 +           *iter != ':' &&
  1.8903 +           *iter != '=') {
  1.8904 +      ++iter;
  1.8905 +    }
  1.8906 +
  1.8907 +    nsAString::const_iterator name_end = iter;
  1.8908 +
  1.8909 +    // Skip whitespace.
  1.8910 +    while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
  1.8911 +      ++iter;
  1.8912 +    }
  1.8913 +
  1.8914 +    if (*iter == ';') {
  1.8915 +      // No value found, skip the ';' and keep going.
  1.8916 +      ++iter;
  1.8917 +
  1.8918 +      continue;
  1.8919 +    }
  1.8920 +
  1.8921 +    nsAString::const_iterator value_start = iter;
  1.8922 +    nsAString::const_iterator value_end = iter;
  1.8923 +
  1.8924 +    if (*iter == ':' || *iter == '=') {
  1.8925 +      // We found name followed by ':' or '='. Look for a value.
  1.8926 +
  1.8927 +      iter++; // Skip the ':' or '='
  1.8928 +
  1.8929 +      // Skip whitespace.
  1.8930 +      while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
  1.8931 +        ++iter;
  1.8932 +      }
  1.8933 +
  1.8934 +      value_start = iter;
  1.8935 +
  1.8936 +      // Skip until we find whitespace, or ';'.
  1.8937 +      while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
  1.8938 +             *iter != ';') {
  1.8939 +        ++iter;
  1.8940 +      }
  1.8941 +
  1.8942 +      value_end = iter;
  1.8943 +
  1.8944 +      // Skip whitespace.
  1.8945 +      while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
  1.8946 +        ++iter;
  1.8947 +      }
  1.8948 +    }
  1.8949 +
  1.8950 +    const nsDependentSubstring& name = Substring(name_start, name_end);
  1.8951 +    const nsDependentSubstring& value = Substring(value_start, value_end);
  1.8952 +
  1.8953 +    if (name.LowerCaseEqualsLiteral("center")) {
  1.8954 +      if (value.LowerCaseEqualsLiteral("on")  ||
  1.8955 +          value.LowerCaseEqualsLiteral("yes") ||
  1.8956 +          value.LowerCaseEqualsLiteral("1")) {
  1.8957 +        aResult.AppendLiteral(",centerscreen=1");
  1.8958 +      }
  1.8959 +    } else if (name.LowerCaseEqualsLiteral("dialogwidth")) {
  1.8960 +      if (!value.IsEmpty()) {
  1.8961 +        aResult.AppendLiteral(",width=");
  1.8962 +        aResult.Append(value);
  1.8963 +      }
  1.8964 +    } else if (name.LowerCaseEqualsLiteral("dialogheight")) {
  1.8965 +      if (!value.IsEmpty()) {
  1.8966 +        aResult.AppendLiteral(",height=");
  1.8967 +        aResult.Append(value);
  1.8968 +      }
  1.8969 +    } else if (name.LowerCaseEqualsLiteral("dialogtop")) {
  1.8970 +      if (!value.IsEmpty()) {
  1.8971 +        aResult.AppendLiteral(",top=");
  1.8972 +        aResult.Append(value);
  1.8973 +      }
  1.8974 +    } else if (name.LowerCaseEqualsLiteral("dialogleft")) {
  1.8975 +      if (!value.IsEmpty()) {
  1.8976 +        aResult.AppendLiteral(",left=");
  1.8977 +        aResult.Append(value);
  1.8978 +      }
  1.8979 +    } else if (name.LowerCaseEqualsLiteral("resizable")) {
  1.8980 +      if (value.LowerCaseEqualsLiteral("on")  ||
  1.8981 +          value.LowerCaseEqualsLiteral("yes") ||
  1.8982 +          value.LowerCaseEqualsLiteral("1")) {
  1.8983 +        aResult.AppendLiteral(",resizable=1");
  1.8984 +      }
  1.8985 +    } else if (name.LowerCaseEqualsLiteral("scroll")) {
  1.8986 +      if (value.LowerCaseEqualsLiteral("off")  ||
  1.8987 +          value.LowerCaseEqualsLiteral("no") ||
  1.8988 +          value.LowerCaseEqualsLiteral("0")) {
  1.8989 +        aResult.AppendLiteral(",scrollbars=0");
  1.8990 +      }
  1.8991 +    }
  1.8992 +
  1.8993 +    if (iter == end) {
  1.8994 +      break;
  1.8995 +    }
  1.8996 +
  1.8997 +    iter++;
  1.8998 +  }
  1.8999 +}
  1.9000 +
  1.9001 +already_AddRefed<nsIVariant>
  1.9002 +nsGlobalWindow::ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument,
  1.9003 +                                const nsAString& aOptions, ErrorResult& aError)
  1.9004 +{
  1.9005 +  if (mDoc) {
  1.9006 +    mDoc->WarnOnceAbout(nsIDocument::eShowModalDialog);
  1.9007 +  }
  1.9008 +
  1.9009 +  FORWARD_TO_OUTER_OR_THROW(ShowModalDialog,
  1.9010 +                            (aUrl, aArgument, aOptions, aError), aError,
  1.9011 +                            nullptr);
  1.9012 +
  1.9013 +  if (Preferences::GetBool("dom.disable_window_showModalDialog", false)) {
  1.9014 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.9015 +    return nullptr;
  1.9016 +  }
  1.9017 +
  1.9018 +  nsRefPtr<DialogValueHolder> argHolder =
  1.9019 +    new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(), aArgument);
  1.9020 +
  1.9021 +  // Before bringing up the window/dialog, unsuppress painting and flush
  1.9022 +  // pending reflows.
  1.9023 +  EnsureReflowFlushAndPaint();
  1.9024 +
  1.9025 +  if (!AreDialogsEnabled()) {
  1.9026 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.9027 +    return nullptr;
  1.9028 +  }
  1.9029 +
  1.9030 +  if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
  1.9031 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.9032 +    return nullptr;
  1.9033 +  }
  1.9034 +
  1.9035 +  nsCOMPtr<nsIDOMWindow> dlgWin;
  1.9036 +  nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
  1.9037 +
  1.9038 +  ConvertDialogOptions(aOptions, options);
  1.9039 +
  1.9040 +  options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
  1.9041 +
  1.9042 +  EnterModalState();
  1.9043 +  uint32_t oldMicroTaskLevel = nsContentUtils::MicroTaskLevel();
  1.9044 +  nsContentUtils::SetMicroTaskLevel(0);
  1.9045 +  aError = OpenInternal(aUrl, EmptyString(), options,
  1.9046 +                        false,          // aDialog
  1.9047 +                        true,           // aContentModal
  1.9048 +                        true,           // aCalledNoScript
  1.9049 +                        true,           // aDoJSFixups
  1.9050 +                        true,           // aNavigate
  1.9051 +                        nullptr, argHolder, // args
  1.9052 +                        GetPrincipal(),     // aCalleePrincipal
  1.9053 +                        nullptr,            // aJSCallerContext
  1.9054 +                        getter_AddRefs(dlgWin));
  1.9055 +  nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel);
  1.9056 +  LeaveModalState();
  1.9057 +  if (aError.Failed()) {
  1.9058 +    return nullptr;
  1.9059 +  }
  1.9060 +
  1.9061 +  nsCOMPtr<nsIDOMModalContentWindow> dialog = do_QueryInterface(dlgWin);
  1.9062 +  if (!dialog) {
  1.9063 +    return nullptr;
  1.9064 +  }
  1.9065 +
  1.9066 +  nsCOMPtr<nsIVariant> retVal;
  1.9067 +  aError = dialog->GetReturnValue(getter_AddRefs(retVal));
  1.9068 +  MOZ_ASSERT(!aError.Failed());
  1.9069 +
  1.9070 +  return retVal.forget();
  1.9071 +}
  1.9072 +
  1.9073 +void
  1.9074 +nsGlobalWindow::ShowModalDialog(JSContext* aCx, const nsAString& aUrl,
  1.9075 +                                JS::Handle<JS::Value> aArgument,
  1.9076 +                                const nsAString& aOptions,
  1.9077 +                                JS::MutableHandle<JS::Value> aRetval,
  1.9078 +                                ErrorResult& aError)
  1.9079 +{
  1.9080 +  nsCOMPtr<nsIVariant> args;
  1.9081 +  aError = nsContentUtils::XPConnect()->JSToVariant(aCx,
  1.9082 +                                                    aArgument,
  1.9083 +                                                    getter_AddRefs(args));
  1.9084 +
  1.9085 +  nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aUrl, args, aOptions, aError);
  1.9086 +  if (aError.Failed()) {
  1.9087 +    return;
  1.9088 +  }
  1.9089 +
  1.9090 +  JS::Rooted<JS::Value> result(aCx);
  1.9091 +  if (retVal) {
  1.9092 +    aError = nsContentUtils::XPConnect()->VariantToJS(aCx,
  1.9093 +                                                      FastGetGlobalJSObject(),
  1.9094 +                                                      retVal, aRetval);
  1.9095 +  } else {
  1.9096 +    aRetval.setNull();
  1.9097 +  }
  1.9098 +}
  1.9099 +
  1.9100 +NS_IMETHODIMP
  1.9101 +nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs_,
  1.9102 +                                const nsAString& aOptions, uint8_t aArgc,
  1.9103 +                                nsIVariant **aRetVal)
  1.9104 +{
  1.9105 +  // Per-spec the |arguments| parameter is supposed to pass through unmodified.
  1.9106 +  // However, XPConnect default-initializes variants to null, rather than
  1.9107 +  // undefined. Fix this up here.
  1.9108 +  nsCOMPtr<nsIVariant> aArgs = aArgs_;
  1.9109 +  if (aArgc < 1) {
  1.9110 +    aArgs = CreateVoidVariant();
  1.9111 +  }
  1.9112 +
  1.9113 +  ErrorResult rv;
  1.9114 +  nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aURI, aArgs, aOptions, rv);
  1.9115 +  retVal.forget(aRetVal);
  1.9116 +
  1.9117 +  return rv.ErrorCode();
  1.9118 +}
  1.9119 +
  1.9120 +class CommandDispatcher : public nsRunnable
  1.9121 +{
  1.9122 +public:
  1.9123 +  CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
  1.9124 +                    const nsAString& aAction)
  1.9125 +  : mDispatcher(aDispatcher), mAction(aAction) {}
  1.9126 +
  1.9127 +  NS_IMETHOD Run()
  1.9128 +  {
  1.9129 +    return mDispatcher->UpdateCommands(mAction);
  1.9130 +  }
  1.9131 +
  1.9132 +  nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
  1.9133 +  nsString                             mAction;
  1.9134 +};
  1.9135 +
  1.9136 +NS_IMETHODIMP
  1.9137 +nsGlobalWindow::UpdateCommands(const nsAString& anAction)
  1.9138 +{
  1.9139 +  nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
  1.9140 +  if (!rootWindow)
  1.9141 +    return NS_OK;
  1.9142 +
  1.9143 +  nsCOMPtr<nsIDOMXULDocument> xulDoc =
  1.9144 +    do_QueryInterface(rootWindow->GetExtantDoc());
  1.9145 +  // See if we contain a XUL document.
  1.9146 +  if (xulDoc) {
  1.9147 +    // Retrieve the command dispatcher and call updateCommands on it.
  1.9148 +    nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
  1.9149 +    xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
  1.9150 +    if (xulCommandDispatcher) {
  1.9151 +      nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
  1.9152 +                                                            anAction));
  1.9153 +    }
  1.9154 +  }
  1.9155 +
  1.9156 +  return NS_OK;
  1.9157 +}
  1.9158 +
  1.9159 +Selection*
  1.9160 +nsGlobalWindow::GetSelection(ErrorResult& aError)
  1.9161 +{
  1.9162 +  FORWARD_TO_OUTER_OR_THROW(GetSelection, (aError), aError, nullptr);
  1.9163 +
  1.9164 +  if (!mDocShell) {
  1.9165 +    return nullptr;
  1.9166 +  }
  1.9167 +
  1.9168 +  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
  1.9169 +  if (!presShell) {
  1.9170 +    return nullptr;
  1.9171 +  }
  1.9172 +
  1.9173 +  return static_cast<Selection*>(presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL));
  1.9174 +}
  1.9175 +
  1.9176 +NS_IMETHODIMP
  1.9177 +nsGlobalWindow::GetSelection(nsISelection** aSelection)
  1.9178 +{
  1.9179 +  ErrorResult rv;
  1.9180 +  nsCOMPtr<nsISelection> selection = GetSelection(rv);
  1.9181 +  selection.forget(aSelection);
  1.9182 +
  1.9183 +  return rv.ErrorCode();
  1.9184 +}
  1.9185 +
  1.9186 +bool
  1.9187 +nsGlobalWindow::Find(const nsAString& aString, bool aCaseSensitive,
  1.9188 +                     bool aBackwards, bool aWrapAround, bool aWholeWord,
  1.9189 +                     bool aSearchInFrames, bool aShowDialog,
  1.9190 +                     ErrorResult& aError)
  1.9191 +{
  1.9192 +  if (Preferences::GetBool("dom.disable_window_find", false)) {
  1.9193 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.9194 +    return false;
  1.9195 +  }
  1.9196 +
  1.9197 +  FORWARD_TO_OUTER_OR_THROW(Find,
  1.9198 +                            (aString, aCaseSensitive, aBackwards, aWrapAround,
  1.9199 +                             aWholeWord, aSearchInFrames, aShowDialog, aError),
  1.9200 +                            aError, false);
  1.9201 +
  1.9202 +  nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
  1.9203 +  if (!finder) {
  1.9204 +    aError.Throw(NS_ERROR_NOT_AVAILABLE);
  1.9205 +    return false;
  1.9206 +  }
  1.9207 +
  1.9208 +  // Set the options of the search
  1.9209 +  aError = finder->SetSearchString(PromiseFlatString(aString).get());
  1.9210 +  if (aError.Failed()) {
  1.9211 +    return false;
  1.9212 +  }
  1.9213 +  finder->SetMatchCase(aCaseSensitive);
  1.9214 +  finder->SetFindBackwards(aBackwards);
  1.9215 +  finder->SetWrapFind(aWrapAround);
  1.9216 +  finder->SetEntireWord(aWholeWord);
  1.9217 +  finder->SetSearchFrames(aSearchInFrames);
  1.9218 +
  1.9219 +  // the nsIWebBrowserFind is initialized to use this window
  1.9220 +  // as the search root, but uses focus to set the current search
  1.9221 +  // frame. If we're being called from JS (as here), this window
  1.9222 +  // should be the current search frame.
  1.9223 +  nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
  1.9224 +  if (framesFinder) {
  1.9225 +    framesFinder->SetRootSearchFrame(this);   // paranoia
  1.9226 +    framesFinder->SetCurrentSearchFrame(this);
  1.9227 +  }
  1.9228 +  
  1.9229 +  // The Find API does not accept empty strings. Launch the Find Dialog.
  1.9230 +  if (aString.IsEmpty() || aShowDialog) {
  1.9231 +    // See if the find dialog is already up using nsIWindowMediator
  1.9232 +    nsCOMPtr<nsIWindowMediator> windowMediator =
  1.9233 +      do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
  1.9234 +
  1.9235 +    nsCOMPtr<nsIDOMWindow> findDialog;
  1.9236 +
  1.9237 +    if (windowMediator) {
  1.9238 +      windowMediator->GetMostRecentWindow(MOZ_UTF16("findInPage"),
  1.9239 +                                          getter_AddRefs(findDialog));
  1.9240 +    }
  1.9241 +
  1.9242 +    if (findDialog) {
  1.9243 +      // The Find dialog is already open, bring it to the top.
  1.9244 +      aError = findDialog->Focus();
  1.9245 +    } else if (finder) {
  1.9246 +      // Open a Find dialog
  1.9247 +      nsCOMPtr<nsIDOMWindow> dialog;
  1.9248 +      aError = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
  1.9249 +                          NS_LITERAL_STRING("_blank"),
  1.9250 +                          NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
  1.9251 +                          finder, getter_AddRefs(dialog));
  1.9252 +    }
  1.9253 +
  1.9254 +    return false;
  1.9255 +  }
  1.9256 +
  1.9257 +  // Launch the search with the passed in search string
  1.9258 +  bool didFind = false;
  1.9259 +  aError = finder->FindNext(&didFind);
  1.9260 +  return didFind;
  1.9261 +}
  1.9262 +
  1.9263 +NS_IMETHODIMP
  1.9264 +nsGlobalWindow::Find(const nsAString& aStr, bool aCaseSensitive,
  1.9265 +                     bool aBackwards, bool aWrapAround, bool aWholeWord,
  1.9266 +                     bool aSearchInFrames, bool aShowDialog,
  1.9267 +                     bool *aDidFind)
  1.9268 +{
  1.9269 +  ErrorResult rv;
  1.9270 +  *aDidFind = Find(aStr, aCaseSensitive, aBackwards, aWrapAround, aWholeWord,
  1.9271 +                   aSearchInFrames, aShowDialog, rv);
  1.9272 +
  1.9273 +  return rv.ErrorCode();
  1.9274 +}
  1.9275 +
  1.9276 +void
  1.9277 +nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
  1.9278 +                     nsAString& aBinaryData, ErrorResult& aError)
  1.9279 +{
  1.9280 +  aError = nsContentUtils::Atob(aAsciiBase64String, aBinaryData);
  1.9281 +}
  1.9282 +
  1.9283 +NS_IMETHODIMP
  1.9284 +nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
  1.9285 +                     nsAString& aBinaryData)
  1.9286 +{
  1.9287 +  ErrorResult rv;
  1.9288 +  Atob(aAsciiBase64String, aBinaryData, rv);
  1.9289 +
  1.9290 +  return rv.ErrorCode();
  1.9291 +}
  1.9292 +
  1.9293 +void
  1.9294 +nsGlobalWindow::Btoa(const nsAString& aBinaryData,
  1.9295 +                     nsAString& aAsciiBase64String, ErrorResult& aError)
  1.9296 +{
  1.9297 +  aError = nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
  1.9298 +}
  1.9299 +
  1.9300 +NS_IMETHODIMP
  1.9301 +nsGlobalWindow::Btoa(const nsAString& aBinaryData,
  1.9302 +                     nsAString& aAsciiBase64String)
  1.9303 +{
  1.9304 +  ErrorResult rv;
  1.9305 +  Btoa(aBinaryData, aAsciiBase64String, rv);
  1.9306 +
  1.9307 +  return rv.ErrorCode();
  1.9308 +}
  1.9309 +
  1.9310 +//*****************************************************************************
  1.9311 +// nsGlobalWindow::nsIDOMEventTarget
  1.9312 +//*****************************************************************************
  1.9313 +
  1.9314 +NS_IMETHODIMP
  1.9315 +nsGlobalWindow::RemoveEventListener(const nsAString& aType,
  1.9316 +                                    nsIDOMEventListener* aListener,
  1.9317 +                                    bool aUseCapture)
  1.9318 +{
  1.9319 +  if (nsRefPtr<EventListenerManager> elm = GetExistingListenerManager()) {
  1.9320 +    elm->RemoveEventListener(aType, aListener, aUseCapture);
  1.9321 +  }
  1.9322 +  return NS_OK;
  1.9323 +}
  1.9324 +
  1.9325 +NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)
  1.9326 +
  1.9327 +NS_IMETHODIMP
  1.9328 +nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
  1.9329 +{
  1.9330 +  FORWARD_TO_INNER(DispatchEvent, (aEvent, aRetVal), NS_OK);
  1.9331 +
  1.9332 +  if (!IsCurrentInnerWindow()) {
  1.9333 +    NS_WARNING("DispatchEvent called on non-current inner window, dropping. "
  1.9334 +               "Please check the window in the caller instead.");
  1.9335 +    return NS_ERROR_FAILURE;
  1.9336 +  }
  1.9337 +
  1.9338 +  if (!mDoc) {
  1.9339 +    return NS_ERROR_FAILURE;
  1.9340 +  }
  1.9341 +
  1.9342 +  // Obtain a presentation shell
  1.9343 +  nsIPresShell *shell = mDoc->GetShell();
  1.9344 +  nsRefPtr<nsPresContext> presContext;
  1.9345 +  if (shell) {
  1.9346 +    // Retrieve the context
  1.9347 +    presContext = shell->GetPresContext();
  1.9348 +  }
  1.9349 +
  1.9350 +  nsEventStatus status = nsEventStatus_eIgnore;
  1.9351 +  nsresult rv =
  1.9352 +    EventDispatcher::DispatchDOMEvent(GetOuterWindow(), nullptr, aEvent,
  1.9353 +                                      presContext, &status);
  1.9354 +
  1.9355 +  *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
  1.9356 +  return rv;
  1.9357 +}
  1.9358 +
  1.9359 +NS_IMETHODIMP
  1.9360 +nsGlobalWindow::AddEventListener(const nsAString& aType,
  1.9361 +                                 nsIDOMEventListener *aListener,
  1.9362 +                                 bool aUseCapture, bool aWantsUntrusted,
  1.9363 +                                 uint8_t aOptionalArgc)
  1.9364 +{
  1.9365 +  NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
  1.9366 +               "Won't check if this is chrome, you want to set "
  1.9367 +               "aWantsUntrusted to false or make the aWantsUntrusted "
  1.9368 +               "explicit by making optional_argc non-zero.");
  1.9369 +
  1.9370 +  if (IsOuterWindow() && mInnerWindow &&
  1.9371 +      !nsContentUtils::CanCallerAccess(mInnerWindow)) {
  1.9372 +    return NS_ERROR_DOM_SECURITY_ERR;
  1.9373 +  }
  1.9374 +
  1.9375 +  if (!aWantsUntrusted &&
  1.9376 +      (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
  1.9377 +    aWantsUntrusted = true;
  1.9378 +  }
  1.9379 +
  1.9380 +  EventListenerManager* manager = GetOrCreateListenerManager();
  1.9381 +  NS_ENSURE_STATE(manager);
  1.9382 +  manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
  1.9383 +  return NS_OK;
  1.9384 +}
  1.9385 +
  1.9386 +void
  1.9387 +nsGlobalWindow::AddEventListener(const nsAString& aType,
  1.9388 +                                 EventListener* aListener,
  1.9389 +                                 bool aUseCapture,
  1.9390 +                                 const Nullable<bool>& aWantsUntrusted,
  1.9391 +                                 ErrorResult& aRv)
  1.9392 +{
  1.9393 +  if (IsOuterWindow() && mInnerWindow &&
  1.9394 +      !nsContentUtils::CanCallerAccess(mInnerWindow)) {
  1.9395 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.9396 +    return;
  1.9397 +  }
  1.9398 +
  1.9399 +  bool wantsUntrusted;
  1.9400 +  if (aWantsUntrusted.IsNull()) {
  1.9401 +    wantsUntrusted = !nsContentUtils::IsChromeDoc(mDoc);
  1.9402 +  } else {
  1.9403 +    wantsUntrusted = aWantsUntrusted.Value();
  1.9404 +  }
  1.9405 +
  1.9406 +  EventListenerManager* manager = GetOrCreateListenerManager();
  1.9407 +  if (!manager) {
  1.9408 +    aRv.Throw(NS_ERROR_UNEXPECTED);
  1.9409 +    return;
  1.9410 +  }
  1.9411 +  manager->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
  1.9412 +}
  1.9413 +
  1.9414 +NS_IMETHODIMP
  1.9415 +nsGlobalWindow::AddSystemEventListener(const nsAString& aType,
  1.9416 +                                       nsIDOMEventListener *aListener,
  1.9417 +                                       bool aUseCapture,
  1.9418 +                                       bool aWantsUntrusted,
  1.9419 +                                       uint8_t aOptionalArgc)
  1.9420 +{
  1.9421 +  NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
  1.9422 +               "Won't check if this is chrome, you want to set "
  1.9423 +               "aWantsUntrusted to false or make the aWantsUntrusted "
  1.9424 +               "explicit by making optional_argc non-zero.");
  1.9425 +
  1.9426 +  if (IsOuterWindow() && mInnerWindow &&
  1.9427 +      !nsContentUtils::CanCallerAccess(mInnerWindow)) {
  1.9428 +    return NS_ERROR_DOM_SECURITY_ERR;
  1.9429 +  }
  1.9430 +
  1.9431 +  if (!aWantsUntrusted &&
  1.9432 +      (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
  1.9433 +    aWantsUntrusted = true;
  1.9434 +  }
  1.9435 +
  1.9436 +  return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
  1.9437 +                                   aWantsUntrusted);
  1.9438 +}
  1.9439 +
  1.9440 +EventListenerManager*
  1.9441 +nsGlobalWindow::GetOrCreateListenerManager()
  1.9442 +{
  1.9443 +  FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager, (), nullptr);
  1.9444 +
  1.9445 +  if (!mListenerManager) {
  1.9446 +    mListenerManager =
  1.9447 +      new EventListenerManager(static_cast<EventTarget*>(this));
  1.9448 +  }
  1.9449 +
  1.9450 +  return mListenerManager;
  1.9451 +}
  1.9452 +
  1.9453 +EventListenerManager*
  1.9454 +nsGlobalWindow::GetExistingListenerManager() const
  1.9455 +{
  1.9456 +  FORWARD_TO_INNER(GetExistingListenerManager, (), nullptr);
  1.9457 +
  1.9458 +  return mListenerManager;
  1.9459 +}
  1.9460 +
  1.9461 +nsIScriptContext*
  1.9462 +nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
  1.9463 +{
  1.9464 +  *aRv = NS_ERROR_UNEXPECTED;
  1.9465 +  NS_ENSURE_TRUE(!IsInnerWindow() || IsCurrentInnerWindow(), nullptr);
  1.9466 +
  1.9467 +  nsIScriptContext* scx;
  1.9468 +  if ((scx = GetContext())) {
  1.9469 +    *aRv = NS_OK;
  1.9470 +    return scx;
  1.9471 +  }
  1.9472 +  return nullptr;
  1.9473 +}
  1.9474 +
  1.9475 +//*****************************************************************************
  1.9476 +// nsGlobalWindow::nsPIDOMWindow
  1.9477 +//*****************************************************************************
  1.9478 +
  1.9479 +nsPIDOMWindow*
  1.9480 +nsGlobalWindow::GetPrivateParent()
  1.9481 +{
  1.9482 +  MOZ_ASSERT(IsOuterWindow());
  1.9483 +
  1.9484 +  nsCOMPtr<nsIDOMWindow> parent;
  1.9485 +  GetParent(getter_AddRefs(parent));
  1.9486 +
  1.9487 +  if (static_cast<nsIDOMWindow *>(this) == parent.get()) {
  1.9488 +    nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
  1.9489 +    if (!chromeElement)
  1.9490 +      return nullptr;             // This is ok, just means a null parent.
  1.9491 +
  1.9492 +    nsIDocument* doc = chromeElement->GetDocument();
  1.9493 +    if (!doc)
  1.9494 +      return nullptr;             // This is ok, just means a null parent.
  1.9495 +
  1.9496 +    return doc->GetWindow();
  1.9497 +  }
  1.9498 +
  1.9499 +  if (parent) {
  1.9500 +    return static_cast<nsGlobalWindow *>
  1.9501 +                      (static_cast<nsIDOMWindow*>(parent.get()));
  1.9502 +  }
  1.9503 +
  1.9504 +  return nullptr;
  1.9505 +}
  1.9506 +
  1.9507 +nsPIDOMWindow*
  1.9508 +nsGlobalWindow::GetPrivateRoot()
  1.9509 +{
  1.9510 +  if (IsInnerWindow()) {
  1.9511 +    nsGlobalWindow* outer = GetOuterWindowInternal();
  1.9512 +    if (!outer) {
  1.9513 +      NS_WARNING("No outer window available!");
  1.9514 +      return nullptr;
  1.9515 +    }
  1.9516 +    return outer->GetPrivateRoot();
  1.9517 +  }
  1.9518 +
  1.9519 +  nsCOMPtr<nsIDOMWindow> top;
  1.9520 +  GetTop(getter_AddRefs(top));
  1.9521 +
  1.9522 +  nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
  1.9523 +  if (chromeElement) {
  1.9524 +    nsIDocument* doc = chromeElement->GetDocument();
  1.9525 +    if (doc) {
  1.9526 +      nsIDOMWindow *parent = doc->GetWindow();
  1.9527 +      if (parent) {
  1.9528 +        parent->GetTop(getter_AddRefs(top));
  1.9529 +      }
  1.9530 +    }
  1.9531 +  }
  1.9532 +
  1.9533 +  return static_cast<nsGlobalWindow*>(top.get());
  1.9534 +}
  1.9535 +
  1.9536 +
  1.9537 +nsIDOMLocation*
  1.9538 +nsGlobalWindow::GetLocation(ErrorResult& aError)
  1.9539 +{
  1.9540 +  FORWARD_TO_INNER_OR_THROW(GetLocation, (aError), aError, nullptr);
  1.9541 +
  1.9542 +  nsIDocShell *docShell = GetDocShell();
  1.9543 +  if (!mLocation && docShell) {
  1.9544 +    mLocation = new nsLocation(docShell);
  1.9545 +  }
  1.9546 +  return mLocation;
  1.9547 +}
  1.9548 +
  1.9549 +NS_IMETHODIMP
  1.9550 +nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
  1.9551 +{
  1.9552 +  ErrorResult rv;
  1.9553 +  nsCOMPtr<nsIDOMLocation> location = GetLocation(rv);
  1.9554 +  location.forget(aLocation);
  1.9555 +
  1.9556 +  return rv.ErrorCode();
  1.9557 +}
  1.9558 +
  1.9559 +void
  1.9560 +nsGlobalWindow::ActivateOrDeactivate(bool aActivate)
  1.9561 +{
  1.9562 +  MOZ_ASSERT(IsOuterWindow());
  1.9563 +
  1.9564 +  // Set / unset mIsActive on the top level window, which is used for the
  1.9565 +  // :-moz-window-inactive pseudoclass, and its sheet (if any).
  1.9566 +  nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
  1.9567 +  if (!mainWidget)
  1.9568 +    return;
  1.9569 +
  1.9570 +  // Get the top level widget (if the main widget is a sheet, this will
  1.9571 +  // be the sheet's top (non-sheet) parent).
  1.9572 +  nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
  1.9573 +  if (!topLevelWidget) {
  1.9574 +    topLevelWidget = mainWidget;
  1.9575 +  }
  1.9576 +
  1.9577 +  nsCOMPtr<nsPIDOMWindow> piMainWindow(
  1.9578 +    do_QueryInterface(static_cast<nsIDOMWindow*>(this)));
  1.9579 +  piMainWindow->SetActive(aActivate);
  1.9580 +
  1.9581 +  if (mainWidget != topLevelWidget) {
  1.9582 +    // This is a workaround for the following problem:
  1.9583 +    // When a window with an open sheet gains or loses focus, only the sheet
  1.9584 +    // window receives the NS_ACTIVATE/NS_DEACTIVATE event.  However the
  1.9585 +    // styling of the containing top level window also needs to change.  We
  1.9586 +    // get around this by calling nsPIDOMWindow::SetActive() on both windows.
  1.9587 +
  1.9588 +    // Get the top level widget's nsGlobalWindow
  1.9589 +    nsCOMPtr<nsIDOMWindow> topLevelWindow;
  1.9590 +
  1.9591 +    // widgetListener should be a nsXULWindow
  1.9592 +    nsIWidgetListener* listener = topLevelWidget->GetWidgetListener();
  1.9593 +    if (listener) {
  1.9594 +      nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
  1.9595 +      nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
  1.9596 +      topLevelWindow = do_GetInterface(req);
  1.9597 +    }
  1.9598 +
  1.9599 +    if (topLevelWindow) {
  1.9600 +      nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
  1.9601 +      piWin->SetActive(aActivate);
  1.9602 +    }
  1.9603 +  }
  1.9604 +}
  1.9605 +
  1.9606 +static bool
  1.9607 +NotifyDocumentTree(nsIDocument* aDocument, void* aData)
  1.9608 +{
  1.9609 +  aDocument->EnumerateSubDocuments(NotifyDocumentTree, nullptr);
  1.9610 +  aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
  1.9611 +  return true;
  1.9612 +}
  1.9613 +
  1.9614 +void
  1.9615 +nsGlobalWindow::SetActive(bool aActive)
  1.9616 +{
  1.9617 +  nsPIDOMWindow::SetActive(aActive);
  1.9618 +  NotifyDocumentTree(mDoc, nullptr);
  1.9619 +}
  1.9620 +
  1.9621 +void nsGlobalWindow::SetIsBackground(bool aIsBackground)
  1.9622 +{
  1.9623 +  MOZ_ASSERT(IsOuterWindow());
  1.9624 +
  1.9625 +  bool resetTimers = (!aIsBackground && IsBackground());
  1.9626 +  nsPIDOMWindow::SetIsBackground(aIsBackground);
  1.9627 +  if (resetTimers) {
  1.9628 +    ResetTimersForNonBackgroundWindow();
  1.9629 +  }
  1.9630 +#ifdef MOZ_GAMEPAD
  1.9631 +  if (!aIsBackground) {
  1.9632 +    nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
  1.9633 +    if (inner) {
  1.9634 +      inner->SyncGamepadState();
  1.9635 +    }
  1.9636 +  }
  1.9637 +#endif
  1.9638 +}
  1.9639 +
  1.9640 +void nsGlobalWindow::MaybeUpdateTouchState()
  1.9641 +{
  1.9642 +  FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
  1.9643 +
  1.9644 +  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.9645 +
  1.9646 +  nsCOMPtr<nsIDOMWindow> focusedWindow;
  1.9647 +  fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
  1.9648 +
  1.9649 +  if(this == focusedWindow) {
  1.9650 +    UpdateTouchState();
  1.9651 +  }
  1.9652 +
  1.9653 +  if (mMayHaveTouchEventListener) {
  1.9654 +    nsCOMPtr<nsIObserverService> observerService =
  1.9655 +      services::GetObserverService();
  1.9656 +
  1.9657 +    if (observerService) {
  1.9658 +      observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
  1.9659 +                                       DOM_TOUCH_LISTENER_ADDED,
  1.9660 +                                       nullptr);
  1.9661 +    }
  1.9662 +  }
  1.9663 +}
  1.9664 +
  1.9665 +void nsGlobalWindow::UpdateTouchState()
  1.9666 +{
  1.9667 +  FORWARD_TO_INNER_VOID(UpdateTouchState, ());
  1.9668 +
  1.9669 +  nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
  1.9670 +  if (!mainWidget) {
  1.9671 +    return;
  1.9672 +  }
  1.9673 +
  1.9674 +  if (mMayHaveTouchEventListener) {
  1.9675 +    mainWidget->RegisterTouchWindow();
  1.9676 +  } else {
  1.9677 +    mainWidget->UnregisterTouchWindow();
  1.9678 +  }
  1.9679 +}
  1.9680 +
  1.9681 +void
  1.9682 +nsGlobalWindow::EnableGamepadUpdates()
  1.9683 +{
  1.9684 +  FORWARD_TO_INNER_VOID(EnableGamepadUpdates, ());
  1.9685 +  if (mHasGamepad) {
  1.9686 +#ifdef MOZ_GAMEPAD
  1.9687 +    nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
  1.9688 +    if (gamepadsvc) {
  1.9689 +      gamepadsvc->AddListener(this);
  1.9690 +    }
  1.9691 +#endif
  1.9692 +  }
  1.9693 +}
  1.9694 +
  1.9695 +void
  1.9696 +nsGlobalWindow::DisableGamepadUpdates()
  1.9697 +{
  1.9698 +  FORWARD_TO_INNER_VOID(DisableGamepadUpdates, ());
  1.9699 +  if (mHasGamepad) {
  1.9700 +#ifdef MOZ_GAMEPAD
  1.9701 +    nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
  1.9702 +    if (gamepadsvc) {
  1.9703 +      gamepadsvc->RemoveListener(this);
  1.9704 +    }
  1.9705 +#endif
  1.9706 +  }
  1.9707 +}
  1.9708 +
  1.9709 +void
  1.9710 +nsGlobalWindow::SetChromeEventHandler(EventTarget* aChromeEventHandler)
  1.9711 +{
  1.9712 +  MOZ_ASSERT(IsOuterWindow());
  1.9713 +
  1.9714 +  SetChromeEventHandlerInternal(aChromeEventHandler);
  1.9715 +  // update the chrome event handler on all our inner windows
  1.9716 +  for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
  1.9717 +       inner != this;
  1.9718 +       inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
  1.9719 +    NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
  1.9720 +                 "bad outer window pointer");
  1.9721 +    inner->SetChromeEventHandlerInternal(aChromeEventHandler);
  1.9722 +  }
  1.9723 +}
  1.9724 +
  1.9725 +static bool IsLink(nsIContent* aContent)
  1.9726 +{
  1.9727 +  return aContent && (aContent->IsHTML(nsGkAtoms::a) ||
  1.9728 +                      aContent->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
  1.9729 +                                            nsGkAtoms::simple, eCaseMatters));
  1.9730 +}
  1.9731 +
  1.9732 +void
  1.9733 +nsGlobalWindow::SetFocusedNode(nsIContent* aNode,
  1.9734 +                               uint32_t aFocusMethod,
  1.9735 +                               bool aNeedsFocus)
  1.9736 +{
  1.9737 +  FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
  1.9738 +
  1.9739 +  if (aNode && aNode->GetCurrentDoc() != mDoc) {
  1.9740 +    NS_WARNING("Trying to set focus to a node from a wrong document");
  1.9741 +    return;
  1.9742 +  }
  1.9743 +
  1.9744 +  if (mCleanedUp) {
  1.9745 +    NS_ASSERTION(!aNode, "Trying to focus cleaned up window!");
  1.9746 +    aNode = nullptr;
  1.9747 +    aNeedsFocus = false;
  1.9748 +  }
  1.9749 +  if (mFocusedNode != aNode) {
  1.9750 +    UpdateCanvasFocus(false, aNode);
  1.9751 +    mFocusedNode = aNode;
  1.9752 +    mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
  1.9753 +    mShowFocusRingForContent = false;
  1.9754 +  }
  1.9755 +
  1.9756 +  if (mFocusedNode) {
  1.9757 +    // if a node was focused by a keypress, turn on focus rings for the
  1.9758 +    // window.
  1.9759 +    if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
  1.9760 +      mFocusByKeyOccurred = true;
  1.9761 +    } else if (
  1.9762 +      // otherwise, we set mShowFocusRingForContent, as we don't want this to
  1.9763 +      // be permanent for the window. On Windows, focus rings are only shown
  1.9764 +      // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
  1.9765 +      // are only hidden for clicks on links.
  1.9766 +#ifndef XP_WIN
  1.9767 +      !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) || !IsLink(aNode) ||
  1.9768 +#endif
  1.9769 +      aFocusMethod & nsIFocusManager::FLAG_SHOWRING) {
  1.9770 +        mShowFocusRingForContent = true;
  1.9771 +    }
  1.9772 +  }
  1.9773 +
  1.9774 +  if (aNeedsFocus)
  1.9775 +    mNeedsFocus = aNeedsFocus;
  1.9776 +}
  1.9777 +
  1.9778 +uint32_t
  1.9779 +nsGlobalWindow::GetFocusMethod()
  1.9780 +{
  1.9781 +  FORWARD_TO_INNER(GetFocusMethod, (), 0);
  1.9782 +
  1.9783 +  return mFocusMethod;
  1.9784 +}
  1.9785 +
  1.9786 +bool
  1.9787 +nsGlobalWindow::ShouldShowFocusRing()
  1.9788 +{
  1.9789 +  FORWARD_TO_INNER(ShouldShowFocusRing, (), false);
  1.9790 +
  1.9791 +  return mShowFocusRings || mShowFocusRingForContent || mFocusByKeyOccurred;
  1.9792 +}
  1.9793 +
  1.9794 +void
  1.9795 +nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
  1.9796 +                                      UIStateChangeType aShowFocusRings)
  1.9797 +{
  1.9798 +  FORWARD_TO_INNER_VOID(SetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
  1.9799 +
  1.9800 +  bool oldShouldShowFocusRing = ShouldShowFocusRing();
  1.9801 +
  1.9802 +  // only change the flags that have been modified
  1.9803 +  if (aShowAccelerators != UIStateChangeType_NoChange)
  1.9804 +    mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
  1.9805 +  if (aShowFocusRings != UIStateChangeType_NoChange)
  1.9806 +    mShowFocusRings = aShowFocusRings == UIStateChangeType_Set;
  1.9807 +
  1.9808 +  // propagate the indicators to child windows
  1.9809 +  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
  1.9810 +  if (docShell) {
  1.9811 +    int32_t childCount = 0;
  1.9812 +    docShell->GetChildCount(&childCount);
  1.9813 +
  1.9814 +    for (int32_t i = 0; i < childCount; ++i) {
  1.9815 +      nsCOMPtr<nsIDocShellTreeItem> childShell;
  1.9816 +      docShell->GetChildAt(i, getter_AddRefs(childShell));
  1.9817 +      nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(childShell);
  1.9818 +      if (childWindow) {
  1.9819 +        childWindow->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
  1.9820 +      }
  1.9821 +    }
  1.9822 +  }
  1.9823 +
  1.9824 +  bool newShouldShowFocusRing = ShouldShowFocusRing();
  1.9825 +  if (mHasFocus && mFocusedNode &&
  1.9826 +      oldShouldShowFocusRing != newShouldShowFocusRing &&
  1.9827 +      mFocusedNode->IsElement()) {
  1.9828 +    // Update mFocusedNode's state.
  1.9829 +    if (newShouldShowFocusRing) {
  1.9830 +      mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);
  1.9831 +    } else {
  1.9832 +      mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);
  1.9833 +    }
  1.9834 +  }
  1.9835 +}
  1.9836 +
  1.9837 +void
  1.9838 +nsGlobalWindow::GetKeyboardIndicators(bool* aShowAccelerators,
  1.9839 +                                      bool* aShowFocusRings)
  1.9840 +{
  1.9841 +  FORWARD_TO_INNER_VOID(GetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
  1.9842 +
  1.9843 +  *aShowAccelerators = mShowAccelerators;
  1.9844 +  *aShowFocusRings = mShowFocusRings;
  1.9845 +}
  1.9846 +
  1.9847 +bool
  1.9848 +nsGlobalWindow::TakeFocus(bool aFocus, uint32_t aFocusMethod)
  1.9849 +{
  1.9850 +  FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false);
  1.9851 +
  1.9852 +  if (mCleanedUp) {
  1.9853 +    return false;
  1.9854 +  }
  1.9855 +  
  1.9856 +  if (aFocus)
  1.9857 +    mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
  1.9858 +
  1.9859 +  if (mHasFocus != aFocus) {
  1.9860 +    mHasFocus = aFocus;
  1.9861 +    UpdateCanvasFocus(true, mFocusedNode);
  1.9862 +  }
  1.9863 +
  1.9864 +  // if mNeedsFocus is true, then the document has not yet received a
  1.9865 +  // document-level focus event. If there is a root content node, then return
  1.9866 +  // true to tell the calling focus manager that a focus event is expected. If
  1.9867 +  // there is no root content node, the document hasn't loaded enough yet, or
  1.9868 +  // there isn't one and there is no point in firing a focus event.
  1.9869 +  if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nullptr) {
  1.9870 +    mNeedsFocus = false;
  1.9871 +    return true;
  1.9872 +  }
  1.9873 +
  1.9874 +  mNeedsFocus = false;
  1.9875 +  return false;
  1.9876 +}
  1.9877 +
  1.9878 +void
  1.9879 +nsGlobalWindow::SetReadyForFocus()
  1.9880 +{
  1.9881 +  FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
  1.9882 +
  1.9883 +  bool oldNeedsFocus = mNeedsFocus;
  1.9884 +  mNeedsFocus = false;
  1.9885 +
  1.9886 +  // update whether focus rings need to be shown using the state from the
  1.9887 +  // root window
  1.9888 +  nsPIDOMWindow* root = GetPrivateRoot();
  1.9889 +  if (root) {
  1.9890 +    bool showAccelerators, showFocusRings;
  1.9891 +    root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
  1.9892 +    mShowFocusRings = showFocusRings;
  1.9893 +  }
  1.9894 +
  1.9895 +  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.9896 +  if (fm)
  1.9897 +    fm->WindowShown(this, oldNeedsFocus);
  1.9898 +}
  1.9899 +
  1.9900 +void
  1.9901 +nsGlobalWindow::PageHidden()
  1.9902 +{
  1.9903 +  FORWARD_TO_INNER_VOID(PageHidden, ());
  1.9904 +
  1.9905 +  // the window is being hidden, so tell the focus manager that the frame is
  1.9906 +  // no longer valid. Use the persisted field to determine if the document
  1.9907 +  // is being destroyed.
  1.9908 +
  1.9909 +  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.9910 +  if (fm)
  1.9911 +    fm->WindowHidden(this);
  1.9912 +
  1.9913 +  mNeedsFocus = true;
  1.9914 +}
  1.9915 +
  1.9916 +class HashchangeCallback : public nsRunnable
  1.9917 +{
  1.9918 +public:
  1.9919 +  HashchangeCallback(const nsAString &aOldURL,
  1.9920 +                     const nsAString &aNewURL,
  1.9921 +                     nsGlobalWindow* aWindow)
  1.9922 +    : mWindow(aWindow)
  1.9923 +  {
  1.9924 +    MOZ_ASSERT(mWindow);
  1.9925 +    MOZ_ASSERT(mWindow->IsInnerWindow());
  1.9926 +    mOldURL.Assign(aOldURL);
  1.9927 +    mNewURL.Assign(aNewURL);
  1.9928 +  }
  1.9929 +
  1.9930 +  NS_IMETHOD Run()
  1.9931 +  {
  1.9932 +    NS_PRECONDITION(NS_IsMainThread(), "Should be called on the main thread.");
  1.9933 +    return mWindow->FireHashchange(mOldURL, mNewURL);
  1.9934 +  }
  1.9935 +
  1.9936 +private:
  1.9937 +  nsString mOldURL;
  1.9938 +  nsString mNewURL;
  1.9939 +  nsRefPtr<nsGlobalWindow> mWindow;
  1.9940 +};
  1.9941 +
  1.9942 +nsresult
  1.9943 +nsGlobalWindow::DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI)
  1.9944 +{
  1.9945 +  FORWARD_TO_INNER(DispatchAsyncHashchange, (aOldURI, aNewURI), NS_OK);
  1.9946 +
  1.9947 +  // Make sure that aOldURI and aNewURI are identical up to the '#', and that
  1.9948 +  // their hashes are different.
  1.9949 +  nsAutoCString oldBeforeHash, oldHash, newBeforeHash, newHash;
  1.9950 +  nsContentUtils::SplitURIAtHash(aOldURI, oldBeforeHash, oldHash);
  1.9951 +  nsContentUtils::SplitURIAtHash(aNewURI, newBeforeHash, newHash);
  1.9952 +
  1.9953 +  NS_ENSURE_STATE(oldBeforeHash.Equals(newBeforeHash));
  1.9954 +  NS_ENSURE_STATE(!oldHash.Equals(newHash));
  1.9955 +
  1.9956 +  nsAutoCString oldSpec, newSpec;
  1.9957 +  aOldURI->GetSpec(oldSpec);
  1.9958 +  aNewURI->GetSpec(newSpec);
  1.9959 +
  1.9960 +  NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
  1.9961 +  NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
  1.9962 +
  1.9963 +  nsCOMPtr<nsIRunnable> callback =
  1.9964 +    new HashchangeCallback(oldWideSpec, newWideSpec, this);
  1.9965 +  return NS_DispatchToMainThread(callback);
  1.9966 +}
  1.9967 +
  1.9968 +nsresult
  1.9969 +nsGlobalWindow::FireHashchange(const nsAString &aOldURL,
  1.9970 +                               const nsAString &aNewURL)
  1.9971 +{
  1.9972 +  MOZ_ASSERT(IsInnerWindow());
  1.9973 +
  1.9974 +  // Don't do anything if the window is frozen.
  1.9975 +  if (IsFrozen())
  1.9976 +    return NS_OK;
  1.9977 +
  1.9978 +  // Get a presentation shell for use in creating the hashchange event.
  1.9979 +  NS_ENSURE_STATE(IsCurrentInnerWindow());
  1.9980 +
  1.9981 +  nsIPresShell *shell = mDoc->GetShell();
  1.9982 +  nsRefPtr<nsPresContext> presContext;
  1.9983 +  if (shell) {
  1.9984 +    presContext = shell->GetPresContext();
  1.9985 +  }
  1.9986 +
  1.9987 +  // Create a new hashchange event.
  1.9988 +  nsCOMPtr<nsIDOMEvent> domEvent;
  1.9989 +  nsresult rv =
  1.9990 +    EventDispatcher::CreateEvent(this, presContext, nullptr,
  1.9991 +                                 NS_LITERAL_STRING("hashchangeevent"),
  1.9992 +                                 getter_AddRefs(domEvent));
  1.9993 +  NS_ENSURE_SUCCESS(rv, rv);
  1.9994 +
  1.9995 +  nsCOMPtr<nsIDOMHashChangeEvent> hashchangeEvent = do_QueryInterface(domEvent);
  1.9996 +  NS_ENSURE_TRUE(hashchangeEvent, NS_ERROR_UNEXPECTED);
  1.9997 +
  1.9998 +  // The hashchange event bubbles and isn't cancellable.
  1.9999 +  rv = hashchangeEvent->InitHashChangeEvent(NS_LITERAL_STRING("hashchange"),
 1.10000 +                                            true, false,
 1.10001 +                                            aOldURL, aNewURL);
 1.10002 +  NS_ENSURE_SUCCESS(rv, rv);
 1.10003 +
 1.10004 +  domEvent->SetTrusted(true);
 1.10005 +
 1.10006 +  bool dummy;
 1.10007 +  return DispatchEvent(hashchangeEvent, &dummy);
 1.10008 +}
 1.10009 +
 1.10010 +nsresult
 1.10011 +nsGlobalWindow::DispatchSyncPopState()
 1.10012 +{
 1.10013 +  FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK);
 1.10014 +
 1.10015 +  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
 1.10016 +               "Must be safe to run script here.");
 1.10017 +
 1.10018 +  // Check that PopState hasn't been pref'ed off.
 1.10019 +  if (!Preferences::GetBool(sPopStatePrefStr, false)) {
 1.10020 +    return NS_OK;
 1.10021 +  }
 1.10022 +
 1.10023 +  nsresult rv = NS_OK;
 1.10024 +
 1.10025 +  // Bail if the window is frozen.
 1.10026 +  if (IsFrozen()) {
 1.10027 +    return NS_OK;
 1.10028 +  }
 1.10029 +
 1.10030 +  // Get the document's pending state object -- it contains the data we're
 1.10031 +  // going to send along with the popstate event.  The object is serialized
 1.10032 +  // using structured clone.
 1.10033 +  nsCOMPtr<nsIVariant> stateObj;
 1.10034 +  rv = mDoc->GetStateObject(getter_AddRefs(stateObj));
 1.10035 +  NS_ENSURE_SUCCESS(rv, rv);
 1.10036 +
 1.10037 +  // Obtain a presentation shell for use in creating a popstate event.
 1.10038 +  nsIPresShell *shell = mDoc->GetShell();
 1.10039 +  nsRefPtr<nsPresContext> presContext;
 1.10040 +  if (shell) {
 1.10041 +    presContext = shell->GetPresContext();
 1.10042 +  }
 1.10043 +
 1.10044 +  // Create a new popstate event
 1.10045 +  nsCOMPtr<nsIDOMEvent> domEvent;
 1.10046 +  rv = EventDispatcher::CreateEvent(this, presContext, nullptr,
 1.10047 +                                    NS_LITERAL_STRING("popstateevent"),
 1.10048 +                                    getter_AddRefs(domEvent));
 1.10049 +  NS_ENSURE_SUCCESS(rv, rv);
 1.10050 +
 1.10051 +  // Initialize the popstate event, which does bubble but isn't cancellable.
 1.10052 +  nsCOMPtr<nsIDOMPopStateEvent> popstateEvent = do_QueryInterface(domEvent);
 1.10053 +  rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"),
 1.10054 +                                        true, false,
 1.10055 +                                        stateObj);
 1.10056 +  NS_ENSURE_SUCCESS(rv, rv);
 1.10057 +
 1.10058 +  domEvent->SetTrusted(true);
 1.10059 +
 1.10060 +  nsCOMPtr<EventTarget> outerWindow =
 1.10061 +    do_QueryInterface(GetOuterWindow());
 1.10062 +  NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
 1.10063 +
 1.10064 +  rv = domEvent->SetTarget(outerWindow);
 1.10065 +  NS_ENSURE_SUCCESS(rv, rv);
 1.10066 +
 1.10067 +  bool dummy; // default action
 1.10068 +  return DispatchEvent(popstateEvent, &dummy);
 1.10069 +}
 1.10070 +
 1.10071 +// Find an nsICanvasFrame under aFrame.  Only search the principal
 1.10072 +// child lists.  aFrame must be non-null.
 1.10073 +static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
 1.10074 +{
 1.10075 +    nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
 1.10076 +    if (canvasFrame) {
 1.10077 +        return canvasFrame;
 1.10078 +    }
 1.10079 +
 1.10080 +    nsIFrame* kid = aFrame->GetFirstPrincipalChild();
 1.10081 +    while (kid) {
 1.10082 +        canvasFrame = FindCanvasFrame(kid);
 1.10083 +        if (canvasFrame) {
 1.10084 +            return canvasFrame;
 1.10085 +        }
 1.10086 +        kid = kid->GetNextSibling();
 1.10087 +    }
 1.10088 +
 1.10089 +    return nullptr;
 1.10090 +}
 1.10091 +
 1.10092 +//-------------------------------------------------------
 1.10093 +// Tells the HTMLFrame/CanvasFrame that is now has focus
 1.10094 +void
 1.10095 +nsGlobalWindow::UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent)
 1.10096 +{
 1.10097 +  MOZ_ASSERT(IsInnerWindow());
 1.10098 +
 1.10099 +  // this is called from the inner window so use GetDocShell
 1.10100 +  nsIDocShell* docShell = GetDocShell();
 1.10101 +  if (!docShell)
 1.10102 +    return;
 1.10103 +
 1.10104 +  bool editable;
 1.10105 +  docShell->GetEditable(&editable);
 1.10106 +  if (editable)
 1.10107 +    return;
 1.10108 +
 1.10109 +  nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
 1.10110 +  if (!presShell || !mDoc)
 1.10111 +    return;
 1.10112 +
 1.10113 +  Element *rootElement = mDoc->GetRootElement();
 1.10114 +  if (rootElement) {
 1.10115 +      if ((mHasFocus || aFocusChanged) &&
 1.10116 +          (mFocusedNode == rootElement || aNewContent == rootElement)) {
 1.10117 +          nsIFrame* frame = rootElement->GetPrimaryFrame();
 1.10118 +          if (frame) {
 1.10119 +              frame = frame->GetParent();
 1.10120 +              nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
 1.10121 +              if (canvasFrame) {
 1.10122 +                  canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
 1.10123 +              }
 1.10124 +          }
 1.10125 +      }
 1.10126 +  } else {
 1.10127 +      // Look for the frame the hard way
 1.10128 +      nsIFrame* frame = presShell->GetRootFrame();
 1.10129 +      if (frame) {
 1.10130 +          nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
 1.10131 +          if (canvasFrame) {
 1.10132 +              canvasFrame->SetHasFocus(false);
 1.10133 +          }
 1.10134 +      }
 1.10135 +  }
 1.10136 +}
 1.10137 +
 1.10138 +already_AddRefed<nsICSSDeclaration>
 1.10139 +nsGlobalWindow::GetComputedStyle(Element& aElt, const nsAString& aPseudoElt,
 1.10140 +                                 ErrorResult& aError)
 1.10141 +{
 1.10142 +  return GetComputedStyleHelper(aElt, aPseudoElt, false, aError);
 1.10143 +}
 1.10144 +
 1.10145 +NS_IMETHODIMP
 1.10146 +nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
 1.10147 +                                 const nsAString& aPseudoElt,
 1.10148 +                                 nsIDOMCSSStyleDeclaration** aReturn)
 1.10149 +{
 1.10150 +  return GetComputedStyleHelper(aElt, aPseudoElt, false, aReturn);
 1.10151 +}
 1.10152 +
 1.10153 +already_AddRefed<nsICSSDeclaration>
 1.10154 +nsGlobalWindow::GetDefaultComputedStyle(Element& aElt,
 1.10155 +                                        const nsAString& aPseudoElt,
 1.10156 +                                        ErrorResult& aError)
 1.10157 +{
 1.10158 +  return GetComputedStyleHelper(aElt, aPseudoElt, true, aError);
 1.10159 +}
 1.10160 +
 1.10161 +NS_IMETHODIMP
 1.10162 +nsGlobalWindow::GetDefaultComputedStyle(nsIDOMElement* aElt,
 1.10163 +                                        const nsAString& aPseudoElt,
 1.10164 +                                        nsIDOMCSSStyleDeclaration** aReturn)
 1.10165 +{
 1.10166 +  return GetComputedStyleHelper(aElt, aPseudoElt, true, aReturn);
 1.10167 +}
 1.10168 +
 1.10169 +nsresult
 1.10170 +nsGlobalWindow::GetComputedStyleHelper(nsIDOMElement* aElt,
 1.10171 +                                       const nsAString& aPseudoElt,
 1.10172 +                                       bool aDefaultStylesOnly,
 1.10173 +                                       nsIDOMCSSStyleDeclaration** aReturn)
 1.10174 +{
 1.10175 +  NS_ENSURE_ARG_POINTER(aReturn);
 1.10176 +  *aReturn = nullptr;
 1.10177 +
 1.10178 +  nsCOMPtr<dom::Element> element = do_QueryInterface(aElt);
 1.10179 +  if (!element) {
 1.10180 +    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 1.10181 +  }
 1.10182 +
 1.10183 +  ErrorResult rv;
 1.10184 +  nsCOMPtr<nsIDOMCSSStyleDeclaration> declaration =
 1.10185 +    GetComputedStyleHelper(*element, aPseudoElt, aDefaultStylesOnly, rv);
 1.10186 +  declaration.forget(aReturn);
 1.10187 +
 1.10188 +  return rv.ErrorCode();
 1.10189 +}
 1.10190 +
 1.10191 +already_AddRefed<nsICSSDeclaration>
 1.10192 +nsGlobalWindow::GetComputedStyleHelper(Element& aElt,
 1.10193 +                                       const nsAString& aPseudoElt,
 1.10194 +                                       bool aDefaultStylesOnly,
 1.10195 +                                       ErrorResult& aError)
 1.10196 +{
 1.10197 +  FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelper,
 1.10198 +                            (aElt, aPseudoElt, aDefaultStylesOnly, aError),
 1.10199 +                            aError, nullptr);
 1.10200 +
 1.10201 +  if (!mDocShell) {
 1.10202 +    return nullptr;
 1.10203 +  }
 1.10204 +
 1.10205 +  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
 1.10206 +
 1.10207 +  if (!presShell) {
 1.10208 +    // Try flushing frames on our parent in case there's a pending
 1.10209 +    // style change that will create the presshell.
 1.10210 +    nsGlobalWindow *parent =
 1.10211 +      static_cast<nsGlobalWindow *>(GetPrivateParent());
 1.10212 +    if (!parent) {
 1.10213 +      return nullptr;
 1.10214 +    }
 1.10215 +
 1.10216 +    parent->FlushPendingNotifications(Flush_Frames);
 1.10217 +
 1.10218 +    // Might have killed mDocShell
 1.10219 +    if (!mDocShell) {
 1.10220 +      return nullptr;
 1.10221 +    }
 1.10222 +
 1.10223 +    presShell = mDocShell->GetPresShell();
 1.10224 +    if (!presShell) {
 1.10225 +      return nullptr;
 1.10226 +    }
 1.10227 +  }
 1.10228 +
 1.10229 +  nsRefPtr<nsComputedDOMStyle> compStyle =
 1.10230 +    NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell,
 1.10231 +                           aDefaultStylesOnly ? nsComputedDOMStyle::eDefaultOnly :
 1.10232 +                                                nsComputedDOMStyle::eAll);
 1.10233 +
 1.10234 +  return compStyle.forget();
 1.10235 +}
 1.10236 +
 1.10237 +nsIDOMStorage*
 1.10238 +nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
 1.10239 +{
 1.10240 +  FORWARD_TO_INNER_OR_THROW(GetSessionStorage, (aError), aError, nullptr);
 1.10241 +
 1.10242 +  nsIPrincipal *principal = GetPrincipal();
 1.10243 +  nsIDocShell* docShell = GetDocShell();
 1.10244 +
 1.10245 +  if (!principal || !docShell || !Preferences::GetBool(kStorageEnabled)) {
 1.10246 +    return nullptr;
 1.10247 +  }
 1.10248 +
 1.10249 +  if (mSessionStorage) {
 1.10250 +#ifdef PR_LOGGING
 1.10251 +    if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
 1.10252 +      PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get());
 1.10253 +    }
 1.10254 +#endif
 1.10255 +    nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(mSessionStorage);
 1.10256 +    if (piStorage) {
 1.10257 +      bool canAccess = piStorage->CanAccess(principal);
 1.10258 +      NS_ASSERTION(canAccess,
 1.10259 +                   "window %x owned sessionStorage "
 1.10260 +                   "that could not be accessed!");
 1.10261 +      if (!canAccess) {
 1.10262 +        mSessionStorage = nullptr;
 1.10263 +      }
 1.10264 +    }
 1.10265 +  }
 1.10266 +
 1.10267 +  if (!mSessionStorage) {
 1.10268 +    nsString documentURI;
 1.10269 +    if (mDoc) {
 1.10270 +      mDoc->GetDocumentURI(documentURI);
 1.10271 +    }
 1.10272 +
 1.10273 +    // If the document has the sandboxed origin flag set
 1.10274 +    // don't allow access to sessionStorage.
 1.10275 +    if (!mDoc) {
 1.10276 +      aError.Throw(NS_ERROR_FAILURE);
 1.10277 +      return nullptr;
 1.10278 +    }
 1.10279 +
 1.10280 +    if (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
 1.10281 +      aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
 1.10282 +      return nullptr;
 1.10283 +    }
 1.10284 +
 1.10285 +    nsresult rv;
 1.10286 +
 1.10287 +    nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(docShell, &rv);
 1.10288 +    if (NS_FAILED(rv)) {
 1.10289 +      aError.Throw(rv);
 1.10290 +      return nullptr;
 1.10291 +    }
 1.10292 +
 1.10293 +    nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
 1.10294 +
 1.10295 +    nsCOMPtr<nsIURI> firstPartyIsolationURI;
 1.10296 +    rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
 1.10297 +    if (NS_FAILED(rv)) {
 1.10298 +      aError.Throw(rv);
 1.10299 +      return nullptr;
 1.10300 +    }
 1.10301 +
 1.10302 +    aError =  storageManager->CreateStorageForFirstParty(firstPartyIsolationURI, principal,
 1.10303 +                                           documentURI,
 1.10304 +                                           loadContext && loadContext->UsePrivateBrowsing(),
 1.10305 +                                           getter_AddRefs(mSessionStorage));
 1.10306 +    if (aError.Failed()) {
 1.10307 +      return nullptr;
 1.10308 +    }
 1.10309 +
 1.10310 +#ifdef PR_LOGGING
 1.10311 +    if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
 1.10312 +      PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
 1.10313 +    }
 1.10314 +#endif
 1.10315 +
 1.10316 +    if (!mSessionStorage) {
 1.10317 +      aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 1.10318 +      return nullptr;
 1.10319 +    }
 1.10320 +  }
 1.10321 +
 1.10322 +#ifdef PR_LOGGING
 1.10323 +  if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
 1.10324 +    PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get());
 1.10325 +  }
 1.10326 +#endif
 1.10327 +
 1.10328 +  return mSessionStorage;
 1.10329 +}
 1.10330 +
 1.10331 +NS_IMETHODIMP
 1.10332 +nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
 1.10333 +{
 1.10334 +  ErrorResult rv;
 1.10335 +  nsCOMPtr<nsIDOMStorage> storage = GetSessionStorage(rv);
 1.10336 +  storage.forget(aSessionStorage);
 1.10337 +
 1.10338 +  return rv.ErrorCode();
 1.10339 +}
 1.10340 +
 1.10341 +nsIDOMStorage*
 1.10342 +nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
 1.10343 +{
 1.10344 +  FORWARD_TO_INNER_OR_THROW(GetLocalStorage, (aError), aError, nullptr);
 1.10345 +
 1.10346 +  if (!Preferences::GetBool(kStorageEnabled)) {
 1.10347 +    return nullptr;
 1.10348 +  }
 1.10349 +
 1.10350 +  if (!mLocalStorage) {
 1.10351 +    if (!DOMStorage::CanUseStorage()) {
 1.10352 +      aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
 1.10353 +      return nullptr;
 1.10354 +    }
 1.10355 +
 1.10356 +    nsIPrincipal *principal = GetPrincipal();
 1.10357 +    if (!principal) {
 1.10358 +      return nullptr;
 1.10359 +    }
 1.10360 +
 1.10361 +    nsresult rv;
 1.10362 +    nsCOMPtr<nsIDOMStorageManager> storageManager =
 1.10363 +      do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
 1.10364 +    if (NS_FAILED(rv)) {
 1.10365 +      aError.Throw(rv);
 1.10366 +      return nullptr;
 1.10367 +    }
 1.10368 +
 1.10369 +    // If the document has the sandboxed origin flag set
 1.10370 +    // don't allow access to localStorage.
 1.10371 +    if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
 1.10372 +      aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
 1.10373 +      return nullptr;
 1.10374 +    }
 1.10375 +
 1.10376 +    nsString documentURI;
 1.10377 +    if (mDoc) {
 1.10378 +      mDoc->GetDocumentURI(documentURI);
 1.10379 +    }
 1.10380 +
 1.10381 +    nsCOMPtr<nsIURI> firstPartyIsolationURI;
 1.10382 +    rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
 1.10383 +    if (NS_FAILED(rv)) {
 1.10384 +      aError.Throw(rv);
 1.10385 +      return nullptr;
 1.10386 +    }
 1.10387 +
 1.10388 +    nsIDocShell* docShell = GetDocShell();
 1.10389 +    nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
 1.10390 +
 1.10391 +    aError = storageManager->CreateStorageForFirstParty(firstPartyIsolationURI, principal,
 1.10392 +                                           documentURI,
 1.10393 +                                           loadContext && loadContext->UsePrivateBrowsing(),
 1.10394 +                                           getter_AddRefs(mLocalStorage));
 1.10395 +  }
 1.10396 +
 1.10397 +  return mLocalStorage;
 1.10398 +}
 1.10399 +
 1.10400 +NS_IMETHODIMP
 1.10401 +nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
 1.10402 +{
 1.10403 +  NS_ENSURE_ARG(aLocalStorage);
 1.10404 +
 1.10405 +  ErrorResult rv;
 1.10406 +  nsCOMPtr<nsIDOMStorage> storage = GetLocalStorage(rv);
 1.10407 +  storage.forget(aLocalStorage);
 1.10408 +
 1.10409 +  return rv.ErrorCode();
 1.10410 +}
 1.10411 +
 1.10412 +indexedDB::IDBFactory*
 1.10413 +nsGlobalWindow::GetIndexedDB(ErrorResult& aError)
 1.10414 +{
 1.10415 +  if (!mIndexedDB) {
 1.10416 +    // If the document has the sandboxed origin flag set
 1.10417 +    // don't allow access to indexedDB.
 1.10418 +    if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
 1.10419 +      aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
 1.10420 +      return nullptr;
 1.10421 +    }
 1.10422 +
 1.10423 +    if (!IsChromeWindow()) {
 1.10424 +      // Whitelist about:home, since it doesn't have a base domain it would not
 1.10425 +      // pass the thirdPartyUtil check, though it should be able to use
 1.10426 +      // indexedDB.
 1.10427 +      bool skipThirdPartyCheck = false;
 1.10428 +      nsIPrincipal *principal = GetPrincipal();
 1.10429 +      if (principal) {
 1.10430 +        nsCOMPtr<nsIURI> uri;
 1.10431 +        principal->GetURI(getter_AddRefs(uri));
 1.10432 +        bool isAbout = false;
 1.10433 +        if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
 1.10434 +          nsAutoCString path;
 1.10435 +          skipThirdPartyCheck = NS_SUCCEEDED(uri->GetPath(path)) &&
 1.10436 +                                path.EqualsLiteral("home");
 1.10437 +        }
 1.10438 +      }
 1.10439 +
 1.10440 +      if (!skipThirdPartyCheck) {
 1.10441 +        nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
 1.10442 +          do_GetService(THIRDPARTYUTIL_CONTRACTID);
 1.10443 +        if (!thirdPartyUtil) {
 1.10444 +          aError.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 1.10445 +          return nullptr;
 1.10446 +        }
 1.10447 +
 1.10448 +        bool isThirdParty;
 1.10449 +        aError = thirdPartyUtil->IsThirdPartyWindow(this, nullptr,
 1.10450 +                                                    &isThirdParty);
 1.10451 +        if (aError.Failed() || isThirdParty) {
 1.10452 +          NS_WARN_IF_FALSE(aError.Failed(),
 1.10453 +                           "IndexedDB is not permitted in a third-party window.");
 1.10454 +          return nullptr;
 1.10455 +        }
 1.10456 +      }
 1.10457 +    }
 1.10458 +
 1.10459 +    // This may be null if being created from a file.
 1.10460 +    aError = indexedDB::IDBFactory::Create(this, nullptr,
 1.10461 +                                           getter_AddRefs(mIndexedDB));
 1.10462 +  }
 1.10463 +
 1.10464 +  return mIndexedDB;
 1.10465 +}
 1.10466 +
 1.10467 +NS_IMETHODIMP
 1.10468 +nsGlobalWindow::GetIndexedDB(nsISupports** _retval)
 1.10469 +{
 1.10470 +  ErrorResult rv;
 1.10471 +  nsCOMPtr<nsISupports> request(GetIndexedDB(rv));
 1.10472 +  request.forget(_retval);
 1.10473 +
 1.10474 +  return rv.ErrorCode();
 1.10475 +}
 1.10476 +
 1.10477 +NS_IMETHODIMP
 1.10478 +nsGlobalWindow::GetMozIndexedDB(nsISupports** _retval)
 1.10479 +{
 1.10480 +  return GetIndexedDB(_retval);
 1.10481 +}
 1.10482 +
 1.10483 +//*****************************************************************************
 1.10484 +// nsGlobalWindow::nsIInterfaceRequestor
 1.10485 +//*****************************************************************************
 1.10486 +
 1.10487 +NS_IMETHODIMP
 1.10488 +nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
 1.10489 +{
 1.10490 +  NS_ENSURE_ARG_POINTER(aSink);
 1.10491 +  *aSink = nullptr;
 1.10492 +
 1.10493 +  if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
 1.10494 +    nsGlobalWindow* outer = GetOuterWindowInternal();
 1.10495 +    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 1.10496 +
 1.10497 +    NS_WARNING("Using deprecated nsIDocCharset: use nsIDocShell.GetCharset() instead ");
 1.10498 +    nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(outer->mDocShell));
 1.10499 +    docCharset.forget(aSink);
 1.10500 +  }
 1.10501 +  else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
 1.10502 +    nsGlobalWindow* outer = GetOuterWindowInternal();
 1.10503 +    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 1.10504 +
 1.10505 +    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(outer->mDocShell));
 1.10506 +    webNav.forget(aSink);
 1.10507 +  }
 1.10508 +  else if (aIID.Equals(NS_GET_IID(nsIDocShell))) {
 1.10509 +    nsGlobalWindow* outer = GetOuterWindowInternal();
 1.10510 +    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 1.10511 +
 1.10512 +    nsCOMPtr<nsIDocShell> docShell = outer->mDocShell;
 1.10513 +    docShell.forget(aSink);
 1.10514 +  }
 1.10515 +#ifdef NS_PRINTING
 1.10516 +  else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
 1.10517 +    nsGlobalWindow* outer = GetOuterWindowInternal();
 1.10518 +    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 1.10519 +
 1.10520 +    if (outer->mDocShell) {
 1.10521 +      nsCOMPtr<nsIContentViewer> viewer;
 1.10522 +      outer->mDocShell->GetContentViewer(getter_AddRefs(viewer));
 1.10523 +      if (viewer) {
 1.10524 +        nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
 1.10525 +        webBrowserPrint.forget(aSink);
 1.10526 +      }
 1.10527 +    }
 1.10528 +  }
 1.10529 +#endif
 1.10530 +  else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
 1.10531 +    nsGlobalWindow* outer = GetOuterWindowInternal();
 1.10532 +    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 1.10533 +
 1.10534 +    if (!mWindowUtils) {
 1.10535 +      mWindowUtils = new nsDOMWindowUtils(outer);
 1.10536 +    }
 1.10537 +
 1.10538 +    *aSink = mWindowUtils;
 1.10539 +    NS_ADDREF(((nsISupports *) *aSink));
 1.10540 +  }
 1.10541 +  else if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
 1.10542 +    nsGlobalWindow* outer = GetOuterWindowInternal();
 1.10543 +    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 1.10544 +
 1.10545 +    nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(outer->mDocShell));
 1.10546 +    loadContext.forget(aSink);
 1.10547 +  }
 1.10548 +  else {
 1.10549 +    return QueryInterface(aIID, aSink);
 1.10550 +  }
 1.10551 +
 1.10552 +  return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
 1.10553 +}
 1.10554 +
 1.10555 +void
 1.10556 +nsGlobalWindow::GetInterface(JSContext* aCx, nsIJSID* aIID,
 1.10557 +                             JS::MutableHandle<JS::Value> aRetval,
 1.10558 +                             ErrorResult& aError)
 1.10559 +{
 1.10560 +  dom::GetInterface(aCx, this, aIID, aRetval, aError);
 1.10561 +}
 1.10562 +
 1.10563 +void
 1.10564 +nsGlobalWindow::FireOfflineStatusEvent()
 1.10565 +{
 1.10566 +  if (!IsCurrentInnerWindow())
 1.10567 +    return;
 1.10568 +  nsAutoString name;
 1.10569 +  if (NS_IsOffline()) {
 1.10570 +    name.AssignLiteral("offline");
 1.10571 +  } else {
 1.10572 +    name.AssignLiteral("online");
 1.10573 +  }
 1.10574 +  // The event is fired at the body element, or if there is no body element,
 1.10575 +  // at the document.
 1.10576 +  nsCOMPtr<EventTarget> eventTarget = mDoc.get();
 1.10577 +  nsHTMLDocument* htmlDoc = mDoc->AsHTMLDocument();
 1.10578 +  if (htmlDoc) {
 1.10579 +    Element* body = htmlDoc->GetBody();
 1.10580 +    if (body) {
 1.10581 +      eventTarget = body;
 1.10582 +    }
 1.10583 +  } else {
 1.10584 +    Element* documentElement = mDoc->GetDocumentElement();
 1.10585 +    if (documentElement) {
 1.10586 +      eventTarget = documentElement;
 1.10587 +    }
 1.10588 +  }
 1.10589 +  nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, true, false);
 1.10590 +}
 1.10591 +
 1.10592 +class NotifyIdleObserverRunnable : public nsRunnable
 1.10593 +{
 1.10594 +public:
 1.10595 +  NotifyIdleObserverRunnable(nsIIdleObserver* aIdleObserver,
 1.10596 +                             uint32_t aTimeInS,
 1.10597 +                             bool aCallOnidle,
 1.10598 +                             nsGlobalWindow* aIdleWindow)
 1.10599 +    : mIdleObserver(aIdleObserver), mTimeInS(aTimeInS), mIdleWindow(aIdleWindow),
 1.10600 +      mCallOnidle(aCallOnidle)
 1.10601 +  { }
 1.10602 +
 1.10603 +  NS_IMETHOD Run()
 1.10604 +  {
 1.10605 +    if (mIdleWindow->ContainsIdleObserver(mIdleObserver, mTimeInS)) {
 1.10606 +      return mCallOnidle ? mIdleObserver->Onidle() : mIdleObserver->Onactive();
 1.10607 +    }
 1.10608 +    return NS_OK;
 1.10609 +  }
 1.10610 +
 1.10611 +private:
 1.10612 +  nsCOMPtr<nsIIdleObserver> mIdleObserver;
 1.10613 +  uint32_t mTimeInS;
 1.10614 +  nsRefPtr<nsGlobalWindow> mIdleWindow;
 1.10615 +
 1.10616 +  // If false then call on active
 1.10617 +  bool mCallOnidle;
 1.10618 +};
 1.10619 +
 1.10620 +void
 1.10621 +nsGlobalWindow::NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
 1.10622 +                                   bool aCallOnidle)
 1.10623 +{
 1.10624 +  MOZ_ASSERT(aIdleObserverHolder);
 1.10625 +  aIdleObserverHolder->mPrevNotificationIdle = aCallOnidle;
 1.10626 +
 1.10627 +  nsCOMPtr<nsIRunnable> caller =
 1.10628 +    new NotifyIdleObserverRunnable(aIdleObserverHolder->mIdleObserver,
 1.10629 +                                   aIdleObserverHolder->mTimeInS,
 1.10630 +                                   aCallOnidle, this);
 1.10631 +  if (NS_FAILED(NS_DispatchToCurrentThread(caller))) {
 1.10632 +    NS_WARNING("Failed to dispatch thread for idle observer notification.");
 1.10633 +  }
 1.10634 +}
 1.10635 +
 1.10636 +bool
 1.10637 +nsGlobalWindow::ContainsIdleObserver(nsIIdleObserver* aIdleObserver, uint32_t aTimeInS)
 1.10638 +{
 1.10639 +  MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
 1.10640 +  bool found = false;
 1.10641 +  nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
 1.10642 +  while (iter.HasMore()) {
 1.10643 +    IdleObserverHolder& idleObserver = iter.GetNext();
 1.10644 +    if (idleObserver.mIdleObserver == aIdleObserver &&
 1.10645 +        idleObserver.mTimeInS == aTimeInS) {
 1.10646 +      found = true;
 1.10647 +      break;
 1.10648 +    }
 1.10649 +  }
 1.10650 +  return found;
 1.10651 +}
 1.10652 +
 1.10653 +void
 1.10654 +IdleActiveTimerCallback(nsITimer* aTimer, void* aClosure)
 1.10655 +{
 1.10656 +  nsRefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
 1.10657 +  MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
 1.10658 +  idleWindow->HandleIdleActiveEvent();
 1.10659 +}
 1.10660 +
 1.10661 +void
 1.10662 +IdleObserverTimerCallback(nsITimer* aTimer, void* aClosure)
 1.10663 +{
 1.10664 +  nsRefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
 1.10665 +  MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
 1.10666 +  idleWindow->HandleIdleObserverCallback();
 1.10667 +}
 1.10668 +
 1.10669 +void
 1.10670 +nsGlobalWindow::HandleIdleObserverCallback()
 1.10671 +{
 1.10672 +  MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 1.10673 +  MOZ_ASSERT(static_cast<uint32_t>(mIdleCallbackIndex) < mIdleObservers.Length(),
 1.10674 +                                  "Idle callback index exceeds array bounds!");
 1.10675 +  IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(mIdleCallbackIndex);
 1.10676 +  NotifyIdleObserver(&idleObserver, true);
 1.10677 +  mIdleCallbackIndex++;
 1.10678 +  if (NS_FAILED(ScheduleNextIdleObserverCallback())) {
 1.10679 +    NS_WARNING("Failed to set next idle observer callback.");
 1.10680 +  }
 1.10681 +}
 1.10682 +
 1.10683 +nsresult
 1.10684 +nsGlobalWindow::ScheduleNextIdleObserverCallback()
 1.10685 +{
 1.10686 +  MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 1.10687 +  MOZ_ASSERT(mIdleService, "No idle service!");
 1.10688 +
 1.10689 +  if (mIdleCallbackIndex < 0 ||
 1.10690 +      static_cast<uint32_t>(mIdleCallbackIndex) >= mIdleObservers.Length()) {
 1.10691 +    return NS_OK;
 1.10692 +  }
 1.10693 +
 1.10694 +  IdleObserverHolder& idleObserver =
 1.10695 +    mIdleObservers.ElementAt(mIdleCallbackIndex);
 1.10696 +
 1.10697 +  uint32_t userIdleTimeMS = 0;
 1.10698 +  nsresult rv = mIdleService->GetIdleTime(&userIdleTimeMS);
 1.10699 +  NS_ENSURE_SUCCESS(rv, rv);
 1.10700 +
 1.10701 +  uint32_t callbackTimeMS = 0;
 1.10702 +  if (idleObserver.mTimeInS * 1000 + mIdleFuzzFactor > userIdleTimeMS) {
 1.10703 +    callbackTimeMS = idleObserver.mTimeInS * 1000 - userIdleTimeMS + mIdleFuzzFactor;
 1.10704 +  }
 1.10705 +
 1.10706 +  mIdleTimer->Cancel();
 1.10707 +  rv = mIdleTimer->InitWithFuncCallback(IdleObserverTimerCallback,
 1.10708 +                                        this,
 1.10709 +                                        callbackTimeMS,
 1.10710 +                                        nsITimer::TYPE_ONE_SHOT);
 1.10711 +  NS_ENSURE_SUCCESS(rv, rv);
 1.10712 +
 1.10713 +  return NS_OK;
 1.10714 +}
 1.10715 +
 1.10716 +uint32_t
 1.10717 +nsGlobalWindow::GetFuzzTimeMS()
 1.10718 +{
 1.10719 +  MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 1.10720 +
 1.10721 +  if (sIdleObserversAPIFuzzTimeDisabled) {
 1.10722 +    return 0;
 1.10723 +  }
 1.10724 +
 1.10725 +  uint32_t randNum = MAX_IDLE_FUZZ_TIME_MS;
 1.10726 +  size_t nbytes = PR_GetRandomNoise(&randNum, sizeof(randNum));
 1.10727 +  if (nbytes != sizeof(randNum)) {
 1.10728 +    NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!");
 1.10729 +    return MAX_IDLE_FUZZ_TIME_MS;
 1.10730 +  }
 1.10731 +
 1.10732 +  if (randNum > MAX_IDLE_FUZZ_TIME_MS) {
 1.10733 +    randNum %= MAX_IDLE_FUZZ_TIME_MS;
 1.10734 +  }
 1.10735 +
 1.10736 +  return randNum;
 1.10737 +}
 1.10738 +
 1.10739 +nsresult
 1.10740 +nsGlobalWindow::ScheduleActiveTimerCallback()
 1.10741 +{
 1.10742 +  MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 1.10743 +
 1.10744 +  if (!mAddActiveEventFuzzTime) {
 1.10745 +    return HandleIdleActiveEvent();
 1.10746 +  }
 1.10747 +
 1.10748 +  MOZ_ASSERT(mIdleTimer);
 1.10749 +  mIdleTimer->Cancel();
 1.10750 +
 1.10751 +  uint32_t fuzzFactorInMS = GetFuzzTimeMS();
 1.10752 +  nsresult rv = mIdleTimer->InitWithFuncCallback(IdleActiveTimerCallback,
 1.10753 +                                                 this,
 1.10754 +                                                 fuzzFactorInMS,
 1.10755 +                                                 nsITimer::TYPE_ONE_SHOT);
 1.10756 +  NS_ENSURE_SUCCESS(rv, rv);
 1.10757 +  return NS_OK;
 1.10758 +}
 1.10759 +
 1.10760 +nsresult
 1.10761 +nsGlobalWindow::HandleIdleActiveEvent()
 1.10762 +{
 1.10763 +  MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 1.10764 +
 1.10765 +  if (mCurrentlyIdle) {
 1.10766 +    mIdleCallbackIndex = 0;
 1.10767 +    mIdleFuzzFactor = GetFuzzTimeMS();
 1.10768 +    nsresult rv = ScheduleNextIdleObserverCallback();
 1.10769 +    NS_ENSURE_SUCCESS(rv, rv);
 1.10770 +    return NS_OK;
 1.10771 +  }
 1.10772 +
 1.10773 +  mIdleCallbackIndex = -1;
 1.10774 +  MOZ_ASSERT(mIdleTimer);
 1.10775 +  mIdleTimer->Cancel();
 1.10776 +  nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
 1.10777 +  while (iter.HasMore()) {
 1.10778 +    IdleObserverHolder& idleObserver = iter.GetNext();
 1.10779 +    if (idleObserver.mPrevNotificationIdle) {
 1.10780 +      NotifyIdleObserver(&idleObserver, false);
 1.10781 +    }
 1.10782 +  }
 1.10783 +
 1.10784 +  return NS_OK;
 1.10785 +}
 1.10786 +
 1.10787 +nsGlobalWindow::SlowScriptResponse
 1.10788 +nsGlobalWindow::ShowSlowScriptDialog()
 1.10789 +{
 1.10790 +  MOZ_ASSERT(IsInnerWindow());
 1.10791 +
 1.10792 +  nsresult rv;
 1.10793 +  AutoJSContext cx;
 1.10794 +
 1.10795 +  // If it isn't safe to run script, then it isn't safe to bring up the prompt
 1.10796 +  // (since that spins the event loop). In that (rare) case, we just kill the
 1.10797 +  // script and report a warning.
 1.10798 +  if (!nsContentUtils::IsSafeToRunScript()) {
 1.10799 +    JS_ReportWarning(cx, "A long running script was terminated");
 1.10800 +    return KillSlowScript;
 1.10801 +  }
 1.10802 +
 1.10803 +  // If our document is not active, just kill the script: we've been unloaded
 1.10804 +  if (!HasActiveDocument()) {
 1.10805 +    return KillSlowScript;
 1.10806 +  }
 1.10807 +
 1.10808 +  // Get the nsIPrompt interface from the docshell
 1.10809 +  nsCOMPtr<nsIDocShell> ds = GetDocShell();
 1.10810 +  NS_ENSURE_TRUE(ds, KillSlowScript);
 1.10811 +  nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
 1.10812 +  NS_ENSURE_TRUE(prompt, KillSlowScript);
 1.10813 +
 1.10814 +  // Check if we should offer the option to debug
 1.10815 +  JS::AutoFilename filename;
 1.10816 +  unsigned lineno;
 1.10817 +  bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
 1.10818 +
 1.10819 +  bool debugPossible = hasFrame && js::CanCallContextDebugHandler(cx);
 1.10820 +#ifdef MOZ_JSDEBUGGER
 1.10821 +  // Get the debugger service if necessary.
 1.10822 +  if (debugPossible) {
 1.10823 +    bool jsds_IsOn = false;
 1.10824 +    const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
 1.10825 +    nsCOMPtr<jsdIExecutionHook> jsdHook;
 1.10826 +    nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
 1.10827 +
 1.10828 +    // Check if there's a user for the debugger service that's 'on' for us
 1.10829 +    if (NS_SUCCEEDED(rv)) {
 1.10830 +      jsds->GetDebuggerHook(getter_AddRefs(jsdHook));
 1.10831 +      jsds->GetIsOn(&jsds_IsOn);
 1.10832 +    }
 1.10833 +
 1.10834 +    // If there is a debug handler registered for this runtime AND
 1.10835 +    // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
 1.10836 +    // then something useful will be done with our request to debug.
 1.10837 +    debugPossible = ((jsds_IsOn && (jsdHook != nullptr)) || !jsds_IsOn);
 1.10838 +  }
 1.10839 +#endif
 1.10840 +
 1.10841 +  // Get localizable strings
 1.10842 +  nsXPIDLString title, msg, stopButton, waitButton, debugButton, neverShowDlg;
 1.10843 +
 1.10844 +  rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 1.10845 +                                          "KillScriptTitle",
 1.10846 +                                          title);
 1.10847 +
 1.10848 +  nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 1.10849 +                                           "StopScriptButton",
 1.10850 +                                           stopButton);
 1.10851 +  if (NS_FAILED(tmp)) {
 1.10852 +    rv = tmp;
 1.10853 +  }
 1.10854 +
 1.10855 +  tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 1.10856 +                                           "WaitForScriptButton",
 1.10857 +                                           waitButton);
 1.10858 +  if (NS_FAILED(tmp)) {
 1.10859 +    rv = tmp;
 1.10860 +  }
 1.10861 +
 1.10862 +  tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 1.10863 +                                           "DontAskAgain",
 1.10864 +                                           neverShowDlg);
 1.10865 +  if (NS_FAILED(tmp)) {
 1.10866 +    rv = tmp;
 1.10867 +  }
 1.10868 +
 1.10869 +
 1.10870 +  if (debugPossible) {
 1.10871 +    tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 1.10872 +                                             "DebugScriptButton",
 1.10873 +                                             debugButton);
 1.10874 +    if (NS_FAILED(tmp)) {
 1.10875 +      rv = tmp;
 1.10876 +    }
 1.10877 +
 1.10878 +    tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 1.10879 +                                             "KillScriptWithDebugMessage",
 1.10880 +                                             msg);
 1.10881 +    if (NS_FAILED(tmp)) {
 1.10882 +      rv = tmp;
 1.10883 +    }
 1.10884 +  }
 1.10885 +  else {
 1.10886 +    tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 1.10887 +                                             "KillScriptMessage",
 1.10888 +                                             msg);
 1.10889 +    if (NS_FAILED(tmp)) {
 1.10890 +      rv = tmp;
 1.10891 +    }
 1.10892 +  }
 1.10893 +
 1.10894 +  // GetStringFromName can return NS_OK and still give nullptr string
 1.10895 +  if (NS_FAILED(rv) || !title || !msg || !stopButton || !waitButton ||
 1.10896 +      (!debugButton && debugPossible) || !neverShowDlg) {
 1.10897 +    NS_ERROR("Failed to get localized strings.");
 1.10898 +    return ContinueSlowScript;
 1.10899 +  }
 1.10900 +
 1.10901 +  // Append file and line number information, if available
 1.10902 +  if (filename.get()) {
 1.10903 +    nsXPIDLString scriptLocation;
 1.10904 +    NS_ConvertUTF8toUTF16 filenameUTF16(filename.get());
 1.10905 +    const char16_t *formatParams[] = { filenameUTF16.get() };
 1.10906 +    rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
 1.10907 +                                               "KillScriptLocation",
 1.10908 +                                               formatParams,
 1.10909 +                                               scriptLocation);
 1.10910 +
 1.10911 +    if (NS_SUCCEEDED(rv) && scriptLocation) {
 1.10912 +      msg.AppendLiteral("\n\n");
 1.10913 +      msg.Append(scriptLocation);
 1.10914 +      msg.Append(':');
 1.10915 +      msg.AppendInt(lineno);
 1.10916 +    }
 1.10917 +  }
 1.10918 +
 1.10919 +  int32_t buttonPressed = 0; // In case the user exits dialog by clicking X.
 1.10920 +  bool neverShowDlgChk = false;
 1.10921 +  uint32_t buttonFlags = nsIPrompt::BUTTON_POS_1_DEFAULT +
 1.10922 +                         (nsIPrompt::BUTTON_TITLE_IS_STRING *
 1.10923 +                          (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
 1.10924 +
 1.10925 +  // Add a third button if necessary.
 1.10926 +  if (debugPossible)
 1.10927 +    buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
 1.10928 +
 1.10929 +  // Null out the operation callback while we're re-entering JS here.
 1.10930 +  JSRuntime* rt = JS_GetRuntime(cx);
 1.10931 +  JSInterruptCallback old = JS_SetInterruptCallback(rt, nullptr);
 1.10932 +
 1.10933 +  // Open the dialog.
 1.10934 +  rv = prompt->ConfirmEx(title, msg, buttonFlags, waitButton, stopButton,
 1.10935 +                         debugButton, neverShowDlg, &neverShowDlgChk,
 1.10936 +                         &buttonPressed);
 1.10937 +
 1.10938 +  JS_SetInterruptCallback(rt, old);
 1.10939 +
 1.10940 +  if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) {
 1.10941 +    return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript;
 1.10942 +  }
 1.10943 +  if ((buttonPressed == 2) && debugPossible) {
 1.10944 +    return js_CallContextDebugHandler(cx) ? ContinueSlowScript : KillSlowScript;
 1.10945 +  }
 1.10946 +  JS_ClearPendingException(cx);
 1.10947 +  return KillSlowScript;
 1.10948 +}
 1.10949 +
 1.10950 +uint32_t
 1.10951 +nsGlobalWindow::FindInsertionIndex(IdleObserverHolder* aIdleObserver)
 1.10952 +{
 1.10953 +  MOZ_ASSERT(IsInnerWindow());
 1.10954 +  MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
 1.10955 +
 1.10956 +  uint32_t i = 0;
 1.10957 +  nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
 1.10958 +  while (iter.HasMore()) {
 1.10959 +    IdleObserverHolder& idleObserver = iter.GetNext();
 1.10960 +    if (idleObserver.mTimeInS > aIdleObserver->mTimeInS) {
 1.10961 +      break;
 1.10962 +    }
 1.10963 +    i++;
 1.10964 +    MOZ_ASSERT(i <= mIdleObservers.Length(), "Array index out of bounds error.");
 1.10965 +  }
 1.10966 +
 1.10967 +  return i;
 1.10968 +}
 1.10969 +
 1.10970 +nsresult
 1.10971 +nsGlobalWindow::RegisterIdleObserver(nsIIdleObserver* aIdleObserver)
 1.10972 +{
 1.10973 +  MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 1.10974 +
 1.10975 +  nsresult rv;
 1.10976 +  if (mIdleObservers.IsEmpty()) {
 1.10977 +    mIdleService = do_GetService("@mozilla.org/widget/idleservice;1", &rv);
 1.10978 +    NS_ENSURE_SUCCESS(rv, rv);
 1.10979 +
 1.10980 +    rv = mIdleService->AddIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
 1.10981 +    NS_ENSURE_SUCCESS(rv, rv);
 1.10982 +
 1.10983 +    if (!mIdleTimer) {
 1.10984 +      mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
 1.10985 +      NS_ENSURE_SUCCESS(rv, rv);
 1.10986 +    } else {
 1.10987 +      mIdleTimer->Cancel();
 1.10988 +    }
 1.10989 +  }
 1.10990 +
 1.10991 +  MOZ_ASSERT(mIdleService);
 1.10992 +  MOZ_ASSERT(mIdleTimer);
 1.10993 +
 1.10994 +  IdleObserverHolder tmpIdleObserver;
 1.10995 +  tmpIdleObserver.mIdleObserver = aIdleObserver;
 1.10996 +  rv = aIdleObserver->GetTime(&tmpIdleObserver.mTimeInS);
 1.10997 +  NS_ENSURE_SUCCESS(rv, rv);
 1.10998 +  NS_ENSURE_ARG_MAX(tmpIdleObserver.mTimeInS, UINT32_MAX / 1000);
 1.10999 +  NS_ENSURE_ARG_MIN(tmpIdleObserver.mTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
 1.11000 +
 1.11001 +  uint32_t insertAtIndex = FindInsertionIndex(&tmpIdleObserver);
 1.11002 +  if (insertAtIndex == mIdleObservers.Length()) {
 1.11003 +    mIdleObservers.AppendElement(tmpIdleObserver);
 1.11004 +  }
 1.11005 +  else {
 1.11006 +    mIdleObservers.InsertElementAt(insertAtIndex, tmpIdleObserver);
 1.11007 +  }
 1.11008 +
 1.11009 +  bool userIsIdle = false;
 1.11010 +  rv = nsContentUtils::IsUserIdle(MIN_IDLE_NOTIFICATION_TIME_S, &userIsIdle);
 1.11011 +  NS_ENSURE_SUCCESS(rv, rv);
 1.11012 +
 1.11013 +  // Special case. First idle observer added to empty list while the user is idle.
 1.11014 +  // Haven't received 'idle' topic notification from slow idle service yet.
 1.11015 +  // Need to wait for the idle notification and then notify idle observers in the list.
 1.11016 +  if (userIsIdle && mIdleCallbackIndex == -1) {
 1.11017 +    return NS_OK;
 1.11018 +  }
 1.11019 +
 1.11020 +  if (!mCurrentlyIdle) {
 1.11021 +    return NS_OK;
 1.11022 +  }
 1.11023 +
 1.11024 +  MOZ_ASSERT(mIdleCallbackIndex >= 0);
 1.11025 +
 1.11026 +  if (static_cast<int32_t>(insertAtIndex) < mIdleCallbackIndex) {
 1.11027 +    IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(insertAtIndex);
 1.11028 +    NotifyIdleObserver(&idleObserver, true);
 1.11029 +    mIdleCallbackIndex++;
 1.11030 +    return NS_OK;
 1.11031 +  }
 1.11032 +
 1.11033 +  if (static_cast<int32_t>(insertAtIndex) == mIdleCallbackIndex) {
 1.11034 +    mIdleTimer->Cancel();
 1.11035 +    rv = ScheduleNextIdleObserverCallback();
 1.11036 +    NS_ENSURE_SUCCESS(rv, rv);
 1.11037 +  }
 1.11038 +  return NS_OK;
 1.11039 +}
 1.11040 +
 1.11041 +nsresult
 1.11042 +nsGlobalWindow::FindIndexOfElementToRemove(nsIIdleObserver* aIdleObserver,
 1.11043 +                                           int32_t* aRemoveElementIndex)
 1.11044 +{
 1.11045 +  MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 1.11046 +  MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
 1.11047 +
 1.11048 +  *aRemoveElementIndex = 0;
 1.11049 +  if (mIdleObservers.IsEmpty()) {
 1.11050 +    return NS_ERROR_FAILURE;
 1.11051 +  }
 1.11052 +
 1.11053 +  uint32_t aIdleObserverTimeInS;
 1.11054 +  nsresult rv = aIdleObserver->GetTime(&aIdleObserverTimeInS);
 1.11055 +  NS_ENSURE_SUCCESS(rv, rv);
 1.11056 +  NS_ENSURE_ARG_MIN(aIdleObserverTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
 1.11057 +
 1.11058 +  nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
 1.11059 +  while (iter.HasMore()) {
 1.11060 +    IdleObserverHolder& idleObserver = iter.GetNext();
 1.11061 +    if (idleObserver.mTimeInS == aIdleObserverTimeInS &&
 1.11062 +        idleObserver.mIdleObserver == aIdleObserver ) {
 1.11063 +      break;
 1.11064 +    }
 1.11065 +    (*aRemoveElementIndex)++;
 1.11066 +  }
 1.11067 +  return static_cast<uint32_t>(*aRemoveElementIndex) >= mIdleObservers.Length() ?
 1.11068 +    NS_ERROR_FAILURE : NS_OK;
 1.11069 +}
 1.11070 +
 1.11071 +nsresult
 1.11072 +nsGlobalWindow::UnregisterIdleObserver(nsIIdleObserver* aIdleObserver)
 1.11073 +{
 1.11074 +  MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 1.11075 +
 1.11076 +  int32_t removeElementIndex;
 1.11077 +  nsresult rv = FindIndexOfElementToRemove(aIdleObserver, &removeElementIndex);
 1.11078 +  if (NS_FAILED(rv)) {
 1.11079 +    NS_WARNING("Idle observer not found in list of idle observers. No idle observer removed.");
 1.11080 +    return NS_OK;
 1.11081 +  }
 1.11082 +  mIdleObservers.RemoveElementAt(removeElementIndex);
 1.11083 +
 1.11084 +  MOZ_ASSERT(mIdleTimer);
 1.11085 +  if (mIdleObservers.IsEmpty() && mIdleService) {
 1.11086 +    rv = mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
 1.11087 +    NS_ENSURE_SUCCESS(rv, rv);
 1.11088 +    mIdleService = nullptr;
 1.11089 +
 1.11090 +    mIdleTimer->Cancel();
 1.11091 +    mIdleCallbackIndex = -1;
 1.11092 +    return NS_OK;
 1.11093 +  }
 1.11094 +
 1.11095 +  if (!mCurrentlyIdle) {
 1.11096 +    return NS_OK;
 1.11097 +  }
 1.11098 +
 1.11099 +  if (removeElementIndex < mIdleCallbackIndex) {
 1.11100 +    mIdleCallbackIndex--;
 1.11101 +    return NS_OK;
 1.11102 +  }
 1.11103 +
 1.11104 +  if (removeElementIndex != mIdleCallbackIndex) {
 1.11105 +    return NS_OK;
 1.11106 +  }
 1.11107 +
 1.11108 +  mIdleTimer->Cancel();
 1.11109 +
 1.11110 +  // If the last element in the array had been notified then decrement
 1.11111 +  // mIdleCallbackIndex because an idle was removed from the list of
 1.11112 +  // idle observers.
 1.11113 +  // Example: add idle observer with time 1, 2, 3,
 1.11114 +  // Idle notifications for idle observers with time 1, 2, 3 are complete
 1.11115 +  // Remove idle observer with time 3 while the user is still idle.
 1.11116 +  // The user never transitioned to active state.
 1.11117 +  // Add an idle observer with idle time 4
 1.11118 +  if (static_cast<uint32_t>(mIdleCallbackIndex) == mIdleObservers.Length()) {
 1.11119 +    mIdleCallbackIndex--;
 1.11120 +  }
 1.11121 +  rv = ScheduleNextIdleObserverCallback();
 1.11122 +  NS_ENSURE_SUCCESS(rv, rv);
 1.11123 +
 1.11124 +  return NS_OK;
 1.11125 +}
 1.11126 +
 1.11127 +nsresult
 1.11128 +nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
 1.11129 +                        const char16_t* aData)
 1.11130 +{
 1.11131 +  if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
 1.11132 +    if (IsFrozen()) {
 1.11133 +      // if an even number of notifications arrive while we're frozen,
 1.11134 +      // we don't need to fire.
 1.11135 +      mFireOfflineStatusChangeEventOnThaw = !mFireOfflineStatusChangeEventOnThaw;
 1.11136 +    } else {
 1.11137 +      FireOfflineStatusEvent();
 1.11138 +    }
 1.11139 +    return NS_OK;
 1.11140 +  }
 1.11141 +
 1.11142 +  if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE)) {
 1.11143 +    mCurrentlyIdle = true;
 1.11144 +    if (IsFrozen()) {
 1.11145 +      // need to fire only one idle event while the window is frozen.
 1.11146 +      mNotifyIdleObserversIdleOnThaw = true;
 1.11147 +      mNotifyIdleObserversActiveOnThaw = false;
 1.11148 +    } else if (IsCurrentInnerWindow()) {
 1.11149 +      HandleIdleActiveEvent();
 1.11150 +    }
 1.11151 +    return NS_OK;
 1.11152 +  }
 1.11153 +
 1.11154 +  if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_ACTIVE)) {
 1.11155 +    mCurrentlyIdle = false;
 1.11156 +    if (IsFrozen()) {
 1.11157 +      mNotifyIdleObserversActiveOnThaw = true;
 1.11158 +      mNotifyIdleObserversIdleOnThaw = false;
 1.11159 +    } else if (IsCurrentInnerWindow()) {
 1.11160 +      MOZ_ASSERT(IsInnerWindow());
 1.11161 +      ScheduleActiveTimerCallback();
 1.11162 +    }
 1.11163 +    return NS_OK;
 1.11164 +  }
 1.11165 +
 1.11166 +  if (!nsCRT::strcmp(aTopic, "dom-storage2-changed")) {
 1.11167 +    if (!IsInnerWindow() || !IsCurrentInnerWindow()) {
 1.11168 +      return NS_OK;
 1.11169 +    }
 1.11170 +
 1.11171 +    nsIPrincipal *principal;
 1.11172 +    nsresult rv;
 1.11173 +
 1.11174 +    nsCOMPtr<nsIDOMStorageEvent> event = do_QueryInterface(aSubject, &rv);
 1.11175 +    NS_ENSURE_SUCCESS(rv, rv);
 1.11176 +
 1.11177 +    nsCOMPtr<nsIDOMStorage> changingStorage;
 1.11178 +    rv = event->GetStorageArea(getter_AddRefs(changingStorage));
 1.11179 +    NS_ENSURE_SUCCESS(rv, rv);
 1.11180 +
 1.11181 +    bool fireMozStorageChanged = false;
 1.11182 +    principal = GetPrincipal();
 1.11183 +    if (!principal) {
 1.11184 +      return NS_OK;
 1.11185 +    }
 1.11186 +
 1.11187 +    nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
 1.11188 +
 1.11189 +    nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell());
 1.11190 +    bool isPrivate = loadContext && loadContext->UsePrivateBrowsing();
 1.11191 +    if (pistorage->IsPrivate() != isPrivate) {
 1.11192 +      return NS_OK;
 1.11193 +    }
 1.11194 +
 1.11195 +    switch (pistorage->GetType())
 1.11196 +    {
 1.11197 +    case nsPIDOMStorage::SessionStorage:
 1.11198 +    {
 1.11199 +      bool check = false;
 1.11200 +
 1.11201 +      nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(GetDocShell());
 1.11202 +      if (storageManager) {
 1.11203 +        nsresult rv;
 1.11204 +        nsCOMPtr<nsIURI> firstPartyIsolationURI;
 1.11205 +        rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
 1.11206 +        NS_ENSURE_SUCCESS(rv, rv);
 1.11207 +
 1.11208 +        rv = storageManager->CheckStorageForFirstParty(firstPartyIsolationURI,
 1.11209 +                                          principal, changingStorage, &check);
 1.11210 +        if (NS_FAILED(rv)) {
 1.11211 +          return rv;
 1.11212 +        }
 1.11213 +      }
 1.11214 +
 1.11215 +      if (!check) {
 1.11216 +        // This storage event is not coming from our storage or is coming
 1.11217 +        // from a different docshell, i.e. it is a clone, ignore this event.
 1.11218 +        return NS_OK;
 1.11219 +      }
 1.11220 +
 1.11221 +#ifdef PR_LOGGING
 1.11222 +      if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
 1.11223 +        PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
 1.11224 +      }
 1.11225 +#endif
 1.11226 +
 1.11227 +      fireMozStorageChanged = SameCOMIdentity(mSessionStorage, changingStorage);
 1.11228 +      break;
 1.11229 +    }
 1.11230 +
 1.11231 +    case nsPIDOMStorage::LocalStorage:
 1.11232 +    {
 1.11233 +      // Allow event fire only for the same principal storages
 1.11234 +      // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
 1.11235 +      nsIPrincipal* storagePrincipal = pistorage->GetPrincipal();
 1.11236 +
 1.11237 +      bool equals = false;
 1.11238 +      rv = storagePrincipal->Equals(principal, &equals);
 1.11239 +      NS_ENSURE_SUCCESS(rv, rv);
 1.11240 +
 1.11241 +      if (!equals)
 1.11242 +        return NS_OK;
 1.11243 +
 1.11244 +      fireMozStorageChanged = SameCOMIdentity(mLocalStorage, changingStorage);
 1.11245 +      break;
 1.11246 +    }
 1.11247 +    default:
 1.11248 +      return NS_OK;
 1.11249 +    }
 1.11250 +
 1.11251 +    // Clone the storage event included in the observer notification. We want
 1.11252 +    // to dispatch clones rather than the original event.
 1.11253 +    rv = CloneStorageEvent(fireMozStorageChanged ?
 1.11254 +                           NS_LITERAL_STRING("MozStorageChanged") :
 1.11255 +                           NS_LITERAL_STRING("storage"),
 1.11256 +                           event);
 1.11257 +    NS_ENSURE_SUCCESS(rv, rv);
 1.11258 +
 1.11259 +    event->SetTrusted(true);
 1.11260 +
 1.11261 +    if (fireMozStorageChanged) {
 1.11262 +      WidgetEvent* internalEvent = event->GetInternalNSEvent();
 1.11263 +      internalEvent->mFlags.mOnlyChromeDispatch = true;
 1.11264 +    }
 1.11265 +
 1.11266 +    if (IsFrozen()) {
 1.11267 +      // This window is frozen, rather than firing the events here,
 1.11268 +      // store the domain in which the change happened and fire the
 1.11269 +      // events if we're ever thawed.
 1.11270 +
 1.11271 +      mPendingStorageEvents.AppendObject(event);
 1.11272 +      return NS_OK;
 1.11273 +    }
 1.11274 +
 1.11275 +    bool defaultActionEnabled;
 1.11276 +    DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
 1.11277 +
 1.11278 +    return NS_OK;
 1.11279 +  }
 1.11280 +
 1.11281 +  if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) {
 1.11282 +    if (mApplicationCache)
 1.11283 +      return NS_OK;
 1.11284 +
 1.11285 +    // Instantiate the application object now. It observes update belonging to
 1.11286 +    // this window's document and correctly updates the applicationCache object
 1.11287 +    // state.
 1.11288 +    nsCOMPtr<nsIDOMOfflineResourceList> applicationCache;
 1.11289 +    GetApplicationCache(getter_AddRefs(applicationCache));
 1.11290 +    nsCOMPtr<nsIObserver> observer = do_QueryInterface(applicationCache);
 1.11291 +    if (observer)
 1.11292 +      observer->Observe(aSubject, aTopic, aData);
 1.11293 +
 1.11294 +    return NS_OK;
 1.11295 +  }
 1.11296 +
 1.11297 +#ifdef MOZ_B2G
 1.11298 +  if (!nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC) ||
 1.11299 +      !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC)) {
 1.11300 +    MOZ_ASSERT(IsInnerWindow());
 1.11301 +    if (!IsCurrentInnerWindow()) {
 1.11302 +      return NS_OK;
 1.11303 +    }
 1.11304 +
 1.11305 +    nsCOMPtr<nsIDOMEvent> event;
 1.11306 +    NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
 1.11307 +    nsresult rv = event->InitEvent(
 1.11308 +      !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC)
 1.11309 +        ? NETWORK_UPLOAD_EVENT_NAME
 1.11310 +        : NETWORK_DOWNLOAD_EVENT_NAME,
 1.11311 +      false, false);
 1.11312 +    NS_ENSURE_SUCCESS(rv, rv);
 1.11313 +
 1.11314 +    event->SetTrusted(true);
 1.11315 +
 1.11316 +    bool dummy;
 1.11317 +    return DispatchEvent(event, &dummy);
 1.11318 +  }
 1.11319 +#endif // MOZ_B2G
 1.11320 +
 1.11321 +  NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
 1.11322 +  return NS_ERROR_FAILURE;
 1.11323 +}
 1.11324 +
 1.11325 +nsresult
 1.11326 +nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
 1.11327 +                                  nsCOMPtr<nsIDOMStorageEvent>& aEvent)
 1.11328 +{
 1.11329 +  nsresult rv;
 1.11330 +
 1.11331 +  bool canBubble;
 1.11332 +  bool cancelable;
 1.11333 +  nsAutoString key;
 1.11334 +  nsAutoString oldValue;
 1.11335 +  nsAutoString newValue;
 1.11336 +  nsAutoString url;
 1.11337 +  nsCOMPtr<nsIDOMStorage> storageArea;
 1.11338 +
 1.11339 +  nsCOMPtr<nsIDOMEvent> domEvent = do_QueryInterface(aEvent, &rv);
 1.11340 +  NS_ENSURE_SUCCESS(rv, rv);
 1.11341 +
 1.11342 +  domEvent->GetBubbles(&canBubble);
 1.11343 +  domEvent->GetCancelable(&cancelable);
 1.11344 +
 1.11345 +  aEvent->GetKey(key);
 1.11346 +  aEvent->GetOldValue(oldValue);
 1.11347 +  aEvent->GetNewValue(newValue);
 1.11348 +  aEvent->GetUrl(url);
 1.11349 +  aEvent->GetStorageArea(getter_AddRefs(storageArea));
 1.11350 +
 1.11351 +  NS_NewDOMStorageEvent(getter_AddRefs(domEvent), this, nullptr, nullptr);
 1.11352 +  aEvent = do_QueryInterface(domEvent);
 1.11353 +  return aEvent->InitStorageEvent(aType, canBubble, cancelable,
 1.11354 +                                  key, oldValue, newValue,
 1.11355 +                                  url, storageArea);
 1.11356 +}
 1.11357 +
 1.11358 +nsresult
 1.11359 +nsGlobalWindow::FireDelayedDOMEvents()
 1.11360 +{
 1.11361 +  FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
 1.11362 +
 1.11363 +  for (int32_t i = 0; i < mPendingStorageEvents.Count(); ++i) {
 1.11364 +    Observe(mPendingStorageEvents[i], "dom-storage2-changed", nullptr);
 1.11365 +  }
 1.11366 +
 1.11367 +  if (mApplicationCache) {
 1.11368 +    static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
 1.11369 +  }
 1.11370 +
 1.11371 +  if (mFireOfflineStatusChangeEventOnThaw) {
 1.11372 +    mFireOfflineStatusChangeEventOnThaw = false;
 1.11373 +    FireOfflineStatusEvent();
 1.11374 +  }
 1.11375 +
 1.11376 +  if (mNotifyIdleObserversIdleOnThaw) {
 1.11377 +    mNotifyIdleObserversIdleOnThaw = false;
 1.11378 +    HandleIdleActiveEvent();
 1.11379 +  }
 1.11380 +
 1.11381 +  if (mNotifyIdleObserversActiveOnThaw) {
 1.11382 +    mNotifyIdleObserversActiveOnThaw = false;
 1.11383 +    ScheduleActiveTimerCallback();
 1.11384 +  }
 1.11385 +
 1.11386 +  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
 1.11387 +  if (docShell) {
 1.11388 +    int32_t childCount = 0;
 1.11389 +    docShell->GetChildCount(&childCount);
 1.11390 +
 1.11391 +    for (int32_t i = 0; i < childCount; ++i) {
 1.11392 +      nsCOMPtr<nsIDocShellTreeItem> childShell;
 1.11393 +      docShell->GetChildAt(i, getter_AddRefs(childShell));
 1.11394 +      NS_ASSERTION(childShell, "null child shell");
 1.11395 +
 1.11396 +      nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
 1.11397 +      if (pWin) {
 1.11398 +        nsGlobalWindow *win =
 1.11399 +          static_cast<nsGlobalWindow*>
 1.11400 +                     (static_cast<nsPIDOMWindow*>(pWin));
 1.11401 +        win->FireDelayedDOMEvents();
 1.11402 +      }
 1.11403 +    }
 1.11404 +  }
 1.11405 +
 1.11406 +  return NS_OK;
 1.11407 +}
 1.11408 +
 1.11409 +//*****************************************************************************
 1.11410 +// nsGlobalWindow: Window Control Functions
 1.11411 +//*****************************************************************************
 1.11412 +
 1.11413 +nsIDOMWindow *
 1.11414 +nsGlobalWindow::GetParentInternal()
 1.11415 +{
 1.11416 +  if (IsInnerWindow()) {
 1.11417 +    nsGlobalWindow* outer = GetOuterWindowInternal();
 1.11418 +    if (!outer) {
 1.11419 +      NS_WARNING("No outer window available!");
 1.11420 +      return nullptr;
 1.11421 +    }
 1.11422 +    return outer->GetParentInternal();
 1.11423 +  }
 1.11424 +
 1.11425 +  nsCOMPtr<nsIDOMWindow> parent;
 1.11426 +  GetParent(getter_AddRefs(parent));
 1.11427 +
 1.11428 +  if (parent && parent != static_cast<nsIDOMWindow *>(this)) {
 1.11429 +    return parent;
 1.11430 +  }
 1.11431 +
 1.11432 +  return nullptr;
 1.11433 +}
 1.11434 +
 1.11435 +void
 1.11436 +nsGlobalWindow::UnblockScriptedClosing()
 1.11437 +{
 1.11438 +  MOZ_ASSERT(IsOuterWindow());
 1.11439 +  mBlockScriptedClosingFlag = false;
 1.11440 +}
 1.11441 +
 1.11442 +class AutoUnblockScriptClosing
 1.11443 +{
 1.11444 +private:
 1.11445 +  nsRefPtr<nsGlobalWindow> mWin;
 1.11446 +public:
 1.11447 +  AutoUnblockScriptClosing(nsGlobalWindow* aWin)
 1.11448 +    : mWin(aWin)
 1.11449 +  {
 1.11450 +    MOZ_ASSERT(mWin);
 1.11451 +    MOZ_ASSERT(mWin->IsOuterWindow());
 1.11452 +  }
 1.11453 +  ~AutoUnblockScriptClosing()
 1.11454 +  {
 1.11455 +    void (nsGlobalWindow::*run)() = &nsGlobalWindow::UnblockScriptedClosing;
 1.11456 +    NS_DispatchToCurrentThread(NS_NewRunnableMethod(mWin, run));
 1.11457 +  }
 1.11458 +};
 1.11459 +
 1.11460 +nsresult
 1.11461 +nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
 1.11462 +                             const nsAString& aOptions, bool aDialog,
 1.11463 +                             bool aContentModal, bool aCalledNoScript,
 1.11464 +                             bool aDoJSFixups, bool aNavigate,
 1.11465 +                             nsIArray *argv,
 1.11466 +                             nsISupports *aExtraArgument,
 1.11467 +                             nsIPrincipal *aCalleePrincipal,
 1.11468 +                             JSContext *aJSCallerContext,
 1.11469 +                             nsIDOMWindow **aReturn)
 1.11470 +{
 1.11471 +  FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
 1.11472 +                                  aContentModal, aCalledNoScript, aDoJSFixups,
 1.11473 +                                  aNavigate, argv, aExtraArgument,
 1.11474 +                                  aCalleePrincipal, aJSCallerContext, aReturn),
 1.11475 +                   NS_ERROR_NOT_INITIALIZED);
 1.11476 +
 1.11477 +#ifdef DEBUG
 1.11478 +  uint32_t argc = 0;
 1.11479 +  if (argv)
 1.11480 +      argv->GetLength(&argc);
 1.11481 +#endif
 1.11482 +  NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
 1.11483 +                  "Can't pass in arguments both ways");
 1.11484 +  NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
 1.11485 +                  "Can't pass JS args when called via the noscript methods");
 1.11486 +  NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
 1.11487 +                  "Shouldn't have caller context when called noscript");
 1.11488 +
 1.11489 +  mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
 1.11490 +
 1.11491 +  // Calls to window.open from script should navigate.
 1.11492 +  MOZ_ASSERT(aCalledNoScript || aNavigate);
 1.11493 +
 1.11494 +  *aReturn = nullptr;
 1.11495 +
 1.11496 +  nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
 1.11497 +  if (!chrome) {
 1.11498 +    // No chrome means we don't want to go through with this open call
 1.11499 +    // -- see nsIWindowWatcher.idl
 1.11500 +    return NS_ERROR_NOT_AVAILABLE;
 1.11501 +  }
 1.11502 +
 1.11503 +  NS_ASSERTION(mDocShell, "Must have docshell here");
 1.11504 +
 1.11505 +  // Popups from apps are never blocked.
 1.11506 +  bool isApp = false;
 1.11507 +  if (mDoc) {
 1.11508 +    isApp = mDoc->NodePrincipal()->GetAppStatus() >=
 1.11509 +              nsIPrincipal::APP_STATUS_INSTALLED;
 1.11510 +  }
 1.11511 +
 1.11512 +  const bool checkForPopup = !nsContentUtils::IsCallerChrome() &&
 1.11513 +    !isApp && !aDialog && !WindowExists(aName, !aCalledNoScript);
 1.11514 +
 1.11515 +  // Note: it's very important that this be an nsXPIDLCString, since we want
 1.11516 +  // .get() on it to return nullptr until we write stuff to it.  The window
 1.11517 +  // watcher expects a null URL string if there is no URL to load.
 1.11518 +  nsXPIDLCString url;
 1.11519 +  nsresult rv = NS_OK;
 1.11520 +
 1.11521 +  // It's important to do this security check before determining whether this
 1.11522 +  // window opening should be blocked, to ensure that we don't FireAbuseEvents
 1.11523 +  // for a window opening that wouldn't have succeeded in the first place.
 1.11524 +  if (!aUrl.IsEmpty()) {
 1.11525 +    AppendUTF16toUTF8(aUrl, url);
 1.11526 +
 1.11527 +    // It's safe to skip the security check below if we're not a dialog
 1.11528 +    // because window.openDialog is not callable from content script.  See bug
 1.11529 +    // 56851.
 1.11530 +    //
 1.11531 +    // If we're not navigating, we assume that whoever *does* navigate the
 1.11532 +    // window will do a security check of their own.
 1.11533 +    if (url.get() && !aDialog && aNavigate)
 1.11534 +      rv = SecurityCheckURL(url.get());
 1.11535 +  }
 1.11536 +
 1.11537 +  if (NS_FAILED(rv))
 1.11538 +    return rv;
 1.11539 +
 1.11540 +  PopupControlState abuseLevel = gPopupControlState;
 1.11541 +  if (checkForPopup) {
 1.11542 +    abuseLevel = RevisePopupAbuseLevel(abuseLevel);
 1.11543 +    if (abuseLevel >= openAbused) {
 1.11544 +      if (aJSCallerContext) {
 1.11545 +        // If script in some other window is doing a window.open on us and
 1.11546 +        // it's being blocked, then it's OK to close us afterwards, probably.
 1.11547 +        // But if we're doing a window.open on ourselves and block the popup,
 1.11548 +        // prevent this window from closing until after this script terminates
 1.11549 +        // so that whatever popup blocker UI the app has will be visible.
 1.11550 +        if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
 1.11551 +          mBlockScriptedClosingFlag = true;
 1.11552 +          closeUnblocker.construct(this);
 1.11553 +        }
 1.11554 +      }
 1.11555 +
 1.11556 +      FireAbuseEvents(true, false, aUrl, aName, aOptions);
 1.11557 +      return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
 1.11558 +    }
 1.11559 +  }
 1.11560 +
 1.11561 +  nsCOMPtr<nsIDOMWindow> domReturn;
 1.11562 +
 1.11563 +  nsCOMPtr<nsIWindowWatcher> wwatch =
 1.11564 +    do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
 1.11565 +  NS_ENSURE_TRUE(wwatch, rv);
 1.11566 +
 1.11567 +  NS_ConvertUTF16toUTF8 options(aOptions);
 1.11568 +  NS_ConvertUTF16toUTF8 name(aName);
 1.11569 +
 1.11570 +  const char *options_ptr = aOptions.IsEmpty() ? nullptr : options.get();
 1.11571 +  const char *name_ptr = aName.IsEmpty() ? nullptr : name.get();
 1.11572 +
 1.11573 +  nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
 1.11574 +  NS_ENSURE_STATE(pwwatch);
 1.11575 +
 1.11576 +  {
 1.11577 +    // Reset popup state while opening a window to prevent the
 1.11578 +    // current state from being active the whole time a modal
 1.11579 +    // dialog is open.
 1.11580 +    nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 1.11581 +
 1.11582 +    if (!aCalledNoScript) {
 1.11583 +      // We asserted at the top of this function that aNavigate is true for
 1.11584 +      // !aCalledNoScript.
 1.11585 +      rv = pwwatch->OpenWindow2(this, url.get(), name_ptr, options_ptr,
 1.11586 +                                /* aCalledFromScript = */ true,
 1.11587 +                                aDialog, aNavigate, argv,
 1.11588 +                                getter_AddRefs(domReturn));
 1.11589 +    } else {
 1.11590 +      // Force a system caller here so that the window watcher won't screw us
 1.11591 +      // up.  We do NOT want this case looking at the JS context on the stack
 1.11592 +      // when searching.  Compare comments on
 1.11593 +      // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
 1.11594 +
 1.11595 +      // Note: Because nsWindowWatcher is so broken, it's actually important
 1.11596 +      // that we don't force a system caller here, because that screws it up
 1.11597 +      // when it tries to compute the caller principal to associate with dialog
 1.11598 +      // arguments. That whole setup just really needs to be rewritten. :-(
 1.11599 +      Maybe<AutoNoJSAPI> nojsapi;
 1.11600 +      if (!aContentModal) {
 1.11601 +        nojsapi.construct();
 1.11602 +      }
 1.11603 +
 1.11604 +
 1.11605 +      rv = pwwatch->OpenWindow2(this, url.get(), name_ptr, options_ptr,
 1.11606 +                                /* aCalledFromScript = */ false,
 1.11607 +                                aDialog, aNavigate, aExtraArgument,
 1.11608 +                                getter_AddRefs(domReturn));
 1.11609 +
 1.11610 +    }
 1.11611 +  }
 1.11612 +
 1.11613 +  NS_ENSURE_SUCCESS(rv, rv);
 1.11614 +
 1.11615 +  // success!
 1.11616 +
 1.11617 +  NS_ENSURE_TRUE(domReturn, NS_OK);
 1.11618 +  domReturn.swap(*aReturn);
 1.11619 +
 1.11620 +  if (aDoJSFixups) {
 1.11621 +    nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
 1.11622 +    if (!chrome_win) {
 1.11623 +      // A new non-chrome window was created from a call to
 1.11624 +      // window.open() from JavaScript, make sure there's a document in
 1.11625 +      // the new window. We do this by simply asking the new window for
 1.11626 +      // its document, this will synchronously create an empty document
 1.11627 +      // if there is no document in the window.
 1.11628 +      // XXXbz should this just use EnsureInnerWindow()?
 1.11629 +#ifdef DEBUG_jst
 1.11630 +      {
 1.11631 +        nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
 1.11632 +        NS_ASSERTION(pidomwin->GetExtantDoc(), "No document in new window!!!");
 1.11633 +      }
 1.11634 +#endif
 1.11635 +
 1.11636 +      nsCOMPtr<nsIDOMDocument> doc;
 1.11637 +      (*aReturn)->GetDocument(getter_AddRefs(doc));
 1.11638 +    }
 1.11639 +  }
 1.11640 +
 1.11641 +  if (checkForPopup) {
 1.11642 +    if (abuseLevel >= openControlled) {
 1.11643 +      nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
 1.11644 +      if (!opened->IsPopupSpamWindow()) {
 1.11645 +        opened->SetPopupSpamWindow(true);
 1.11646 +        ++gOpenPopupSpamCount;
 1.11647 +      }
 1.11648 +    }
 1.11649 +    if (abuseLevel >= openAbused)
 1.11650 +      FireAbuseEvents(false, true, aUrl, aName, aOptions);
 1.11651 +  }
 1.11652 +
 1.11653 +  return rv;
 1.11654 +}
 1.11655 +
 1.11656 +//*****************************************************************************
 1.11657 +// nsGlobalWindow: Timeout Functions
 1.11658 +//*****************************************************************************
 1.11659 +
 1.11660 +uint32_t sNestingLevel;
 1.11661 +
 1.11662 +nsGlobalWindow*
 1.11663 +nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult& aError)
 1.11664 +{
 1.11665 +  nsGlobalWindow* currentInner;
 1.11666 +  nsGlobalWindow* forwardTo;
 1.11667 +  if (IsInnerWindow()) {
 1.11668 +    nsGlobalWindow* outer = GetOuterWindowInternal();
 1.11669 +    currentInner = outer ? outer->GetCurrentInnerWindowInternal() : this;
 1.11670 +
 1.11671 +    forwardTo = this;
 1.11672 +  } else {
 1.11673 +    currentInner = GetCurrentInnerWindowInternal();
 1.11674 +
 1.11675 +    // This needs to forward to the inner window, but since the current
 1.11676 +    // inner may not be the inner in the calling scope, we need to treat
 1.11677 +    // this specially here as we don't want timeouts registered in a
 1.11678 +    // dying inner window to get registered and run on the current inner
 1.11679 +    // window. To get this right, we need to forward this call to the
 1.11680 +    // inner window that's calling window.setTimeout().
 1.11681 +
 1.11682 +    forwardTo = CallerInnerWindow();
 1.11683 +    if (!forwardTo) {
 1.11684 +      aError.Throw(NS_ERROR_NOT_AVAILABLE);
 1.11685 +      return nullptr;
 1.11686 +    }
 1.11687 +
 1.11688 +    // If the caller and the callee share the same outer window, forward to the
 1.11689 +    // caller inner. Else, we forward to the current inner (e.g. someone is
 1.11690 +    // calling setTimeout() on a reference to some other window).
 1.11691 +    if (forwardTo->GetOuterWindow() != this || !forwardTo->IsInnerWindow()) {
 1.11692 +      if (!currentInner) {
 1.11693 +        NS_WARNING("No inner window available!");
 1.11694 +        aError.Throw(NS_ERROR_NOT_INITIALIZED);
 1.11695 +        return nullptr;
 1.11696 +      }
 1.11697 +
 1.11698 +      return currentInner;
 1.11699 +    }
 1.11700 +  }
 1.11701 +
 1.11702 +  // If forwardTo is not the window with an active document then we want the
 1.11703 +  // call to setTimeout/Interval to be a noop, so return null but don't set an
 1.11704 +  // error.
 1.11705 +  return forwardTo->HasActiveDocument() ? currentInner : nullptr;
 1.11706 +}
 1.11707 +
 1.11708 +int32_t
 1.11709 +nsGlobalWindow::SetTimeout(JSContext* aCx, Function& aFunction,
 1.11710 +                           int32_t aTimeout,
 1.11711 +                           const Sequence<JS::Value>& aArguments,
 1.11712 +                           ErrorResult& aError)
 1.11713 +{
 1.11714 +  return SetTimeoutOrInterval(aFunction, aTimeout, aArguments, false, aError);
 1.11715 +}
 1.11716 +
 1.11717 +int32_t
 1.11718 +nsGlobalWindow::SetTimeout(JSContext* aCx, const nsAString& aHandler,
 1.11719 +                           int32_t aTimeout,
 1.11720 +                           const Sequence<JS::Value>& /* unused */,
 1.11721 +                           ErrorResult& aError)
 1.11722 +{
 1.11723 +  return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError);
 1.11724 +}
 1.11725 +
 1.11726 +static bool
 1.11727 +IsInterval(const Optional<int32_t>& aTimeout, int32_t& aResultTimeout)
 1.11728 +{
 1.11729 +  if (aTimeout.WasPassed()) {
 1.11730 +    aResultTimeout = aTimeout.Value();
 1.11731 +    return true;
 1.11732 +  }
 1.11733 +
 1.11734 +  // If no interval was specified, treat this like a timeout, to avoid setting
 1.11735 +  // an interval of 0 milliseconds.
 1.11736 +  aResultTimeout = 0;
 1.11737 +  return false;
 1.11738 +}
 1.11739 +
 1.11740 +int32_t
 1.11741 +nsGlobalWindow::SetInterval(JSContext* aCx, Function& aFunction,
 1.11742 +                            const Optional<int32_t>& aTimeout,
 1.11743 +                            const Sequence<JS::Value>& aArguments,
 1.11744 +                            ErrorResult& aError)
 1.11745 +{
 1.11746 +  int32_t timeout;
 1.11747 +  bool isInterval = IsInterval(aTimeout, timeout);
 1.11748 +  return SetTimeoutOrInterval(aFunction, timeout, aArguments, isInterval,
 1.11749 +                              aError);
 1.11750 +}
 1.11751 +
 1.11752 +int32_t
 1.11753 +nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler,
 1.11754 +                            const Optional<int32_t>& aTimeout,
 1.11755 +                            const Sequence<JS::Value>& /* unused */,
 1.11756 +                            ErrorResult& aError)
 1.11757 +{
 1.11758 +  int32_t timeout;
 1.11759 +  bool isInterval = IsInterval(aTimeout, timeout);
 1.11760 +  return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError);
 1.11761 +}
 1.11762 +
 1.11763 +nsresult
 1.11764 +nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
 1.11765 +                                     int32_t interval,
 1.11766 +                                     bool aIsInterval, int32_t *aReturn)
 1.11767 +{
 1.11768 +  MOZ_ASSERT(IsInnerWindow());
 1.11769 +
 1.11770 +  // If we don't have a document (we could have been unloaded since
 1.11771 +  // the call to setTimeout was made), do nothing.
 1.11772 +  if (!mDoc) {
 1.11773 +    return NS_OK;
 1.11774 +  }
 1.11775 +
 1.11776 +  // Disallow negative intervals.  If aIsInterval also disallow 0,
 1.11777 +  // because we use that as a "don't repeat" flag.
 1.11778 +  interval = std::max(aIsInterval ? 1 : 0, interval);
 1.11779 +
 1.11780 +  // Make sure we don't proceed with an interval larger than our timer
 1.11781 +  // code can handle. (Note: we already forced |interval| to be non-negative,
 1.11782 +  // so the uint32_t cast (to avoid compiler warnings) is ok.)
 1.11783 +  uint32_t maxTimeoutMs = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
 1.11784 +  if (static_cast<uint32_t>(interval) > maxTimeoutMs) {
 1.11785 +    interval = maxTimeoutMs;
 1.11786 +  }
 1.11787 +
 1.11788 +  nsRefPtr<nsTimeout> timeout = new nsTimeout();
 1.11789 +  timeout->mIsInterval = aIsInterval;
 1.11790 +  timeout->mInterval = interval;
 1.11791 +  timeout->mScriptHandler = aHandler;
 1.11792 +
 1.11793 +  // Now clamp the actual interval we will use for the timer based on
 1.11794 +  uint32_t nestingLevel = sNestingLevel + 1;
 1.11795 +  uint32_t realInterval = interval;
 1.11796 +  if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
 1.11797 +    // Don't allow timeouts less than DOMMinTimeoutValue() from
 1.11798 +    // now...
 1.11799 +    realInterval = std::max(realInterval, uint32_t(DOMMinTimeoutValue()));
 1.11800 +  }
 1.11801 +
 1.11802 +  // Get principal of currently executing code, save for execution of timeout.
 1.11803 +  // If our principals subsume the subject principal then use the subject
 1.11804 +  // principal. Otherwise, use our principal to avoid running script in
 1.11805 +  // elevated principals.
 1.11806 +
 1.11807 +  nsCOMPtr<nsIPrincipal> subjectPrincipal;
 1.11808 +  nsresult rv;
 1.11809 +  rv = nsContentUtils::GetSecurityManager()->
 1.11810 +    GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
 1.11811 +  if (NS_FAILED(rv)) {
 1.11812 +    return NS_ERROR_FAILURE;
 1.11813 +  }
 1.11814 +
 1.11815 +  bool subsumes = false;
 1.11816 +  nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
 1.11817 +
 1.11818 +  // Note the direction of this test: We don't allow setTimeouts running with
 1.11819 +  // chrome privileges on content windows, but we do allow setTimeouts running
 1.11820 +  // with content privileges on chrome windows (where they can't do very much,
 1.11821 +  // of course).
 1.11822 +  rv = ourPrincipal->Subsumes(subjectPrincipal, &subsumes);
 1.11823 +  if (NS_FAILED(rv)) {
 1.11824 +    return NS_ERROR_FAILURE;
 1.11825 +  }
 1.11826 +
 1.11827 +  if (subsumes) {
 1.11828 +    timeout->mPrincipal = subjectPrincipal;
 1.11829 +  } else {
 1.11830 +    timeout->mPrincipal = ourPrincipal;
 1.11831 +  }
 1.11832 +
 1.11833 +  ++gTimeoutsRecentlySet;
 1.11834 +  TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
 1.11835 +
 1.11836 +  if (!IsFrozen() && !mTimeoutsSuspendDepth) {
 1.11837 +    // If we're not currently frozen, then we set timeout->mWhen to be the
 1.11838 +    // actual firing time of the timer (i.e., now + delta). We also actually
 1.11839 +    // create a timer and fire it off.
 1.11840 +
 1.11841 +    timeout->mWhen = TimeStamp::Now() + delta;
 1.11842 +
 1.11843 +    timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
 1.11844 +    if (NS_FAILED(rv)) {
 1.11845 +      return rv;
 1.11846 +    }
 1.11847 +
 1.11848 +    nsRefPtr<nsTimeout> copy = timeout;
 1.11849 +
 1.11850 +    rv = timeout->InitTimer(TimerCallback, realInterval);
 1.11851 +    if (NS_FAILED(rv)) {
 1.11852 +      return rv;
 1.11853 +    }
 1.11854 +
 1.11855 +    // The timeout is now also held in the timer's closure.
 1.11856 +    unused << copy.forget();
 1.11857 +  } else {
 1.11858 +    // If we are frozen, however, then we instead simply set
 1.11859 +    // timeout->mTimeRemaining to be the "time remaining" in the timeout (i.e.,
 1.11860 +    // the interval itself). We don't create a timer for it, since that will
 1.11861 +    // happen when we are thawed and the timeout will then get a timer and run
 1.11862 +    // to completion.
 1.11863 +
 1.11864 +    timeout->mTimeRemaining = delta;
 1.11865 +  }
 1.11866 +
 1.11867 +  timeout->mWindow = this;
 1.11868 +
 1.11869 +  if (!aIsInterval) {
 1.11870 +    timeout->mNestingLevel = nestingLevel;
 1.11871 +  }
 1.11872 +
 1.11873 +  // No popups from timeouts by default
 1.11874 +  timeout->mPopupState = openAbused;
 1.11875 +
 1.11876 +  if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
 1.11877 +    // This timeout is *not* set from another timeout and it's set
 1.11878 +    // while popups are enabled. Propagate the state to the timeout if
 1.11879 +    // its delay (interval) is equal to or less than what
 1.11880 +    // "dom.disable_open_click_delay" is set to (in ms).
 1.11881 +
 1.11882 +    int32_t delay =
 1.11883 +      Preferences::GetInt("dom.disable_open_click_delay");
 1.11884 +
 1.11885 +    // This is checking |interval|, not realInterval, on purpose,
 1.11886 +    // because our lower bound for |realInterval| could be pretty high
 1.11887 +    // in some cases.
 1.11888 +    if (interval <= delay) {
 1.11889 +      timeout->mPopupState = gPopupControlState;
 1.11890 +    }
 1.11891 +  }
 1.11892 +
 1.11893 +  InsertTimeoutIntoList(timeout);
 1.11894 +
 1.11895 +  timeout->mPublicId = ++mTimeoutPublicIdCounter;
 1.11896 +  *aReturn = timeout->mPublicId;
 1.11897 +
 1.11898 +  return NS_OK;
 1.11899 +
 1.11900 +}
 1.11901 +
 1.11902 +nsresult
 1.11903 +nsGlobalWindow::SetTimeoutOrInterval(bool aIsInterval, int32_t *aReturn)
 1.11904 +{
 1.11905 +  // This needs to forward to the inner window, but since the current
 1.11906 +  // inner may not be the inner in the calling scope, we need to treat
 1.11907 +  // this specially here as we don't want timeouts registered in a
 1.11908 +  // dying inner window to get registered and run on the current inner
 1.11909 +  // window. To get this right, we need to forward this call to the
 1.11910 +  // inner window that's calling window.setTimeout().
 1.11911 +
 1.11912 +  if (IsOuterWindow()) {
 1.11913 +    nsGlobalWindow* callerInner = CallerInnerWindow();
 1.11914 +    NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
 1.11915 +
 1.11916 +    // If the caller and the callee share the same outer window,
 1.11917 +    // forward to the callee inner. Else, we forward to the current
 1.11918 +    // inner (e.g. someone is calling setTimeout() on a reference to
 1.11919 +    // some other window).
 1.11920 +
 1.11921 +    if (callerInner->GetOuterWindow() == this &&
 1.11922 +        callerInner->IsInnerWindow()) {
 1.11923 +      return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
 1.11924 +    }
 1.11925 +
 1.11926 +    FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
 1.11927 +                     NS_ERROR_NOT_INITIALIZED);
 1.11928 +  }
 1.11929 +
 1.11930 +  int32_t interval = 0;
 1.11931 +  bool isInterval = aIsInterval;
 1.11932 +  nsCOMPtr<nsIScriptTimeoutHandler> handler;
 1.11933 +  nsresult rv = NS_CreateJSTimeoutHandler(this,
 1.11934 +                                          &isInterval,
 1.11935 +                                          &interval,
 1.11936 +                                          getter_AddRefs(handler));
 1.11937 +  if (!handler) {
 1.11938 +    *aReturn = 0;
 1.11939 +    return rv;
 1.11940 +  }
 1.11941 +
 1.11942 +  return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
 1.11943 +}
 1.11944 +
 1.11945 +int32_t
 1.11946 +nsGlobalWindow::SetTimeoutOrInterval(Function& aFunction, int32_t aTimeout,
 1.11947 +                                     const Sequence<JS::Value>& aArguments,
 1.11948 +                                     bool aIsInterval, ErrorResult& aError)
 1.11949 +{
 1.11950 +  nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
 1.11951 +  if (!inner) {
 1.11952 +    return -1;
 1.11953 +  }
 1.11954 +
 1.11955 +  if (inner != this) {
 1.11956 +    return inner->SetTimeoutOrInterval(aFunction, aTimeout, aArguments,
 1.11957 +                                       aIsInterval, aError);
 1.11958 +  }
 1.11959 +
 1.11960 +  nsCOMPtr<nsIScriptTimeoutHandler> handler =
 1.11961 +    NS_CreateJSTimeoutHandler(this, aFunction, aArguments, aError);
 1.11962 +  if (!handler) {
 1.11963 +    return 0;
 1.11964 +  }
 1.11965 +
 1.11966 +  int32_t result;
 1.11967 +  aError = SetTimeoutOrInterval(handler, aTimeout, aIsInterval, &result);
 1.11968 +  return result;
 1.11969 +}
 1.11970 +
 1.11971 +int32_t
 1.11972 +nsGlobalWindow::SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
 1.11973 +                                     int32_t aTimeout, bool aIsInterval,
 1.11974 +                                     ErrorResult& aError)
 1.11975 +{
 1.11976 +  nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
 1.11977 +  if (!inner) {
 1.11978 +    return -1;
 1.11979 +  }
 1.11980 +
 1.11981 +  if (inner != this) {
 1.11982 +    return inner->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
 1.11983 +                                       aError);
 1.11984 +  }
 1.11985 +
 1.11986 +  nsCOMPtr<nsIScriptTimeoutHandler> handler =
 1.11987 +    NS_CreateJSTimeoutHandler(aCx, this, aHandler, aError);
 1.11988 +  if (!handler) {
 1.11989 +    return 0;
 1.11990 +  }
 1.11991 +
 1.11992 +  int32_t result;
 1.11993 +  aError = SetTimeoutOrInterval(handler, aTimeout, aIsInterval, &result);
 1.11994 +  return result;
 1.11995 +}
 1.11996 +
 1.11997 +bool
 1.11998 +nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
 1.11999 +                                  nsIScriptContext* aScx)
 1.12000 +{
 1.12001 +  // Hold on to the timeout in case mExpr or mFunObj releases its
 1.12002 +  // doc.
 1.12003 +  nsRefPtr<nsTimeout> timeout = aTimeout;
 1.12004 +  nsTimeout* last_running_timeout = mRunningTimeout;
 1.12005 +  mRunningTimeout = timeout;
 1.12006 +  timeout->mRunning = true;
 1.12007 +
 1.12008 +  // Push this timeout's popup control state, which should only be
 1.12009 +  // eabled the first time a timeout fires that was created while
 1.12010 +  // popups were enabled and with a delay less than
 1.12011 +  // "dom.disable_open_click_delay".
 1.12012 +  nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
 1.12013 +
 1.12014 +  // Clear the timeout's popup state, if any, to prevent interval
 1.12015 +  // timeouts from repeatedly opening poups.
 1.12016 +  timeout->mPopupState = openAbused;
 1.12017 +
 1.12018 +  ++gRunningTimeoutDepth;
 1.12019 +  ++mTimeoutFiringDepth;
 1.12020 +
 1.12021 +  bool trackNestingLevel = !timeout->mIsInterval;
 1.12022 +  uint32_t nestingLevel;
 1.12023 +  if (trackNestingLevel) {
 1.12024 +    nestingLevel = sNestingLevel;
 1.12025 +    sNestingLevel = timeout->mNestingLevel;
 1.12026 +  }
 1.12027 +
 1.12028 +  nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
 1.12029 +  nsRefPtr<Function> callback = handler->GetCallback();
 1.12030 +  if (!callback) {
 1.12031 +    // Evaluate the timeout expression.
 1.12032 +    const char16_t* script = handler->GetHandlerText();
 1.12033 +    NS_ASSERTION(script, "timeout has no script nor handler text!");
 1.12034 +
 1.12035 +    const char* filename = nullptr;
 1.12036 +    uint32_t lineNo = 0;
 1.12037 +    handler->GetLocation(&filename, &lineNo);
 1.12038 +
 1.12039 +    // New script entry point required, due to the "Create a script" sub-step of
 1.12040 +    // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialization-steps
 1.12041 +    AutoEntryScript entryScript(this, true, aScx->GetNativeContext());
 1.12042 +    JS::CompileOptions options(entryScript.cx());
 1.12043 +    options.setFileAndLine(filename, lineNo)
 1.12044 +           .setVersion(JSVERSION_DEFAULT);
 1.12045 +    JS::Rooted<JSObject*> global(entryScript.cx(), FastGetGlobalJSObject());
 1.12046 +    nsJSUtils::EvaluateString(entryScript.cx(), nsDependentString(script),
 1.12047 +                              global, options);
 1.12048 +  } else {
 1.12049 +    // Hold strong ref to ourselves while we call the callback.
 1.12050 +    nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
 1.12051 +    ErrorResult ignored;
 1.12052 +    JS::Rooted<JS::Value> ignoredVal(CycleCollectedJSRuntime::Get()->Runtime());
 1.12053 +    callback->Call(me, handler->GetArgs(), &ignoredVal, ignored);
 1.12054 +  }
 1.12055 +
 1.12056 +  // We ignore any failures from calling EvaluateString() on the context or
 1.12057 +  // Call() on a Function here since we're in a loop
 1.12058 +  // where we're likely to be running timeouts whose OS timers
 1.12059 +  // didn't fire in time and we don't want to not fire those timers
 1.12060 +  // now just because execution of one timer failed. We can't
 1.12061 +  // propagate the error to anyone who cares about it from this
 1.12062 +  // point anyway, and the script context should have already reported
 1.12063 +  // the script error in the usual way - so we just drop it.
 1.12064 +
 1.12065 +  if (trackNestingLevel) {
 1.12066 +    sNestingLevel = nestingLevel;
 1.12067 +  }
 1.12068 +
 1.12069 +  --mTimeoutFiringDepth;
 1.12070 +  --gRunningTimeoutDepth;
 1.12071 +
 1.12072 +  mRunningTimeout = last_running_timeout;
 1.12073 +  timeout->mRunning = false;
 1.12074 +  return timeout->mCleared;
 1.12075 +}
 1.12076 +
 1.12077 +bool
 1.12078 +nsGlobalWindow::RescheduleTimeout(nsTimeout* aTimeout, const TimeStamp& now,
 1.12079 +                                  bool aRunningPendingTimeouts)
 1.12080 +{
 1.12081 +  if (!aTimeout->mIsInterval) {
 1.12082 +    if (aTimeout->mTimer) {
 1.12083 +      // The timeout still has an OS timer, and it's not an interval,
 1.12084 +      // that means that the OS timer could still fire; cancel the OS
 1.12085 +      // timer and release its reference to the timeout.
 1.12086 +      aTimeout->mTimer->Cancel();
 1.12087 +      aTimeout->mTimer = nullptr;
 1.12088 +      aTimeout->Release();
 1.12089 +    }
 1.12090 +    return false;
 1.12091 +  }
 1.12092 +
 1.12093 +  // Compute time to next timeout for interval timer.
 1.12094 +  // Make sure nextInterval is at least DOMMinTimeoutValue().
 1.12095 +  TimeDuration nextInterval =
 1.12096 +    TimeDuration::FromMilliseconds(std::max(aTimeout->mInterval,
 1.12097 +                                          uint32_t(DOMMinTimeoutValue())));
 1.12098 +
 1.12099 +  // If we're running pending timeouts, set the next interval to be
 1.12100 +  // relative to "now", and not to when the timeout that was pending
 1.12101 +  // should have fired.
 1.12102 +  TimeStamp firingTime;
 1.12103 +  if (aRunningPendingTimeouts) {
 1.12104 +    firingTime = now + nextInterval;
 1.12105 +  } else {
 1.12106 +    firingTime = aTimeout->mWhen + nextInterval;
 1.12107 +  }
 1.12108 +
 1.12109 +  TimeStamp currentNow = TimeStamp::Now();
 1.12110 +  TimeDuration delay = firingTime - currentNow;
 1.12111 +
 1.12112 +  // And make sure delay is nonnegative; that might happen if the timer
 1.12113 +  // thread is firing our timers somewhat early or if they're taking a long
 1.12114 +  // time to run the callback.
 1.12115 +  if (delay < TimeDuration(0)) {
 1.12116 +    delay = TimeDuration(0);
 1.12117 +  }
 1.12118 +
 1.12119 +  if (!aTimeout->mTimer) {
 1.12120 +    NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
 1.12121 +                 "How'd our timer end up null if we're not frozen or "
 1.12122 +                 "suspended?");
 1.12123 +
 1.12124 +    aTimeout->mTimeRemaining = delay;
 1.12125 +    return true;
 1.12126 +  }
 1.12127 +
 1.12128 +  aTimeout->mWhen = currentNow + delay;
 1.12129 +
 1.12130 +  // Reschedule the OS timer. Don't bother returning any error codes if
 1.12131 +  // this fails since the callers of this method don't care about them.
 1.12132 +  nsresult rv = aTimeout->InitTimer(TimerCallback, delay.ToMilliseconds());
 1.12133 +
 1.12134 +  if (NS_FAILED(rv)) {
 1.12135 +    NS_ERROR("Error initializing timer for DOM timeout!");
 1.12136 +
 1.12137 +    // We failed to initialize the new OS timer, this timer does
 1.12138 +    // us no good here so we just cancel it (just in case) and
 1.12139 +    // null out the pointer to the OS timer, this will release the
 1.12140 +    // OS timer. As we continue executing the code below we'll end
 1.12141 +    // up deleting the timeout since it's not an interval timeout
 1.12142 +    // any more (since timeout->mTimer == nullptr).
 1.12143 +    aTimeout->mTimer->Cancel();
 1.12144 +    aTimeout->mTimer = nullptr;
 1.12145 +
 1.12146 +    // Now that the OS timer no longer has a reference to the
 1.12147 +    // timeout we need to drop that reference.
 1.12148 +    aTimeout->Release();
 1.12149 +
 1.12150 +    return false;
 1.12151 +  }
 1.12152 +
 1.12153 +  return true;
 1.12154 +}
 1.12155 +
 1.12156 +void
 1.12157 +nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
 1.12158 +{
 1.12159 +  // If a modal dialog is open for this window, return early. Pending
 1.12160 +  // timeouts will run when the modal dialog is dismissed.
 1.12161 +  if (IsInModalState() || mTimeoutsSuspendDepth) {
 1.12162 +    return;
 1.12163 +  }
 1.12164 +
 1.12165 +  NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
 1.12166 +  NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
 1.12167 +
 1.12168 +  nsTimeout *nextTimeout;
 1.12169 +  nsTimeout *last_expired_timeout, *last_insertion_point;
 1.12170 +  uint32_t firingDepth = mTimeoutFiringDepth + 1;
 1.12171 +
 1.12172 +  // Make sure that the window and the script context don't go away as
 1.12173 +  // a result of running timeouts
 1.12174 +  nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
 1.12175 +
 1.12176 +  // A native timer has gone off. See which of our timeouts need
 1.12177 +  // servicing
 1.12178 +  TimeStamp now = TimeStamp::Now();
 1.12179 +  TimeStamp deadline;
 1.12180 +
 1.12181 +  if (aTimeout && aTimeout->mWhen > now) {
 1.12182 +    // The OS timer fired early (which can happen due to the timers
 1.12183 +    // having lower precision than TimeStamp does).  Set |deadline| to
 1.12184 +    // be the time when the OS timer *should* have fired so that any
 1.12185 +    // timers that *should* have fired before aTimeout *will* be fired
 1.12186 +    // now.
 1.12187 +
 1.12188 +    deadline = aTimeout->mWhen;
 1.12189 +  } else {
 1.12190 +    deadline = now;
 1.12191 +  }
 1.12192 +
 1.12193 +  // The timeout list is kept in deadline order. Discover the latest
 1.12194 +  // timeout whose deadline has expired. On some platforms, native
 1.12195 +  // timeout events fire "early", so we need to test the timer as well
 1.12196 +  // as the deadline.
 1.12197 +  last_expired_timeout = nullptr;
 1.12198 +  for (nsTimeout *timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
 1.12199 +    if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
 1.12200 +        (timeout->mFiringDepth == 0)) {
 1.12201 +      // Mark any timeouts that are on the list to be fired with the
 1.12202 +      // firing depth so that we can reentrantly run timeouts
 1.12203 +      timeout->mFiringDepth = firingDepth;
 1.12204 +      last_expired_timeout = timeout;
 1.12205 +    }
 1.12206 +  }
 1.12207 +
 1.12208 +  // Maybe the timeout that the event was fired for has been deleted
 1.12209 +  // and there are no others timeouts with deadlines that make them
 1.12210 +  // eligible for execution yet. Go away.
 1.12211 +  if (!last_expired_timeout) {
 1.12212 +    return;
 1.12213 +  }
 1.12214 +
 1.12215 +  // Record telemetry information about timers set recently.
 1.12216 +  TimeDuration recordingInterval = TimeDuration::FromMilliseconds(STATISTICS_INTERVAL);
 1.12217 +  if (gLastRecordedRecentTimeouts.IsNull() ||
 1.12218 +      now - gLastRecordedRecentTimeouts > recordingInterval) {
 1.12219 +    uint32_t count = gTimeoutsRecentlySet;
 1.12220 +    gTimeoutsRecentlySet = 0;
 1.12221 +    Telemetry::Accumulate(Telemetry::DOM_TIMERS_RECENTLY_SET, count);
 1.12222 +    gLastRecordedRecentTimeouts = now;
 1.12223 +  }
 1.12224 +
 1.12225 +  // Insert a dummy timeout into the list of timeouts between the
 1.12226 +  // portion of the list that we are about to process now and those
 1.12227 +  // timeouts that will be processed in a future call to
 1.12228 +  // win_run_timeout(). This dummy timeout serves as the head of the
 1.12229 +  // list for any timeouts inserted as a result of running a timeout.
 1.12230 +  nsRefPtr<nsTimeout> dummy_timeout = new nsTimeout();
 1.12231 +  dummy_timeout->mFiringDepth = firingDepth;
 1.12232 +  dummy_timeout->mWhen = now;
 1.12233 +  last_expired_timeout->setNext(dummy_timeout);
 1.12234 +  dummy_timeout->AddRef();
 1.12235 +
 1.12236 +  last_insertion_point = mTimeoutInsertionPoint;
 1.12237 +  // If we ever start setting mTimeoutInsertionPoint to a non-dummy timeout,
 1.12238 +  // the logic in ResetTimersForNonBackgroundWindow will need to change.
 1.12239 +  mTimeoutInsertionPoint = dummy_timeout;
 1.12240 +
 1.12241 +  Telemetry::AutoCounter<Telemetry::DOM_TIMERS_FIRED_PER_NATIVE_TIMEOUT> timeoutsRan;
 1.12242 +
 1.12243 +  for (nsTimeout *timeout = mTimeouts.getFirst();
 1.12244 +       timeout != dummy_timeout && !IsFrozen();
 1.12245 +       timeout = nextTimeout) {
 1.12246 +    nextTimeout = timeout->getNext();
 1.12247 +
 1.12248 +    if (timeout->mFiringDepth != firingDepth) {
 1.12249 +      // We skip the timeout since it's on the list to run at another
 1.12250 +      // depth.
 1.12251 +
 1.12252 +      continue;
 1.12253 +    }
 1.12254 +
 1.12255 +    if (mTimeoutsSuspendDepth) {
 1.12256 +      // Some timer did suspend us. Make sure the
 1.12257 +      // rest of the timers get executed later.
 1.12258 +      timeout->mFiringDepth = 0;
 1.12259 +      continue;
 1.12260 +    }
 1.12261 +
 1.12262 +    // The timeout is on the list to run at this depth, go ahead and
 1.12263 +    // process it.
 1.12264 +
 1.12265 +    // Get the script context (a strong ref to prevent it going away)
 1.12266 +    // for this timeout and ensure the script language is enabled.
 1.12267 +    nsCOMPtr<nsIScriptContext> scx = GetContextInternal();
 1.12268 +
 1.12269 +    if (!scx) {
 1.12270 +      // No context means this window was closed or never properly
 1.12271 +      // initialized for this language.
 1.12272 +      continue;
 1.12273 +    }
 1.12274 +
 1.12275 +    // This timeout is good to run
 1.12276 +    ++timeoutsRan;
 1.12277 +    bool timeout_was_cleared = RunTimeoutHandler(timeout, scx);
 1.12278 +
 1.12279 +    if (timeout_was_cleared) {
 1.12280 +      // The running timeout's window was cleared, this means that
 1.12281 +      // ClearAllTimeouts() was called from a *nested* call, possibly
 1.12282 +      // through a timeout that fired while a modal (to this window)
 1.12283 +      // dialog was open or through other non-obvious paths.
 1.12284 +      MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
 1.12285 +
 1.12286 +      mTimeoutInsertionPoint = last_insertion_point;
 1.12287 +
 1.12288 +      return;
 1.12289 +    }
 1.12290 +
 1.12291 +    // If we have a regular interval timer, we re-schedule the
 1.12292 +    // timeout, accounting for clock drift.
 1.12293 +    bool needsReinsertion = RescheduleTimeout(timeout, now, !aTimeout);
 1.12294 +
 1.12295 +    // Running a timeout can cause another timeout to be deleted, so
 1.12296 +    // we need to reset the pointer to the following timeout.
 1.12297 +    nextTimeout = timeout->getNext();
 1.12298 +
 1.12299 +    timeout->remove();
 1.12300 +
 1.12301 +    if (needsReinsertion) {
 1.12302 +      // Insert interval timeout onto list sorted in deadline order.
 1.12303 +      // AddRefs timeout.
 1.12304 +      InsertTimeoutIntoList(timeout);
 1.12305 +    }
 1.12306 +
 1.12307 +    // Release the timeout struct since it's possibly out of the list
 1.12308 +    timeout->Release();
 1.12309 +  }
 1.12310 +
 1.12311 +  // Take the dummy timeout off the head of the list
 1.12312 +  dummy_timeout->remove();
 1.12313 +  dummy_timeout->Release();
 1.12314 +  MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
 1.12315 +
 1.12316 +  mTimeoutInsertionPoint = last_insertion_point;
 1.12317 +}
 1.12318 +
 1.12319 +void
 1.12320 +nsGlobalWindow::ClearTimeoutOrInterval(int32_t aTimerID, ErrorResult& aError)
 1.12321 +{
 1.12322 +  FORWARD_TO_INNER_OR_THROW(ClearTimeoutOrInterval, (aTimerID, aError),
 1.12323 +                            aError, );
 1.12324 +
 1.12325 +  uint32_t public_id = (uint32_t)aTimerID;
 1.12326 +  nsTimeout *timeout;
 1.12327 +
 1.12328 +  for (timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
 1.12329 +    if (timeout->mPublicId == public_id) {
 1.12330 +      if (timeout->mRunning) {
 1.12331 +        /* We're running from inside the timeout. Mark this
 1.12332 +           timeout for deferred deletion by the code in
 1.12333 +           RunTimeout() */
 1.12334 +        timeout->mIsInterval = false;
 1.12335 +      }
 1.12336 +      else {
 1.12337 +        /* Delete the timeout from the pending timeout list */
 1.12338 +        timeout->remove();
 1.12339 +
 1.12340 +        if (timeout->mTimer) {
 1.12341 +          timeout->mTimer->Cancel();
 1.12342 +          timeout->mTimer = nullptr;
 1.12343 +          timeout->Release();
 1.12344 +        }
 1.12345 +        timeout->Release();
 1.12346 +      }
 1.12347 +      break;
 1.12348 +    }
 1.12349 +  }
 1.12350 +}
 1.12351 +
 1.12352 +nsresult nsGlobalWindow::ResetTimersForNonBackgroundWindow()
 1.12353 +{
 1.12354 +  FORWARD_TO_INNER(ResetTimersForNonBackgroundWindow, (),
 1.12355 +                   NS_ERROR_NOT_INITIALIZED);
 1.12356 +
 1.12357 +  if (IsFrozen() || mTimeoutsSuspendDepth) {
 1.12358 +    return NS_OK;
 1.12359 +  }
 1.12360 +
 1.12361 +  TimeStamp now = TimeStamp::Now();
 1.12362 +
 1.12363 +  // If mTimeoutInsertionPoint is non-null, we're in the middle of firing
 1.12364 +  // timers and the timers we're planning to fire all come before
 1.12365 +  // mTimeoutInsertionPoint; mTimeoutInsertionPoint itself is a dummy timeout
 1.12366 +  // with an mWhen that may be semi-bogus.  In that case, we don't need to do
 1.12367 +  // anything with mTimeoutInsertionPoint or anything before it, so should
 1.12368 +  // start at the timer after mTimeoutInsertionPoint, if there is one.
 1.12369 +  // Otherwise, start at the beginning of the list.
 1.12370 +  for (nsTimeout *timeout = mTimeoutInsertionPoint ?
 1.12371 +         mTimeoutInsertionPoint->getNext() : mTimeouts.getFirst();
 1.12372 +       timeout; ) {
 1.12373 +    // It's important that this check be <= so that we guarantee that
 1.12374 +    // taking std::max with |now| won't make a quantity equal to
 1.12375 +    // timeout->mWhen below.
 1.12376 +    if (timeout->mWhen <= now) {
 1.12377 +      timeout = timeout->getNext();
 1.12378 +      continue;
 1.12379 +    }
 1.12380 +
 1.12381 +    if (timeout->mWhen - now >
 1.12382 +        TimeDuration::FromMilliseconds(gMinBackgroundTimeoutValue)) {
 1.12383 +      // No need to loop further.  Timeouts are sorted in mWhen order
 1.12384 +      // and the ones after this point were all set up for at least
 1.12385 +      // gMinBackgroundTimeoutValue ms and hence were not clamped.
 1.12386 +      break;
 1.12387 +    }
 1.12388 +
 1.12389 +    /* We switched from background. Re-init the timer appropriately */
 1.12390 +    // Compute the interval the timer should have had if it had not been set in a
 1.12391 +    // background window
 1.12392 +    TimeDuration interval =
 1.12393 +      TimeDuration::FromMilliseconds(std::max(timeout->mInterval,
 1.12394 +                                            uint32_t(DOMMinTimeoutValue())));
 1.12395 +    uint32_t oldIntervalMillisecs = 0;
 1.12396 +    timeout->mTimer->GetDelay(&oldIntervalMillisecs);
 1.12397 +    TimeDuration oldInterval = TimeDuration::FromMilliseconds(oldIntervalMillisecs);
 1.12398 +    if (oldInterval > interval) {
 1.12399 +      // unclamp
 1.12400 +      TimeStamp firingTime =
 1.12401 +        std::max(timeout->mWhen - oldInterval + interval, now);
 1.12402 +
 1.12403 +      NS_ASSERTION(firingTime < timeout->mWhen,
 1.12404 +                   "Our firing time should strictly decrease!");
 1.12405 +
 1.12406 +      TimeDuration delay = firingTime - now;
 1.12407 +      timeout->mWhen = firingTime;
 1.12408 +
 1.12409 +      // Since we reset mWhen we need to move |timeout| to the right
 1.12410 +      // place in the list so that it remains sorted by mWhen.
 1.12411 +      
 1.12412 +      // Get the pointer to the next timeout now, before we move the
 1.12413 +      // current timeout in the list.
 1.12414 +      nsTimeout* nextTimeout = timeout->getNext();
 1.12415 +
 1.12416 +      // It is safe to remove and re-insert because mWhen is now
 1.12417 +      // strictly smaller than it used to be, so we know we'll insert
 1.12418 +      // |timeout| before nextTimeout.
 1.12419 +      NS_ASSERTION(!nextTimeout ||
 1.12420 +                   timeout->mWhen < nextTimeout->mWhen, "How did that happen?");
 1.12421 +      timeout->remove();
 1.12422 +      // InsertTimeoutIntoList will addref |timeout| and reset
 1.12423 +      // mFiringDepth.  Make sure to undo that after calling it.
 1.12424 +      uint32_t firingDepth = timeout->mFiringDepth;
 1.12425 +      InsertTimeoutIntoList(timeout);
 1.12426 +      timeout->mFiringDepth = firingDepth;
 1.12427 +      timeout->Release();
 1.12428 +
 1.12429 +      nsresult rv = timeout->InitTimer(TimerCallback, delay.ToMilliseconds());
 1.12430 +
 1.12431 +      if (NS_FAILED(rv)) {
 1.12432 +        NS_WARNING("Error resetting non background timer for DOM timeout!");
 1.12433 +        return rv;
 1.12434 +      }
 1.12435 +
 1.12436 +      timeout = nextTimeout;
 1.12437 +    } else {
 1.12438 +      timeout = timeout->getNext();
 1.12439 +    }
 1.12440 +  }
 1.12441 +
 1.12442 +  return NS_OK;
 1.12443 +}
 1.12444 +
 1.12445 +void
 1.12446 +nsGlobalWindow::ClearAllTimeouts()
 1.12447 +{
 1.12448 +  nsTimeout *timeout, *nextTimeout;
 1.12449 +
 1.12450 +  for (timeout = mTimeouts.getFirst(); timeout; timeout = nextTimeout) {
 1.12451 +    /* If RunTimeout() is higher up on the stack for this
 1.12452 +       window, e.g. as a result of document.write from a timeout,
 1.12453 +       then we need to reset the list insertion point for
 1.12454 +       newly-created timeouts in case the user adds a timeout,
 1.12455 +       before we pop the stack back to RunTimeout. */
 1.12456 +    if (mRunningTimeout == timeout)
 1.12457 +      mTimeoutInsertionPoint = nullptr;
 1.12458 +
 1.12459 +    nextTimeout = timeout->getNext();
 1.12460 +
 1.12461 +    if (timeout->mTimer) {
 1.12462 +      timeout->mTimer->Cancel();
 1.12463 +      timeout->mTimer = nullptr;
 1.12464 +
 1.12465 +      // Drop the count since the timer isn't going to hold on
 1.12466 +      // anymore.
 1.12467 +      timeout->Release();
 1.12468 +    }
 1.12469 +
 1.12470 +    // Set timeout->mCleared to true to indicate that the timeout was
 1.12471 +    // cleared and taken out of the list of timeouts
 1.12472 +    timeout->mCleared = true;
 1.12473 +
 1.12474 +    // Drop the count since we're removing it from the list.
 1.12475 +    timeout->Release();
 1.12476 +  }
 1.12477 +
 1.12478 +  // Clear out our list
 1.12479 +  mTimeouts.clear();
 1.12480 +}
 1.12481 +
 1.12482 +void
 1.12483 +nsGlobalWindow::InsertTimeoutIntoList(nsTimeout *aTimeout)
 1.12484 +{
 1.12485 +  NS_ASSERTION(IsInnerWindow(),
 1.12486 +               "InsertTimeoutIntoList() called on outer window!");
 1.12487 +
 1.12488 +  // Start at mLastTimeout and go backwards.  Don't go further than
 1.12489 +  // mTimeoutInsertionPoint, though.  This optimizes for the common case of
 1.12490 +  // insertion at the end.
 1.12491 +  nsTimeout* prevSibling;
 1.12492 +  for (prevSibling = mTimeouts.getLast();
 1.12493 +       prevSibling && prevSibling != mTimeoutInsertionPoint &&
 1.12494 +         // This condition needs to match the one in SetTimeoutOrInterval that
 1.12495 +         // determines whether to set mWhen or mTimeRemaining.
 1.12496 +         ((IsFrozen() || mTimeoutsSuspendDepth) ?
 1.12497 +          prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
 1.12498 +          prevSibling->mWhen > aTimeout->mWhen);
 1.12499 +       prevSibling = prevSibling->getPrevious()) {
 1.12500 +    /* Do nothing; just searching */
 1.12501 +  }
 1.12502 +
 1.12503 +  // Now link in aTimeout after prevSibling.
 1.12504 +  if (prevSibling) {
 1.12505 +    prevSibling->setNext(aTimeout);
 1.12506 +  } else {
 1.12507 +    mTimeouts.insertFront(aTimeout);
 1.12508 +  }
 1.12509 +
 1.12510 +  aTimeout->mFiringDepth = 0;
 1.12511 +
 1.12512 +  // Increment the timeout's reference count since it's now held on to
 1.12513 +  // by the list
 1.12514 +  aTimeout->AddRef();
 1.12515 +}
 1.12516 +
 1.12517 +// static
 1.12518 +void
 1.12519 +nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
 1.12520 +{
 1.12521 +  nsRefPtr<nsTimeout> timeout = (nsTimeout *)aClosure;
 1.12522 +
 1.12523 +  timeout->mWindow->RunTimeout(timeout);
 1.12524 +}
 1.12525 +
 1.12526 +//*****************************************************************************
 1.12527 +// nsGlobalWindow: Helper Functions
 1.12528 +//*****************************************************************************
 1.12529 +
 1.12530 +already_AddRefed<nsIDocShellTreeOwner>
 1.12531 +nsGlobalWindow::GetTreeOwner()
 1.12532 +{
 1.12533 +  FORWARD_TO_OUTER(GetTreeOwner, (), nullptr);
 1.12534 +
 1.12535 +  // If there's no docShellAsItem, this window must have been closed,
 1.12536 +  // in that case there is no tree owner.
 1.12537 +
 1.12538 +  if (!mDocShell) {
 1.12539 +    return nullptr;
 1.12540 +  }
 1.12541 +
 1.12542 +  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
 1.12543 +  mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
 1.12544 +  return treeOwner.forget();
 1.12545 +}
 1.12546 +
 1.12547 +already_AddRefed<nsIBaseWindow>
 1.12548 +nsGlobalWindow::GetTreeOwnerWindow()
 1.12549 +{
 1.12550 +  MOZ_ASSERT(IsOuterWindow());
 1.12551 +
 1.12552 +  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
 1.12553 +
 1.12554 +  // If there's no mDocShell, this window must have been closed,
 1.12555 +  // in that case there is no tree owner.
 1.12556 +
 1.12557 +  if (mDocShell) {
 1.12558 +    mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
 1.12559 +  }
 1.12560 +
 1.12561 +  nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
 1.12562 +  return baseWindow.forget();
 1.12563 +}
 1.12564 +
 1.12565 +already_AddRefed<nsIWebBrowserChrome>
 1.12566 +nsGlobalWindow::GetWebBrowserChrome()
 1.12567 +{
 1.12568 +  nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
 1.12569 +
 1.12570 +  nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
 1.12571 +  return browserChrome.forget();
 1.12572 +}
 1.12573 +
 1.12574 +nsIScrollableFrame *
 1.12575 +nsGlobalWindow::GetScrollFrame()
 1.12576 +{
 1.12577 +  FORWARD_TO_OUTER(GetScrollFrame, (), nullptr);
 1.12578 +
 1.12579 +  if (!mDocShell) {
 1.12580 +    return nullptr;
 1.12581 +  }
 1.12582 +
 1.12583 +  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
 1.12584 +  if (presShell) {
 1.12585 +    return presShell->GetRootScrollFrameAsScrollable();
 1.12586 +  }
 1.12587 +  return nullptr;
 1.12588 +}
 1.12589 +
 1.12590 +nsresult
 1.12591 +nsGlobalWindow::SecurityCheckURL(const char *aURL)
 1.12592 +{
 1.12593 +  nsCOMPtr<nsPIDOMWindow> sourceWindow;
 1.12594 +  JSContext* topCx = nsContentUtils::GetCurrentJSContext();
 1.12595 +  if (topCx) {
 1.12596 +    sourceWindow = do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(topCx));
 1.12597 +  }
 1.12598 +  if (!sourceWindow) {
 1.12599 +    sourceWindow = this;
 1.12600 +  }
 1.12601 +  AutoJSContext cx;
 1.12602 +  nsGlobalWindow* sourceWin = static_cast<nsGlobalWindow*>(sourceWindow.get());
 1.12603 +  JSAutoCompartment ac(cx, sourceWin->GetGlobalJSObject());
 1.12604 +
 1.12605 +  // Resolve the baseURI, which could be relative to the calling window.
 1.12606 +  //
 1.12607 +  // Note the algorithm to get the base URI should match the one
 1.12608 +  // used to actually kick off the load in nsWindowWatcher.cpp.
 1.12609 +  nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
 1.12610 +  nsIURI* baseURI = nullptr;
 1.12611 +  nsAutoCString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
 1.12612 +  if (doc) {
 1.12613 +    baseURI = doc->GetDocBaseURI();
 1.12614 +    charset = doc->GetDocumentCharacterSet();
 1.12615 +  }
 1.12616 +  nsCOMPtr<nsIURI> uri;
 1.12617 +  nsresult rv = NS_NewURI(getter_AddRefs(uri), nsDependentCString(aURL),
 1.12618 +                          charset.get(), baseURI);
 1.12619 +  if (NS_WARN_IF(NS_FAILED(rv))) {
 1.12620 +    return rv;
 1.12621 +  }
 1.12622 +
 1.12623 +  if (NS_FAILED(nsContentUtils::GetSecurityManager()->
 1.12624 +        CheckLoadURIFromScript(cx, uri))) {
 1.12625 +    return NS_ERROR_FAILURE;
 1.12626 +  }
 1.12627 +
 1.12628 +  return NS_OK;
 1.12629 +}
 1.12630 +
 1.12631 +void
 1.12632 +nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
 1.12633 +{
 1.12634 +  if (mDoc) {
 1.12635 +    mDoc->FlushPendingNotifications(aType);
 1.12636 +  }
 1.12637 +}
 1.12638 +
 1.12639 +void
 1.12640 +nsGlobalWindow::EnsureSizeUpToDate()
 1.12641 +{
 1.12642 +  MOZ_ASSERT(IsOuterWindow());
 1.12643 +
 1.12644 +  // If we're a subframe, make sure our size is up to date.  It's OK that this
 1.12645 +  // crosses the content/chrome boundary, since chrome can have pending reflows
 1.12646 +  // too.
 1.12647 +  nsGlobalWindow *parent =
 1.12648 +    static_cast<nsGlobalWindow *>(GetPrivateParent());
 1.12649 +  if (parent) {
 1.12650 +    parent->FlushPendingNotifications(Flush_Layout);
 1.12651 +  }
 1.12652 +}
 1.12653 +
 1.12654 +already_AddRefed<nsISupports>
 1.12655 +nsGlobalWindow::SaveWindowState()
 1.12656 +{
 1.12657 +  NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
 1.12658 +
 1.12659 +  if (!mContext || !GetWrapperPreserveColor()) {
 1.12660 +    // The window may be getting torn down; don't bother saving state.
 1.12661 +    return nullptr;
 1.12662 +  }
 1.12663 +
 1.12664 +  nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
 1.12665 +  NS_ASSERTION(inner, "No inner window to save");
 1.12666 +
 1.12667 +  // Don't do anything else to this inner window! After this point, all
 1.12668 +  // calls to SetTimeoutOrInterval will create entries in the timeout
 1.12669 +  // list that will only run after this window has come out of the bfcache.
 1.12670 +  // Also, while we're frozen, we won't dispatch online/offline events
 1.12671 +  // to the page.
 1.12672 +  inner->Freeze();
 1.12673 +
 1.12674 +  nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
 1.12675 +
 1.12676 +#ifdef DEBUG_PAGE_CACHE
 1.12677 +  printf("saving window state, state = %p\n", (void*)state);
 1.12678 +#endif
 1.12679 +
 1.12680 +  return state.forget();
 1.12681 +}
 1.12682 +
 1.12683 +nsresult
 1.12684 +nsGlobalWindow::RestoreWindowState(nsISupports *aState)
 1.12685 +{
 1.12686 +  NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
 1.12687 +
 1.12688 +  if (!mContext || !GetWrapperPreserveColor()) {
 1.12689 +    // The window may be getting torn down; don't bother restoring state.
 1.12690 +    return NS_OK;
 1.12691 +  }
 1.12692 +
 1.12693 +  nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
 1.12694 +  NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
 1.12695 +
 1.12696 +#ifdef DEBUG_PAGE_CACHE
 1.12697 +  printf("restoring window state, state = %p\n", (void*)holder);
 1.12698 +#endif
 1.12699 +
 1.12700 +  // And we're ready to go!
 1.12701 +  nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
 1.12702 +
 1.12703 +  // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
 1.12704 +  // it easy to tell which link was last clicked when going back a page.
 1.12705 +  nsIContent* focusedNode = inner->GetFocusedNode();
 1.12706 +  if (IsLink(focusedNode)) {
 1.12707 +    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
 1.12708 +    if (fm) {
 1.12709 +      nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
 1.12710 +      fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
 1.12711 +                                   nsIFocusManager::FLAG_SHOWRING);
 1.12712 +    }
 1.12713 +  }
 1.12714 +
 1.12715 +  inner->Thaw();
 1.12716 +
 1.12717 +  holder->DidRestoreWindow();
 1.12718 +
 1.12719 +  return NS_OK;
 1.12720 +}
 1.12721 +
 1.12722 +void
 1.12723 +nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease,
 1.12724 +                                bool aFreezeChildren)
 1.12725 +{
 1.12726 +  FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren));
 1.12727 +
 1.12728 +  bool suspended = (mTimeoutsSuspendDepth != 0);
 1.12729 +  mTimeoutsSuspendDepth += aIncrease;
 1.12730 +
 1.12731 +  if (!suspended) {
 1.12732 +    nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
 1.12733 +    if (ac) {
 1.12734 +      for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
 1.12735 +        ac->RemoveWindowListener(mEnabledSensors[i], this);
 1.12736 +    }
 1.12737 +    DisableGamepadUpdates();
 1.12738 +
 1.12739 +    // Suspend all of the workers for this window.
 1.12740 +    mozilla::dom::workers::SuspendWorkersForWindow(this);
 1.12741 +
 1.12742 +    TimeStamp now = TimeStamp::Now();
 1.12743 +    for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
 1.12744 +      // Set mTimeRemaining to be the time remaining for this timer.
 1.12745 +      if (t->mWhen > now)
 1.12746 +        t->mTimeRemaining = t->mWhen - now;
 1.12747 +      else
 1.12748 +        t->mTimeRemaining = TimeDuration(0);
 1.12749 +  
 1.12750 +      // Drop the XPCOM timer; we'll reschedule when restoring the state.
 1.12751 +      if (t->mTimer) {
 1.12752 +        t->mTimer->Cancel();
 1.12753 +        t->mTimer = nullptr;
 1.12754 +  
 1.12755 +        // Drop the reference that the timer's closure had on this timeout, we'll
 1.12756 +        // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
 1.12757 +        // passing null for the context, since this shouldn't actually release this
 1.12758 +        // timeout.
 1.12759 +        t->Release();
 1.12760 +      }
 1.12761 +    }
 1.12762 +
 1.12763 +    // Suspend all of the AudioContexts for this window
 1.12764 +    for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
 1.12765 +      mAudioContexts[i]->Suspend();
 1.12766 +    }
 1.12767 +  }
 1.12768 +
 1.12769 +  // Suspend our children as well.
 1.12770 +  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
 1.12771 +  if (docShell) {
 1.12772 +    int32_t childCount = 0;
 1.12773 +    docShell->GetChildCount(&childCount);
 1.12774 +
 1.12775 +    for (int32_t i = 0; i < childCount; ++i) {
 1.12776 +      nsCOMPtr<nsIDocShellTreeItem> childShell;
 1.12777 +      docShell->GetChildAt(i, getter_AddRefs(childShell));
 1.12778 +      NS_ASSERTION(childShell, "null child shell");
 1.12779 +
 1.12780 +      nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
 1.12781 +      if (pWin) {
 1.12782 +        nsGlobalWindow *win =
 1.12783 +          static_cast<nsGlobalWindow*>
 1.12784 +                     (static_cast<nsPIDOMWindow*>(pWin));
 1.12785 +        NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
 1.12786 +        nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
 1.12787 +
 1.12788 +        // This is a bit hackish. Only freeze/suspend windows which are truly our
 1.12789 +        // subwindows.
 1.12790 +        nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
 1.12791 +        if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
 1.12792 +          continue;
 1.12793 +        }
 1.12794 +
 1.12795 +        win->SuspendTimeouts(aIncrease, aFreezeChildren);
 1.12796 +
 1.12797 +        if (inner && aFreezeChildren) {
 1.12798 +          inner->Freeze();
 1.12799 +        }
 1.12800 +      }
 1.12801 +    }
 1.12802 +  }
 1.12803 +}
 1.12804 +
 1.12805 +nsresult
 1.12806 +nsGlobalWindow::ResumeTimeouts(bool aThawChildren)
 1.12807 +{
 1.12808 +  FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
 1.12809 +
 1.12810 +  NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
 1.12811 +  --mTimeoutsSuspendDepth;
 1.12812 +  bool shouldResume = (mTimeoutsSuspendDepth == 0) && !mInnerObjectsFreed;
 1.12813 +  nsresult rv;
 1.12814 +
 1.12815 +  if (shouldResume) {
 1.12816 +    nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
 1.12817 +    if (ac) {
 1.12818 +      for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
 1.12819 +        ac->AddWindowListener(mEnabledSensors[i], this);
 1.12820 +    }
 1.12821 +    EnableGamepadUpdates();
 1.12822 +
 1.12823 +    // Resume all of the AudioContexts for this window
 1.12824 +    for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
 1.12825 +      mAudioContexts[i]->Resume();
 1.12826 +    }
 1.12827 +
 1.12828 +    // Resume all of the workers for this window.
 1.12829 +    mozilla::dom::workers::ResumeWorkersForWindow(this);
 1.12830 +
 1.12831 +    // Restore all of the timeouts, using the stored time remaining
 1.12832 +    // (stored in timeout->mTimeRemaining).
 1.12833 +
 1.12834 +    TimeStamp now = TimeStamp::Now();
 1.12835 +
 1.12836 +#ifdef DEBUG
 1.12837 +    bool _seenDummyTimeout = false;
 1.12838 +#endif
 1.12839 +
 1.12840 +    for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
 1.12841 +      // There's a chance we're being called with RunTimeout on the stack in which
 1.12842 +      // case we have a dummy timeout in the list that *must not* be resumed. It
 1.12843 +      // can be identified by a null mWindow.
 1.12844 +      if (!t->mWindow) {
 1.12845 +#ifdef DEBUG
 1.12846 +        NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
 1.12847 +        _seenDummyTimeout = true;
 1.12848 +#endif
 1.12849 +        continue;
 1.12850 +      }
 1.12851 +
 1.12852 +      // XXXbz the combination of the way |delay| and |t->mWhen| are set here
 1.12853 +      // makes no sense.  Are we trying to impose that min timeout value or
 1.12854 +      // not???
 1.12855 +      uint32_t delay =
 1.12856 +        std::max(int32_t(t->mTimeRemaining.ToMilliseconds()),
 1.12857 +               DOMMinTimeoutValue());
 1.12858 +
 1.12859 +      // Set mWhen back to the time when the timer is supposed to
 1.12860 +      // fire.
 1.12861 +      t->mWhen = now + t->mTimeRemaining;
 1.12862 +
 1.12863 +      t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
 1.12864 +      NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
 1.12865 +
 1.12866 +      rv = t->InitTimer(TimerCallback, delay);
 1.12867 +      if (NS_FAILED(rv)) {
 1.12868 +        t->mTimer = nullptr;
 1.12869 +        return rv;
 1.12870 +      }
 1.12871 +
 1.12872 +      // Add a reference for the new timer's closure.
 1.12873 +      t->AddRef();
 1.12874 +    }
 1.12875 +  }
 1.12876 +
 1.12877 +  // Resume our children as well.
 1.12878 +  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
 1.12879 +  if (docShell) {
 1.12880 +    int32_t childCount = 0;
 1.12881 +    docShell->GetChildCount(&childCount);
 1.12882 +
 1.12883 +    for (int32_t i = 0; i < childCount; ++i) {
 1.12884 +      nsCOMPtr<nsIDocShellTreeItem> childShell;
 1.12885 +      docShell->GetChildAt(i, getter_AddRefs(childShell));
 1.12886 +      NS_ASSERTION(childShell, "null child shell");
 1.12887 +
 1.12888 +      nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
 1.12889 +      if (pWin) {
 1.12890 +        nsGlobalWindow *win =
 1.12891 +          static_cast<nsGlobalWindow*>
 1.12892 +                     (static_cast<nsPIDOMWindow*>(pWin));
 1.12893 +
 1.12894 +        NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
 1.12895 +        nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
 1.12896 +
 1.12897 +        // This is a bit hackish. Only thaw/resume windows which are truly our
 1.12898 +        // subwindows.
 1.12899 +        nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
 1.12900 +        if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
 1.12901 +          continue;
 1.12902 +        }
 1.12903 +
 1.12904 +        if (inner && aThawChildren) {
 1.12905 +          inner->Thaw();
 1.12906 +        }
 1.12907 +
 1.12908 +        rv = win->ResumeTimeouts(aThawChildren);
 1.12909 +        NS_ENSURE_SUCCESS(rv, rv);
 1.12910 +      }
 1.12911 +    }
 1.12912 +  }
 1.12913 +
 1.12914 +  return NS_OK;
 1.12915 +}
 1.12916 +
 1.12917 +uint32_t
 1.12918 +nsGlobalWindow::TimeoutSuspendCount()
 1.12919 +{
 1.12920 +  FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
 1.12921 +  return mTimeoutsSuspendDepth;
 1.12922 +}
 1.12923 +
 1.12924 +void
 1.12925 +nsGlobalWindow::EnableDeviceSensor(uint32_t aType)
 1.12926 +{
 1.12927 +  MOZ_ASSERT(IsInnerWindow());
 1.12928 +
 1.12929 +  bool alreadyEnabled = false;
 1.12930 +  for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
 1.12931 +    if (mEnabledSensors[i] == aType) {
 1.12932 +      alreadyEnabled = true;
 1.12933 +      break;
 1.12934 +    }
 1.12935 +  }
 1.12936 +
 1.12937 +  mEnabledSensors.AppendElement(aType);
 1.12938 +
 1.12939 +  if (alreadyEnabled) {
 1.12940 +    return;
 1.12941 +  }
 1.12942 +
 1.12943 +  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
 1.12944 +  if (ac) {
 1.12945 +    ac->AddWindowListener(aType, this);
 1.12946 +  }
 1.12947 +}
 1.12948 +
 1.12949 +void
 1.12950 +nsGlobalWindow::DisableDeviceSensor(uint32_t aType)
 1.12951 +{
 1.12952 +  MOZ_ASSERT(IsInnerWindow());
 1.12953 +
 1.12954 +  int32_t doomedElement = -1;
 1.12955 +  int32_t listenerCount = 0;
 1.12956 +  for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
 1.12957 +    if (mEnabledSensors[i] == aType) {
 1.12958 +      doomedElement = i;
 1.12959 +      listenerCount++;
 1.12960 +    }
 1.12961 +  }
 1.12962 +
 1.12963 +  if (doomedElement == -1) {
 1.12964 +    return;
 1.12965 +  }
 1.12966 +
 1.12967 +  mEnabledSensors.RemoveElementAt(doomedElement);
 1.12968 +
 1.12969 +  if (listenerCount > 1) {
 1.12970 +    return;
 1.12971 +  }
 1.12972 +
 1.12973 +  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
 1.12974 +  if (ac) {
 1.12975 +    ac->RemoveWindowListener(aType, this);
 1.12976 +  }
 1.12977 +}
 1.12978 +
 1.12979 +void
 1.12980 +nsGlobalWindow::SetHasGamepadEventListener(bool aHasGamepad/* = true*/)
 1.12981 +{
 1.12982 +  FORWARD_TO_INNER_VOID(SetHasGamepadEventListener, (aHasGamepad));
 1.12983 +  mHasGamepad = aHasGamepad;
 1.12984 +  if (aHasGamepad) {
 1.12985 +    EnableGamepadUpdates();
 1.12986 +  }
 1.12987 +}
 1.12988 +
 1.12989 +void
 1.12990 +nsGlobalWindow::EnableTimeChangeNotifications()
 1.12991 +{
 1.12992 +  mozilla::time::AddWindowListener(this);
 1.12993 +}
 1.12994 +
 1.12995 +void
 1.12996 +nsGlobalWindow::DisableTimeChangeNotifications()
 1.12997 +{
 1.12998 +  mozilla::time::RemoveWindowListener(this);
 1.12999 +}
 1.13000 +
 1.13001 +static PLDHashOperator
 1.13002 +CollectSizeAndListenerCount(
 1.13003 +  nsPtrHashKey<DOMEventTargetHelper>* aEntry,
 1.13004 +  void *arg)
 1.13005 +{
 1.13006 +  nsWindowSizes* windowSizes = static_cast<nsWindowSizes*>(arg);
 1.13007 +
 1.13008 +  DOMEventTargetHelper* et = aEntry->GetKey();
 1.13009 +
 1.13010 +  if (nsCOMPtr<nsISizeOfEventTarget> iSizeOf = do_QueryObject(et)) {
 1.13011 +    windowSizes->mDOMEventTargetsSize +=
 1.13012 +      iSizeOf->SizeOfEventTargetIncludingThis(windowSizes->mMallocSizeOf);
 1.13013 +  }
 1.13014 +
 1.13015 +  if (EventListenerManager* elm = et->GetExistingListenerManager()) {
 1.13016 +    windowSizes->mDOMEventListenersCount += elm->ListenerCount();
 1.13017 +  }
 1.13018 +
 1.13019 +  return PL_DHASH_NEXT;
 1.13020 +}
 1.13021 +
 1.13022 +void
 1.13023 +nsGlobalWindow::AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
 1.13024 +{
 1.13025 +  aWindowSizes->mDOMOtherSize += aWindowSizes->mMallocSizeOf(this);
 1.13026 +
 1.13027 +  if (IsInnerWindow()) {
 1.13028 +    EventListenerManager* elm = GetExistingListenerManager();
 1.13029 +    if (elm) {
 1.13030 +      aWindowSizes->mDOMOtherSize +=
 1.13031 +        elm->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
 1.13032 +      aWindowSizes->mDOMEventListenersCount +=
 1.13033 +        elm->ListenerCount();
 1.13034 +    }
 1.13035 +    if (mDoc) {
 1.13036 +      mDoc->DocAddSizeOfIncludingThis(aWindowSizes);
 1.13037 +    }
 1.13038 +  }
 1.13039 +
 1.13040 +  if (mNavigator) {
 1.13041 +    aWindowSizes->mDOMOtherSize +=
 1.13042 +      mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
 1.13043 +  }
 1.13044 +
 1.13045 +  // The things pointed to by the entries will be measured below, so we
 1.13046 +  // use nullptr for the callback here.
 1.13047 +  aWindowSizes->mDOMEventTargetsSize +=
 1.13048 +    mEventTargetObjects.SizeOfExcludingThis(nullptr,
 1.13049 +                                            aWindowSizes->mMallocSizeOf);
 1.13050 +  aWindowSizes->mDOMEventTargetsCount +=
 1.13051 +    const_cast<nsTHashtable<nsPtrHashKey<DOMEventTargetHelper> >*>
 1.13052 +      (&mEventTargetObjects)->EnumerateEntries(CollectSizeAndListenerCount,
 1.13053 +                                               aWindowSizes);
 1.13054 +}
 1.13055 +
 1.13056 +
 1.13057 +#ifdef MOZ_GAMEPAD
 1.13058 +void
 1.13059 +nsGlobalWindow::AddGamepad(uint32_t aIndex, Gamepad* aGamepad)
 1.13060 +{
 1.13061 +  FORWARD_TO_INNER_VOID(AddGamepad, (aIndex, aGamepad));
 1.13062 +  mGamepads.Put(aIndex, aGamepad);
 1.13063 +}
 1.13064 +
 1.13065 +void
 1.13066 +nsGlobalWindow::RemoveGamepad(uint32_t aIndex)
 1.13067 +{
 1.13068 +  FORWARD_TO_INNER_VOID(RemoveGamepad, (aIndex));
 1.13069 +  mGamepads.Remove(aIndex);
 1.13070 +}
 1.13071 +
 1.13072 +// static
 1.13073 +PLDHashOperator
 1.13074 +nsGlobalWindow::EnumGamepadsForGet(const uint32_t& aKey, Gamepad* aData,
 1.13075 +                                   void* aUserArg)
 1.13076 +{
 1.13077 +  nsTArray<nsRefPtr<Gamepad> >* array =
 1.13078 +    static_cast<nsTArray<nsRefPtr<Gamepad> >*>(aUserArg);
 1.13079 +  array->EnsureLengthAtLeast(aKey + 1);
 1.13080 +  (*array)[aKey] = aData;
 1.13081 +  return PL_DHASH_NEXT;
 1.13082 +}
 1.13083 +
 1.13084 +void
 1.13085 +nsGlobalWindow::GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads)
 1.13086 +{
 1.13087 +  FORWARD_TO_INNER_VOID(GetGamepads, (aGamepads));
 1.13088 +  aGamepads.Clear();
 1.13089 +  // mGamepads.Count() may not be sufficient, but it's not harmful.
 1.13090 +  aGamepads.SetCapacity(mGamepads.Count());
 1.13091 +  mGamepads.EnumerateRead(EnumGamepadsForGet, &aGamepads);
 1.13092 +}
 1.13093 +
 1.13094 +already_AddRefed<Gamepad>
 1.13095 +nsGlobalWindow::GetGamepad(uint32_t aIndex)
 1.13096 +{
 1.13097 +  FORWARD_TO_INNER(GetGamepad, (aIndex), nullptr);
 1.13098 +  nsRefPtr<Gamepad> gamepad;
 1.13099 +  if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
 1.13100 +    return gamepad.forget();
 1.13101 +  }
 1.13102 +
 1.13103 +  return nullptr;
 1.13104 +}
 1.13105 +
 1.13106 +void
 1.13107 +nsGlobalWindow::SetHasSeenGamepadInput(bool aHasSeen)
 1.13108 +{
 1.13109 +  FORWARD_TO_INNER_VOID(SetHasSeenGamepadInput, (aHasSeen));
 1.13110 +  mHasSeenGamepadInput = aHasSeen;
 1.13111 +}
 1.13112 +
 1.13113 +bool
 1.13114 +nsGlobalWindow::HasSeenGamepadInput()
 1.13115 +{
 1.13116 +  FORWARD_TO_INNER(HasSeenGamepadInput, (), false);
 1.13117 +  return mHasSeenGamepadInput;
 1.13118 +}
 1.13119 +
 1.13120 +// static
 1.13121 +PLDHashOperator
 1.13122 +nsGlobalWindow::EnumGamepadsForSync(const uint32_t& aKey, Gamepad* aData,
 1.13123 +                                    void* aUserArg)
 1.13124 +{
 1.13125 +  nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
 1.13126 +  gamepadsvc->SyncGamepadState(aKey, aData);
 1.13127 +  return PL_DHASH_NEXT;
 1.13128 +}
 1.13129 +
 1.13130 +void
 1.13131 +nsGlobalWindow::SyncGamepadState()
 1.13132 +{
 1.13133 +  FORWARD_TO_INNER_VOID(SyncGamepadState, ());
 1.13134 +  if (mHasSeenGamepadInput) {
 1.13135 +    mGamepads.EnumerateRead(EnumGamepadsForSync, nullptr);
 1.13136 +  }
 1.13137 +}
 1.13138 +#endif
 1.13139 +// nsGlobalChromeWindow implementation
 1.13140 +
 1.13141 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
 1.13142 +
 1.13143 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
 1.13144 +                                                  nsGlobalWindow)
 1.13145 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserDOMWindow)
 1.13146 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
 1.13147 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 1.13148 +
 1.13149 +
 1.13150 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow,
 1.13151 +                                                nsGlobalWindow)
 1.13152 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserDOMWindow)
 1.13153 +  if (tmp->mMessageManager) {
 1.13154 +    static_cast<nsFrameMessageManager*>(
 1.13155 +      tmp->mMessageManager.get())->Disconnect();
 1.13156 +    NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
 1.13157 +  }
 1.13158 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 1.13159 +
 1.13160 +DOMCI_DATA(ChromeWindow, nsGlobalChromeWindow)
 1.13161 +
 1.13162 +// QueryInterface implementation for nsGlobalChromeWindow
 1.13163 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
 1.13164 +  NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
 1.13165 +  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
 1.13166 +NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
 1.13167 +
 1.13168 +NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
 1.13169 +NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
 1.13170 +
 1.13171 +NS_IMETHODIMP
 1.13172 +nsGlobalChromeWindow::GetWindowState(uint16_t* aWindowState)
 1.13173 +{
 1.13174 +  *aWindowState = WindowState();
 1.13175 +  return NS_OK;
 1.13176 +}
 1.13177 +
 1.13178 +uint16_t
 1.13179 +nsGlobalWindow::WindowState()
 1.13180 +{
 1.13181 +  nsCOMPtr<nsIWidget> widget = GetMainWidget();
 1.13182 +
 1.13183 +  int32_t mode = widget ? widget->SizeMode() : 0;
 1.13184 +
 1.13185 +  switch (mode) {
 1.13186 +    case nsSizeMode_Minimized:
 1.13187 +      return nsIDOMChromeWindow::STATE_MINIMIZED;
 1.13188 +    case nsSizeMode_Maximized:
 1.13189 +      return nsIDOMChromeWindow::STATE_MAXIMIZED;
 1.13190 +    case nsSizeMode_Fullscreen:
 1.13191 +      return nsIDOMChromeWindow::STATE_FULLSCREEN;
 1.13192 +    case nsSizeMode_Normal:
 1.13193 +      return nsIDOMChromeWindow::STATE_NORMAL;
 1.13194 +    default:
 1.13195 +      NS_WARNING("Illegal window state for this chrome window");
 1.13196 +      break;
 1.13197 +  }
 1.13198 +
 1.13199 +  return nsIDOMChromeWindow::STATE_NORMAL;
 1.13200 +}
 1.13201 +
 1.13202 +NS_IMETHODIMP
 1.13203 +nsGlobalChromeWindow::Maximize()
 1.13204 +{
 1.13205 +  ErrorResult rv;
 1.13206 +  Maximize(rv);
 1.13207 +  return rv.ErrorCode();
 1.13208 +}
 1.13209 +
 1.13210 +void
 1.13211 +nsGlobalWindow::Maximize(ErrorResult& aError)
 1.13212 +{
 1.13213 +  nsCOMPtr<nsIWidget> widget = GetMainWidget();
 1.13214 +
 1.13215 +  if (widget) {
 1.13216 +    aError = widget->SetSizeMode(nsSizeMode_Maximized);
 1.13217 +  }
 1.13218 +}
 1.13219 +
 1.13220 +NS_IMETHODIMP
 1.13221 +nsGlobalChromeWindow::Minimize()
 1.13222 +{
 1.13223 +  ErrorResult rv;
 1.13224 +  Minimize(rv);
 1.13225 +  return rv.ErrorCode();
 1.13226 +}
 1.13227 +
 1.13228 +void
 1.13229 +nsGlobalWindow::Minimize(ErrorResult& aError)
 1.13230 +{
 1.13231 +  nsCOMPtr<nsIWidget> widget = GetMainWidget();
 1.13232 +
 1.13233 +  if (widget) {
 1.13234 +    aError = widget->SetSizeMode(nsSizeMode_Minimized);
 1.13235 +  }
 1.13236 +}
 1.13237 +
 1.13238 +NS_IMETHODIMP
 1.13239 +nsGlobalChromeWindow::Restore()
 1.13240 +{
 1.13241 +  ErrorResult rv;
 1.13242 +  Restore(rv);
 1.13243 +  return rv.ErrorCode();
 1.13244 +}
 1.13245 +
 1.13246 +void
 1.13247 +nsGlobalWindow::Restore(ErrorResult& aError)
 1.13248 +{
 1.13249 +  nsCOMPtr<nsIWidget> widget = GetMainWidget();
 1.13250 +
 1.13251 +  if (widget) {
 1.13252 +    aError = widget->SetSizeMode(nsSizeMode_Normal);
 1.13253 +  }
 1.13254 +}
 1.13255 +
 1.13256 +NS_IMETHODIMP
 1.13257 +nsGlobalChromeWindow::GetAttention()
 1.13258 +{
 1.13259 +  ErrorResult rv;
 1.13260 +  GetAttention(rv);
 1.13261 +  return rv.ErrorCode();
 1.13262 +}
 1.13263 +
 1.13264 +void
 1.13265 +nsGlobalWindow::GetAttention(ErrorResult& aResult)
 1.13266 +{
 1.13267 +  return GetAttentionWithCycleCount(-1, aResult);
 1.13268 +}
 1.13269 +
 1.13270 +NS_IMETHODIMP
 1.13271 +nsGlobalChromeWindow::GetAttentionWithCycleCount(int32_t aCycleCount)
 1.13272 +{
 1.13273 +  ErrorResult rv;
 1.13274 +  GetAttentionWithCycleCount(aCycleCount, rv);
 1.13275 +  return rv.ErrorCode();
 1.13276 +}
 1.13277 +
 1.13278 +void
 1.13279 +nsGlobalWindow::GetAttentionWithCycleCount(int32_t aCycleCount,
 1.13280 +                                           ErrorResult& aError)
 1.13281 +{
 1.13282 +  nsCOMPtr<nsIWidget> widget = GetMainWidget();
 1.13283 +
 1.13284 +  if (widget) {
 1.13285 +    aError = widget->GetAttention(aCycleCount);
 1.13286 +  }
 1.13287 +}
 1.13288 +
 1.13289 +NS_IMETHODIMP
 1.13290 +nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent, nsIDOMElement* aPanel)
 1.13291 +{
 1.13292 +  NS_ENSURE_TRUE(aMouseDownEvent, NS_ERROR_FAILURE);
 1.13293 +  Event* mouseDownEvent = aMouseDownEvent->InternalDOMEvent();
 1.13294 +  NS_ENSURE_TRUE(mouseDownEvent, NS_ERROR_FAILURE);
 1.13295 +
 1.13296 +  nsCOMPtr<Element> panel = do_QueryInterface(aPanel);
 1.13297 +  NS_ENSURE_TRUE(panel || !aPanel, NS_ERROR_FAILURE);
 1.13298 +
 1.13299 +  ErrorResult rv;
 1.13300 +  BeginWindowMove(*mouseDownEvent, panel, rv);
 1.13301 +  return rv.ErrorCode();
 1.13302 +}
 1.13303 +
 1.13304 +void
 1.13305 +nsGlobalWindow::BeginWindowMove(Event& aMouseDownEvent, Element* aPanel,
 1.13306 +                                ErrorResult& aError)
 1.13307 +{
 1.13308 +  nsCOMPtr<nsIWidget> widget;
 1.13309 +
 1.13310 +  // if a panel was supplied, use its widget instead.
 1.13311 +#ifdef MOZ_XUL
 1.13312 +  if (aPanel) {
 1.13313 +    nsIFrame* frame = aPanel->GetPrimaryFrame();
 1.13314 +    if (!frame || frame->GetType() != nsGkAtoms::menuPopupFrame) {
 1.13315 +      return;
 1.13316 +    }
 1.13317 +
 1.13318 +    widget = (static_cast<nsMenuPopupFrame*>(frame))->GetWidget();
 1.13319 +  }
 1.13320 +  else {
 1.13321 +#endif
 1.13322 +    widget = GetMainWidget();
 1.13323 +#ifdef MOZ_XUL
 1.13324 +  }
 1.13325 +#endif
 1.13326 +
 1.13327 +  if (!widget) {
 1.13328 +    return;
 1.13329 +  }
 1.13330 +
 1.13331 +  WidgetMouseEvent* mouseEvent =
 1.13332 +    aMouseDownEvent.GetInternalNSEvent()->AsMouseEvent();
 1.13333 +  if (!mouseEvent || mouseEvent->eventStructType != NS_MOUSE_EVENT) {
 1.13334 +    aError.Throw(NS_ERROR_FAILURE);
 1.13335 +    return;
 1.13336 +  }
 1.13337 +
 1.13338 +  aError = widget->BeginMoveDrag(mouseEvent);
 1.13339 +}
 1.13340 +
 1.13341 +//Note: This call will lock the cursor, it will not change as it moves.
 1.13342 +//To unlock, the cursor must be set back to CURSOR_AUTO.
 1.13343 +NS_IMETHODIMP
 1.13344 +nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
 1.13345 +{
 1.13346 +  ErrorResult rv;
 1.13347 +  SetCursor(aCursor, rv);
 1.13348 +  return rv.ErrorCode();
 1.13349 +}
 1.13350 +
 1.13351 +void
 1.13352 +nsGlobalWindow::SetCursor(const nsAString& aCursor, ErrorResult& aError)
 1.13353 +{
 1.13354 +  FORWARD_TO_OUTER_OR_THROW(SetCursor, (aCursor, aError), aError, );
 1.13355 +
 1.13356 +  int32_t cursor;
 1.13357 +
 1.13358 +  if (aCursor.EqualsLiteral("auto"))
 1.13359 +    cursor = NS_STYLE_CURSOR_AUTO;
 1.13360 +  else {
 1.13361 +    nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
 1.13362 +    if (eCSSKeyword_UNKNOWN == keyword ||
 1.13363 +        !nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
 1.13364 +      return;
 1.13365 +    }
 1.13366 +  }
 1.13367 +
 1.13368 +  nsRefPtr<nsPresContext> presContext;
 1.13369 +  if (mDocShell) {
 1.13370 +    mDocShell->GetPresContext(getter_AddRefs(presContext));
 1.13371 +  }
 1.13372 +
 1.13373 +  if (presContext) {
 1.13374 +    // Need root widget.
 1.13375 +    nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
 1.13376 +    if (!presShell) {
 1.13377 +      aError.Throw(NS_ERROR_FAILURE);
 1.13378 +      return;
 1.13379 +    }
 1.13380 +
 1.13381 +    nsViewManager* vm = presShell->GetViewManager();
 1.13382 +    if (!vm) {
 1.13383 +      aError.Throw(NS_ERROR_FAILURE);
 1.13384 +      return;
 1.13385 +    }
 1.13386 +
 1.13387 +    nsView* rootView = vm->GetRootView();
 1.13388 +    if (!rootView) {
 1.13389 +      aError.Throw(NS_ERROR_FAILURE);
 1.13390 +      return;
 1.13391 +    }
 1.13392 +
 1.13393 +    nsIWidget* widget = rootView->GetNearestWidget(nullptr);
 1.13394 +    if (!widget) {
 1.13395 +      aError.Throw(NS_ERROR_FAILURE);
 1.13396 +      return;
 1.13397 +    }
 1.13398 +
 1.13399 +    // Call esm and set cursor.
 1.13400 +    aError = presContext->EventStateManager()->SetCursor(cursor, nullptr,
 1.13401 +                                                         false, 0.0f, 0.0f,
 1.13402 +                                                         widget, true);
 1.13403 +  }
 1.13404 +}
 1.13405 +
 1.13406 +NS_IMETHODIMP
 1.13407 +nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
 1.13408 +{
 1.13409 +  ErrorResult rv;
 1.13410 +  NS_IF_ADDREF(*aBrowserWindow = GetBrowserDOMWindow(rv));
 1.13411 +  return rv.ErrorCode();
 1.13412 +}
 1.13413 +
 1.13414 +nsIBrowserDOMWindow*
 1.13415 +nsGlobalWindow::GetBrowserDOMWindow(ErrorResult& aError)
 1.13416 +{
 1.13417 +  FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindow, (aError), aError, nullptr);
 1.13418 +
 1.13419 +  MOZ_ASSERT(IsChromeWindow());
 1.13420 +  return static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow;
 1.13421 +}
 1.13422 +
 1.13423 +NS_IMETHODIMP
 1.13424 +nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
 1.13425 +{
 1.13426 +  ErrorResult rv;
 1.13427 +  SetBrowserDOMWindow(aBrowserWindow, rv);
 1.13428 +  return rv.ErrorCode();
 1.13429 +}
 1.13430 +
 1.13431 +void
 1.13432 +nsGlobalWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow,
 1.13433 +                                    ErrorResult& aError)
 1.13434 +{
 1.13435 +  FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindow, (aBrowserWindow, aError),
 1.13436 +                            aError, );
 1.13437 +  MOZ_ASSERT(IsChromeWindow());
 1.13438 +  static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow = aBrowserWindow;
 1.13439 +}
 1.13440 +
 1.13441 +NS_IMETHODIMP
 1.13442 +nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement* aDefaultButton)
 1.13443 +{
 1.13444 +  nsCOMPtr<Element> defaultButton = do_QueryInterface(aDefaultButton);
 1.13445 +  NS_ENSURE_ARG(defaultButton);
 1.13446 +
 1.13447 +  ErrorResult rv;
 1.13448 +  NotifyDefaultButtonLoaded(*defaultButton, rv);
 1.13449 +  return rv.ErrorCode();
 1.13450 +}
 1.13451 +
 1.13452 +void
 1.13453 +nsGlobalWindow::NotifyDefaultButtonLoaded(Element& aDefaultButton,
 1.13454 +                                          ErrorResult& aError)
 1.13455 +{
 1.13456 +#ifdef MOZ_XUL
 1.13457 +  // Don't snap to a disabled button.
 1.13458 +  nsCOMPtr<nsIDOMXULControlElement> xulControl =
 1.13459 +                                      do_QueryInterface(&aDefaultButton);
 1.13460 +  if (!xulControl) {
 1.13461 +    aError.Throw(NS_ERROR_FAILURE);
 1.13462 +    return;
 1.13463 +  }
 1.13464 +  bool disabled;
 1.13465 +  aError = xulControl->GetDisabled(&disabled);
 1.13466 +  if (aError.Failed() || disabled) {
 1.13467 +    return;
 1.13468 +  }
 1.13469 +
 1.13470 +  // Get the button rect in screen coordinates.
 1.13471 +  nsIFrame *frame = aDefaultButton.GetPrimaryFrame();
 1.13472 +  if (!frame) {
 1.13473 +    aError.Throw(NS_ERROR_FAILURE);
 1.13474 +    return;
 1.13475 +  }
 1.13476 +  nsIntRect buttonRect = frame->GetScreenRect();
 1.13477 +
 1.13478 +  // Get the widget rect in screen coordinates.
 1.13479 +  nsIWidget *widget = GetNearestWidget();
 1.13480 +  if (!widget) {
 1.13481 +    aError.Throw(NS_ERROR_FAILURE);
 1.13482 +    return;
 1.13483 +  }
 1.13484 +  nsIntRect widgetRect;
 1.13485 +  aError = widget->GetScreenBounds(widgetRect);
 1.13486 +  if (aError.Failed()) {
 1.13487 +    return;
 1.13488 +  }
 1.13489 +
 1.13490 +  // Convert the buttonRect coordinates from screen to the widget.
 1.13491 +  buttonRect -= widgetRect.TopLeft();
 1.13492 +  nsresult rv = widget->OnDefaultButtonLoaded(buttonRect);
 1.13493 +  if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
 1.13494 +    aError.Throw(rv);
 1.13495 +  }
 1.13496 +#else
 1.13497 +  aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
 1.13498 +#endif
 1.13499 +}
 1.13500 +
 1.13501 +NS_IMETHODIMP
 1.13502 +nsGlobalChromeWindow::GetMessageManager(nsIMessageBroadcaster** aManager)
 1.13503 +{
 1.13504 +  ErrorResult rv;
 1.13505 +  NS_IF_ADDREF(*aManager = GetMessageManager(rv));
 1.13506 +  return rv.ErrorCode();
 1.13507 +}
 1.13508 +
 1.13509 +nsIMessageBroadcaster*
 1.13510 +nsGlobalWindow::GetMessageManager(ErrorResult& aError)
 1.13511 +{
 1.13512 +  FORWARD_TO_INNER_OR_THROW(GetMessageManager, (aError), aError, nullptr);
 1.13513 +  MOZ_ASSERT(IsChromeWindow());
 1.13514 +  nsGlobalChromeWindow* myself = static_cast<nsGlobalChromeWindow*>(this);
 1.13515 +  if (!myself->mMessageManager) {
 1.13516 +    nsIScriptContext* scx = GetContextInternal();
 1.13517 +    if (NS_WARN_IF(!scx || !(scx->GetNativeContext()))) {
 1.13518 +      aError.Throw(NS_ERROR_UNEXPECTED);
 1.13519 +      return nullptr;
 1.13520 +    }
 1.13521 +
 1.13522 +    nsCOMPtr<nsIMessageBroadcaster> globalMM =
 1.13523 +      do_GetService("@mozilla.org/globalmessagemanager;1");
 1.13524 +    myself->mMessageManager =
 1.13525 +      new nsFrameMessageManager(nullptr,
 1.13526 +                                static_cast<nsFrameMessageManager*>(globalMM.get()),
 1.13527 +                                MM_CHROME | MM_BROADCASTER);
 1.13528 +  }
 1.13529 +  return myself->mMessageManager;
 1.13530 +}
 1.13531 +
 1.13532 +// nsGlobalModalWindow implementation
 1.13533 +
 1.13534 +// QueryInterface implementation for nsGlobalModalWindow
 1.13535 +DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
 1.13536 +
 1.13537 +NS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow)
 1.13538 +  NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
 1.13539 +  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
 1.13540 +NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
 1.13541 +
 1.13542 +NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
 1.13543 +NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
 1.13544 +
 1.13545 +
 1.13546 +void
 1.13547 +nsGlobalWindow::GetDialogArguments(JSContext* aCx,
 1.13548 +                                   JS::MutableHandle<JS::Value> aRetval,
 1.13549 +                                   ErrorResult& aError)
 1.13550 +{
 1.13551 +  FORWARD_TO_OUTER_OR_THROW(GetDialogArguments, (aCx, aRetval, aError),
 1.13552 +                            aError, );
 1.13553 +
 1.13554 +  MOZ_ASSERT(IsModalContentWindow(),
 1.13555 +             "This should only be called on modal windows!");
 1.13556 +
 1.13557 +  // This does an internal origin check, and returns undefined if the subject
 1.13558 +  // does not subsumes the origin of the arguments.
 1.13559 +  JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
 1.13560 +  JSAutoCompartment ac(aCx, wrapper);
 1.13561 +  mDialogArguments->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
 1.13562 +                        aRetval, aError);
 1.13563 +}
 1.13564 +
 1.13565 +NS_IMETHODIMP
 1.13566 +nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments)
 1.13567 +{
 1.13568 +  FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
 1.13569 +                                        NS_ERROR_NOT_INITIALIZED);
 1.13570 +
 1.13571 +  // This does an internal origin check, and returns undefined if the subject
 1.13572 +  // does not subsumes the origin of the arguments.
 1.13573 +  return mDialogArguments->Get(nsContentUtils::GetSubjectPrincipal(), aArguments);
 1.13574 +}
 1.13575 +
 1.13576 +void
 1.13577 +nsGlobalWindow::GetReturnValue(JSContext* aCx,
 1.13578 +                               JS::MutableHandle<JS::Value> aReturnValue,
 1.13579 +                               ErrorResult& aError)
 1.13580 +{
 1.13581 +  FORWARD_TO_OUTER_OR_THROW(GetReturnValue, (aCx, aReturnValue, aError),
 1.13582 +                            aError, );
 1.13583 +
 1.13584 +  MOZ_ASSERT(IsModalContentWindow(),
 1.13585 +             "This should only be called on modal windows!");
 1.13586 +
 1.13587 +  if (mReturnValue) {
 1.13588 +    JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
 1.13589 +    JSAutoCompartment ac(aCx, wrapper);
 1.13590 +    mReturnValue->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
 1.13591 +                      aReturnValue, aError);
 1.13592 +  } else {
 1.13593 +    aReturnValue.setUndefined();
 1.13594 +  }
 1.13595 +}
 1.13596 +
 1.13597 +NS_IMETHODIMP
 1.13598 +nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
 1.13599 +{
 1.13600 +  FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
 1.13601 +
 1.13602 +  nsCOMPtr<nsIVariant> result;
 1.13603 +  if (!mReturnValue) {
 1.13604 +    nsCOMPtr<nsIVariant> variant = CreateVoidVariant();
 1.13605 +    variant.forget(aRetVal);
 1.13606 +    return NS_OK;
 1.13607 +  }
 1.13608 +  return mReturnValue->Get(nsContentUtils::GetSubjectPrincipal(), aRetVal);
 1.13609 +}
 1.13610 +
 1.13611 +void
 1.13612 +nsGlobalWindow::SetReturnValue(JSContext* aCx,
 1.13613 +                               JS::Handle<JS::Value> aReturnValue,
 1.13614 +                               ErrorResult& aError)
 1.13615 +{
 1.13616 +  FORWARD_TO_OUTER_OR_THROW(SetReturnValue, (aCx, aReturnValue, aError),
 1.13617 +                            aError, );
 1.13618 +
 1.13619 +  MOZ_ASSERT(IsModalContentWindow(),
 1.13620 +             "This should only be called on modal windows!");
 1.13621 +
 1.13622 +  nsCOMPtr<nsIVariant> returnValue;
 1.13623 +  aError =
 1.13624 +    nsContentUtils::XPConnect()->JSToVariant(aCx, aReturnValue,
 1.13625 +                                             getter_AddRefs(returnValue));
 1.13626 +  if (!aError.Failed()) {
 1.13627 +    mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
 1.13628 +                                         returnValue);
 1.13629 +  }
 1.13630 +}
 1.13631 +
 1.13632 +NS_IMETHODIMP
 1.13633 +nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
 1.13634 +{
 1.13635 +  FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
 1.13636 +
 1.13637 +  mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
 1.13638 +                                       aRetVal);
 1.13639 +  return NS_OK;
 1.13640 +}
 1.13641 +
 1.13642 +/* static */
 1.13643 +bool
 1.13644 +nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
 1.13645 +{
 1.13646 +  // For now, have to deal with XPConnect objects here.
 1.13647 +  return xpc::WindowOrNull(aGlobal)->IsModalContentWindow();
 1.13648 +}
 1.13649 +
 1.13650 +NS_IMETHODIMP
 1.13651 +nsGlobalWindow::GetConsole(JSContext* aCx,
 1.13652 +                           JS::MutableHandle<JS::Value> aConsole)
 1.13653 +{
 1.13654 +  ErrorResult rv;
 1.13655 +  nsRefPtr<Console> console = GetConsole(rv);
 1.13656 +  if (rv.Failed()) {
 1.13657 +    return rv.ErrorCode();
 1.13658 +  }
 1.13659 +
 1.13660 +  if (!WrapNewBindingObject(aCx, console, aConsole)) {
 1.13661 +    return NS_ERROR_FAILURE;
 1.13662 +  }
 1.13663 +
 1.13664 +  return NS_OK;
 1.13665 +}
 1.13666 +
 1.13667 +NS_IMETHODIMP
 1.13668 +nsGlobalWindow::SetConsole(JSContext* aCx, JS::Handle<JS::Value> aValue)
 1.13669 +{
 1.13670 +  JS::Rooted<JSObject*> thisObj(aCx, GetWrapper());
 1.13671 +  if (!thisObj) {
 1.13672 +    return NS_ERROR_UNEXPECTED;
 1.13673 +  }
 1.13674 +
 1.13675 +  if (!JS_WrapObject(aCx, &thisObj) ||
 1.13676 +      !JS_DefineProperty(aCx, thisObj, "console", aValue,
 1.13677 +                         JSPROP_ENUMERATE, JS_PropertyStub,
 1.13678 +                         JS_StrictPropertyStub)) {
 1.13679 +    return NS_ERROR_FAILURE;
 1.13680 +  }
 1.13681 +
 1.13682 +  return NS_OK;
 1.13683 +}
 1.13684 +
 1.13685 +Console*
 1.13686 +nsGlobalWindow::GetConsole(ErrorResult& aRv)
 1.13687 +{
 1.13688 +  FORWARD_TO_INNER_OR_THROW(GetConsole, (aRv), aRv, nullptr);
 1.13689 +
 1.13690 +  if (!mConsole) {
 1.13691 +    mConsole = new Console(this);
 1.13692 +  }
 1.13693 +
 1.13694 +  return mConsole;
 1.13695 +}
 1.13696 +
 1.13697 +already_AddRefed<External>
 1.13698 +nsGlobalWindow::GetExternal(ErrorResult& aRv)
 1.13699 +{
 1.13700 +  FORWARD_TO_INNER_OR_THROW(GetExternal, (aRv), aRv, nullptr);
 1.13701 +
 1.13702 +#ifdef HAVE_SIDEBAR
 1.13703 +  if (!mExternal) {
 1.13704 +    AutoJSContext cx;
 1.13705 +    JS::Rooted<JSObject*> jsImplObj(cx);
 1.13706 +    ConstructJSImplementation(cx, "@mozilla.org/sidebar;1",
 1.13707 +                              this, &jsImplObj, aRv);
 1.13708 +    if (aRv.Failed()) {
 1.13709 +      return nullptr;
 1.13710 +    }
 1.13711 +    mExternal = new External(jsImplObj, this);
 1.13712 +  }
 1.13713 +
 1.13714 +  nsRefPtr<External> external = static_cast<External*>(mExternal.get());
 1.13715 +  return external.forget();
 1.13716 +#else
 1.13717 +  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 1.13718 +  return nullptr;
 1.13719 +#endif
 1.13720 +}
 1.13721 +
 1.13722 +void
 1.13723 +nsGlobalWindow::GetSidebar(OwningExternalOrWindowProxy& aResult,
 1.13724 +                           ErrorResult& aRv)
 1.13725 +{
 1.13726 +  FORWARD_TO_INNER_OR_THROW(GetSidebar, (aResult, aRv), aRv, );
 1.13727 +
 1.13728 +#ifdef HAVE_SIDEBAR
 1.13729 +  // First check for a named frame named "sidebar"
 1.13730 +  nsCOMPtr<nsIDOMWindow> domWindow = GetChildWindow(NS_LITERAL_STRING("sidebar"));
 1.13731 +  if (domWindow) {
 1.13732 +    aResult.SetAsWindowProxy() = domWindow.forget();
 1.13733 +    return;
 1.13734 +  }
 1.13735 +
 1.13736 +  nsRefPtr<External> external = GetExternal(aRv);
 1.13737 +  if (external) {
 1.13738 +    aResult.SetAsExternal() = external;
 1.13739 +  }
 1.13740 +#else
 1.13741 +  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 1.13742 +#endif
 1.13743 +}
 1.13744 +
 1.13745 +/* static */
 1.13746 +bool
 1.13747 +nsGlobalWindow::WindowOnWebIDL(JSContext* aCx, JSObject* aObj)
 1.13748 +{
 1.13749 +  DebugOnly<nsGlobalWindow*> win;
 1.13750 +  MOZ_ASSERT_IF(IsDOMObject(aObj),
 1.13751 +                NS_SUCCEEDED(UNWRAP_OBJECT(Window, aObj, win)));
 1.13752 +
 1.13753 +  return IsDOMObject(aObj);
 1.13754 +}
 1.13755 +
 1.13756 +#ifdef MOZ_B2G
 1.13757 +void
 1.13758 +nsGlobalWindow::EnableNetworkEvent(uint32_t aType)
 1.13759 +{
 1.13760 +  MOZ_ASSERT(IsInnerWindow());
 1.13761 +
 1.13762 +  nsCOMPtr<nsIPermissionManager> permMgr =
 1.13763 +    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
 1.13764 +  if (!permMgr) {
 1.13765 +    NS_ERROR("No PermissionManager available!");
 1.13766 +    return;
 1.13767 +  }
 1.13768 +
 1.13769 +  uint32_t permission = nsIPermissionManager::DENY_ACTION;
 1.13770 +  permMgr->TestExactPermissionFromPrincipal(GetPrincipal(), "network-events",
 1.13771 +                                            &permission);
 1.13772 +
 1.13773 +  if (permission != nsIPermissionManager::ALLOW_ACTION) {
 1.13774 +    return;
 1.13775 +  }
 1.13776 +
 1.13777 +  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
 1.13778 +  if (!os) {
 1.13779 +    NS_ERROR("ObserverService should be available!");
 1.13780 +    return;
 1.13781 +  }
 1.13782 +
 1.13783 +  switch (aType) {
 1.13784 +    case NS_NETWORK_UPLOAD_EVENT:
 1.13785 +      if (!mNetworkUploadObserverEnabled) {
 1.13786 +        mNetworkUploadObserverEnabled = true;
 1.13787 +        os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC, false);
 1.13788 +      }
 1.13789 +      break;
 1.13790 +    case NS_NETWORK_DOWNLOAD_EVENT:
 1.13791 +      if (!mNetworkDownloadObserverEnabled) {
 1.13792 +        mNetworkDownloadObserverEnabled = true;
 1.13793 +        os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC, false);
 1.13794 +      }
 1.13795 +      break;
 1.13796 +  }
 1.13797 +}
 1.13798 +
 1.13799 +void
 1.13800 +nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
 1.13801 +{
 1.13802 +  MOZ_ASSERT(IsInnerWindow());
 1.13803 +
 1.13804 +  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
 1.13805 +  if (!os) {
 1.13806 +    return;
 1.13807 +  }
 1.13808 +
 1.13809 +  switch (aType) {
 1.13810 +    case NS_NETWORK_UPLOAD_EVENT:
 1.13811 +      if (mNetworkUploadObserverEnabled) {
 1.13812 +        mNetworkUploadObserverEnabled = false;
 1.13813 +        os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC);
 1.13814 +      }
 1.13815 +      break;
 1.13816 +    case NS_NETWORK_DOWNLOAD_EVENT:
 1.13817 +      if (mNetworkDownloadObserverEnabled) {
 1.13818 +        mNetworkDownloadObserverEnabled = false;
 1.13819 +        os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC);
 1.13820 +      }
 1.13821 +      break;
 1.13822 +  }
 1.13823 +}
 1.13824 +#endif // MOZ_B2G
 1.13825 +
 1.13826 +#define EVENT(name_, id_, type_, struct_)                                    \
 1.13827 +  NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx,                  \
 1.13828 +                                             JS::MutableHandle<JS::Value> vp) { \
 1.13829 +    EventHandlerNonNull* h = GetOn##name_();                                 \
 1.13830 +    vp.setObjectOrNull(h ? h->Callable().get() : nullptr);                   \
 1.13831 +    return NS_OK;                                                            \
 1.13832 +  }                                                                          \
 1.13833 +  NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx,                  \
 1.13834 +                                             JS::Handle<JS::Value> v) {      \
 1.13835 +    nsRefPtr<EventHandlerNonNull> handler;                                   \
 1.13836 +    JS::Rooted<JSObject*> callable(cx);                                      \
 1.13837 +    if (v.isObject() &&                                                      \
 1.13838 +        JS_ObjectIsCallable(cx, callable = &v.toObject())) {                 \
 1.13839 +      handler = new EventHandlerNonNull(callable, GetIncumbentGlobal());     \
 1.13840 +    }                                                                        \
 1.13841 +    SetOn##name_(handler);                                                   \
 1.13842 +    return NS_OK;                                                            \
 1.13843 +  }
 1.13844 +#define ERROR_EVENT(name_, id_, type_, struct_)                              \
 1.13845 +  NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx,                  \
 1.13846 +                                             JS::MutableHandle<JS::Value> vp) { \
 1.13847 +    EventListenerManager *elm = GetExistingListenerManager();                \
 1.13848 +    if (elm) {                                                               \
 1.13849 +      OnErrorEventHandlerNonNull* h = elm->GetOnErrorEventHandler();         \
 1.13850 +      if (h) {                                                               \
 1.13851 +        vp.setObject(*h->Callable());                                        \
 1.13852 +        return NS_OK;                                                        \
 1.13853 +      }                                                                      \
 1.13854 +    }                                                                        \
 1.13855 +    vp.setNull();                                                            \
 1.13856 +    return NS_OK;                                                            \
 1.13857 +  }                                                                          \
 1.13858 +  NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx,                  \
 1.13859 +                                             JS::Handle<JS::Value> v) {      \
 1.13860 +    EventListenerManager *elm = GetOrCreateListenerManager();                \
 1.13861 +    if (!elm) {                                                              \
 1.13862 +      return NS_ERROR_OUT_OF_MEMORY;                                         \
 1.13863 +    }                                                                        \
 1.13864 +                                                                             \
 1.13865 +    nsRefPtr<OnErrorEventHandlerNonNull> handler;                            \
 1.13866 +    JS::Rooted<JSObject*> callable(cx);                                      \
 1.13867 +    if (v.isObject() &&                                                      \
 1.13868 +        JS_ObjectIsCallable(cx, callable = &v.toObject())) {                 \
 1.13869 +      handler = new OnErrorEventHandlerNonNull(callable, GetIncumbentGlobal()); \
 1.13870 +    }                                                                        \
 1.13871 +    elm->SetEventHandler(handler);                                           \
 1.13872 +    return NS_OK;                                                            \
 1.13873 +  }
 1.13874 +#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                       \
 1.13875 +  NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx,                  \
 1.13876 +                                             JS::MutableHandle<JS::Value> vp) { \
 1.13877 +    EventListenerManager *elm = GetExistingListenerManager();                \
 1.13878 +    if (elm) {                                                               \
 1.13879 +      OnBeforeUnloadEventHandlerNonNull* h =                                 \
 1.13880 +        elm->GetOnBeforeUnloadEventHandler();                                \
 1.13881 +      if (h) {                                                               \
 1.13882 +        vp.setObject(*h->Callable());                                        \
 1.13883 +        return NS_OK;                                                        \
 1.13884 +      }                                                                      \
 1.13885 +    }                                                                        \
 1.13886 +    vp.setNull();                                                            \
 1.13887 +    return NS_OK;                                                            \
 1.13888 +  }                                                                          \
 1.13889 +  NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx,                  \
 1.13890 +                                             JS::Handle<JS::Value> v) {      \
 1.13891 +    EventListenerManager *elm = GetOrCreateListenerManager();                \
 1.13892 +    if (!elm) {                                                              \
 1.13893 +      return NS_ERROR_OUT_OF_MEMORY;                                         \
 1.13894 +    }                                                                        \
 1.13895 +                                                                             \
 1.13896 +    nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handler;                     \
 1.13897 +    JS::Rooted<JSObject*> callable(cx);                                      \
 1.13898 +    if (v.isObject() &&                                                      \
 1.13899 +        JS_ObjectIsCallable(cx, callable = &v.toObject())) {                 \
 1.13900 +      handler = new OnBeforeUnloadEventHandlerNonNull(callable, GetIncumbentGlobal()); \
 1.13901 +    }                                                                        \
 1.13902 +    elm->SetEventHandler(handler);                                           \
 1.13903 +    return NS_OK;                                                            \
 1.13904 +  }
 1.13905 +#define WINDOW_ONLY_EVENT EVENT
 1.13906 +#define TOUCH_EVENT EVENT
 1.13907 +#include "mozilla/EventNameList.h"
 1.13908 +#undef TOUCH_EVENT
 1.13909 +#undef WINDOW_ONLY_EVENT
 1.13910 +#undef BEFOREUNLOAD_EVENT
 1.13911 +#undef ERROR_EVENT
 1.13912 +#undef EVENT
 1.13913 +
 1.13914 +#ifdef _WINDOWS_
 1.13915 +#error "Never include windows.h in this file!"
 1.13916 +#endif

mercurial