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