dom/base/nsGlobalWindow.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "nsGlobalWindow.h"
michael@0 8
michael@0 9 #include <algorithm>
michael@0 10
michael@0 11 #include "mozilla/MemoryReporting.h"
michael@0 12
michael@0 13 // Local Includes
michael@0 14 #include "Navigator.h"
michael@0 15 #include "nsScreen.h"
michael@0 16 #include "nsHistory.h"
michael@0 17 #include "nsPerformance.h"
michael@0 18 #include "nsDOMNavigationTiming.h"
michael@0 19 #include "nsIDOMStorage.h"
michael@0 20 #include "nsIDOMStorageManager.h"
michael@0 21 #include "DOMStorage.h"
michael@0 22 #include "nsDOMOfflineResourceList.h"
michael@0 23 #include "nsError.h"
michael@0 24 #include "nsIIdleService.h"
michael@0 25 #include "nsISizeOfEventTarget.h"
michael@0 26 #include "nsDOMJSUtils.h"
michael@0 27 #include "nsArrayUtils.h"
michael@0 28 #include "nsIDOMWindowCollection.h"
michael@0 29 #include "nsDOMWindowList.h"
michael@0 30 #include "mozilla/dom/WakeLock.h"
michael@0 31 #include "mozilla/dom/power/PowerManagerService.h"
michael@0 32 #include "nsIDocShellTreeOwner.h"
michael@0 33 #include "nsIPermissionManager.h"
michael@0 34 #include "nsIScriptContext.h"
michael@0 35 #include "nsIScriptTimeoutHandler.h"
michael@0 36 #include "nsIController.h"
michael@0 37 #include "nsScriptNameSpaceManager.h"
michael@0 38 #include "nsWindowMemoryReporter.h"
michael@0 39
michael@0 40 // Helper Classes
michael@0 41 #include "nsJSUtils.h"
michael@0 42 #include "jsapi.h" // for JSAutoRequest
michael@0 43 #include "js/OldDebugAPI.h" // for JS_ClearWatchPointsForObject
michael@0 44 #include "jswrapper.h"
michael@0 45 #include "nsReadableUtils.h"
michael@0 46 #include "nsDOMClassInfo.h"
michael@0 47 #include "nsJSEnvironment.h"
michael@0 48 #include "ScriptSettings.h"
michael@0 49 #include "mozilla/Preferences.h"
michael@0 50 #include "mozilla/Likely.h"
michael@0 51 #include "mozilla/unused.h"
michael@0 52
michael@0 53 // Other Classes
michael@0 54 #include "mozilla/dom/BarProps.h"
michael@0 55 #include "nsContentCID.h"
michael@0 56 #include "nsLayoutStatics.h"
michael@0 57 #include "nsCCUncollectableMarker.h"
michael@0 58 #include "mozilla/dom/workers/Workers.h"
michael@0 59 #include "mozilla/dom/MessagePortList.h"
michael@0 60 #include "nsJSPrincipals.h"
michael@0 61 #include "mozilla/Attributes.h"
michael@0 62 #include "mozilla/Debug.h"
michael@0 63 #include "mozilla/EventListenerManager.h"
michael@0 64 #include "mozilla/EventStates.h"
michael@0 65 #include "mozilla/MouseEvents.h"
michael@0 66 #include "AudioChannelService.h"
michael@0 67 #include "MessageEvent.h"
michael@0 68
michael@0 69 // Interfaces Needed
michael@0 70 #include "nsIFrame.h"
michael@0 71 #include "nsCanvasFrame.h"
michael@0 72 #include "nsIWidget.h"
michael@0 73 #include "nsIWidgetListener.h"
michael@0 74 #include "nsIBaseWindow.h"
michael@0 75 #include "nsIDeviceSensors.h"
michael@0 76 #include "nsIContent.h"
michael@0 77 #include "nsIDocShell.h"
michael@0 78 #include "nsIDocCharset.h"
michael@0 79 #include "nsIDocument.h"
michael@0 80 #include "Crypto.h"
michael@0 81 #ifndef MOZ_DISABLE_CRYPTOLEGACY
michael@0 82 #include "nsIDOMCryptoLegacy.h"
michael@0 83 #endif
michael@0 84 #include "nsIDOMDocument.h"
michael@0 85 #include "nsIDOMElement.h"
michael@0 86 #include "nsIDOMEvent.h"
michael@0 87 #include "nsIDOMPopupBlockedEvent.h"
michael@0 88 #include "nsIDOMPopStateEvent.h"
michael@0 89 #include "nsIDOMHashChangeEvent.h"
michael@0 90 #include "nsIDOMOfflineResourceList.h"
michael@0 91 #include "nsPIDOMStorage.h"
michael@0 92 #include "nsDOMString.h"
michael@0 93 #include "nsIEmbeddingSiteWindow.h"
michael@0 94 #include "nsThreadUtils.h"
michael@0 95 #include "nsILoadContext.h"
michael@0 96 #include "nsIMarkupDocumentViewer.h"
michael@0 97 #include "nsIPresShell.h"
michael@0 98 #include "nsIScriptSecurityManager.h"
michael@0 99 #include "nsIScrollableFrame.h"
michael@0 100 #include "nsView.h"
michael@0 101 #include "nsViewManager.h"
michael@0 102 #include "nsISelectionController.h"
michael@0 103 #include "nsISelection.h"
michael@0 104 #include "nsIPrompt.h"
michael@0 105 #include "nsIPromptService.h"
michael@0 106 #include "nsIPromptFactory.h"
michael@0 107 #include "nsIWritablePropertyBag2.h"
michael@0 108 #include "nsIWebNavigation.h"
michael@0 109 #include "nsIWebBrowserChrome.h"
michael@0 110 #include "nsIWebBrowserFind.h" // For window.find()
michael@0 111 #include "nsIWindowMediator.h" // For window.find()
michael@0 112 #include "nsComputedDOMStyle.h"
michael@0 113 #include "nsIEntropyCollector.h"
michael@0 114 #include "nsDOMCID.h"
michael@0 115 #include "nsDOMWindowUtils.h"
michael@0 116 #include "nsIWindowWatcher.h"
michael@0 117 #include "nsPIWindowWatcher.h"
michael@0 118 #include "nsIContentViewer.h"
michael@0 119 #include "nsIScriptError.h"
michael@0 120 #include "nsIControllers.h"
michael@0 121 #include "nsIControllerContext.h"
michael@0 122 #include "nsGlobalWindowCommands.h"
michael@0 123 #include "nsAutoPtr.h"
michael@0 124 #include "nsContentUtils.h"
michael@0 125 #include "nsCxPusher.h"
michael@0 126 #include "nsCSSProps.h"
michael@0 127 #include "nsIDOMFile.h"
michael@0 128 #include "nsIDOMFileList.h"
michael@0 129 #include "nsIURIFixup.h"
michael@0 130 #ifndef DEBUG
michael@0 131 #include "nsIAppStartup.h"
michael@0 132 #include "nsToolkitCompsCID.h"
michael@0 133 #endif
michael@0 134 #include "nsCDefaultURIFixup.h"
michael@0 135 #include "mozilla/EventDispatcher.h"
michael@0 136 #include "mozilla/EventStateManager.h"
michael@0 137 #include "nsIObserverService.h"
michael@0 138 #include "nsFocusManager.h"
michael@0 139 #include "nsIXULWindow.h"
michael@0 140 #include "nsITimedChannel.h"
michael@0 141 #include "nsServiceManagerUtils.h"
michael@0 142 #ifdef MOZ_XUL
michael@0 143 #include "nsIDOMXULControlElement.h"
michael@0 144 #include "nsMenuPopupFrame.h"
michael@0 145 #endif
michael@0 146 #include "nsIDOMCustomEvent.h"
michael@0 147 #include "nsIFrameRequestCallback.h"
michael@0 148 #include "nsIJARChannel.h"
michael@0 149
michael@0 150 #include "xpcprivate.h"
michael@0 151
michael@0 152 #ifdef NS_PRINTING
michael@0 153 #include "nsIPrintSettings.h"
michael@0 154 #include "nsIPrintSettingsService.h"
michael@0 155 #include "nsIWebBrowserPrint.h"
michael@0 156 #endif
michael@0 157
michael@0 158 #include "nsWindowRoot.h"
michael@0 159 #include "nsNetCID.h"
michael@0 160 #include "nsIArray.h"
michael@0 161
michael@0 162 // XXX An unfortunate dependency exists here (two XUL files).
michael@0 163 #include "nsIDOMXULDocument.h"
michael@0 164 #include "nsIDOMXULCommandDispatcher.h"
michael@0 165
michael@0 166 #include "nsBindingManager.h"
michael@0 167 #include "nsXBLService.h"
michael@0 168
michael@0 169 // used for popup blocking, needs to be converted to something
michael@0 170 // belonging to the back-end like nsIContentPolicy
michael@0 171 #include "nsIPopupWindowManager.h"
michael@0 172
michael@0 173 #include "nsIDragService.h"
michael@0 174 #include "mozilla/dom/Element.h"
michael@0 175 #include "mozilla/dom/Selection.h"
michael@0 176 #include "nsFrameLoader.h"
michael@0 177 #include "nsISupportsPrimitives.h"
michael@0 178 #include "nsXPCOMCID.h"
michael@0 179 #include "GeneratedEvents.h"
michael@0 180 #include "GeneratedEventClasses.h"
michael@0 181 #include "mozIThirdPartyUtil.h"
michael@0 182 #ifdef MOZ_LOGGING
michael@0 183 // so we can get logging even in release builds
michael@0 184 #define FORCE_PR_LOG 1
michael@0 185 #endif
michael@0 186 #include "prlog.h"
michael@0 187 #include "prenv.h"
michael@0 188 #include "prprf.h"
michael@0 189
michael@0 190 #include "mozilla/dom/MessageChannel.h"
michael@0 191 #include "mozilla/dom/MessagePort.h"
michael@0 192 #include "mozilla/dom/MessagePortBinding.h"
michael@0 193 #include "mozilla/dom/indexedDB/IDBFactory.h"
michael@0 194 #include "mozilla/dom/quota/QuotaManager.h"
michael@0 195
michael@0 196 #include "mozilla/dom/StructuredCloneTags.h"
michael@0 197
michael@0 198 #ifdef MOZ_GAMEPAD
michael@0 199 #include "mozilla/dom/GamepadService.h"
michael@0 200 #endif
michael@0 201
michael@0 202 #include "nsRefreshDriver.h"
michael@0 203
michael@0 204 #include "mozilla/Services.h"
michael@0 205 #include "mozilla/Telemetry.h"
michael@0 206 #include "nsLocation.h"
michael@0 207 #include "nsHTMLDocument.h"
michael@0 208 #include "nsWrapperCacheInlines.h"
michael@0 209 #include "mozilla/DOMEventTargetHelper.h"
michael@0 210 #include "prrng.h"
michael@0 211 #include "nsSandboxFlags.h"
michael@0 212 #include "TimeChangeObserver.h"
michael@0 213 #include "mozilla/dom/AudioContext.h"
michael@0 214 #include "mozilla/dom/BrowserElementDictionariesBinding.h"
michael@0 215 #include "mozilla/dom/Console.h"
michael@0 216 #include "mozilla/dom/FunctionBinding.h"
michael@0 217 #include "mozilla/dom/WindowBinding.h"
michael@0 218 #include "nsITabChild.h"
michael@0 219 #include "mozilla/dom/MediaQueryList.h"
michael@0 220 #include "mozilla/dom/ScriptSettings.h"
michael@0 221 #ifdef HAVE_SIDEBAR
michael@0 222 #include "mozilla/dom/ExternalBinding.h"
michael@0 223 #endif
michael@0 224
michael@0 225 #ifdef MOZ_WEBSPEECH
michael@0 226 #include "mozilla/dom/SpeechSynthesis.h"
michael@0 227 #endif
michael@0 228
michael@0 229 #ifdef MOZ_JSDEBUGGER
michael@0 230 #include "jsdIDebuggerService.h"
michael@0 231 #endif
michael@0 232
michael@0 233 #ifdef MOZ_B2G
michael@0 234 #include "nsPISocketTransportService.h"
michael@0 235 #endif
michael@0 236
michael@0 237 // Apple system headers seem to have a check() macro. <sigh>
michael@0 238 #ifdef check
michael@0 239 class nsIScriptTimeoutHandler;
michael@0 240 #undef check
michael@0 241 #endif // check
michael@0 242 #include "AccessCheck.h"
michael@0 243
michael@0 244 #ifdef ANDROID
michael@0 245 #include <android/log.h>
michael@0 246 #endif
michael@0 247
michael@0 248 #ifdef PR_LOGGING
michael@0 249 static PRLogModuleInfo* gDOMLeakPRLog;
michael@0 250 #endif
michael@0 251
michael@0 252 #ifdef XP_WIN
michael@0 253 #include <process.h>
michael@0 254 #define getpid _getpid
michael@0 255 #else
michael@0 256 #include <unistd.h> // for getpid()
michael@0 257 #endif
michael@0 258
michael@0 259 static const char kStorageEnabled[] = "dom.storage.enabled";
michael@0 260
michael@0 261 using namespace mozilla;
michael@0 262 using namespace mozilla::dom;
michael@0 263 using namespace mozilla::dom::ipc;
michael@0 264 using mozilla::TimeStamp;
michael@0 265 using mozilla::TimeDuration;
michael@0 266
michael@0 267 nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sWindowsById = nullptr;
michael@0 268 bool nsGlobalWindow::sWarnedAboutWindowInternal = false;
michael@0 269 bool nsGlobalWindow::sIdleObserversAPIFuzzTimeDisabled = false;
michael@0 270
michael@0 271 static nsIEntropyCollector *gEntropyCollector = nullptr;
michael@0 272 static int32_t gRefCnt = 0;
michael@0 273 static int32_t gOpenPopupSpamCount = 0;
michael@0 274 static PopupControlState gPopupControlState = openAbused;
michael@0 275 static int32_t gRunningTimeoutDepth = 0;
michael@0 276 static bool gMouseDown = false;
michael@0 277 static bool gDragServiceDisabled = false;
michael@0 278 static FILE *gDumpFile = nullptr;
michael@0 279 static uint64_t gNextWindowID = 0;
michael@0 280 static uint32_t gSerialCounter = 0;
michael@0 281 static uint32_t gTimeoutsRecentlySet = 0;
michael@0 282 static TimeStamp gLastRecordedRecentTimeouts;
michael@0 283 #define STATISTICS_INTERVAL (30 * PR_MSEC_PER_SEC)
michael@0 284
michael@0 285 #ifdef DEBUG_jst
michael@0 286 int32_t gTimeoutCnt = 0;
michael@0 287 #endif
michael@0 288
michael@0 289 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
michael@0 290 #define DEBUG_PAGE_CACHE
michael@0 291 #endif
michael@0 292
michael@0 293 #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
michael@0 294
michael@0 295 // The default shortest interval/timeout we permit
michael@0 296 #define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
michael@0 297 #define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
michael@0 298 static int32_t gMinTimeoutValue;
michael@0 299 static int32_t gMinBackgroundTimeoutValue;
michael@0 300 inline int32_t
michael@0 301 nsGlobalWindow::DOMMinTimeoutValue() const {
michael@0 302 bool isBackground = !mOuterWindow || mOuterWindow->IsBackground();
michael@0 303 return
michael@0 304 std::max(isBackground ? gMinBackgroundTimeoutValue : gMinTimeoutValue, 0);
michael@0 305 }
michael@0 306
michael@0 307 // The number of nested timeouts before we start clamping. HTML5 says 1, WebKit
michael@0 308 // uses 5.
michael@0 309 #define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
michael@0 310
michael@0 311 // The longest interval (as PRIntervalTime) we permit, or that our
michael@0 312 // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
michael@0 313 // nsTimerImpl.h for details.
michael@0 314 #define DOM_MAX_TIMEOUT_VALUE DELAY_INTERVAL_LIMIT
michael@0 315
michael@0 316 #define FORWARD_TO_OUTER(method, args, err_rval) \
michael@0 317 PR_BEGIN_MACRO \
michael@0 318 if (IsInnerWindow()) { \
michael@0 319 nsGlobalWindow *outer = GetOuterWindowInternal(); \
michael@0 320 if (!HasActiveDocument()) { \
michael@0 321 NS_WARNING(outer ? \
michael@0 322 "Inner window does not have active document." : \
michael@0 323 "No outer window available!"); \
michael@0 324 return err_rval; \
michael@0 325 } \
michael@0 326 return outer->method args; \
michael@0 327 } \
michael@0 328 PR_END_MACRO
michael@0 329
michael@0 330 #define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval) \
michael@0 331 PR_BEGIN_MACRO \
michael@0 332 if (IsInnerWindow()) { \
michael@0 333 nsGlobalWindow *outer = GetOuterWindowInternal(); \
michael@0 334 if (!HasActiveDocument()) { \
michael@0 335 if (!outer) { \
michael@0 336 NS_WARNING("No outer window available!"); \
michael@0 337 errorresult.Throw(NS_ERROR_NOT_INITIALIZED); \
michael@0 338 } else { \
michael@0 339 errorresult.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \
michael@0 340 } \
michael@0 341 } else { \
michael@0 342 return outer->method args; \
michael@0 343 } \
michael@0 344 return err_rval; \
michael@0 345 } \
michael@0 346 PR_END_MACRO
michael@0 347
michael@0 348 #define FORWARD_TO_OUTER_VOID(method, args) \
michael@0 349 PR_BEGIN_MACRO \
michael@0 350 if (IsInnerWindow()) { \
michael@0 351 nsGlobalWindow *outer = GetOuterWindowInternal(); \
michael@0 352 if (!HasActiveDocument()) { \
michael@0 353 NS_WARNING(outer ? \
michael@0 354 "Inner window does not have active document." : \
michael@0 355 "No outer window available!"); \
michael@0 356 return; \
michael@0 357 } \
michael@0 358 outer->method args; \
michael@0 359 return; \
michael@0 360 } \
michael@0 361 PR_END_MACRO
michael@0 362
michael@0 363 #define FORWARD_TO_OUTER_CHROME(method, args, err_rval) \
michael@0 364 PR_BEGIN_MACRO \
michael@0 365 if (IsInnerWindow()) { \
michael@0 366 nsGlobalWindow *outer = GetOuterWindowInternal(); \
michael@0 367 if (!HasActiveDocument()) { \
michael@0 368 NS_WARNING(outer ? \
michael@0 369 "Inner window does not have active document." : \
michael@0 370 "No outer window available!"); \
michael@0 371 return err_rval; \
michael@0 372 } \
michael@0 373 return ((nsGlobalChromeWindow *)outer)->method args; \
michael@0 374 } \
michael@0 375 PR_END_MACRO
michael@0 376
michael@0 377 #define FORWARD_TO_INNER_CHROME(method, args, err_rval) \
michael@0 378 PR_BEGIN_MACRO \
michael@0 379 if (IsOuterWindow()) { \
michael@0 380 if (!mInnerWindow) { \
michael@0 381 NS_WARNING("No inner window available!"); \
michael@0 382 return err_rval; \
michael@0 383 } \
michael@0 384 return ((nsGlobalChromeWindow *)mInnerWindow)->method args; \
michael@0 385 } \
michael@0 386 PR_END_MACRO
michael@0 387
michael@0 388 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
michael@0 389 PR_BEGIN_MACRO \
michael@0 390 if (IsInnerWindow()) { \
michael@0 391 nsGlobalWindow *outer = GetOuterWindowInternal(); \
michael@0 392 if (!HasActiveDocument()) { \
michael@0 393 NS_WARNING(outer ? \
michael@0 394 "Inner window does not have active document." : \
michael@0 395 "No outer window available!"); \
michael@0 396 return err_rval; \
michael@0 397 } \
michael@0 398 return ((nsGlobalModalWindow *)outer)->method args; \
michael@0 399 } \
michael@0 400 PR_END_MACRO
michael@0 401
michael@0 402 #define FORWARD_TO_INNER(method, args, err_rval) \
michael@0 403 PR_BEGIN_MACRO \
michael@0 404 if (IsOuterWindow()) { \
michael@0 405 if (!mInnerWindow) { \
michael@0 406 NS_WARNING("No inner window available!"); \
michael@0 407 return err_rval; \
michael@0 408 } \
michael@0 409 return GetCurrentInnerWindowInternal()->method args; \
michael@0 410 } \
michael@0 411 PR_END_MACRO
michael@0 412
michael@0 413 #define FORWARD_TO_INNER_OR_THROW(method, args, errorresult, err_rval) \
michael@0 414 PR_BEGIN_MACRO \
michael@0 415 if (IsOuterWindow()) { \
michael@0 416 if (!mInnerWindow) { \
michael@0 417 NS_WARNING("No inner window available!"); \
michael@0 418 errorresult.Throw(NS_ERROR_NOT_INITIALIZED); \
michael@0 419 return err_rval; \
michael@0 420 } \
michael@0 421 return GetCurrentInnerWindowInternal()->method args; \
michael@0 422 } \
michael@0 423 PR_END_MACRO
michael@0 424
michael@0 425 #define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
michael@0 426 PR_BEGIN_MACRO \
michael@0 427 if (IsOuterWindow()) { \
michael@0 428 if (!mInnerWindow) { \
michael@0 429 NS_WARNING("No inner window available!"); \
michael@0 430 return err_rval; \
michael@0 431 } \
michael@0 432 return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
michael@0 433 } \
michael@0 434 PR_END_MACRO
michael@0 435
michael@0 436 #define FORWARD_TO_INNER_VOID(method, args) \
michael@0 437 PR_BEGIN_MACRO \
michael@0 438 if (IsOuterWindow()) { \
michael@0 439 if (!mInnerWindow) { \
michael@0 440 NS_WARNING("No inner window available!"); \
michael@0 441 return; \
michael@0 442 } \
michael@0 443 GetCurrentInnerWindowInternal()->method args; \
michael@0 444 return; \
michael@0 445 } \
michael@0 446 PR_END_MACRO
michael@0 447
michael@0 448 // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
michael@0 449 // inner doesn't already exists.
michael@0 450 #define FORWARD_TO_INNER_CREATE(method, args, err_rval) \
michael@0 451 PR_BEGIN_MACRO \
michael@0 452 if (IsOuterWindow()) { \
michael@0 453 if (!mInnerWindow) { \
michael@0 454 if (mIsClosed) { \
michael@0 455 return err_rval; \
michael@0 456 } \
michael@0 457 nsCOMPtr<nsIDOMDocument> doc; \
michael@0 458 nsresult fwdic_nr = GetDocument(getter_AddRefs(doc)); \
michael@0 459 NS_ENSURE_SUCCESS(fwdic_nr, err_rval); \
michael@0 460 if (!mInnerWindow) { \
michael@0 461 return err_rval; \
michael@0 462 } \
michael@0 463 } \
michael@0 464 return GetCurrentInnerWindowInternal()->method args; \
michael@0 465 } \
michael@0 466 PR_END_MACRO
michael@0 467
michael@0 468 // CIDs
michael@0 469 static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
michael@0 470
michael@0 471 static const char sPopStatePrefStr[] = "browser.history.allowPopState";
michael@0 472
michael@0 473 #define NETWORK_UPLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkupload")
michael@0 474 #define NETWORK_DOWNLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkdownload")
michael@0 475
michael@0 476 /**
michael@0 477 * An indirect observer object that means we don't have to implement nsIObserver
michael@0 478 * on nsGlobalWindow, where any script could see it.
michael@0 479 */
michael@0 480 class nsGlobalWindowObserver MOZ_FINAL : public nsIObserver,
michael@0 481 public nsIInterfaceRequestor
michael@0 482 {
michael@0 483 public:
michael@0 484 nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
michael@0 485 NS_DECL_ISUPPORTS
michael@0 486 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
michael@0 487 {
michael@0 488 if (!mWindow)
michael@0 489 return NS_OK;
michael@0 490 return mWindow->Observe(aSubject, aTopic, aData);
michael@0 491 }
michael@0 492 void Forget() { mWindow = nullptr; }
michael@0 493 NS_IMETHODIMP GetInterface(const nsIID& aIID, void** aResult)
michael@0 494 {
michael@0 495 if (mWindow && aIID.Equals(NS_GET_IID(nsIDOMWindow)) && mWindow) {
michael@0 496 return mWindow->QueryInterface(aIID, aResult);
michael@0 497 }
michael@0 498 return NS_NOINTERFACE;
michael@0 499 }
michael@0 500
michael@0 501 private:
michael@0 502 nsGlobalWindow* mWindow;
michael@0 503 };
michael@0 504
michael@0 505 NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)
michael@0 506
michael@0 507 nsTimeout::nsTimeout()
michael@0 508 : mCleared(false),
michael@0 509 mRunning(false),
michael@0 510 mIsInterval(false),
michael@0 511 mPublicId(0),
michael@0 512 mInterval(0),
michael@0 513 mFiringDepth(0),
michael@0 514 mNestingLevel(0),
michael@0 515 mPopupState(openAllowed)
michael@0 516 {
michael@0 517 #ifdef DEBUG_jst
michael@0 518 {
michael@0 519 extern int gTimeoutCnt;
michael@0 520
michael@0 521 ++gTimeoutCnt;
michael@0 522 }
michael@0 523 #endif
michael@0 524
michael@0 525 MOZ_COUNT_CTOR(nsTimeout);
michael@0 526 }
michael@0 527
michael@0 528 nsTimeout::~nsTimeout()
michael@0 529 {
michael@0 530 #ifdef DEBUG_jst
michael@0 531 {
michael@0 532 extern int gTimeoutCnt;
michael@0 533
michael@0 534 --gTimeoutCnt;
michael@0 535 }
michael@0 536 #endif
michael@0 537
michael@0 538 if (mTimer) {
michael@0 539 mTimer->Cancel();
michael@0 540 mTimer = nullptr;
michael@0 541 }
michael@0 542
michael@0 543 MOZ_COUNT_DTOR(nsTimeout);
michael@0 544 }
michael@0 545
michael@0 546 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
michael@0 547
michael@0 548 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsTimeout)
michael@0 549 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTimeout)
michael@0 550 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
michael@0 551 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
michael@0 552 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler)
michael@0 553 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 554 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
michael@0 555 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
michael@0 556
michael@0 557 // Return true if this timeout has a refcount of 1. This is used to check
michael@0 558 // that dummy_timeout doesn't leak from nsGlobalWindow::RunTimeout.
michael@0 559 bool
michael@0 560 nsTimeout::HasRefCntOne()
michael@0 561 {
michael@0 562 return mRefCnt.get() == 1;
michael@0 563 }
michael@0 564
michael@0 565 nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
michael@0 566 : mFrameElement(nullptr), mDocShell(nullptr), mModalStateDepth(0),
michael@0 567 mRunningTimeout(nullptr), mMutationBits(0), mIsDocumentLoaded(false),
michael@0 568 mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nullptr),
michael@0 569 mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
michael@0 570 mMayHaveMouseEnterLeaveEventListener(false),
michael@0 571 mMayHavePointerEnterLeaveEventListener(false),
michael@0 572 mIsModalContentWindow(false),
michael@0 573 mIsActive(false), mIsBackground(false),
michael@0 574 mAudioMuted(false), mAudioVolume(1.0),
michael@0 575 mInnerWindow(nullptr), mOuterWindow(aOuterWindow),
michael@0 576 // Make sure no actual window ends up with mWindowID == 0
michael@0 577 mWindowID(++gNextWindowID), mHasNotifiedGlobalCreated(false),
michael@0 578 mMarkedCCGeneration(0)
michael@0 579 {}
michael@0 580
michael@0 581 nsPIDOMWindow::~nsPIDOMWindow() {}
michael@0 582
michael@0 583 // DialogValueHolder CC goop.
michael@0 584 NS_IMPL_CYCLE_COLLECTION(DialogValueHolder, mValue)
michael@0 585
michael@0 586 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DialogValueHolder)
michael@0 587 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 588 NS_INTERFACE_MAP_END
michael@0 589
michael@0 590 NS_IMPL_CYCLE_COLLECTING_ADDREF(DialogValueHolder)
michael@0 591 NS_IMPL_CYCLE_COLLECTING_RELEASE(DialogValueHolder)
michael@0 592
michael@0 593 //*****************************************************************************
michael@0 594 // nsOuterWindowProxy: Outer Window Proxy
michael@0 595 //*****************************************************************************
michael@0 596
michael@0 597 class nsOuterWindowProxy : public js::Wrapper
michael@0 598 {
michael@0 599 public:
michael@0 600 nsOuterWindowProxy() : js::Wrapper(0) { }
michael@0 601
michael@0 602 virtual bool finalizeInBackground(JS::Value priv) {
michael@0 603 return false;
michael@0 604 }
michael@0 605
michael@0 606 virtual const char *className(JSContext *cx,
michael@0 607 JS::Handle<JSObject*> wrapper) MOZ_OVERRIDE;
michael@0 608 virtual void finalize(JSFreeOp *fop, JSObject *proxy) MOZ_OVERRIDE;
michael@0 609
michael@0 610 // Fundamental traps
michael@0 611 virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
michael@0 612 MOZ_OVERRIDE;
michael@0 613 virtual bool preventExtensions(JSContext *cx,
michael@0 614 JS::Handle<JSObject*> proxy) MOZ_OVERRIDE;
michael@0 615 virtual bool getPropertyDescriptor(JSContext* cx,
michael@0 616 JS::Handle<JSObject*> proxy,
michael@0 617 JS::Handle<jsid> id,
michael@0 618 JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 619 virtual bool getOwnPropertyDescriptor(JSContext* cx,
michael@0 620 JS::Handle<JSObject*> proxy,
michael@0 621 JS::Handle<jsid> id,
michael@0 622 JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 623 virtual bool defineProperty(JSContext* cx,
michael@0 624 JS::Handle<JSObject*> proxy,
michael@0 625 JS::Handle<jsid> id,
michael@0 626 JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 627 virtual bool getOwnPropertyNames(JSContext *cx,
michael@0 628 JS::Handle<JSObject*> proxy,
michael@0 629 JS::AutoIdVector &props) MOZ_OVERRIDE;
michael@0 630 virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 631 JS::Handle<jsid> id,
michael@0 632 bool *bp) MOZ_OVERRIDE;
michael@0 633 virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 634 JS::AutoIdVector &props) MOZ_OVERRIDE;
michael@0 635
michael@0 636 virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 637 JS::Handle<jsid> id, JS::Handle<JSObject*> callable) MOZ_OVERRIDE;
michael@0 638 virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 639 JS::Handle<jsid> id) MOZ_OVERRIDE;
michael@0 640
michael@0 641 // Derived traps
michael@0 642 virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 643 JS::Handle<jsid> id, bool *bp) MOZ_OVERRIDE;
michael@0 644 virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 645 JS::Handle<jsid> id, bool *bp) MOZ_OVERRIDE;
michael@0 646 virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 647 JS::Handle<JSObject*> receiver,
michael@0 648 JS::Handle<jsid> id,
michael@0 649 JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
michael@0 650 virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 651 JS::Handle<JSObject*> receiver,
michael@0 652 JS::Handle<jsid> id,
michael@0 653 bool strict,
michael@0 654 JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
michael@0 655 virtual bool keys(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 656 JS::AutoIdVector &props) MOZ_OVERRIDE;
michael@0 657 virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 658 unsigned flags,
michael@0 659 JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
michael@0 660
michael@0 661 static nsOuterWindowProxy singleton;
michael@0 662
michael@0 663 protected:
michael@0 664 nsGlobalWindow* GetWindow(JSObject *proxy)
michael@0 665 {
michael@0 666 return nsGlobalWindow::FromSupports(
michael@0 667 static_cast<nsISupports*>(js::GetProxyExtra(proxy, 0).toPrivate()));
michael@0 668 }
michael@0 669
michael@0 670 // False return value means we threw an exception. True return value
michael@0 671 // but false "found" means we didn't have a subframe at that index.
michael@0 672 bool GetSubframeWindow(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 673 JS::Handle<jsid> id,
michael@0 674 JS::MutableHandle<JS::Value> vp,
michael@0 675 bool &found);
michael@0 676
michael@0 677 // Returns a non-null window only if id is an index and we have a
michael@0 678 // window at that index.
michael@0 679 already_AddRefed<nsIDOMWindow> GetSubframeWindow(JSContext *cx,
michael@0 680 JS::Handle<JSObject*> proxy,
michael@0 681 JS::Handle<jsid> id);
michael@0 682
michael@0 683 bool AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
michael@0 684 JS::AutoIdVector &props);
michael@0 685 };
michael@0 686
michael@0 687 const js::Class OuterWindowProxyClass =
michael@0 688 PROXY_CLASS_WITH_EXT(
michael@0 689 "Proxy",
michael@0 690 0, /* additional slots */
michael@0 691 0, /* additional class flags */
michael@0 692 nullptr, /* call */
michael@0 693 nullptr, /* construct */
michael@0 694 PROXY_MAKE_EXT(
michael@0 695 nullptr, /* outerObject */
michael@0 696 js::proxy_innerObject,
michael@0 697 nullptr, /* iteratorObject */
michael@0 698 false /* isWrappedNative */
michael@0 699 ));
michael@0 700
michael@0 701 bool
michael@0 702 nsOuterWindowProxy::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 703 bool *extensible)
michael@0 704 {
michael@0 705 // If [[Extensible]] could be false, then navigating a window could navigate
michael@0 706 // to a window that's [[Extensible]] after being at one that wasn't: an
michael@0 707 // invariant violation. So always report true for this.
michael@0 708 *extensible = true;
michael@0 709 return true;
michael@0 710 }
michael@0 711
michael@0 712 bool
michael@0 713 nsOuterWindowProxy::preventExtensions(JSContext *cx,
michael@0 714 JS::Handle<JSObject*> proxy)
michael@0 715 {
michael@0 716 // See above.
michael@0 717 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
michael@0 718 JSMSG_CANT_CHANGE_EXTENSIBILITY);
michael@0 719 return false;
michael@0 720 }
michael@0 721
michael@0 722 const char *
michael@0 723 nsOuterWindowProxy::className(JSContext *cx, JS::Handle<JSObject*> proxy)
michael@0 724 {
michael@0 725 MOZ_ASSERT(js::IsProxy(proxy));
michael@0 726
michael@0 727 return "Window";
michael@0 728 }
michael@0 729
michael@0 730 void
michael@0 731 nsOuterWindowProxy::finalize(JSFreeOp *fop, JSObject *proxy)
michael@0 732 {
michael@0 733 nsGlobalWindow* global = GetWindow(proxy);
michael@0 734 if (global) {
michael@0 735 global->ClearWrapper();
michael@0 736
michael@0 737 // Ideally we would use OnFinalize here, but it's possible that
michael@0 738 // EnsureScriptEnvironment will later be called on the window, and we don't
michael@0 739 // want to create a new script object in that case. Therefore, we need to
michael@0 740 // write a non-null value that will reliably crash when dereferenced.
michael@0 741 global->PoisonOuterWindowProxy(proxy);
michael@0 742 }
michael@0 743 }
michael@0 744
michael@0 745 bool
michael@0 746 nsOuterWindowProxy::getPropertyDescriptor(JSContext* cx,
michael@0 747 JS::Handle<JSObject*> proxy,
michael@0 748 JS::Handle<jsid> id,
michael@0 749 JS::MutableHandle<JSPropertyDescriptor> desc)
michael@0 750 {
michael@0 751 // The only thing we can do differently from js::Wrapper is shadow stuff with
michael@0 752 // our indexed properties, so we can just try getOwnPropertyDescriptor and if
michael@0 753 // that gives us nothing call on through to js::Wrapper.
michael@0 754 desc.object().set(nullptr);
michael@0 755 if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) {
michael@0 756 return false;
michael@0 757 }
michael@0 758
michael@0 759 if (desc.object()) {
michael@0 760 return true;
michael@0 761 }
michael@0 762
michael@0 763 return js::Wrapper::getPropertyDescriptor(cx, proxy, id, desc);
michael@0 764 }
michael@0 765
michael@0 766 bool
michael@0 767 nsOuterWindowProxy::getOwnPropertyDescriptor(JSContext* cx,
michael@0 768 JS::Handle<JSObject*> proxy,
michael@0 769 JS::Handle<jsid> id,
michael@0 770 JS::MutableHandle<JSPropertyDescriptor> desc)
michael@0 771 {
michael@0 772 bool found;
michael@0 773 if (!GetSubframeWindow(cx, proxy, id, desc.value(), found)) {
michael@0 774 return false;
michael@0 775 }
michael@0 776 if (found) {
michael@0 777 FillPropertyDescriptor(desc, proxy, true);
michael@0 778 return true;
michael@0 779 }
michael@0 780 // else fall through to js::Wrapper
michael@0 781
michael@0 782 return js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
michael@0 783 }
michael@0 784
michael@0 785 bool
michael@0 786 nsOuterWindowProxy::defineProperty(JSContext* cx,
michael@0 787 JS::Handle<JSObject*> proxy,
michael@0 788 JS::Handle<jsid> id,
michael@0 789 JS::MutableHandle<JSPropertyDescriptor> desc)
michael@0 790 {
michael@0 791 int32_t index = GetArrayIndexFromId(cx, id);
michael@0 792 if (IsArrayIndex(index)) {
michael@0 793 // Spec says to Reject whether this is a supported index or not,
michael@0 794 // since we have no indexed setter or indexed creator. That means
michael@0 795 // throwing in strict mode (FIXME: Bug 828137), doing nothing in
michael@0 796 // non-strict mode.
michael@0 797 return true;
michael@0 798 }
michael@0 799
michael@0 800 return js::Wrapper::defineProperty(cx, proxy, id, desc);
michael@0 801 }
michael@0 802
michael@0 803 bool
michael@0 804 nsOuterWindowProxy::getOwnPropertyNames(JSContext *cx,
michael@0 805 JS::Handle<JSObject*> proxy,
michael@0 806 JS::AutoIdVector &props)
michael@0 807 {
michael@0 808 // Just our indexed stuff followed by our "normal" own property names.
michael@0 809 if (!AppendIndexedPropertyNames(cx, proxy, props)) {
michael@0 810 return false;
michael@0 811 }
michael@0 812
michael@0 813 JS::AutoIdVector innerProps(cx);
michael@0 814 if (!js::Wrapper::getOwnPropertyNames(cx, proxy, innerProps)) {
michael@0 815 return false;
michael@0 816 }
michael@0 817 return js::AppendUnique(cx, props, innerProps);
michael@0 818 }
michael@0 819
michael@0 820 bool
michael@0 821 nsOuterWindowProxy::delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 822 JS::Handle<jsid> id, bool *bp)
michael@0 823 {
michael@0 824 if (nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id)) {
michael@0 825 // Reject (which means throw if strict, else return false) the delete.
michael@0 826 // Except we don't even know whether we're strict. See bug 803157.
michael@0 827 *bp = false;
michael@0 828 return true;
michael@0 829 }
michael@0 830
michael@0 831 int32_t index = GetArrayIndexFromId(cx, id);
michael@0 832 if (IsArrayIndex(index)) {
michael@0 833 // Indexed, but not supported. Spec says return true.
michael@0 834 *bp = true;
michael@0 835 return true;
michael@0 836 }
michael@0 837
michael@0 838 return js::Wrapper::delete_(cx, proxy, id, bp);
michael@0 839 }
michael@0 840
michael@0 841 bool
michael@0 842 nsOuterWindowProxy::enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 843 JS::AutoIdVector &props)
michael@0 844 {
michael@0 845 // Just our indexed stuff followed by our "normal" own property names.
michael@0 846 if (!AppendIndexedPropertyNames(cx, proxy, props)) {
michael@0 847 return false;
michael@0 848 }
michael@0 849
michael@0 850 JS::AutoIdVector innerProps(cx);
michael@0 851 if (!js::Wrapper::enumerate(cx, proxy, innerProps)) {
michael@0 852 return false;
michael@0 853 }
michael@0 854 return js::AppendUnique(cx, props, innerProps);
michael@0 855 }
michael@0 856
michael@0 857 bool
michael@0 858 nsOuterWindowProxy::has(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 859 JS::Handle<jsid> id, bool *bp)
michael@0 860 {
michael@0 861 if (nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id)) {
michael@0 862 *bp = true;
michael@0 863 return true;
michael@0 864 }
michael@0 865
michael@0 866 return js::Wrapper::has(cx, proxy, id, bp);
michael@0 867 }
michael@0 868
michael@0 869 bool
michael@0 870 nsOuterWindowProxy::hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 871 JS::Handle<jsid> id, bool *bp)
michael@0 872 {
michael@0 873 if (nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id)) {
michael@0 874 *bp = true;
michael@0 875 return true;
michael@0 876 }
michael@0 877
michael@0 878 return js::Wrapper::hasOwn(cx, proxy, id, bp);
michael@0 879 }
michael@0 880
michael@0 881 bool
michael@0 882 nsOuterWindowProxy::get(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 883 JS::Handle<JSObject*> receiver,
michael@0 884 JS::Handle<jsid> id,
michael@0 885 JS::MutableHandle<JS::Value> vp)
michael@0 886 {
michael@0 887 if (id == nsDOMClassInfo::sWrappedJSObject_id &&
michael@0 888 xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
michael@0 889 vp.set(JS::ObjectValue(*proxy));
michael@0 890 return true;
michael@0 891 }
michael@0 892
michael@0 893 bool found;
michael@0 894 if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
michael@0 895 return false;
michael@0 896 }
michael@0 897 if (found) {
michael@0 898 return true;
michael@0 899 }
michael@0 900 // Else fall through to js::Wrapper
michael@0 901
michael@0 902 return js::Wrapper::get(cx, proxy, receiver, id, vp);
michael@0 903 }
michael@0 904
michael@0 905 bool
michael@0 906 nsOuterWindowProxy::set(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 907 JS::Handle<JSObject*> receiver,
michael@0 908 JS::Handle<jsid> id,
michael@0 909 bool strict,
michael@0 910 JS::MutableHandle<JS::Value> vp)
michael@0 911 {
michael@0 912 int32_t index = GetArrayIndexFromId(cx, id);
michael@0 913 if (IsArrayIndex(index)) {
michael@0 914 // Reject (which means throw if and only if strict) the set.
michael@0 915 if (strict) {
michael@0 916 // XXXbz This needs to throw, but see bug 828137.
michael@0 917 }
michael@0 918 return true;
michael@0 919 }
michael@0 920
michael@0 921 return js::Wrapper::set(cx, proxy, receiver, id, strict, vp);
michael@0 922 }
michael@0 923
michael@0 924 bool
michael@0 925 nsOuterWindowProxy::keys(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 926 JS::AutoIdVector &props)
michael@0 927 {
michael@0 928 // BaseProxyHandler::keys seems to do what we want here: call
michael@0 929 // getOwnPropertyNames and then filter out the non-enumerable properties.
michael@0 930 return js::BaseProxyHandler::keys(cx, proxy, props);
michael@0 931 }
michael@0 932
michael@0 933 bool
michael@0 934 nsOuterWindowProxy::iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 935 unsigned flags, JS::MutableHandle<JS::Value> vp)
michael@0 936 {
michael@0 937 // BaseProxyHandler::iterate seems to do what we want here: fall
michael@0 938 // back on the property names returned from keys() and enumerate().
michael@0 939 return js::BaseProxyHandler::iterate(cx, proxy, flags, vp);
michael@0 940 }
michael@0 941
michael@0 942 bool
michael@0 943 nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
michael@0 944 JS::Handle<JSObject*> proxy,
michael@0 945 JS::Handle<jsid> id,
michael@0 946 JS::MutableHandle<JS::Value> vp,
michael@0 947 bool& found)
michael@0 948 {
michael@0 949 nsCOMPtr<nsIDOMWindow> frame = GetSubframeWindow(cx, proxy, id);
michael@0 950 if (!frame) {
michael@0 951 found = false;
michael@0 952 return true;
michael@0 953 }
michael@0 954
michael@0 955 found = true;
michael@0 956 // Just return the window's global
michael@0 957 nsGlobalWindow* global = static_cast<nsGlobalWindow*>(frame.get());
michael@0 958 global->EnsureInnerWindow();
michael@0 959 JSObject* obj = global->FastGetGlobalJSObject();
michael@0 960 // This null check fixes a hard-to-reproduce crash that occurs when we
michael@0 961 // get here when we're mid-call to nsDocShell::Destroy. See bug 640904
michael@0 962 // comment 105.
michael@0 963 if (MOZ_UNLIKELY(!obj)) {
michael@0 964 return xpc::Throw(cx, NS_ERROR_FAILURE);
michael@0 965 }
michael@0 966
michael@0 967 vp.setObject(*obj);
michael@0 968 return JS_WrapValue(cx, vp);
michael@0 969 }
michael@0 970
michael@0 971 already_AddRefed<nsIDOMWindow>
michael@0 972 nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
michael@0 973 JS::Handle<JSObject*> proxy,
michael@0 974 JS::Handle<jsid> id)
michael@0 975 {
michael@0 976 int32_t index = GetArrayIndexFromId(cx, id);
michael@0 977 if (!IsArrayIndex(index)) {
michael@0 978 return nullptr;
michael@0 979 }
michael@0 980
michael@0 981 nsGlobalWindow* win = GetWindow(proxy);
michael@0 982 bool unused;
michael@0 983 return win->IndexedGetter(index, unused);
michael@0 984 }
michael@0 985
michael@0 986 bool
michael@0 987 nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
michael@0 988 JS::AutoIdVector &props)
michael@0 989 {
michael@0 990 uint32_t length = GetWindow(proxy)->Length();
michael@0 991 MOZ_ASSERT(int32_t(length) >= 0);
michael@0 992 if (!props.reserve(props.length() + length)) {
michael@0 993 return false;
michael@0 994 }
michael@0 995 for (int32_t i = 0; i < int32_t(length); ++i) {
michael@0 996 props.append(INT_TO_JSID(i));
michael@0 997 }
michael@0 998
michael@0 999 return true;
michael@0 1000 }
michael@0 1001
michael@0 1002 bool
michael@0 1003 nsOuterWindowProxy::watch(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 1004 JS::Handle<jsid> id, JS::Handle<JSObject*> callable)
michael@0 1005 {
michael@0 1006 return js::WatchGuts(cx, proxy, id, callable);
michael@0 1007 }
michael@0 1008
michael@0 1009 bool
michael@0 1010 nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
michael@0 1011 JS::Handle<jsid> id)
michael@0 1012 {
michael@0 1013 return js::UnwatchGuts(cx, proxy, id);
michael@0 1014 }
michael@0 1015
michael@0 1016 nsOuterWindowProxy
michael@0 1017 nsOuterWindowProxy::singleton;
michael@0 1018
michael@0 1019 class nsChromeOuterWindowProxy : public nsOuterWindowProxy
michael@0 1020 {
michael@0 1021 public:
michael@0 1022 nsChromeOuterWindowProxy() : nsOuterWindowProxy() {}
michael@0 1023
michael@0 1024 virtual const char *className(JSContext *cx, JS::Handle<JSObject*> wrapper) MOZ_OVERRIDE;
michael@0 1025
michael@0 1026 static nsChromeOuterWindowProxy singleton;
michael@0 1027 };
michael@0 1028
michael@0 1029 const char *
michael@0 1030 nsChromeOuterWindowProxy::className(JSContext *cx,
michael@0 1031 JS::Handle<JSObject*> proxy)
michael@0 1032 {
michael@0 1033 MOZ_ASSERT(js::IsProxy(proxy));
michael@0 1034
michael@0 1035 return "ChromeWindow";
michael@0 1036 }
michael@0 1037
michael@0 1038 nsChromeOuterWindowProxy
michael@0 1039 nsChromeOuterWindowProxy::singleton;
michael@0 1040
michael@0 1041 static JSObject*
michael@0 1042 NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> parent, bool isChrome)
michael@0 1043 {
michael@0 1044 JSAutoCompartment ac(cx, parent);
michael@0 1045 js::WrapperOptions options;
michael@0 1046 options.setClass(&OuterWindowProxyClass);
michael@0 1047 options.setSingleton(true);
michael@0 1048 JSObject *obj = js::Wrapper::New(cx, parent, parent,
michael@0 1049 isChrome ? &nsChromeOuterWindowProxy::singleton
michael@0 1050 : &nsOuterWindowProxy::singleton,
michael@0 1051 &options);
michael@0 1052
michael@0 1053 NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
michael@0 1054 return obj;
michael@0 1055 }
michael@0 1056
michael@0 1057 //*****************************************************************************
michael@0 1058 //*** nsGlobalWindow: Object Management
michael@0 1059 //*****************************************************************************
michael@0 1060
michael@0 1061 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
michael@0 1062 : nsPIDOMWindow(aOuterWindow),
michael@0 1063 mIdleFuzzFactor(0),
michael@0 1064 mIdleCallbackIndex(-1),
michael@0 1065 mCurrentlyIdle(false),
michael@0 1066 mAddActiveEventFuzzTime(true),
michael@0 1067 mIsFrozen(false),
michael@0 1068 mFullScreen(false),
michael@0 1069 mIsClosed(false),
michael@0 1070 mInClose(false),
michael@0 1071 mHavePendingClose(false),
michael@0 1072 mHadOriginalOpener(false),
michael@0 1073 mIsPopupSpam(false),
michael@0 1074 mBlockScriptedClosingFlag(false),
michael@0 1075 mFireOfflineStatusChangeEventOnThaw(false),
michael@0 1076 mNotifyIdleObserversIdleOnThaw(false),
michael@0 1077 mNotifyIdleObserversActiveOnThaw(false),
michael@0 1078 mCreatingInnerWindow(false),
michael@0 1079 mIsChrome(false),
michael@0 1080 mCleanMessageManager(false),
michael@0 1081 mNeedsFocus(true),
michael@0 1082 mHasFocus(false),
michael@0 1083 #if defined(XP_MACOSX)
michael@0 1084 mShowAccelerators(false),
michael@0 1085 mShowFocusRings(false),
michael@0 1086 #else
michael@0 1087 mShowAccelerators(true),
michael@0 1088 mShowFocusRings(true),
michael@0 1089 #endif
michael@0 1090 mShowFocusRingForContent(false),
michael@0 1091 mFocusByKeyOccurred(false),
michael@0 1092 mInnerObjectsFreed(false),
michael@0 1093 mHasGamepad(false),
michael@0 1094 #ifdef MOZ_GAMEPAD
michael@0 1095 mHasSeenGamepadInput(false),
michael@0 1096 #endif
michael@0 1097 mNotifiedIDDestroyed(false),
michael@0 1098 mAllowScriptsToClose(false),
michael@0 1099 mTimeoutInsertionPoint(nullptr),
michael@0 1100 mTimeoutPublicIdCounter(1),
michael@0 1101 mTimeoutFiringDepth(0),
michael@0 1102 mTimeoutsSuspendDepth(0),
michael@0 1103 mFocusMethod(0),
michael@0 1104 mSerial(0),
michael@0 1105 #ifdef DEBUG
michael@0 1106 mSetOpenerWindowCalled(false),
michael@0 1107 #endif
michael@0 1108 #ifdef MOZ_B2G
michael@0 1109 mNetworkUploadObserverEnabled(false),
michael@0 1110 mNetworkDownloadObserverEnabled(false),
michael@0 1111 #endif
michael@0 1112 mCleanedUp(false),
michael@0 1113 mDialogAbuseCount(0),
michael@0 1114 mAreDialogsEnabled(true)
michael@0 1115 {
michael@0 1116 nsLayoutStatics::AddRef();
michael@0 1117
michael@0 1118 // Initialize the PRCList (this).
michael@0 1119 PR_INIT_CLIST(this);
michael@0 1120
michael@0 1121 if (aOuterWindow) {
michael@0 1122 // |this| is an inner window, add this inner window to the outer
michael@0 1123 // window list of inners.
michael@0 1124 PR_INSERT_AFTER(this, aOuterWindow);
michael@0 1125
michael@0 1126 mObserver = new nsGlobalWindowObserver(this);
michael@0 1127 if (mObserver) {
michael@0 1128 NS_ADDREF(mObserver);
michael@0 1129 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
michael@0 1130 if (os) {
michael@0 1131 // Watch for online/offline status changes so we can fire events. Use
michael@0 1132 // a strong reference.
michael@0 1133 os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
michael@0 1134 false);
michael@0 1135
michael@0 1136 // Watch for dom-storage2-changed so we can fire storage
michael@0 1137 // events. Use a strong reference.
michael@0 1138 os->AddObserver(mObserver, "dom-storage2-changed", false);
michael@0 1139 }
michael@0 1140 }
michael@0 1141 } else {
michael@0 1142 // |this| is an outer window. Outer windows start out frozen and
michael@0 1143 // remain frozen until they get an inner window, so freeze this
michael@0 1144 // outer window here.
michael@0 1145 Freeze();
michael@0 1146
michael@0 1147 mObserver = nullptr;
michael@0 1148 SetIsDOMBinding();
michael@0 1149 }
michael@0 1150
michael@0 1151 // We could have failed the first time through trying
michael@0 1152 // to create the entropy collector, so we should
michael@0 1153 // try to get one until we succeed.
michael@0 1154
michael@0 1155 gRefCnt++;
michael@0 1156
michael@0 1157 if (gRefCnt == 1) {
michael@0 1158 Preferences::AddIntVarCache(&gMinTimeoutValue,
michael@0 1159 "dom.min_timeout_value",
michael@0 1160 DEFAULT_MIN_TIMEOUT_VALUE);
michael@0 1161 Preferences::AddIntVarCache(&gMinBackgroundTimeoutValue,
michael@0 1162 "dom.min_background_timeout_value",
michael@0 1163 DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE);
michael@0 1164 Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled,
michael@0 1165 "dom.idle-observers-api.fuzz_time.disabled",
michael@0 1166 false);
michael@0 1167 }
michael@0 1168
michael@0 1169 if (gDumpFile == nullptr) {
michael@0 1170 const nsAdoptingCString& fname =
michael@0 1171 Preferences::GetCString("browser.dom.window.dump.file");
michael@0 1172 if (!fname.IsEmpty()) {
michael@0 1173 // if this fails to open, Dump() knows to just go to stdout
michael@0 1174 // on null.
michael@0 1175 gDumpFile = fopen(fname, "wb+");
michael@0 1176 } else {
michael@0 1177 gDumpFile = stdout;
michael@0 1178 }
michael@0 1179 }
michael@0 1180
michael@0 1181 mSerial = ++gSerialCounter;
michael@0 1182
michael@0 1183 #ifdef DEBUG
michael@0 1184 if (!PR_GetEnv("MOZ_QUIET")) {
michael@0 1185 printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
michael@0 1186 gRefCnt,
michael@0 1187 static_cast<void*>(ToCanonicalSupports(this)),
michael@0 1188 getpid(),
michael@0 1189 gSerialCounter,
michael@0 1190 static_cast<void*>(ToCanonicalSupports(aOuterWindow)));
michael@0 1191 }
michael@0 1192 #endif
michael@0 1193
michael@0 1194 #ifdef PR_LOGGING
michael@0 1195 if (gDOMLeakPRLog)
michael@0 1196 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
michael@0 1197 ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
michael@0 1198 #endif
michael@0 1199
michael@0 1200 NS_ASSERTION(sWindowsById, "Windows hash table must be created!");
michael@0 1201 NS_ASSERTION(!sWindowsById->Get(mWindowID),
michael@0 1202 "This window shouldn't be in the hash table yet!");
michael@0 1203 // We seem to see crashes in release builds because of null |sWindowsById|.
michael@0 1204 if (sWindowsById) {
michael@0 1205 sWindowsById->Put(mWindowID, this);
michael@0 1206 }
michael@0 1207 }
michael@0 1208
michael@0 1209 /* static */
michael@0 1210 void
michael@0 1211 nsGlobalWindow::Init()
michael@0 1212 {
michael@0 1213 CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
michael@0 1214 NS_ASSERTION(gEntropyCollector,
michael@0 1215 "gEntropyCollector should have been initialized!");
michael@0 1216
michael@0 1217 #ifdef PR_LOGGING
michael@0 1218 gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
michael@0 1219 NS_ASSERTION(gDOMLeakPRLog, "gDOMLeakPRLog should have been initialized!");
michael@0 1220 #endif
michael@0 1221
michael@0 1222 sWindowsById = new WindowByIdTable();
michael@0 1223 }
michael@0 1224
michael@0 1225 static PLDHashOperator
michael@0 1226 DisconnectEventTargetObjects(nsPtrHashKey<DOMEventTargetHelper>* aKey,
michael@0 1227 void* aClosure)
michael@0 1228 {
michael@0 1229 nsRefPtr<DOMEventTargetHelper> target = aKey->GetKey();
michael@0 1230 target->DisconnectFromOwner();
michael@0 1231 return PL_DHASH_NEXT;
michael@0 1232 }
michael@0 1233
michael@0 1234 nsGlobalWindow::~nsGlobalWindow()
michael@0 1235 {
michael@0 1236 mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
michael@0 1237 mEventTargetObjects.Clear();
michael@0 1238
michael@0 1239 // We have to check if sWindowsById isn't null because ::Shutdown might have
michael@0 1240 // been called.
michael@0 1241 if (sWindowsById) {
michael@0 1242 NS_ASSERTION(sWindowsById->Get(mWindowID),
michael@0 1243 "This window should be in the hash table");
michael@0 1244 sWindowsById->Remove(mWindowID);
michael@0 1245 }
michael@0 1246
michael@0 1247 --gRefCnt;
michael@0 1248
michael@0 1249 #ifdef DEBUG
michael@0 1250 if (!PR_GetEnv("MOZ_QUIET")) {
michael@0 1251 nsAutoCString url;
michael@0 1252 if (mLastOpenedURI) {
michael@0 1253 mLastOpenedURI->GetSpec(url);
michael@0 1254
michael@0 1255 // Data URLs can be very long, so truncate to avoid flooding the log.
michael@0 1256 const uint32_t maxURLLength = 1000;
michael@0 1257 if (url.Length() > maxURLLength) {
michael@0 1258 url.Truncate(maxURLLength);
michael@0 1259 }
michael@0 1260 }
michael@0 1261
michael@0 1262 nsGlobalWindow* outer = static_cast<nsGlobalWindow*>(mOuterWindow.get());
michael@0 1263 printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n",
michael@0 1264 gRefCnt,
michael@0 1265 static_cast<void*>(ToCanonicalSupports(this)),
michael@0 1266 getpid(),
michael@0 1267 mSerial,
michael@0 1268 static_cast<void*>(ToCanonicalSupports(outer)),
michael@0 1269 url.get());
michael@0 1270 }
michael@0 1271 #endif
michael@0 1272
michael@0 1273 #ifdef PR_LOGGING
michael@0 1274 if (gDOMLeakPRLog)
michael@0 1275 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
michael@0 1276 ("DOMWINDOW %p destroyed", this));
michael@0 1277 #endif
michael@0 1278
michael@0 1279 if (IsOuterWindow()) {
michael@0 1280 JSObject *proxy = GetWrapperPreserveColor();
michael@0 1281 if (proxy) {
michael@0 1282 js::SetProxyExtra(proxy, 0, js::PrivateValue(nullptr));
michael@0 1283 }
michael@0 1284
michael@0 1285 // An outer window is destroyed with inner windows still possibly
michael@0 1286 // alive, iterate through the inner windows and null out their
michael@0 1287 // back pointer to this outer, and pull them out of the list of
michael@0 1288 // inner windows.
michael@0 1289
michael@0 1290 nsGlobalWindow *w;
michael@0 1291 while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
michael@0 1292 PR_REMOVE_AND_INIT_LINK(w);
michael@0 1293 }
michael@0 1294
michael@0 1295 DropOuterWindowDocs();
michael@0 1296 } else {
michael@0 1297 Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
michael@0 1298 mMutationBits ? 1 : 0);
michael@0 1299
michael@0 1300 if (mListenerManager) {
michael@0 1301 mListenerManager->Disconnect();
michael@0 1302 mListenerManager = nullptr;
michael@0 1303 }
michael@0 1304
michael@0 1305 // An inner window is destroyed, pull it out of the outer window's
michael@0 1306 // list if inner windows.
michael@0 1307
michael@0 1308 PR_REMOVE_LINK(this);
michael@0 1309
michael@0 1310 // If our outer window's inner window is this window, null out the
michael@0 1311 // outer window's reference to this window that's being deleted.
michael@0 1312 nsGlobalWindow *outer = GetOuterWindowInternal();
michael@0 1313 if (outer) {
michael@0 1314 outer->MaybeClearInnerWindow(this);
michael@0 1315 }
michael@0 1316 }
michael@0 1317
michael@0 1318 // Outer windows are always supposed to call CleanUp before letting themselves
michael@0 1319 // be destroyed. And while CleanUp generally seems to be intended to clean up
michael@0 1320 // outers, we've historically called it for both. Changing this would probably
michael@0 1321 // involve auditing all of the references that inners and outers can have, and
michael@0 1322 // separating the handling into CleanUp() and FreeInnerObjects.
michael@0 1323 if (IsInnerWindow()) {
michael@0 1324 CleanUp();
michael@0 1325 } else {
michael@0 1326 MOZ_ASSERT(mCleanedUp);
michael@0 1327 }
michael@0 1328
michael@0 1329 nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
michael@0 1330 if (ac)
michael@0 1331 ac->RemoveWindowAsListener(this);
michael@0 1332
michael@0 1333 nsLayoutStatics::Release();
michael@0 1334 }
michael@0 1335
michael@0 1336 void
michael@0 1337 nsGlobalWindow::AddEventTargetObject(DOMEventTargetHelper* aObject)
michael@0 1338 {
michael@0 1339 mEventTargetObjects.PutEntry(aObject);
michael@0 1340 }
michael@0 1341
michael@0 1342 void
michael@0 1343 nsGlobalWindow::RemoveEventTargetObject(DOMEventTargetHelper* aObject)
michael@0 1344 {
michael@0 1345 mEventTargetObjects.RemoveEntry(aObject);
michael@0 1346 }
michael@0 1347
michael@0 1348 // static
michael@0 1349 void
michael@0 1350 nsGlobalWindow::ShutDown()
michael@0 1351 {
michael@0 1352 if (gDumpFile && gDumpFile != stdout) {
michael@0 1353 fclose(gDumpFile);
michael@0 1354 }
michael@0 1355 gDumpFile = nullptr;
michael@0 1356
michael@0 1357 NS_IF_RELEASE(gEntropyCollector);
michael@0 1358
michael@0 1359 delete sWindowsById;
michael@0 1360 sWindowsById = nullptr;
michael@0 1361 }
michael@0 1362
michael@0 1363 // static
michael@0 1364 void
michael@0 1365 nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
michael@0 1366 {
michael@0 1367 if (aWindow->mCachedXBLPrototypeHandlers &&
michael@0 1368 aWindow->mCachedXBLPrototypeHandlers->Count() > 0) {
michael@0 1369 aWindow->mCachedXBLPrototypeHandlers->Clear();
michael@0 1370 }
michael@0 1371 }
michael@0 1372
michael@0 1373 void
michael@0 1374 nsGlobalWindow::MaybeForgiveSpamCount()
michael@0 1375 {
michael@0 1376 if (IsOuterWindow() &&
michael@0 1377 IsPopupSpamWindow())
michael@0 1378 {
michael@0 1379 SetPopupSpamWindow(false);
michael@0 1380 --gOpenPopupSpamCount;
michael@0 1381 NS_ASSERTION(gOpenPopupSpamCount >= 0,
michael@0 1382 "Unbalanced decrement of gOpenPopupSpamCount");
michael@0 1383 }
michael@0 1384 }
michael@0 1385
michael@0 1386 void
michael@0 1387 nsGlobalWindow::DropOuterWindowDocs()
michael@0 1388 {
michael@0 1389 MOZ_ASSERT(IsOuterWindow());
michael@0 1390 MOZ_ASSERT_IF(mDoc, !mDoc->EventHandlingSuppressed());
michael@0 1391 mDoc = nullptr;
michael@0 1392 mSuspendedDoc = nullptr;
michael@0 1393 }
michael@0 1394
michael@0 1395 void
michael@0 1396 nsGlobalWindow::CleanUp()
michael@0 1397 {
michael@0 1398 // Guarantee idempotence.
michael@0 1399 if (mCleanedUp)
michael@0 1400 return;
michael@0 1401 mCleanedUp = true;
michael@0 1402
michael@0 1403 mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
michael@0 1404 mEventTargetObjects.Clear();
michael@0 1405
michael@0 1406 if (mObserver) {
michael@0 1407 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
michael@0 1408 if (os) {
michael@0 1409 os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
michael@0 1410 os->RemoveObserver(mObserver, "dom-storage2-changed");
michael@0 1411 }
michael@0 1412
michael@0 1413 #ifdef MOZ_B2G
michael@0 1414 DisableNetworkEvent(NS_NETWORK_UPLOAD_EVENT);
michael@0 1415 DisableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT);
michael@0 1416 #endif // MOZ_B2G
michael@0 1417
michael@0 1418 if (mIdleService) {
michael@0 1419 mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
michael@0 1420 }
michael@0 1421
michael@0 1422 // Drop its reference to this dying window, in case for some bogus reason
michael@0 1423 // the object stays around.
michael@0 1424 mObserver->Forget();
michael@0 1425 NS_RELEASE(mObserver);
michael@0 1426 }
michael@0 1427
michael@0 1428 if (mNavigator) {
michael@0 1429 mNavigator->Invalidate();
michael@0 1430 mNavigator = nullptr;
michael@0 1431 }
michael@0 1432
michael@0 1433 mScreen = nullptr;
michael@0 1434 mMenubar = nullptr;
michael@0 1435 mToolbar = nullptr;
michael@0 1436 mLocationbar = nullptr;
michael@0 1437 mPersonalbar = nullptr;
michael@0 1438 mStatusbar = nullptr;
michael@0 1439 mScrollbars = nullptr;
michael@0 1440 mLocation = nullptr;
michael@0 1441 mHistory = nullptr;
michael@0 1442 mFrames = nullptr;
michael@0 1443 mWindowUtils = nullptr;
michael@0 1444 mApplicationCache = nullptr;
michael@0 1445 mIndexedDB = nullptr;
michael@0 1446
michael@0 1447 mConsole = nullptr;
michael@0 1448
michael@0 1449 mExternal = nullptr;
michael@0 1450
michael@0 1451 mPerformance = nullptr;
michael@0 1452
michael@0 1453 #ifdef MOZ_WEBSPEECH
michael@0 1454 mSpeechSynthesis = nullptr;
michael@0 1455 #endif
michael@0 1456
michael@0 1457 ClearControllers();
michael@0 1458
michael@0 1459 mOpener = nullptr; // Forces Release
michael@0 1460 if (mContext) {
michael@0 1461 mContext = nullptr; // Forces Release
michael@0 1462 }
michael@0 1463 mChromeEventHandler = nullptr; // Forces Release
michael@0 1464 mParentTarget = nullptr;
michael@0 1465
michael@0 1466 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
michael@0 1467
michael@0 1468 if (inner) {
michael@0 1469 inner->CleanUp();
michael@0 1470 }
michael@0 1471
michael@0 1472 DisableGamepadUpdates();
michael@0 1473 mHasGamepad = false;
michael@0 1474
michael@0 1475 if (mCleanMessageManager) {
michael@0 1476 NS_ABORT_IF_FALSE(mIsChrome, "only chrome should have msg manager cleaned");
michael@0 1477 nsGlobalChromeWindow *asChrome = static_cast<nsGlobalChromeWindow*>(this);
michael@0 1478 if (asChrome->mMessageManager) {
michael@0 1479 static_cast<nsFrameMessageManager*>(
michael@0 1480 asChrome->mMessageManager.get())->Disconnect();
michael@0 1481 }
michael@0 1482 }
michael@0 1483
michael@0 1484 mArguments = nullptr;
michael@0 1485 mDialogArguments = nullptr;
michael@0 1486
michael@0 1487 CleanupCachedXBLHandlers(this);
michael@0 1488
michael@0 1489 for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
michael@0 1490 mAudioContexts[i]->Shutdown();
michael@0 1491 }
michael@0 1492 mAudioContexts.Clear();
michael@0 1493
michael@0 1494 if (mIdleTimer) {
michael@0 1495 mIdleTimer->Cancel();
michael@0 1496 mIdleTimer = nullptr;
michael@0 1497 }
michael@0 1498
michael@0 1499 DisableTimeChangeNotifications();
michael@0 1500 }
michael@0 1501
michael@0 1502 void
michael@0 1503 nsGlobalWindow::ClearControllers()
michael@0 1504 {
michael@0 1505 if (mControllers) {
michael@0 1506 uint32_t count;
michael@0 1507 mControllers->GetControllerCount(&count);
michael@0 1508
michael@0 1509 while (count--) {
michael@0 1510 nsCOMPtr<nsIController> controller;
michael@0 1511 mControllers->GetControllerAt(count, getter_AddRefs(controller));
michael@0 1512
michael@0 1513 nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
michael@0 1514 if (context)
michael@0 1515 context->SetCommandContext(nullptr);
michael@0 1516 }
michael@0 1517
michael@0 1518 mControllers = nullptr;
michael@0 1519 }
michael@0 1520 }
michael@0 1521
michael@0 1522 void
michael@0 1523 nsGlobalWindow::FreeInnerObjects()
michael@0 1524 {
michael@0 1525 NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
michael@0 1526
michael@0 1527 // Make sure that this is called before we null out the document and
michael@0 1528 // other members that the window destroyed observers could
michael@0 1529 // re-create.
michael@0 1530 NotifyDOMWindowDestroyed(this);
michael@0 1531
michael@0 1532 mInnerObjectsFreed = true;
michael@0 1533
michael@0 1534 // Kill all of the workers for this window.
michael@0 1535 mozilla::dom::workers::CancelWorkersForWindow(this);
michael@0 1536
michael@0 1537 // Close all offline storages for this window.
michael@0 1538 quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
michael@0 1539 if (quotaManager) {
michael@0 1540 quotaManager->AbortCloseStoragesForWindow(this);
michael@0 1541 }
michael@0 1542
michael@0 1543 ClearAllTimeouts();
michael@0 1544
michael@0 1545 if (mIdleTimer) {
michael@0 1546 mIdleTimer->Cancel();
michael@0 1547 mIdleTimer = nullptr;
michael@0 1548 }
michael@0 1549
michael@0 1550 mIdleObservers.Clear();
michael@0 1551
michael@0 1552 mChromeEventHandler = nullptr;
michael@0 1553
michael@0 1554 if (mListenerManager) {
michael@0 1555 mListenerManager->Disconnect();
michael@0 1556 mListenerManager = nullptr;
michael@0 1557 }
michael@0 1558
michael@0 1559 mLocation = nullptr;
michael@0 1560 mHistory = nullptr;
michael@0 1561
michael@0 1562 if (mNavigator) {
michael@0 1563 mNavigator->OnNavigation();
michael@0 1564 mNavigator->Invalidate();
michael@0 1565 mNavigator = nullptr;
michael@0 1566 }
michael@0 1567
michael@0 1568 if (mScreen) {
michael@0 1569 mScreen = nullptr;
michael@0 1570 }
michael@0 1571
michael@0 1572 if (mDoc) {
michael@0 1573 // Remember the document's principal and URI.
michael@0 1574 mDocumentPrincipal = mDoc->NodePrincipal();
michael@0 1575 mDocumentURI = mDoc->GetDocumentURI();
michael@0 1576 mDocBaseURI = mDoc->GetDocBaseURI();
michael@0 1577
michael@0 1578 while (mDoc->EventHandlingSuppressed()) {
michael@0 1579 mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false);
michael@0 1580 }
michael@0 1581
michael@0 1582 // Note: we don't have to worry about eAnimationsOnly suppressions because
michael@0 1583 // they won't leak.
michael@0 1584 }
michael@0 1585
michael@0 1586 // Remove our reference to the document and the document principal.
michael@0 1587 mFocusedNode = nullptr;
michael@0 1588
michael@0 1589 if (mApplicationCache) {
michael@0 1590 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
michael@0 1591 mApplicationCache = nullptr;
michael@0 1592 }
michael@0 1593
michael@0 1594 mIndexedDB = nullptr;
michael@0 1595
michael@0 1596 NotifyWindowIDDestroyed("inner-window-destroyed");
michael@0 1597
michael@0 1598 CleanupCachedXBLHandlers(this);
michael@0 1599
michael@0 1600 for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
michael@0 1601 mAudioContexts[i]->Shutdown();
michael@0 1602 }
michael@0 1603 mAudioContexts.Clear();
michael@0 1604
michael@0 1605 #ifdef MOZ_GAMEPAD
michael@0 1606 DisableGamepadUpdates();
michael@0 1607 mHasGamepad = false;
michael@0 1608 mGamepads.Clear();
michael@0 1609 #endif
michael@0 1610 }
michael@0 1611
michael@0 1612 //*****************************************************************************
michael@0 1613 // nsGlobalWindow::nsISupports
michael@0 1614 //*****************************************************************************
michael@0 1615
michael@0 1616 DOMCI_DATA(Window, nsGlobalWindow)
michael@0 1617
michael@0 1618 // QueryInterface implementation for nsGlobalWindow
michael@0 1619 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
michael@0 1620 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
michael@0 1621 // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
michael@0 1622 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
michael@0 1623 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
michael@0 1624 #ifdef MOZ_B2G
michael@0 1625 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowB2G)
michael@0 1626 #endif // MOZ_B2G
michael@0 1627 #ifdef MOZ_WEBSPEECH
michael@0 1628 NS_INTERFACE_MAP_ENTRY(nsISpeechSynthesisGetter)
michael@0 1629 #endif // MOZ_B2G
michael@0 1630 NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
michael@0 1631 if (aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) {
michael@0 1632 foundInterface = static_cast<nsIDOMWindowInternal*>(this);
michael@0 1633 if (!sWarnedAboutWindowInternal) {
michael@0 1634 sWarnedAboutWindowInternal = true;
michael@0 1635 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
michael@0 1636 NS_LITERAL_CSTRING("Extensions"), mDoc,
michael@0 1637 nsContentUtils::eDOM_PROPERTIES,
michael@0 1638 "nsIDOMWindowInternalWarning");
michael@0 1639 }
michael@0 1640 } else
michael@0 1641 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
michael@0 1642 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
michael@0 1643 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
michael@0 1644 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
michael@0 1645 NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
michael@0 1646 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
michael@0 1647 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
michael@0 1648 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
michael@0 1649 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowPerformance)
michael@0 1650 NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver)
michael@0 1651 NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
michael@0 1652 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
michael@0 1653 NS_INTERFACE_MAP_END
michael@0 1654
michael@0 1655
michael@0 1656 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
michael@0 1657 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
michael@0 1658
michael@0 1659 static PLDHashOperator
michael@0 1660 MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
michael@0 1661 {
michael@0 1662 JS::ExposeObjectToActiveJS(aData);
michael@0 1663 return PL_DHASH_NEXT;
michael@0 1664 }
michael@0 1665
michael@0 1666 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
michael@0 1667 if (tmp->IsBlackForCC(false)) {
michael@0 1668 if (tmp->mCachedXBLPrototypeHandlers) {
michael@0 1669 tmp->mCachedXBLPrototypeHandlers->Enumerate(MarkXBLHandlers, nullptr);
michael@0 1670 }
michael@0 1671 if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
michael@0 1672 elm->MarkForCC();
michael@0 1673 }
michael@0 1674 tmp->UnmarkGrayTimers();
michael@0 1675 return true;
michael@0 1676 }
michael@0 1677 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
michael@0 1678
michael@0 1679 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)
michael@0 1680 return tmp->IsBlackForCC(true);
michael@0 1681 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
michael@0 1682
michael@0 1683 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)
michael@0 1684 return tmp->IsBlackForCC(false);
michael@0 1685 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
michael@0 1686
michael@0 1687 inline void
michael@0 1688 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
michael@0 1689 IdleObserverHolder& aField,
michael@0 1690 const char* aName,
michael@0 1691 unsigned aFlags)
michael@0 1692 {
michael@0 1693 CycleCollectionNoteChild(aCallback, aField.mIdleObserver.get(), aName, aFlags);
michael@0 1694 }
michael@0 1695
michael@0 1696 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
michael@0 1697
michael@0 1698 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
michael@0 1699 if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
michael@0 1700 char name[512];
michael@0 1701 PR_snprintf(name, sizeof(name), "nsGlobalWindow #%ld", tmp->mWindowID);
michael@0 1702 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
michael@0 1703 } else {
michael@0 1704 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow, tmp->mRefCnt.get())
michael@0 1705 }
michael@0 1706
michael@0 1707 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
michael@0 1708
michael@0 1709 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
michael@0 1710 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
michael@0 1711 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments)
michael@0 1712 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue)
michael@0 1713 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
michael@0 1714
michael@0 1715 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
michael@0 1716
michael@0 1717 #ifdef MOZ_WEBSPEECH
michael@0 1718 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
michael@0 1719 #endif
michael@0 1720
michael@0 1721 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)
michael@0 1722
michael@0 1723 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
michael@0 1724
michael@0 1725 for (nsTimeout* timeout = tmp->mTimeouts.getFirst();
michael@0 1726 timeout;
michael@0 1727 timeout = timeout->getNext()) {
michael@0 1728 cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(nsTimeout));
michael@0 1729 }
michael@0 1730
michael@0 1731 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
michael@0 1732 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
michael@0 1733 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
michael@0 1734 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
michael@0 1735 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
michael@0 1736 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
michael@0 1737 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
michael@0 1738 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
michael@0 1739
michael@0 1740 #ifdef MOZ_GAMEPAD
michael@0 1741 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
michael@0 1742 #endif
michael@0 1743
michael@0 1744 // Traverse stuff from nsPIDOMWindow
michael@0 1745 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
michael@0 1746 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
michael@0 1747 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
michael@0 1748 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode)
michael@0 1749
michael@0 1750 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
michael@0 1751 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
michael@0 1752 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
michael@0 1753 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
michael@0 1754 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
michael@0 1755 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
michael@0 1756 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
michael@0 1757 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
michael@0 1758 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
michael@0 1759 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
michael@0 1760 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 1761
michael@0 1762 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
michael@0 1763 nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
michael@0 1764
michael@0 1765 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
michael@0 1766
michael@0 1767 NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
michael@0 1768 NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
michael@0 1769 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments)
michael@0 1770 NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue)
michael@0 1771 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
michael@0 1772
michael@0 1773 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
michael@0 1774
michael@0 1775 #ifdef MOZ_WEBSPEECH
michael@0 1776 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
michael@0 1777 #endif
michael@0 1778
michael@0 1779 if (tmp->mOuterWindow) {
michael@0 1780 static_cast<nsGlobalWindow*>(tmp->mOuterWindow.get())->MaybeClearInnerWindow(tmp);
michael@0 1781 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
michael@0 1782 }
michael@0 1783
michael@0 1784 if (tmp->mListenerManager) {
michael@0 1785 tmp->mListenerManager->Disconnect();
michael@0 1786 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
michael@0 1787 }
michael@0 1788 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
michael@0 1789 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
michael@0 1790 if (tmp->mApplicationCache) {
michael@0 1791 static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();
michael@0 1792 NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
michael@0 1793 }
michael@0 1794 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
michael@0 1795 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
michael@0 1796 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
michael@0 1797 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
michael@0 1798 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
michael@0 1799
michael@0 1800 #ifdef MOZ_GAMEPAD
michael@0 1801 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
michael@0 1802 #endif
michael@0 1803
michael@0 1804 // Unlink stuff from nsPIDOMWindow
michael@0 1805 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
michael@0 1806 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
michael@0 1807 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
michael@0 1808 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode)
michael@0 1809
michael@0 1810 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
michael@0 1811 NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
michael@0 1812 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
michael@0 1813 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
michael@0 1814 NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
michael@0 1815 NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
michael@0 1816 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
michael@0 1817 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
michael@0 1818 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
michael@0 1819 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
michael@0 1820 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
michael@0 1821
michael@0 1822 #ifdef DEBUG
michael@0 1823 void
michael@0 1824 nsGlobalWindow::RiskyUnlink()
michael@0 1825 {
michael@0 1826 NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);
michael@0 1827 }
michael@0 1828 #endif
michael@0 1829
michael@0 1830 struct TraceData
michael@0 1831 {
michael@0 1832 const TraceCallbacks& callbacks;
michael@0 1833 void* closure;
michael@0 1834 };
michael@0 1835
michael@0 1836 static PLDHashOperator
michael@0 1837 TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
michael@0 1838 {
michael@0 1839 TraceData* data = static_cast<TraceData*>(aClosure);
michael@0 1840 data->callbacks.Trace(&aData, "Cached XBL prototype handler", data->closure);
michael@0 1841 return PL_DHASH_NEXT;
michael@0 1842 }
michael@0 1843
michael@0 1844 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
michael@0 1845 if (tmp->mCachedXBLPrototypeHandlers) {
michael@0 1846 TraceData data = { aCallbacks, aClosure };
michael@0 1847 tmp->mCachedXBLPrototypeHandlers->Enumerate(TraceXBLHandlers, &data);
michael@0 1848 }
michael@0 1849 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
michael@0 1850 NS_IMPL_CYCLE_COLLECTION_TRACE_END
michael@0 1851
michael@0 1852 bool
michael@0 1853 nsGlobalWindow::IsBlackForCC(bool aTracingNeeded)
michael@0 1854 {
michael@0 1855 if (!nsCCUncollectableMarker::sGeneration) {
michael@0 1856 return false;
michael@0 1857 }
michael@0 1858
michael@0 1859 return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
michael@0 1860 IsBlack()) &&
michael@0 1861 (!aTracingNeeded ||
michael@0 1862 HasNothingToTrace(static_cast<nsIDOMEventTarget*>(this)));
michael@0 1863 }
michael@0 1864
michael@0 1865 void
michael@0 1866 nsGlobalWindow::UnmarkGrayTimers()
michael@0 1867 {
michael@0 1868 for (nsTimeout* timeout = mTimeouts.getFirst();
michael@0 1869 timeout;
michael@0 1870 timeout = timeout->getNext()) {
michael@0 1871 if (timeout->mScriptHandler) {
michael@0 1872 Function* f = timeout->mScriptHandler->GetCallback();
michael@0 1873 if (f) {
michael@0 1874 // Callable() already does xpc_UnmarkGrayObject.
michael@0 1875 DebugOnly<JS::Handle<JSObject*> > o = f->Callable();
michael@0 1876 MOZ_ASSERT(!xpc_IsGrayGCThing(o.value), "Should have been unmarked");
michael@0 1877 }
michael@0 1878 }
michael@0 1879 }
michael@0 1880 }
michael@0 1881
michael@0 1882 //*****************************************************************************
michael@0 1883 // nsGlobalWindow::nsIScriptGlobalObject
michael@0 1884 //*****************************************************************************
michael@0 1885
michael@0 1886 nsresult
michael@0 1887 nsGlobalWindow::EnsureScriptEnvironment()
michael@0 1888 {
michael@0 1889 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 1890 if (!outer) {
michael@0 1891 NS_WARNING("No outer window available!");
michael@0 1892 return NS_ERROR_FAILURE;
michael@0 1893 }
michael@0 1894
michael@0 1895 if (outer->GetWrapperPreserveColor()) {
michael@0 1896 return NS_OK;
michael@0 1897 }
michael@0 1898
michael@0 1899 NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(),
michael@0 1900 "No cached wrapper, but we have an inner window?");
michael@0 1901
michael@0 1902 // If this window is a [i]frame, don't bother GC'ing when the frame's context
michael@0 1903 // is destroyed since a GC will happen when the frameset or host document is
michael@0 1904 // destroyed anyway.
michael@0 1905 nsCOMPtr<nsIScriptContext> context = new nsJSContext(!IsFrame(), outer);
michael@0 1906
michael@0 1907 NS_ASSERTION(!outer->mContext, "Will overwrite mContext!");
michael@0 1908
michael@0 1909 // should probably assert the context is clean???
michael@0 1910 context->WillInitializeContext();
michael@0 1911
michael@0 1912 nsresult rv = context->InitContext();
michael@0 1913 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1914
michael@0 1915 outer->mContext = context;
michael@0 1916 return NS_OK;
michael@0 1917 }
michael@0 1918
michael@0 1919 nsIScriptContext *
michael@0 1920 nsGlobalWindow::GetScriptContext()
michael@0 1921 {
michael@0 1922 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 1923 return outer ? outer->mContext : nullptr;
michael@0 1924 }
michael@0 1925
michael@0 1926 JSObject *
michael@0 1927 nsGlobalWindow::GetGlobalJSObject()
michael@0 1928 {
michael@0 1929 return FastGetGlobalJSObject();
michael@0 1930 }
michael@0 1931
michael@0 1932 void
michael@0 1933 nsGlobalWindow::TraceGlobalJSObject(JSTracer* aTrc)
michael@0 1934 {
michael@0 1935 TraceWrapper(aTrc, "active window global");
michael@0 1936 }
michael@0 1937
michael@0 1938 /* static */
michael@0 1939 JSObject*
michael@0 1940 nsGlobalWindow::OuterObject(JSContext* aCx, JS::Handle<JSObject*> aObj)
michael@0 1941 {
michael@0 1942 nsGlobalWindow* origWin;
michael@0 1943 UNWRAP_OBJECT(Window, aObj, origWin);
michael@0 1944 nsGlobalWindow* win = origWin->GetOuterWindowInternal();
michael@0 1945
michael@0 1946 if (!win) {
michael@0 1947 // If we no longer have an outer window. No code should ever be
michael@0 1948 // running on a window w/o an outer, which means this hook should
michael@0 1949 // never be called when we have no outer. But just in case, return
michael@0 1950 // null to prevent leaking an inner window to code in a different
michael@0 1951 // window.
michael@0 1952 NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
michael@0 1953 return nullptr;
michael@0 1954 }
michael@0 1955
michael@0 1956 JS::Rooted<JSObject*> winObj(aCx, win->FastGetGlobalJSObject());
michael@0 1957 MOZ_ASSERT(winObj);
michael@0 1958
michael@0 1959 // Note that while |wrapper| is same-compartment with cx, the outer window
michael@0 1960 // might not be. If we're running script in an inactive scope and evalute
michael@0 1961 // |this|, the outer window is actually a cross-compartment wrapper. So we
michael@0 1962 // need to wrap here.
michael@0 1963 if (!JS_WrapObject(aCx, &winObj)) {
michael@0 1964 NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
michael@0 1965 return nullptr;
michael@0 1966 }
michael@0 1967
michael@0 1968 return winObj;
michael@0 1969 }
michael@0 1970
michael@0 1971 bool
michael@0 1972 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
michael@0 1973 {
michael@0 1974 // We reuse the inner window when:
michael@0 1975 // a. We are currently at our original document.
michael@0 1976 // b. At least one of the following conditions are true:
michael@0 1977 // -- The new document is the same as the old document. This means that we're
michael@0 1978 // getting called from document.open().
michael@0 1979 // -- The new document has the same origin as what we have loaded right now.
michael@0 1980
michael@0 1981 if (!mDoc || !aNewDocument) {
michael@0 1982 return false;
michael@0 1983 }
michael@0 1984
michael@0 1985 if (!mDoc->IsInitialDocument()) {
michael@0 1986 return false;
michael@0 1987 }
michael@0 1988
michael@0 1989 NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
michael@0 1990 "How'd this happen?");
michael@0 1991
michael@0 1992 // Great, we're the original document, check for one of the other
michael@0 1993 // conditions.
michael@0 1994
michael@0 1995 if (mDoc == aNewDocument) {
michael@0 1996 return true;
michael@0 1997 }
michael@0 1998
michael@0 1999 bool equal;
michael@0 2000 if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
michael@0 2001 &equal)) &&
michael@0 2002 equal) {
michael@0 2003 // The origin is the same.
michael@0 2004 return true;
michael@0 2005 }
michael@0 2006
michael@0 2007 return false;
michael@0 2008 }
michael@0 2009
michael@0 2010 void
michael@0 2011 nsGlobalWindow::SetInitialPrincipalToSubject()
michael@0 2012 {
michael@0 2013 FORWARD_TO_OUTER_VOID(SetInitialPrincipalToSubject, ());
michael@0 2014
michael@0 2015 // First, grab the subject principal.
michael@0 2016 nsCOMPtr<nsIPrincipal> newWindowPrincipal = nsContentUtils::GetSubjectPrincipal();
michael@0 2017 if (!newWindowPrincipal) {
michael@0 2018 newWindowPrincipal = nsContentUtils::GetSystemPrincipal();
michael@0 2019 }
michael@0 2020
michael@0 2021 // Now, if we're about to use the system principal or an nsExpandedPrincipal,
michael@0 2022 // make sure we're not using it for a content docshell.
michael@0 2023 if (nsContentUtils::IsSystemOrExpandedPrincipal(newWindowPrincipal) &&
michael@0 2024 GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome) {
michael@0 2025 newWindowPrincipal = nullptr;
michael@0 2026 }
michael@0 2027
michael@0 2028 // If there's an existing document, bail if it either:
michael@0 2029 if (mDoc) {
michael@0 2030 // (a) is not an initial about:blank document, or
michael@0 2031 if (!mDoc->IsInitialDocument())
michael@0 2032 return;
michael@0 2033 // (b) already has the correct principal.
michael@0 2034 if (mDoc->NodePrincipal() == newWindowPrincipal)
michael@0 2035 return;
michael@0 2036
michael@0 2037 #ifdef DEBUG
michael@0 2038 // If we have a document loaded at this point, it had better be about:blank.
michael@0 2039 // Otherwise, something is really weird.
michael@0 2040 nsCOMPtr<nsIURI> uri;
michael@0 2041 mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
michael@0 2042 NS_ASSERTION(uri && NS_IsAboutBlank(uri) &&
michael@0 2043 NS_IsAboutBlank(mDoc->GetDocumentURI()),
michael@0 2044 "Unexpected original document");
michael@0 2045 #endif
michael@0 2046 }
michael@0 2047
michael@0 2048 GetDocShell()->CreateAboutBlankContentViewer(newWindowPrincipal);
michael@0 2049 mDoc->SetIsInitialDocument(true);
michael@0 2050
michael@0 2051 nsCOMPtr<nsIPresShell> shell = GetDocShell()->GetPresShell();
michael@0 2052
michael@0 2053 if (shell && !shell->DidInitialize()) {
michael@0 2054 // Ensure that if someone plays with this document they will get
michael@0 2055 // layout happening.
michael@0 2056 nsRect r = shell->GetPresContext()->GetVisibleArea();
michael@0 2057 shell->Initialize(r.width, r.height);
michael@0 2058 }
michael@0 2059 }
michael@0 2060
michael@0 2061 PopupControlState
michael@0 2062 PushPopupControlState(PopupControlState aState, bool aForce)
michael@0 2063 {
michael@0 2064 MOZ_ASSERT(NS_IsMainThread());
michael@0 2065
michael@0 2066 PopupControlState oldState = gPopupControlState;
michael@0 2067
michael@0 2068 if (aState < gPopupControlState || aForce) {
michael@0 2069 gPopupControlState = aState;
michael@0 2070 }
michael@0 2071
michael@0 2072 return oldState;
michael@0 2073 }
michael@0 2074
michael@0 2075 void
michael@0 2076 PopPopupControlState(PopupControlState aState)
michael@0 2077 {
michael@0 2078 MOZ_ASSERT(NS_IsMainThread());
michael@0 2079
michael@0 2080 gPopupControlState = aState;
michael@0 2081 }
michael@0 2082
michael@0 2083 PopupControlState
michael@0 2084 nsGlobalWindow::PushPopupControlState(PopupControlState aState,
michael@0 2085 bool aForce) const
michael@0 2086 {
michael@0 2087 return ::PushPopupControlState(aState, aForce);
michael@0 2088 }
michael@0 2089
michael@0 2090 void
michael@0 2091 nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
michael@0 2092 {
michael@0 2093 ::PopPopupControlState(aState);
michael@0 2094 }
michael@0 2095
michael@0 2096 PopupControlState
michael@0 2097 nsGlobalWindow::GetPopupControlState() const
michael@0 2098 {
michael@0 2099 MOZ_ASSERT(NS_IsMainThread());
michael@0 2100 return gPopupControlState;
michael@0 2101 }
michael@0 2102
michael@0 2103 #define WINDOWSTATEHOLDER_IID \
michael@0 2104 {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
michael@0 2105
michael@0 2106 class WindowStateHolder MOZ_FINAL : public nsISupports
michael@0 2107 {
michael@0 2108 public:
michael@0 2109 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
michael@0 2110 NS_DECL_ISUPPORTS
michael@0 2111
michael@0 2112 WindowStateHolder(nsGlobalWindow *aWindow);
michael@0 2113
michael@0 2114 nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
michael@0 2115
michael@0 2116 void DidRestoreWindow()
michael@0 2117 {
michael@0 2118 mInnerWindow = nullptr;
michael@0 2119 }
michael@0 2120
michael@0 2121 protected:
michael@0 2122 ~WindowStateHolder();
michael@0 2123
michael@0 2124 nsRefPtr<nsGlobalWindow> mInnerWindow;
michael@0 2125 };
michael@0 2126
michael@0 2127 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
michael@0 2128
michael@0 2129 WindowStateHolder::WindowStateHolder(nsGlobalWindow* aWindow)
michael@0 2130 : mInnerWindow(aWindow)
michael@0 2131 {
michael@0 2132 NS_PRECONDITION(aWindow, "null window");
michael@0 2133 NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
michael@0 2134
michael@0 2135 // We hold onto this to make sure the inner window doesn't go away. The outer
michael@0 2136 // window ends up recalculating it anyway.
michael@0 2137 mInnerWindow->PreserveWrapper(ToSupports(mInnerWindow));
michael@0 2138
michael@0 2139 aWindow->SuspendTimeouts();
michael@0 2140
michael@0 2141 // When a global goes into the bfcache, we disable script.
michael@0 2142 xpc::Scriptability::Get(aWindow->GetWrapperPreserveColor()).SetDocShellAllowsScript(false);
michael@0 2143 }
michael@0 2144
michael@0 2145 WindowStateHolder::~WindowStateHolder()
michael@0 2146 {
michael@0 2147 if (mInnerWindow) {
michael@0 2148 // This window was left in the bfcache and is now going away. We need to
michael@0 2149 // free it up.
michael@0 2150 // Note that FreeInnerObjects may already have been called on the
michael@0 2151 // inner window if its outer has already had SetDocShell(null)
michael@0 2152 // called.
michael@0 2153 mInnerWindow->FreeInnerObjects();
michael@0 2154 }
michael@0 2155 }
michael@0 2156
michael@0 2157 NS_IMPL_ISUPPORTS(WindowStateHolder, WindowStateHolder)
michael@0 2158
michael@0 2159 // We need certain special behavior for remote XUL whitelisted domains, but we
michael@0 2160 // don't want that behavior to take effect in automation, because we whitelist
michael@0 2161 // all the mochitest domains. So we need to check a pref here.
michael@0 2162 static bool
michael@0 2163 TreatAsRemoteXUL(nsIPrincipal* aPrincipal)
michael@0 2164 {
michael@0 2165 MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(aPrincipal));
michael@0 2166 return nsContentUtils::AllowXULXBLForPrincipal(aPrincipal) &&
michael@0 2167 !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
michael@0 2168 }
michael@0 2169
michael@0 2170 /**
michael@0 2171 * Create a new global object that will be used for an inner window.
michael@0 2172 * Return the native global and an nsISupports 'holder' that can be used
michael@0 2173 * to manage the lifetime of it.
michael@0 2174 */
michael@0 2175 static nsresult
michael@0 2176 CreateNativeGlobalForInner(JSContext* aCx,
michael@0 2177 nsGlobalWindow* aNewInner,
michael@0 2178 nsIURI* aURI,
michael@0 2179 nsIPrincipal* aPrincipal,
michael@0 2180 JS::MutableHandle<JSObject*> aGlobal)
michael@0 2181 {
michael@0 2182 MOZ_ASSERT(aCx);
michael@0 2183 MOZ_ASSERT(aNewInner);
michael@0 2184 MOZ_ASSERT(aNewInner->IsInnerWindow());
michael@0 2185 MOZ_ASSERT(aPrincipal);
michael@0 2186
michael@0 2187 // DOMWindow with nsEP is not supported, we have to make sure
michael@0 2188 // no one creates one accidentally.
michael@0 2189 nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(aPrincipal);
michael@0 2190 MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported");
michael@0 2191
michael@0 2192 nsGlobalWindow *top = nullptr;
michael@0 2193 if (aNewInner->GetOuterWindow()) {
michael@0 2194 top = aNewInner->GetTop();
michael@0 2195 }
michael@0 2196 JS::CompartmentOptions options;
michael@0 2197 if (top) {
michael@0 2198 if (top->GetGlobalJSObject()) {
michael@0 2199 options.setSameZoneAs(top->GetGlobalJSObject());
michael@0 2200 }
michael@0 2201 }
michael@0 2202
michael@0 2203 nsIXPConnect* xpc = nsContentUtils::XPConnect();
michael@0 2204
michael@0 2205 // Determine if we need the Components object.
michael@0 2206 bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
michael@0 2207 TreatAsRemoteXUL(aPrincipal);
michael@0 2208 uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
michael@0 2209 flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
michael@0 2210
michael@0 2211 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
michael@0 2212 nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
michael@0 2213 aCx, ToSupports(aNewInner),
michael@0 2214 aPrincipal, flags, options, getter_AddRefs(holder));
michael@0 2215 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2216
michael@0 2217 aGlobal.set(holder->GetJSObject());
michael@0 2218
michael@0 2219 // Set the location information for the new global, so that tools like
michael@0 2220 // about:memory may use that information
michael@0 2221 MOZ_ASSERT(aGlobal);
michael@0 2222 MOZ_ASSERT(aNewInner->GetWrapperPreserveColor() == aGlobal);
michael@0 2223 xpc::SetLocationForGlobal(aGlobal, aURI);
michael@0 2224
michael@0 2225 return NS_OK;
michael@0 2226 }
michael@0 2227
michael@0 2228 nsresult
michael@0 2229 nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
michael@0 2230 nsISupports* aState,
michael@0 2231 bool aForceReuseInnerWindow)
michael@0 2232 {
michael@0 2233 NS_PRECONDITION(mDocumentPrincipal == nullptr,
michael@0 2234 "mDocumentPrincipal prematurely set!");
michael@0 2235 MOZ_ASSERT(aDocument);
michael@0 2236
michael@0 2237 if (IsInnerWindow()) {
michael@0 2238 if (!mOuterWindow) {
michael@0 2239 return NS_ERROR_NOT_INITIALIZED;
michael@0 2240 }
michael@0 2241
michael@0 2242 // Refuse to set a new document if the call came from an inner
michael@0 2243 // window that's not the current inner window.
michael@0 2244 if (mOuterWindow->GetCurrentInnerWindow() != this) {
michael@0 2245 return NS_ERROR_NOT_AVAILABLE;
michael@0 2246 }
michael@0 2247
michael@0 2248 return GetOuterWindowInternal()->SetNewDocument(aDocument, aState,
michael@0 2249 aForceReuseInnerWindow);
michael@0 2250 }
michael@0 2251
michael@0 2252 NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
michael@0 2253
michael@0 2254 if (IsFrozen()) {
michael@0 2255 // This outer is now getting its first inner, thaw the outer now
michael@0 2256 // that it's ready and is getting an inner window.
michael@0 2257
michael@0 2258 Thaw();
michael@0 2259 }
michael@0 2260
michael@0 2261 NS_ASSERTION(!GetCurrentInnerWindow() ||
michael@0 2262 GetCurrentInnerWindow()->GetExtantDoc() == mDoc,
michael@0 2263 "Uh, mDoc doesn't match the current inner window "
michael@0 2264 "document!");
michael@0 2265
michael@0 2266 bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
michael@0 2267 if (aForceReuseInnerWindow &&
michael@0 2268 !wouldReuseInnerWindow &&
michael@0 2269 mDoc &&
michael@0 2270 mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
michael@0 2271 NS_ERROR("Attempted forced inner window reuse while changing principal");
michael@0 2272 return NS_ERROR_UNEXPECTED;
michael@0 2273 }
michael@0 2274
michael@0 2275 nsCOMPtr<nsIDocument> oldDoc = mDoc;
michael@0 2276
michael@0 2277 nsIScriptContext *scx = GetContextInternal();
michael@0 2278 NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
michael@0 2279
michael@0 2280 JSContext *cx = scx->GetNativeContext();
michael@0 2281
michael@0 2282 #ifndef MOZ_DISABLE_CRYPTOLEGACY
michael@0 2283 // clear smartcard events, our document has gone away.
michael@0 2284 if (mCrypto && XRE_GetProcessType() != GeckoProcessType_Content) {
michael@0 2285 nsresult rv = mCrypto->SetEnableSmartCardEvents(false);
michael@0 2286 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2287 }
michael@0 2288 #endif
michael@0 2289
michael@0 2290 if (!mDoc) {
michael@0 2291 // First document load.
michael@0 2292
michael@0 2293 // Get our private root. If it is equal to us, then we need to
michael@0 2294 // attach our global key bindings that handles browser scrolling
michael@0 2295 // and other browser commands.
michael@0 2296 nsIDOMWindow* privateRoot = nsGlobalWindow::GetPrivateRoot();
michael@0 2297
michael@0 2298 if (privateRoot == static_cast<nsIDOMWindow*>(this)) {
michael@0 2299 nsXBLService::AttachGlobalKeyHandler(mChromeEventHandler);
michael@0 2300 }
michael@0 2301 }
michael@0 2302
michael@0 2303 /* No mDocShell means we're already been partially closed down. When that
michael@0 2304 happens, setting status isn't a big requirement, so don't. (Doesn't happen
michael@0 2305 under normal circumstances, but bug 49615 describes a case.) */
michael@0 2306
michael@0 2307 nsContentUtils::AddScriptRunner(
michael@0 2308 NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
michael@0 2309
michael@0 2310 // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
michael@0 2311 // window (see bug 776497). Be safe.
michael@0 2312 bool reUseInnerWindow = (aForceReuseInnerWindow || wouldReuseInnerWindow) &&
michael@0 2313 GetCurrentInnerWindowInternal();
michael@0 2314
michael@0 2315 nsresult rv = NS_OK;
michael@0 2316
michael@0 2317 // Set mDoc even if this is an outer window to avoid
michael@0 2318 // having to *always* reach into the inner window to find the
michael@0 2319 // document.
michael@0 2320 mDoc = aDocument;
michael@0 2321 if (IsInnerWindow() && IsDOMBinding()) {
michael@0 2322 WindowBinding::ClearCachedDocumentValue(cx, this);
michael@0 2323 }
michael@0 2324
michael@0 2325 // Take this opportunity to clear mSuspendedDoc. Our old inner window is now
michael@0 2326 // responsible for unsuspending it.
michael@0 2327 mSuspendedDoc = nullptr;
michael@0 2328
michael@0 2329 #ifdef DEBUG
michael@0 2330 mLastOpenedURI = aDocument->GetDocumentURI();
michael@0 2331 #endif
michael@0 2332
michael@0 2333 mContext->WillInitializeContext();
michael@0 2334
michael@0 2335 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
michael@0 2336
michael@0 2337 if (currentInner && currentInner->mNavigator) {
michael@0 2338 currentInner->mNavigator->OnNavigation();
michael@0 2339 }
michael@0 2340
michael@0 2341 nsRefPtr<nsGlobalWindow> newInnerWindow;
michael@0 2342 bool createdInnerWindow = false;
michael@0 2343
michael@0 2344 bool thisChrome = IsChromeWindow();
michael@0 2345
michael@0 2346 nsCxPusher cxPusher;
michael@0 2347 cxPusher.Push(cx);
michael@0 2348
michael@0 2349 // Check if we're near the stack limit before we get anywhere near the
michael@0 2350 // transplanting code.
michael@0 2351 JS_CHECK_RECURSION(cx, return NS_ERROR_FAILURE);
michael@0 2352
michael@0 2353 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
michael@0 2354 NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
michael@0 2355
michael@0 2356 JS::Rooted<JSObject*> newInnerGlobal(cx);
michael@0 2357 if (reUseInnerWindow) {
michael@0 2358 // We're reusing the current inner window.
michael@0 2359 NS_ASSERTION(!currentInner->IsFrozen(),
michael@0 2360 "We should never be reusing a shared inner window");
michael@0 2361 newInnerWindow = currentInner;
michael@0 2362 newInnerGlobal = currentInner->GetWrapperPreserveColor();
michael@0 2363
michael@0 2364 if (aDocument != oldDoc) {
michael@0 2365 JS::ExposeObjectToActiveJS(newInnerGlobal);
michael@0 2366 }
michael@0 2367
michael@0 2368 // We're reusing the inner window, but this still counts as a navigation,
michael@0 2369 // so all expandos and such defined on the outer window should go away. Force
michael@0 2370 // all Xray wrappers to be recomputed.
michael@0 2371 JS::Rooted<JSObject*> rootedObject(cx, GetWrapperPreserveColor());
michael@0 2372 JS::ExposeObjectToActiveJS(rootedObject);
michael@0 2373 if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
michael@0 2374 return NS_ERROR_FAILURE;
michael@0 2375 }
michael@0 2376
michael@0 2377 // Inner windows are only reused for same-origin principals, but the principals
michael@0 2378 // don't necessarily match exactly. Update the principal on the compartment to
michael@0 2379 // match the new document.
michael@0 2380 // NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
michael@0 2381 // because we haven't yet set its mDoc to aDocument.
michael@0 2382 JSCompartment *compartment = js::GetObjectCompartment(newInnerGlobal);
michael@0 2383 #ifdef DEBUG
michael@0 2384 bool sameOrigin = false;
michael@0 2385 nsIPrincipal *existing =
michael@0 2386 nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment));
michael@0 2387 aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
michael@0 2388 MOZ_ASSERT(sameOrigin);
michael@0 2389 #endif
michael@0 2390 JS_SetCompartmentPrincipals(compartment,
michael@0 2391 nsJSPrincipals::get(aDocument->NodePrincipal()));
michael@0 2392 } else {
michael@0 2393 if (aState) {
michael@0 2394 newInnerWindow = wsh->GetInnerWindow();
michael@0 2395 newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
michael@0 2396 } else {
michael@0 2397 if (thisChrome) {
michael@0 2398 newInnerWindow = new nsGlobalChromeWindow(this);
michael@0 2399 } else if (mIsModalContentWindow) {
michael@0 2400 newInnerWindow = new nsGlobalModalWindow(this);
michael@0 2401 } else {
michael@0 2402 newInnerWindow = new nsGlobalWindow(this);
michael@0 2403 }
michael@0 2404
michael@0 2405 // Freeze the outer window and null out the inner window so
michael@0 2406 // that initializing classes on the new inner doesn't end up
michael@0 2407 // reaching into the old inner window for classes etc.
michael@0 2408 //
michael@0 2409 // [This happens with Object.prototype when XPConnect creates
michael@0 2410 // a temporary global while initializing classes; the reason
michael@0 2411 // being that xpconnect creates the temp global w/o a parent
michael@0 2412 // and proto, which makes the JS engine look up classes in
michael@0 2413 // cx->globalObject, i.e. this outer window].
michael@0 2414
michael@0 2415 mInnerWindow = nullptr;
michael@0 2416
michael@0 2417 Freeze();
michael@0 2418 mCreatingInnerWindow = true;
michael@0 2419 // Every script context we are initialized with must create a
michael@0 2420 // new global.
michael@0 2421 rv = CreateNativeGlobalForInner(cx, newInnerWindow,
michael@0 2422 aDocument->GetDocumentURI(),
michael@0 2423 aDocument->NodePrincipal(),
michael@0 2424 &newInnerGlobal);
michael@0 2425 NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
michael@0 2426 newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
michael@0 2427 "Failed to get script global");
michael@0 2428
michael@0 2429 mCreatingInnerWindow = false;
michael@0 2430 createdInnerWindow = true;
michael@0 2431 Thaw();
michael@0 2432
michael@0 2433 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2434 }
michael@0 2435
michael@0 2436 if (currentInner && currentInner->GetWrapperPreserveColor()) {
michael@0 2437 if (oldDoc == aDocument) {
michael@0 2438 // Move the navigator from the old inner window to the new one since
michael@0 2439 // this is a document.write. This is safe from a same-origin point of
michael@0 2440 // view because document.write can only be used by the same origin.
michael@0 2441 newInnerWindow->mNavigator = currentInner->mNavigator;
michael@0 2442 currentInner->mNavigator = nullptr;
michael@0 2443 if (newInnerWindow->mNavigator) {
michael@0 2444 newInnerWindow->mNavigator->SetWindow(newInnerWindow);
michael@0 2445 }
michael@0 2446
michael@0 2447 // Make a copy of the old window's performance object on document.open.
michael@0 2448 // Note that we have to force eager creation of it here, because we need
michael@0 2449 // to grab the current document channel and whatnot before that changes.
michael@0 2450 currentInner->CreatePerformanceObjectIfNeeded();
michael@0 2451 if (currentInner->mPerformance) {
michael@0 2452 newInnerWindow->mPerformance =
michael@0 2453 new nsPerformance(newInnerWindow,
michael@0 2454 currentInner->mPerformance->GetDOMTiming(),
michael@0 2455 currentInner->mPerformance->GetChannel(),
michael@0 2456 currentInner->mPerformance->GetParentPerformance());
michael@0 2457 }
michael@0 2458 }
michael@0 2459
michael@0 2460 // Don't free objects on our current inner window if it's going to be
michael@0 2461 // held in the bfcache.
michael@0 2462 if (!currentInner->IsFrozen()) {
michael@0 2463 currentInner->FreeInnerObjects();
michael@0 2464 }
michael@0 2465 }
michael@0 2466
michael@0 2467 mInnerWindow = newInnerWindow;
michael@0 2468
michael@0 2469 if (!GetWrapperPreserveColor()) {
michael@0 2470 JS::Rooted<JSObject*> outer(cx,
michael@0 2471 NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
michael@0 2472 NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
michael@0 2473
michael@0 2474 js::SetProxyExtra(outer, 0, js::PrivateValue(ToSupports(this)));
michael@0 2475
michael@0 2476 // Inform the nsJSContext, which is the canonical holder of the outer.
michael@0 2477 mContext->SetWindowProxy(outer);
michael@0 2478 mContext->DidInitializeContext();
michael@0 2479
michael@0 2480 SetWrapper(mContext->GetWindowProxy());
michael@0 2481 } else {
michael@0 2482 JS::ExposeObjectToActiveJS(newInnerGlobal);
michael@0 2483 JS::Rooted<JSObject*> outerObject(cx,
michael@0 2484 NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
michael@0 2485 if (!outerObject) {
michael@0 2486 NS_ERROR("out of memory");
michael@0 2487 return NS_ERROR_FAILURE;
michael@0 2488 }
michael@0 2489
michael@0 2490 JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
michael@0 2491
michael@0 2492 js::SetProxyExtra(obj, 0, js::PrivateValue(nullptr));
michael@0 2493
michael@0 2494 outerObject = xpc::TransplantObject(cx, obj, outerObject);
michael@0 2495 if (!outerObject) {
michael@0 2496 NS_ERROR("unable to transplant wrappers, probably OOM");
michael@0 2497 return NS_ERROR_FAILURE;
michael@0 2498 }
michael@0 2499
michael@0 2500 js::SetProxyExtra(outerObject, 0, js::PrivateValue(ToSupports(this)));
michael@0 2501
michael@0 2502 SetWrapper(outerObject);
michael@0 2503
michael@0 2504 {
michael@0 2505 JSAutoCompartment ac(cx, outerObject);
michael@0 2506
michael@0 2507 JS_SetParent(cx, outerObject, newInnerGlobal);
michael@0 2508
michael@0 2509 // Inform the nsJSContext, which is the canonical holder of the outer.
michael@0 2510 mContext->SetWindowProxy(outerObject);
michael@0 2511
michael@0 2512 NS_ASSERTION(!JS_IsExceptionPending(cx),
michael@0 2513 "We might overwrite a pending exception!");
michael@0 2514 XPCWrappedNativeScope* scope = xpc::GetObjectScope(outerObject);
michael@0 2515 if (scope->mWaiverWrapperMap) {
michael@0 2516 scope->mWaiverWrapperMap->Reparent(cx, newInnerGlobal);
michael@0 2517 }
michael@0 2518 }
michael@0 2519 }
michael@0 2520
michael@0 2521 // Enter the new global's compartment.
michael@0 2522 JSAutoCompartment ac(cx, GetWrapperPreserveColor());
michael@0 2523
michael@0 2524 // Set scriptability based on the state of the docshell.
michael@0 2525 bool allow = GetDocShell()->GetCanExecuteScripts();
michael@0 2526 xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);
michael@0 2527
michael@0 2528 // If we created a new inner window above, we need to do the last little bit
michael@0 2529 // of initialization now that the dust has settled.
michael@0 2530 if (createdInnerWindow) {
michael@0 2531 nsIXPConnect *xpc = nsContentUtils::XPConnect();
michael@0 2532 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
michael@0 2533 nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerGlobal,
michael@0 2534 getter_AddRefs(wrapper));
michael@0 2535 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2536 NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
michael@0 2537 rv = wrapper->FinishInitForWrappedGlobal();
michael@0 2538 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2539 }
michael@0 2540
michael@0 2541 if (!aState) {
michael@0 2542 JS::Rooted<JSObject*> rootedWrapper(cx, GetWrapperPreserveColor());
michael@0 2543 if (!JS_DefineProperty(cx, newInnerGlobal, "window", rootedWrapper,
michael@0 2544 JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
michael@0 2545 JS_PropertyStub, JS_StrictPropertyStub)) {
michael@0 2546 NS_ERROR("can't create the 'window' property");
michael@0 2547 return NS_ERROR_FAILURE;
michael@0 2548 }
michael@0 2549 }
michael@0 2550 }
michael@0 2551
michael@0 2552 JSAutoCompartment ac(cx, GetWrapperPreserveColor());
michael@0 2553
michael@0 2554 if (!aState && !reUseInnerWindow) {
michael@0 2555 // Loading a new page and creating a new inner window, *not*
michael@0 2556 // restoring from session history.
michael@0 2557
michael@0 2558 // Now that both the the inner and outer windows are initialized
michael@0 2559 // let the script context do its magic to hook them together.
michael@0 2560 MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor());
michael@0 2561 #ifdef DEBUG
michael@0 2562 JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
michael@0 2563 JS::Rooted<JSObject*> proto1(cx), proto2(cx);
michael@0 2564 JS_GetPrototype(cx, rootedJSObject, &proto1);
michael@0 2565 JS_GetPrototype(cx, newInnerGlobal, &proto2);
michael@0 2566 NS_ASSERTION(proto1 == proto2,
michael@0 2567 "outer and inner globals should have the same prototype");
michael@0 2568 #endif
michael@0 2569
michael@0 2570 nsCOMPtr<Element> frame = GetFrameElementInternal();
michael@0 2571 if (frame) {
michael@0 2572 nsPIDOMWindow* parentWindow = frame->OwnerDoc()->GetWindow();
michael@0 2573 if (parentWindow && parentWindow->TimeoutSuspendCount()) {
michael@0 2574 SuspendTimeouts(parentWindow->TimeoutSuspendCount());
michael@0 2575 }
michael@0 2576 }
michael@0 2577 }
michael@0 2578
michael@0 2579 // Add an extra ref in case we release mContext during GC.
michael@0 2580 nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
michael@0 2581
michael@0 2582 aDocument->SetScriptGlobalObject(newInnerWindow);
michael@0 2583
michael@0 2584 if (!aState) {
michael@0 2585 if (reUseInnerWindow) {
michael@0 2586 if (newInnerWindow->mDoc != aDocument) {
michael@0 2587 newInnerWindow->mDoc = aDocument;
michael@0 2588
michael@0 2589 if (newInnerWindow->IsDOMBinding()) {
michael@0 2590 WindowBinding::ClearCachedDocumentValue(cx, newInnerWindow);
michael@0 2591 } else {
michael@0 2592 // We're reusing the inner window for a new document. In this
michael@0 2593 // case we don't clear the inner window's scope, but we must
michael@0 2594 // make sure the cached document property gets updated.
michael@0 2595
michael@0 2596 JS::Rooted<JSObject*> obj(cx,
michael@0 2597 currentInner->GetWrapperPreserveColor());
michael@0 2598 ::JS_DeleteProperty(cx, obj, "document");
michael@0 2599 }
michael@0 2600 }
michael@0 2601 } else {
michael@0 2602 newInnerWindow->InnerSetNewDocument(cx, aDocument);
michael@0 2603
michael@0 2604 // Initialize DOM classes etc on the inner window.
michael@0 2605 JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
michael@0 2606 rv = mContext->InitClasses(obj);
michael@0 2607 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2608 }
michael@0 2609
michael@0 2610 // If the document comes from a JAR, check if the channel was determined
michael@0 2611 // to be unsafe. If so, permanently disable script on the compartment by
michael@0 2612 // calling Block() and throwing away the key.
michael@0 2613 nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aDocument->GetChannel());
michael@0 2614 if (jarChannel && jarChannel->GetIsUnsafe()) {
michael@0 2615 xpc::Scriptability::Get(newInnerGlobal).Block();
michael@0 2616 }
michael@0 2617
michael@0 2618 if (mArguments) {
michael@0 2619 newInnerWindow->DefineArgumentsProperty(mArguments);
michael@0 2620 mArguments = nullptr;
michael@0 2621 }
michael@0 2622
michael@0 2623 // Give the new inner window our chrome event handler (since it
michael@0 2624 // doesn't have one).
michael@0 2625 newInnerWindow->mChromeEventHandler = mChromeEventHandler;
michael@0 2626 }
michael@0 2627
michael@0 2628 mContext->GC(JS::gcreason::SET_NEW_DOCUMENT);
michael@0 2629 mContext->DidInitializeContext();
michael@0 2630
michael@0 2631 // We wait to fire the debugger hook until the window is all set up and hooked
michael@0 2632 // up with the outer. See bug 969156.
michael@0 2633 if (createdInnerWindow) {
michael@0 2634 JS::Rooted<JSObject*> global(cx, newInnerWindow->GetWrapper());
michael@0 2635 JS_FireOnNewGlobalObject(cx, global);
michael@0 2636 }
michael@0 2637
michael@0 2638 if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
michael@0 2639 // We should probably notify. However if this is the, arguably bad,
michael@0 2640 // situation when we're creating a temporary non-chrome-about-blank
michael@0 2641 // document in a chrome docshell, don't notify just yet. Instead wait
michael@0 2642 // until we have a real chrome doc.
michael@0 2643 if (!mDocShell ||
michael@0 2644 mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome ||
michael@0 2645 nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
michael@0 2646 newInnerWindow->mHasNotifiedGlobalCreated = true;
michael@0 2647 nsContentUtils::AddScriptRunner(
michael@0 2648 NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated));
michael@0 2649 }
michael@0 2650 }
michael@0 2651
michael@0 2652 PreloadLocalStorage();
michael@0 2653
michael@0 2654 return NS_OK;
michael@0 2655 }
michael@0 2656
michael@0 2657 void
michael@0 2658 nsGlobalWindow::PreloadLocalStorage()
michael@0 2659 {
michael@0 2660 if (!Preferences::GetBool(kStorageEnabled)) {
michael@0 2661 return;
michael@0 2662 }
michael@0 2663
michael@0 2664 if (IsChromeWindow()) {
michael@0 2665 return;
michael@0 2666 }
michael@0 2667
michael@0 2668 nsIPrincipal* principal = GetPrincipal();
michael@0 2669 if (!principal) {
michael@0 2670 return;
michael@0 2671 }
michael@0 2672
michael@0 2673 nsresult rv;
michael@0 2674 nsCOMPtr<nsIURI> firstPartyIsolationURI;
michael@0 2675 rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
michael@0 2676 if (NS_FAILED(rv)) {
michael@0 2677 return;
michael@0 2678 }
michael@0 2679
michael@0 2680 nsCOMPtr<nsIDOMStorageManager> storageManager =
michael@0 2681 do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
michael@0 2682 if (NS_FAILED(rv)) {
michael@0 2683 return;
michael@0 2684 }
michael@0 2685
michael@0 2686 storageManager->PrecacheStorageForFirstParty(firstPartyIsolationURI, principal);
michael@0 2687 }
michael@0 2688
michael@0 2689 void
michael@0 2690 nsGlobalWindow::DispatchDOMWindowCreated()
michael@0 2691 {
michael@0 2692 if (!mDoc) {
michael@0 2693 return;
michael@0 2694 }
michael@0 2695
michael@0 2696 // Fire DOMWindowCreated at chrome event listeners
michael@0 2697 nsContentUtils::DispatchChromeEvent(mDoc, mDoc, NS_LITERAL_STRING("DOMWindowCreated"),
michael@0 2698 true /* bubbles */,
michael@0 2699 false /* not cancellable */);
michael@0 2700
michael@0 2701 nsCOMPtr<nsIObserverService> observerService =
michael@0 2702 mozilla::services::GetObserverService();
michael@0 2703 if (observerService) {
michael@0 2704 nsAutoString origin;
michael@0 2705 nsIPrincipal* principal = mDoc->NodePrincipal();
michael@0 2706 nsContentUtils::GetUTFOrigin(principal, origin);
michael@0 2707 observerService->
michael@0 2708 NotifyObservers(static_cast<nsIDOMWindow*>(this),
michael@0 2709 nsContentUtils::IsSystemPrincipal(principal) ?
michael@0 2710 "chrome-document-global-created" :
michael@0 2711 "content-document-global-created",
michael@0 2712 origin.get());
michael@0 2713 }
michael@0 2714 }
michael@0 2715
michael@0 2716 void
michael@0 2717 nsGlobalWindow::ClearStatus()
michael@0 2718 {
michael@0 2719 SetStatus(EmptyString());
michael@0 2720 }
michael@0 2721
michael@0 2722 void
michael@0 2723 nsGlobalWindow::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument)
michael@0 2724 {
michael@0 2725 NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
michael@0 2726 MOZ_ASSERT(aDocument);
michael@0 2727
michael@0 2728 #ifdef PR_LOGGING
michael@0 2729 if (gDOMLeakPRLog && PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
michael@0 2730 nsIURI *uri = aDocument->GetDocumentURI();
michael@0 2731 nsAutoCString spec;
michael@0 2732 if (uri)
michael@0 2733 uri->GetSpec(spec);
michael@0 2734 PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
michael@0 2735 }
michael@0 2736 #endif
michael@0 2737
michael@0 2738 mDoc = aDocument;
michael@0 2739 if (IsDOMBinding()) {
michael@0 2740 WindowBinding::ClearCachedDocumentValue(aCx, this);
michael@0 2741 }
michael@0 2742 mFocusedNode = nullptr;
michael@0 2743 mLocalStorage = nullptr;
michael@0 2744 mSessionStorage = nullptr;
michael@0 2745
michael@0 2746 #ifdef DEBUG
michael@0 2747 mLastOpenedURI = aDocument->GetDocumentURI();
michael@0 2748 #endif
michael@0 2749
michael@0 2750 Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
michael@0 2751 mMutationBits ? 1 : 0);
michael@0 2752
michael@0 2753 // Clear our mutation bitfield.
michael@0 2754 mMutationBits = 0;
michael@0 2755 }
michael@0 2756
michael@0 2757 void
michael@0 2758 nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
michael@0 2759 {
michael@0 2760 NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
michael@0 2761 MOZ_ASSERT(aDocShell);
michael@0 2762
michael@0 2763 if (aDocShell == mDocShell) {
michael@0 2764 return;
michael@0 2765 }
michael@0 2766
michael@0 2767 mDocShell = aDocShell; // Weak Reference
michael@0 2768
michael@0 2769 NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
michael@0 2770
michael@0 2771 if (mFrames) {
michael@0 2772 mFrames->SetDocShell(aDocShell);
michael@0 2773 }
michael@0 2774
michael@0 2775 // Get our enclosing chrome shell and retrieve its global window impl, so
michael@0 2776 // that we can do some forwarding to the chrome document.
michael@0 2777 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
michael@0 2778 mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
michael@0 2779 mChromeEventHandler = do_QueryInterface(chromeEventHandler);
michael@0 2780 if (!mChromeEventHandler) {
michael@0 2781 // We have no chrome event handler. If we have a parent,
michael@0 2782 // get our chrome event handler from the parent. If
michael@0 2783 // we don't have a parent, then we need to make a new
michael@0 2784 // window root object that will function as a chrome event
michael@0 2785 // handler and receive all events that occur anywhere inside
michael@0 2786 // our window.
michael@0 2787 nsCOMPtr<nsIDOMWindow> parentWindow;
michael@0 2788 GetParent(getter_AddRefs(parentWindow));
michael@0 2789 if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
michael@0 2790 nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
michael@0 2791 mChromeEventHandler = piWindow->GetChromeEventHandler();
michael@0 2792 }
michael@0 2793 else {
michael@0 2794 mChromeEventHandler = NS_NewWindowRoot(this);
michael@0 2795 }
michael@0 2796 }
michael@0 2797
michael@0 2798 bool docShellActive;
michael@0 2799 mDocShell->GetIsActive(&docShellActive);
michael@0 2800 mIsBackground = !docShellActive;
michael@0 2801 }
michael@0 2802
michael@0 2803 void
michael@0 2804 nsGlobalWindow::DetachFromDocShell()
michael@0 2805 {
michael@0 2806 NS_ASSERTION(IsOuterWindow(), "Uh, DetachFromDocShell() called on inner window!");
michael@0 2807
michael@0 2808 // DetachFromDocShell means the window is being torn down. Drop our
michael@0 2809 // reference to the script context, allowing it to be deleted
michael@0 2810 // later. Meanwhile, keep our weak reference to the script object
michael@0 2811 // so that it can be retrieved later (until it is finalized by the JS GC).
michael@0 2812
michael@0 2813 NS_ASSERTION(mTimeouts.isEmpty(), "Uh, outer window holds timeouts!");
michael@0 2814
michael@0 2815 // Call FreeInnerObjects on all inner windows, not just the current
michael@0 2816 // one, since some could be held by WindowStateHolder objects that
michael@0 2817 // are GC-owned.
michael@0 2818 for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
michael@0 2819 inner != this;
michael@0 2820 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
michael@0 2821 NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
michael@0 2822 "bad outer window pointer");
michael@0 2823 inner->FreeInnerObjects();
michael@0 2824 }
michael@0 2825
michael@0 2826 // Make sure that this is called before we null out the document.
michael@0 2827 NotifyDOMWindowDestroyed(this);
michael@0 2828
michael@0 2829 NotifyWindowIDDestroyed("outer-window-destroyed");
michael@0 2830
michael@0 2831 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
michael@0 2832
michael@0 2833 if (currentInner) {
michael@0 2834 NS_ASSERTION(mDoc, "Must have doc!");
michael@0 2835
michael@0 2836 // Remember the document's principal and URI.
michael@0 2837 mDocumentPrincipal = mDoc->NodePrincipal();
michael@0 2838 mDocumentURI = mDoc->GetDocumentURI();
michael@0 2839 mDocBaseURI = mDoc->GetDocBaseURI();
michael@0 2840
michael@0 2841 // Release our document reference
michael@0 2842 DropOuterWindowDocs();
michael@0 2843 mFocusedNode = nullptr;
michael@0 2844 }
michael@0 2845
michael@0 2846 ClearControllers();
michael@0 2847
michael@0 2848 mChromeEventHandler = nullptr; // force release now
michael@0 2849
michael@0 2850 if (mContext) {
michael@0 2851 mContext->GC(JS::gcreason::SET_DOC_SHELL);
michael@0 2852 mContext = nullptr;
michael@0 2853 }
michael@0 2854
michael@0 2855 mDocShell = nullptr; // Weak Reference
michael@0 2856
michael@0 2857 NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
michael@0 2858
michael@0 2859 if (mFrames) {
michael@0 2860 mFrames->SetDocShell(nullptr);
michael@0 2861 }
michael@0 2862
michael@0 2863 MaybeForgiveSpamCount();
michael@0 2864 CleanUp();
michael@0 2865 }
michael@0 2866
michael@0 2867 void
michael@0 2868 nsGlobalWindow::SetOpenerWindow(nsIDOMWindow* aOpener,
michael@0 2869 bool aOriginalOpener)
michael@0 2870 {
michael@0 2871 FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
michael@0 2872
michael@0 2873 NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
michael@0 2874 "aOriginalOpener is true, but not first call to "
michael@0 2875 "SetOpenerWindow!");
michael@0 2876 NS_ASSERTION(aOpener || !aOriginalOpener,
michael@0 2877 "Shouldn't set mHadOriginalOpener if aOpener is null");
michael@0 2878
michael@0 2879 mOpener = do_GetWeakReference(aOpener);
michael@0 2880 NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
michael@0 2881
michael@0 2882 if (aOriginalOpener) {
michael@0 2883 mHadOriginalOpener = true;
michael@0 2884 }
michael@0 2885
michael@0 2886 #ifdef DEBUG
michael@0 2887 mSetOpenerWindowCalled = true;
michael@0 2888 #endif
michael@0 2889 }
michael@0 2890
michael@0 2891 static
michael@0 2892 already_AddRefed<EventTarget>
michael@0 2893 TryGetTabChildGlobalAsEventTarget(nsISupports *aFrom)
michael@0 2894 {
michael@0 2895 nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(aFrom);
michael@0 2896 if (!frameLoaderOwner) {
michael@0 2897 return nullptr;
michael@0 2898 }
michael@0 2899
michael@0 2900 nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
michael@0 2901 if (!frameLoader) {
michael@0 2902 return nullptr;
michael@0 2903 }
michael@0 2904
michael@0 2905 nsCOMPtr<EventTarget> target = frameLoader->GetTabChildGlobalAsEventTarget();
michael@0 2906 return target.forget();
michael@0 2907 }
michael@0 2908
michael@0 2909 void
michael@0 2910 nsGlobalWindow::UpdateParentTarget()
michael@0 2911 {
michael@0 2912 // Try to get our frame element's tab child global (its in-process message
michael@0 2913 // manager). If that fails, fall back to the chrome event handler's tab
michael@0 2914 // child global, and if it doesn't have one, just use the chrome event
michael@0 2915 // handler itself.
michael@0 2916
michael@0 2917 nsCOMPtr<Element> frameElement = GetFrameElementInternal();
michael@0 2918 nsCOMPtr<EventTarget> eventTarget =
michael@0 2919 TryGetTabChildGlobalAsEventTarget(frameElement);
michael@0 2920
michael@0 2921 if (!eventTarget) {
michael@0 2922 nsGlobalWindow* topWin = GetScriptableTop();
michael@0 2923 if (topWin) {
michael@0 2924 frameElement = topWin->GetFrameElementInternal();
michael@0 2925 eventTarget = TryGetTabChildGlobalAsEventTarget(frameElement);
michael@0 2926 }
michael@0 2927 }
michael@0 2928
michael@0 2929 if (!eventTarget) {
michael@0 2930 eventTarget = TryGetTabChildGlobalAsEventTarget(mChromeEventHandler);
michael@0 2931 }
michael@0 2932
michael@0 2933 if (!eventTarget) {
michael@0 2934 eventTarget = mChromeEventHandler;
michael@0 2935 }
michael@0 2936
michael@0 2937 mParentTarget = eventTarget;
michael@0 2938 }
michael@0 2939
michael@0 2940 EventTarget*
michael@0 2941 nsGlobalWindow::GetTargetForDOMEvent()
michael@0 2942 {
michael@0 2943 return GetOuterWindowInternal();
michael@0 2944 }
michael@0 2945
michael@0 2946 EventTarget*
michael@0 2947 nsGlobalWindow::GetTargetForEventTargetChain()
michael@0 2948 {
michael@0 2949 return IsInnerWindow() ? this : GetCurrentInnerWindowInternal();
michael@0 2950 }
michael@0 2951
michael@0 2952 nsresult
michael@0 2953 nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor)
michael@0 2954 {
michael@0 2955 return NS_OK;
michael@0 2956 }
michael@0 2957
michael@0 2958 JSContext*
michael@0 2959 nsGlobalWindow::GetJSContextForEventHandlers()
michael@0 2960 {
michael@0 2961 return nullptr;
michael@0 2962 }
michael@0 2963
michael@0 2964 nsresult
michael@0 2965 nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
michael@0 2966 {
michael@0 2967 NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
michael@0 2968 static uint32_t count = 0;
michael@0 2969 uint32_t msg = aVisitor.mEvent->message;
michael@0 2970
michael@0 2971 aVisitor.mCanHandle = true;
michael@0 2972 aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
michael@0 2973 if ((msg == NS_MOUSE_MOVE) && gEntropyCollector) {
michael@0 2974 //Chances are this counter will overflow during the life of the
michael@0 2975 //process, but that's OK for our case. Means we get a little
michael@0 2976 //more entropy.
michael@0 2977 if (count++ % 100 == 0) {
michael@0 2978 //Since the high bits seem to be zero's most of the time,
michael@0 2979 //let's only take the lowest half of the point structure.
michael@0 2980 int16_t myCoord[2];
michael@0 2981
michael@0 2982 myCoord[0] = aVisitor.mEvent->refPoint.x;
michael@0 2983 myCoord[1] = aVisitor.mEvent->refPoint.y;
michael@0 2984 gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
michael@0 2985 gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
michael@0 2986 sizeof(uint32_t));
michael@0 2987 }
michael@0 2988 } else if (msg == NS_RESIZE_EVENT) {
michael@0 2989 mIsHandlingResizeEvent = true;
michael@0 2990 } else if (msg == NS_MOUSE_BUTTON_DOWN &&
michael@0 2991 aVisitor.mEvent->mFlags.mIsTrusted) {
michael@0 2992 gMouseDown = true;
michael@0 2993 } else if ((msg == NS_MOUSE_BUTTON_UP ||
michael@0 2994 msg == NS_DRAGDROP_END) &&
michael@0 2995 aVisitor.mEvent->mFlags.mIsTrusted) {
michael@0 2996 gMouseDown = false;
michael@0 2997 if (gDragServiceDisabled) {
michael@0 2998 nsCOMPtr<nsIDragService> ds =
michael@0 2999 do_GetService("@mozilla.org/widget/dragservice;1");
michael@0 3000 if (ds) {
michael@0 3001 gDragServiceDisabled = false;
michael@0 3002 ds->Unsuppress();
michael@0 3003 }
michael@0 3004 }
michael@0 3005 }
michael@0 3006
michael@0 3007 aVisitor.mParentTarget = GetParentTarget();
michael@0 3008
michael@0 3009 // Handle 'active' event.
michael@0 3010 if (!mIdleObservers.IsEmpty() &&
michael@0 3011 aVisitor.mEvent->mFlags.mIsTrusted &&
michael@0 3012 (aVisitor.mEvent->HasMouseEventMessage() ||
michael@0 3013 aVisitor.mEvent->HasDragEventMessage())) {
michael@0 3014 mAddActiveEventFuzzTime = false;
michael@0 3015 }
michael@0 3016
michael@0 3017 return NS_OK;
michael@0 3018 }
michael@0 3019
michael@0 3020 bool
michael@0 3021 nsGlobalWindow::ShouldPromptToBlockDialogs()
michael@0 3022 {
michael@0 3023 MOZ_ASSERT(IsOuterWindow());
michael@0 3024
michael@0 3025 nsGlobalWindow *topWindow = GetScriptableTop();
michael@0 3026 if (!topWindow) {
michael@0 3027 NS_ASSERTION(!mDocShell, "ShouldPromptToBlockDialogs() called without a top window?");
michael@0 3028 return true;
michael@0 3029 }
michael@0 3030
michael@0 3031 topWindow = topWindow->GetCurrentInnerWindowInternal();
michael@0 3032 if (!topWindow) {
michael@0 3033 return true;
michael@0 3034 }
michael@0 3035
michael@0 3036 return topWindow->DialogsAreBeingAbused();
michael@0 3037 }
michael@0 3038
michael@0 3039 bool
michael@0 3040 nsGlobalWindow::AreDialogsEnabled()
michael@0 3041 {
michael@0 3042 nsGlobalWindow *topWindow = GetScriptableTop();
michael@0 3043 if (!topWindow) {
michael@0 3044 NS_ERROR("AreDialogsEnabled() called without a top window?");
michael@0 3045 return false;
michael@0 3046 }
michael@0 3047
michael@0 3048 // TODO: Warn if no top window?
michael@0 3049 topWindow = topWindow->GetCurrentInnerWindowInternal();
michael@0 3050 if (!topWindow) {
michael@0 3051 return false;
michael@0 3052 }
michael@0 3053
michael@0 3054 // Dialogs are blocked if the content viewer is hidden
michael@0 3055 if (mDocShell) {
michael@0 3056 nsCOMPtr<nsIContentViewer> cv;
michael@0 3057 mDocShell->GetContentViewer(getter_AddRefs(cv));
michael@0 3058
michael@0 3059 bool isHidden;
michael@0 3060 cv->GetIsHidden(&isHidden);
michael@0 3061 if (isHidden) {
michael@0 3062 return false;
michael@0 3063 }
michael@0 3064 }
michael@0 3065
michael@0 3066 return topWindow->mAreDialogsEnabled;
michael@0 3067 }
michael@0 3068
michael@0 3069 bool
michael@0 3070 nsGlobalWindow::DialogsAreBeingAbused()
michael@0 3071 {
michael@0 3072 MOZ_ASSERT(IsInnerWindow());
michael@0 3073 NS_ASSERTION(GetScriptableTop() &&
michael@0 3074 GetScriptableTop()->GetCurrentInnerWindowInternal() == this,
michael@0 3075 "DialogsAreBeingAbused called with invalid window");
michael@0 3076
michael@0 3077 if (mLastDialogQuitTime.IsNull() ||
michael@0 3078 nsContentUtils::IsCallerChrome()) {
michael@0 3079 return false;
michael@0 3080 }
michael@0 3081
michael@0 3082 TimeDuration dialogInterval(TimeStamp::Now() - mLastDialogQuitTime);
michael@0 3083 if (dialogInterval.ToSeconds() <
michael@0 3084 Preferences::GetInt("dom.successive_dialog_time_limit",
michael@0 3085 DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT)) {
michael@0 3086 mDialogAbuseCount++;
michael@0 3087
michael@0 3088 return GetPopupControlState() > openAllowed ||
michael@0 3089 mDialogAbuseCount > MAX_SUCCESSIVE_DIALOG_COUNT;
michael@0 3090 }
michael@0 3091
michael@0 3092 // Reset the abuse counter
michael@0 3093 mDialogAbuseCount = 0;
michael@0 3094
michael@0 3095 return false;
michael@0 3096 }
michael@0 3097
michael@0 3098 bool
michael@0 3099 nsGlobalWindow::ConfirmDialogIfNeeded()
michael@0 3100 {
michael@0 3101 MOZ_ASSERT(IsOuterWindow());
michael@0 3102
michael@0 3103 NS_ENSURE_TRUE(mDocShell, false);
michael@0 3104 nsCOMPtr<nsIPromptService> promptSvc =
michael@0 3105 do_GetService("@mozilla.org/embedcomp/prompt-service;1");
michael@0 3106
michael@0 3107 if (!promptSvc) {
michael@0 3108 return true;
michael@0 3109 }
michael@0 3110
michael@0 3111 // Reset popup state while opening a modal dialog, and firing events
michael@0 3112 // about the dialog, to prevent the current state from being active
michael@0 3113 // the whole time a modal dialog is open.
michael@0 3114 nsAutoPopupStatePusher popupStatePusher(openAbused, true);
michael@0 3115
michael@0 3116 bool disableDialog = false;
michael@0 3117 nsXPIDLString label, title;
michael@0 3118 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
michael@0 3119 "ScriptDialogLabel", label);
michael@0 3120 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
michael@0 3121 "ScriptDialogPreventTitle", title);
michael@0 3122 promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
michael@0 3123 if (disableDialog) {
michael@0 3124 DisableDialogs();
michael@0 3125 return false;
michael@0 3126 }
michael@0 3127
michael@0 3128 return true;
michael@0 3129 }
michael@0 3130
michael@0 3131 void
michael@0 3132 nsGlobalWindow::DisableDialogs()
michael@0 3133 {
michael@0 3134 nsGlobalWindow *topWindow = GetScriptableTop();
michael@0 3135 if (!topWindow) {
michael@0 3136 NS_ERROR("DisableDialogs() called without a top window?");
michael@0 3137 return;
michael@0 3138 }
michael@0 3139
michael@0 3140 topWindow = topWindow->GetCurrentInnerWindowInternal();
michael@0 3141 // TODO: Warn if no top window?
michael@0 3142 if (topWindow) {
michael@0 3143 topWindow->mAreDialogsEnabled = false;
michael@0 3144 }
michael@0 3145 }
michael@0 3146
michael@0 3147 void
michael@0 3148 nsGlobalWindow::EnableDialogs()
michael@0 3149 {
michael@0 3150 nsGlobalWindow *topWindow = GetScriptableTop();
michael@0 3151 if (!topWindow) {
michael@0 3152 NS_ERROR("EnableDialogs() called without a top window?");
michael@0 3153 return;
michael@0 3154 }
michael@0 3155
michael@0 3156 // TODO: Warn if no top window?
michael@0 3157 topWindow = topWindow->GetCurrentInnerWindowInternal();
michael@0 3158 if (topWindow) {
michael@0 3159 topWindow->mAreDialogsEnabled = true;
michael@0 3160 }
michael@0 3161 }
michael@0 3162
michael@0 3163 nsresult
michael@0 3164 nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
michael@0 3165 {
michael@0 3166 NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
michael@0 3167
michael@0 3168 // Return early if there is nothing to do.
michael@0 3169 switch (aVisitor.mEvent->message) {
michael@0 3170 case NS_RESIZE_EVENT:
michael@0 3171 case NS_PAGE_UNLOAD:
michael@0 3172 case NS_LOAD:
michael@0 3173 break;
michael@0 3174 default:
michael@0 3175 return NS_OK;
michael@0 3176 }
michael@0 3177
michael@0 3178 /* mChromeEventHandler and mContext go dangling in the middle of this
michael@0 3179 function under some circumstances (events that destroy the window)
michael@0 3180 without this addref. */
michael@0 3181 nsCOMPtr<nsIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
michael@0 3182 nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
michael@0 3183
michael@0 3184 if (aVisitor.mEvent->message == NS_RESIZE_EVENT) {
michael@0 3185 mIsHandlingResizeEvent = false;
michael@0 3186 } else if (aVisitor.mEvent->message == NS_PAGE_UNLOAD &&
michael@0 3187 aVisitor.mEvent->mFlags.mIsTrusted) {
michael@0 3188 // Execute bindingdetached handlers before we tear ourselves
michael@0 3189 // down.
michael@0 3190 if (mDoc) {
michael@0 3191 mDoc->BindingManager()->ExecuteDetachedHandlers();
michael@0 3192 }
michael@0 3193 mIsDocumentLoaded = false;
michael@0 3194 } else if (aVisitor.mEvent->message == NS_LOAD &&
michael@0 3195 aVisitor.mEvent->mFlags.mIsTrusted) {
michael@0 3196 // This is page load event since load events don't propagate to |window|.
michael@0 3197 // @see nsDocument::PreHandleEvent.
michael@0 3198 mIsDocumentLoaded = true;
michael@0 3199
michael@0 3200 nsCOMPtr<Element> element = GetFrameElementInternal();
michael@0 3201 nsIDocShell* docShell = GetDocShell();
michael@0 3202 if (element && GetParentInternal() &&
michael@0 3203 docShell && docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
michael@0 3204 // If we're not in chrome, or at a chrome boundary, fire the
michael@0 3205 // onload event for the frame element.
michael@0 3206
michael@0 3207 nsEventStatus status = nsEventStatus_eIgnore;
michael@0 3208 WidgetEvent event(aVisitor.mEvent->mFlags.mIsTrusted, NS_LOAD);
michael@0 3209 event.mFlags.mBubbles = false;
michael@0 3210
michael@0 3211 // Most of the time we could get a pres context to pass in here,
michael@0 3212 // but not always (i.e. if this window is not shown there won't
michael@0 3213 // be a pres context available). Since we're not firing a GUI
michael@0 3214 // event we don't need a pres context anyway so we just pass
michael@0 3215 // null as the pres context all the time here.
michael@0 3216 EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status);
michael@0 3217 }
michael@0 3218 }
michael@0 3219
michael@0 3220 return NS_OK;
michael@0 3221 }
michael@0 3222
michael@0 3223 nsresult
michael@0 3224 nsGlobalWindow::DispatchDOMEvent(WidgetEvent* aEvent,
michael@0 3225 nsIDOMEvent* aDOMEvent,
michael@0 3226 nsPresContext* aPresContext,
michael@0 3227 nsEventStatus* aEventStatus)
michael@0 3228 {
michael@0 3229 return EventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),
michael@0 3230 aEvent, aDOMEvent, aPresContext,
michael@0 3231 aEventStatus);
michael@0 3232 }
michael@0 3233
michael@0 3234 void
michael@0 3235 nsGlobalWindow::PoisonOuterWindowProxy(JSObject *aObject)
michael@0 3236 {
michael@0 3237 MOZ_ASSERT(IsOuterWindow());
michael@0 3238 if (aObject == GetWrapperPreserveColor()) {
michael@0 3239 PoisonWrapper();
michael@0 3240 }
michael@0 3241 }
michael@0 3242
michael@0 3243 nsresult
michael@0 3244 nsGlobalWindow::SetArguments(nsIArray *aArguments)
michael@0 3245 {
michael@0 3246 MOZ_ASSERT(IsOuterWindow());
michael@0 3247 nsresult rv;
michael@0 3248
michael@0 3249 // Historically, we've used the same machinery to handle openDialog arguments
michael@0 3250 // (exposed via window.arguments) and showModalDialog arguments (exposed via
michael@0 3251 // window.dialogArguments), even though the former is XUL-only and uses an XPCOM
michael@0 3252 // array while the latter is web-exposed and uses an arbitrary JS value.
michael@0 3253 // Moreover, per-spec |dialogArguments| is a property of the browsing context
michael@0 3254 // (outer), whereas |arguments| lives on the inner.
michael@0 3255 //
michael@0 3256 // We've now mostly separated them, but the difference is still opaque to
michael@0 3257 // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
michael@0 3258 // embedding waltz we do here).
michael@0 3259 //
michael@0 3260 // So we need to demultiplex the two cases here.
michael@0 3261 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
michael@0 3262 if (mIsModalContentWindow) {
michael@0 3263 // nsWindowWatcher blindly converts the original nsISupports into an array
michael@0 3264 // of length 1. We need to recover it, and then cast it back to the concrete
michael@0 3265 // object we know it to be.
michael@0 3266 nsCOMPtr<nsISupports> supports = do_QueryElementAt(aArguments, 0, &rv);
michael@0 3267 NS_ENSURE_SUCCESS(rv, rv);
michael@0 3268 mDialogArguments = static_cast<DialogValueHolder*>(supports.get());
michael@0 3269 } else {
michael@0 3270 mArguments = aArguments;
michael@0 3271 rv = currentInner->DefineArgumentsProperty(aArguments);
michael@0 3272 NS_ENSURE_SUCCESS(rv, rv);
michael@0 3273 }
michael@0 3274
michael@0 3275 return NS_OK;
michael@0 3276 }
michael@0 3277
michael@0 3278 nsresult
michael@0 3279 nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
michael@0 3280 {
michael@0 3281 MOZ_ASSERT(!mIsModalContentWindow); // Handled separately.
michael@0 3282 nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
michael@0 3283 NS_ENSURE_TRUE(aArguments && ctx, NS_ERROR_NOT_INITIALIZED);
michael@0 3284 AutoJSContext cx;
michael@0 3285
michael@0 3286 JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
michael@0 3287 return ctx->SetProperty(obj, "arguments", aArguments);
michael@0 3288 }
michael@0 3289
michael@0 3290 //*****************************************************************************
michael@0 3291 // nsGlobalWindow::nsIScriptObjectPrincipal
michael@0 3292 //*****************************************************************************
michael@0 3293
michael@0 3294 nsIPrincipal*
michael@0 3295 nsGlobalWindow::GetPrincipal()
michael@0 3296 {
michael@0 3297 if (mDoc) {
michael@0 3298 // If we have a document, get the principal from the document
michael@0 3299 return mDoc->NodePrincipal();
michael@0 3300 }
michael@0 3301
michael@0 3302 if (mDocumentPrincipal) {
michael@0 3303 return mDocumentPrincipal;
michael@0 3304 }
michael@0 3305
michael@0 3306 // If we don't have a principal and we don't have a document we
michael@0 3307 // ask the parent window for the principal. This can happen when
michael@0 3308 // loading a frameset that has a <frame src="javascript:xxx">, in
michael@0 3309 // that case the global window is used in JS before we've loaded
michael@0 3310 // a document into the window.
michael@0 3311
michael@0 3312 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
michael@0 3313 do_QueryInterface(GetParentInternal());
michael@0 3314
michael@0 3315 if (objPrincipal) {
michael@0 3316 return objPrincipal->GetPrincipal();
michael@0 3317 }
michael@0 3318
michael@0 3319 return nullptr;
michael@0 3320 }
michael@0 3321
michael@0 3322 //*****************************************************************************
michael@0 3323 // nsGlobalWindow::nsIDOMWindow
michael@0 3324 //*****************************************************************************
michael@0 3325
michael@0 3326 nsIURI*
michael@0 3327 nsPIDOMWindow::GetDocumentURI() const
michael@0 3328 {
michael@0 3329 return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
michael@0 3330 }
michael@0 3331
michael@0 3332 nsIURI*
michael@0 3333 nsPIDOMWindow::GetDocBaseURI() const
michael@0 3334 {
michael@0 3335 return mDoc ? mDoc->GetDocBaseURI() : mDocBaseURI.get();
michael@0 3336 }
michael@0 3337
michael@0 3338 void
michael@0 3339 nsPIDOMWindow::MaybeCreateDoc()
michael@0 3340 {
michael@0 3341 MOZ_ASSERT(!mDoc);
michael@0 3342 if (nsIDocShell* docShell = GetDocShell()) {
michael@0 3343 // Note that |document| here is the same thing as our mDoc, but we
michael@0 3344 // don't have to explicitly set the member variable because the docshell
michael@0 3345 // has already called SetNewDocument().
michael@0 3346 nsCOMPtr<nsIDocument> document = do_GetInterface(docShell);
michael@0 3347 }
michael@0 3348 }
michael@0 3349
michael@0 3350 Element*
michael@0 3351 nsPIDOMWindow::GetFrameElementInternal() const
michael@0 3352 {
michael@0 3353 if (mOuterWindow) {
michael@0 3354 return mOuterWindow->GetFrameElementInternal();
michael@0 3355 }
michael@0 3356
michael@0 3357 NS_ASSERTION(!IsInnerWindow(),
michael@0 3358 "GetFrameElementInternal() called on orphan inner window");
michael@0 3359
michael@0 3360 return mFrameElement;
michael@0 3361 }
michael@0 3362
michael@0 3363 void
michael@0 3364 nsPIDOMWindow::SetFrameElementInternal(Element* aFrameElement)
michael@0 3365 {
michael@0 3366 if (IsOuterWindow()) {
michael@0 3367 mFrameElement = aFrameElement;
michael@0 3368
michael@0 3369 return;
michael@0 3370 }
michael@0 3371
michael@0 3372 if (!mOuterWindow) {
michael@0 3373 NS_ERROR("frameElement set on inner window with no outer!");
michael@0 3374
michael@0 3375 return;
michael@0 3376 }
michael@0 3377
michael@0 3378 mOuterWindow->SetFrameElementInternal(aFrameElement);
michael@0 3379 }
michael@0 3380
michael@0 3381 void
michael@0 3382 nsPIDOMWindow::AddAudioContext(AudioContext* aAudioContext)
michael@0 3383 {
michael@0 3384 mAudioContexts.AppendElement(aAudioContext);
michael@0 3385
michael@0 3386 nsIDocShell* docShell = GetDocShell();
michael@0 3387 if (docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline()) {
michael@0 3388 aAudioContext->Mute();
michael@0 3389 }
michael@0 3390 }
michael@0 3391
michael@0 3392 void
michael@0 3393 nsPIDOMWindow::RemoveAudioContext(AudioContext* aAudioContext)
michael@0 3394 {
michael@0 3395 mAudioContexts.RemoveElement(aAudioContext);
michael@0 3396 }
michael@0 3397
michael@0 3398 void
michael@0 3399 nsPIDOMWindow::MuteAudioContexts()
michael@0 3400 {
michael@0 3401 for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
michael@0 3402 if (!mAudioContexts[i]->IsOffline()) {
michael@0 3403 mAudioContexts[i]->Mute();
michael@0 3404 }
michael@0 3405 }
michael@0 3406 }
michael@0 3407
michael@0 3408 void
michael@0 3409 nsPIDOMWindow::UnmuteAudioContexts()
michael@0 3410 {
michael@0 3411 for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
michael@0 3412 if (!mAudioContexts[i]->IsOffline()) {
michael@0 3413 mAudioContexts[i]->Unmute();
michael@0 3414 }
michael@0 3415 }
michael@0 3416 }
michael@0 3417
michael@0 3418 NS_IMETHODIMP
michael@0 3419 nsGlobalWindow::GetDocument(nsIDOMDocument** aDocument)
michael@0 3420 {
michael@0 3421 nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(GetDocument());
michael@0 3422 document.forget(aDocument);
michael@0 3423 return NS_OK;
michael@0 3424 }
michael@0 3425
michael@0 3426 nsIDOMWindow*
michael@0 3427 nsGlobalWindow::GetWindow(ErrorResult& aError)
michael@0 3428 {
michael@0 3429 FORWARD_TO_OUTER_OR_THROW(GetWindow, (aError), aError, nullptr);
michael@0 3430
michael@0 3431 return this;
michael@0 3432 }
michael@0 3433
michael@0 3434 NS_IMETHODIMP
michael@0 3435 nsGlobalWindow::GetWindow(nsIDOMWindow** aWindow)
michael@0 3436 {
michael@0 3437 ErrorResult rv;
michael@0 3438 nsCOMPtr<nsIDOMWindow> window = GetWindow(rv);
michael@0 3439 window.forget(aWindow);
michael@0 3440
michael@0 3441 return rv.ErrorCode();
michael@0 3442 }
michael@0 3443
michael@0 3444 nsIDOMWindow*
michael@0 3445 nsGlobalWindow::GetSelf(ErrorResult& aError)
michael@0 3446 {
michael@0 3447 FORWARD_TO_OUTER_OR_THROW(GetSelf, (aError), aError, nullptr);
michael@0 3448
michael@0 3449 return this;
michael@0 3450 }
michael@0 3451
michael@0 3452 NS_IMETHODIMP
michael@0 3453 nsGlobalWindow::GetSelf(nsIDOMWindow** aWindow)
michael@0 3454 {
michael@0 3455 ErrorResult rv;
michael@0 3456 nsCOMPtr<nsIDOMWindow> window = GetSelf(rv);
michael@0 3457 window.forget(aWindow);
michael@0 3458
michael@0 3459 return rv.ErrorCode();
michael@0 3460 }
michael@0 3461
michael@0 3462 Navigator*
michael@0 3463 nsGlobalWindow::GetNavigator(ErrorResult& aError)
michael@0 3464 {
michael@0 3465 FORWARD_TO_INNER_OR_THROW(GetNavigator, (aError), aError, nullptr);
michael@0 3466
michael@0 3467 if (!mNavigator) {
michael@0 3468 mNavigator = new Navigator(this);
michael@0 3469 }
michael@0 3470
michael@0 3471 return mNavigator;
michael@0 3472 }
michael@0 3473
michael@0 3474 NS_IMETHODIMP
michael@0 3475 nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
michael@0 3476 {
michael@0 3477 ErrorResult rv;
michael@0 3478 nsCOMPtr<nsIDOMNavigator> navigator = GetNavigator(rv);
michael@0 3479 navigator.forget(aNavigator);
michael@0 3480
michael@0 3481 return rv.ErrorCode();
michael@0 3482 }
michael@0 3483
michael@0 3484 nsScreen*
michael@0 3485 nsGlobalWindow::GetScreen(ErrorResult& aError)
michael@0 3486 {
michael@0 3487 FORWARD_TO_INNER_OR_THROW(GetScreen, (aError), aError, nullptr);
michael@0 3488
michael@0 3489 if (!mScreen) {
michael@0 3490 mScreen = nsScreen::Create(this);
michael@0 3491 if (!mScreen) {
michael@0 3492 aError.Throw(NS_ERROR_UNEXPECTED);
michael@0 3493 return nullptr;
michael@0 3494 }
michael@0 3495 }
michael@0 3496
michael@0 3497 return mScreen;
michael@0 3498 }
michael@0 3499
michael@0 3500 NS_IMETHODIMP
michael@0 3501 nsGlobalWindow::GetScreen(nsIDOMScreen** aScreen)
michael@0 3502 {
michael@0 3503 ErrorResult rv;
michael@0 3504 nsRefPtr<nsScreen> screen = GetScreen(rv);
michael@0 3505 screen.forget(aScreen);
michael@0 3506
michael@0 3507 return rv.ErrorCode();
michael@0 3508 }
michael@0 3509
michael@0 3510 nsHistory*
michael@0 3511 nsGlobalWindow::GetHistory(ErrorResult& aError)
michael@0 3512 {
michael@0 3513 FORWARD_TO_INNER_OR_THROW(GetHistory, (aError), aError, nullptr);
michael@0 3514
michael@0 3515 if (!mHistory) {
michael@0 3516 mHistory = new nsHistory(this);
michael@0 3517 }
michael@0 3518
michael@0 3519 return mHistory;
michael@0 3520 }
michael@0 3521
michael@0 3522 NS_IMETHODIMP
michael@0 3523 nsGlobalWindow::GetHistory(nsISupports** aHistory)
michael@0 3524 {
michael@0 3525 ErrorResult rv;
michael@0 3526 nsCOMPtr<nsISupports> history = GetHistory(rv);
michael@0 3527 history.forget(aHistory);
michael@0 3528
michael@0 3529 return rv.ErrorCode();
michael@0 3530 }
michael@0 3531
michael@0 3532 nsPerformance*
michael@0 3533 nsGlobalWindow::GetPerformance(ErrorResult& aError)
michael@0 3534 {
michael@0 3535 FORWARD_TO_INNER_OR_THROW(GetPerformance, (aError), aError, nullptr);
michael@0 3536
michael@0 3537 nsPerformance* p = nsPIDOMWindow::GetPerformance();
michael@0 3538 if (!p) {
michael@0 3539 aError.Throw(NS_ERROR_FAILURE);
michael@0 3540 }
michael@0 3541 return p;
michael@0 3542 }
michael@0 3543
michael@0 3544 NS_IMETHODIMP
michael@0 3545 nsGlobalWindow::GetPerformance(nsISupports** aPerformance)
michael@0 3546 {
michael@0 3547 ErrorResult rv;
michael@0 3548 nsCOMPtr<nsISupports> performance = GetPerformance(rv);
michael@0 3549 performance.forget(aPerformance);
michael@0 3550
michael@0 3551 return rv.ErrorCode();
michael@0 3552 }
michael@0 3553
michael@0 3554 nsPerformance*
michael@0 3555 nsPIDOMWindow::GetPerformance()
michael@0 3556 {
michael@0 3557 MOZ_ASSERT(IsInnerWindow());
michael@0 3558 CreatePerformanceObjectIfNeeded();
michael@0 3559 return mPerformance;
michael@0 3560 }
michael@0 3561
michael@0 3562 void
michael@0 3563 nsPIDOMWindow::CreatePerformanceObjectIfNeeded()
michael@0 3564 {
michael@0 3565 if (mPerformance || !mDoc) {
michael@0 3566 return;
michael@0 3567 }
michael@0 3568 nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
michael@0 3569 nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
michael@0 3570 bool timingEnabled = false;
michael@0 3571 if (!timedChannel ||
michael@0 3572 !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
michael@0 3573 !timingEnabled) {
michael@0 3574 timedChannel = nullptr;
michael@0 3575 }
michael@0 3576 if (timing) {
michael@0 3577 // If we are dealing with an iframe, we will need the parent's performance
michael@0 3578 // object (so we can add the iframe as a resource of that page).
michael@0 3579 nsPerformance* parentPerformance = nullptr;
michael@0 3580 nsCOMPtr<nsIDOMWindow> parentWindow;
michael@0 3581 GetScriptableParent(getter_AddRefs(parentWindow));
michael@0 3582 nsCOMPtr<nsPIDOMWindow> parentPWindow = do_GetInterface(parentWindow);
michael@0 3583 if (GetOuterWindow() != parentPWindow) {
michael@0 3584 if (parentPWindow && !parentPWindow->IsInnerWindow()) {
michael@0 3585 parentPWindow = parentPWindow->GetCurrentInnerWindow();
michael@0 3586 }
michael@0 3587 if (parentPWindow) {
michael@0 3588 parentPerformance = parentPWindow->GetPerformance();
michael@0 3589 }
michael@0 3590 }
michael@0 3591 mPerformance =
michael@0 3592 new nsPerformance(this, timing, timedChannel, parentPerformance);
michael@0 3593 }
michael@0 3594 }
michael@0 3595
michael@0 3596 bool
michael@0 3597 nsPIDOMWindow::GetAudioMuted() const
michael@0 3598 {
michael@0 3599 if (!IsInnerWindow()) {
michael@0 3600 return mInnerWindow->GetAudioMuted();
michael@0 3601 }
michael@0 3602
michael@0 3603 return mAudioMuted;
michael@0 3604 }
michael@0 3605
michael@0 3606 void
michael@0 3607 nsPIDOMWindow::SetAudioMuted(bool aMuted)
michael@0 3608 {
michael@0 3609 if (!IsInnerWindow()) {
michael@0 3610 mInnerWindow->SetAudioMuted(aMuted);
michael@0 3611 return;
michael@0 3612 }
michael@0 3613
michael@0 3614 if (mAudioMuted == aMuted) {
michael@0 3615 return;
michael@0 3616 }
michael@0 3617
michael@0 3618 mAudioMuted = aMuted;
michael@0 3619 RefreshMediaElements();
michael@0 3620 }
michael@0 3621
michael@0 3622 float
michael@0 3623 nsPIDOMWindow::GetAudioVolume() const
michael@0 3624 {
michael@0 3625 if (!IsInnerWindow()) {
michael@0 3626 return mInnerWindow->GetAudioVolume();
michael@0 3627 }
michael@0 3628
michael@0 3629 return mAudioVolume;
michael@0 3630 }
michael@0 3631
michael@0 3632 nsresult
michael@0 3633 nsPIDOMWindow::SetAudioVolume(float aVolume)
michael@0 3634 {
michael@0 3635 if (!IsInnerWindow()) {
michael@0 3636 return mInnerWindow->SetAudioVolume(aVolume);
michael@0 3637 }
michael@0 3638
michael@0 3639 if (aVolume < 0.0) {
michael@0 3640 return NS_ERROR_DOM_INDEX_SIZE_ERR;
michael@0 3641 }
michael@0 3642
michael@0 3643 if (mAudioVolume == aVolume) {
michael@0 3644 return NS_OK;
michael@0 3645 }
michael@0 3646
michael@0 3647 mAudioVolume = aVolume;
michael@0 3648 RefreshMediaElements();
michael@0 3649 return NS_OK;
michael@0 3650 }
michael@0 3651
michael@0 3652 float
michael@0 3653 nsPIDOMWindow::GetAudioGlobalVolume()
michael@0 3654 {
michael@0 3655 float globalVolume = 1.0;
michael@0 3656 nsCOMPtr<nsPIDOMWindow> window = this;
michael@0 3657
michael@0 3658 do {
michael@0 3659 if (window->GetAudioMuted()) {
michael@0 3660 return 0;
michael@0 3661 }
michael@0 3662
michael@0 3663 globalVolume *= window->GetAudioVolume();
michael@0 3664
michael@0 3665 nsCOMPtr<nsIDOMWindow> win;
michael@0 3666 window->GetParent(getter_AddRefs(win));
michael@0 3667 if (window == win) {
michael@0 3668 break;
michael@0 3669 }
michael@0 3670
michael@0 3671 window = do_QueryInterface(win);
michael@0 3672
michael@0 3673 // If there is not parent, or we are the toplevel or the volume is
michael@0 3674 // already 0.0, we don't continue.
michael@0 3675 } while (window && window != this && globalVolume);
michael@0 3676
michael@0 3677 return globalVolume;
michael@0 3678 }
michael@0 3679
michael@0 3680 void
michael@0 3681 nsPIDOMWindow::RefreshMediaElements()
michael@0 3682 {
michael@0 3683 nsRefPtr<AudioChannelService> service =
michael@0 3684 AudioChannelService::GetAudioChannelService();
michael@0 3685 if (service) {
michael@0 3686 service->RefreshAgentsVolume(this);
michael@0 3687 }
michael@0 3688 }
michael@0 3689
michael@0 3690 // nsISpeechSynthesisGetter
michael@0 3691
michael@0 3692 #ifdef MOZ_WEBSPEECH
michael@0 3693 SpeechSynthesis*
michael@0 3694 nsGlobalWindow::GetSpeechSynthesis(ErrorResult& aError)
michael@0 3695 {
michael@0 3696 FORWARD_TO_INNER_OR_THROW(GetSpeechSynthesis, (aError), aError, nullptr);
michael@0 3697
michael@0 3698 if (!mSpeechSynthesis) {
michael@0 3699 mSpeechSynthesis = new SpeechSynthesis(this);
michael@0 3700 }
michael@0 3701
michael@0 3702 return mSpeechSynthesis;
michael@0 3703 }
michael@0 3704
michael@0 3705 NS_IMETHODIMP
michael@0 3706 nsGlobalWindow::GetSpeechSynthesis(nsISupports** aSpeechSynthesis)
michael@0 3707 {
michael@0 3708 ErrorResult rv;
michael@0 3709 nsCOMPtr<nsISupports> speechSynthesis;
michael@0 3710 if (Preferences::GetBool("media.webspeech.synth.enabled")) {
michael@0 3711 speechSynthesis = GetSpeechSynthesis(rv);
michael@0 3712 }
michael@0 3713 speechSynthesis.forget(aSpeechSynthesis);
michael@0 3714
michael@0 3715 return rv.ErrorCode();
michael@0 3716 }
michael@0 3717 #endif
michael@0 3718
michael@0 3719 already_AddRefed<nsIDOMWindow>
michael@0 3720 nsGlobalWindow::GetParent(ErrorResult& aError)
michael@0 3721 {
michael@0 3722 FORWARD_TO_OUTER_OR_THROW(GetParent, (aError), aError, nullptr);
michael@0 3723
michael@0 3724 if (!mDocShell) {
michael@0 3725 return nullptr;
michael@0 3726 }
michael@0 3727
michael@0 3728 nsCOMPtr<nsIDOMWindow> parent;
michael@0 3729 if (mDocShell->GetIsBrowserOrApp()) {
michael@0 3730 parent = this;
michael@0 3731 } else {
michael@0 3732 aError = GetRealParent(getter_AddRefs(parent));
michael@0 3733 }
michael@0 3734
michael@0 3735 return parent.forget();
michael@0 3736 }
michael@0 3737
michael@0 3738 /**
michael@0 3739 * GetScriptableParent is called when script reads window.parent.
michael@0 3740 *
michael@0 3741 * In contrast to GetRealParent, GetScriptableParent respects <iframe
michael@0 3742 * mozbrowser> boundaries, so if |this| is contained by an <iframe
michael@0 3743 * mozbrowser>, we will return |this| as its own parent.
michael@0 3744 */
michael@0 3745 NS_IMETHODIMP
michael@0 3746 nsGlobalWindow::GetScriptableParent(nsIDOMWindow** aParent)
michael@0 3747 {
michael@0 3748 ErrorResult rv;
michael@0 3749 nsCOMPtr<nsIDOMWindow> parent = GetParent(rv);
michael@0 3750 parent.forget(aParent);
michael@0 3751
michael@0 3752 return rv.ErrorCode();
michael@0 3753 }
michael@0 3754
michael@0 3755 /**
michael@0 3756 * nsIDOMWindow::GetParent (when called from C++) is just a wrapper around
michael@0 3757 * GetRealParent.
michael@0 3758 */
michael@0 3759 NS_IMETHODIMP
michael@0 3760 nsGlobalWindow::GetRealParent(nsIDOMWindow** aParent)
michael@0 3761 {
michael@0 3762 FORWARD_TO_OUTER(GetRealParent, (aParent), NS_ERROR_NOT_INITIALIZED);
michael@0 3763
michael@0 3764 *aParent = nullptr;
michael@0 3765 if (!mDocShell) {
michael@0 3766 return NS_OK;
michael@0 3767 }
michael@0 3768
michael@0 3769 nsCOMPtr<nsIDocShell> parent;
michael@0 3770 mDocShell->GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
michael@0 3771
michael@0 3772 if (parent) {
michael@0 3773 nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(parent));
michael@0 3774 NS_ENSURE_SUCCESS(CallQueryInterface(globalObject.get(), aParent),
michael@0 3775 NS_ERROR_FAILURE);
michael@0 3776 }
michael@0 3777 else {
michael@0 3778 *aParent = static_cast<nsIDOMWindow*>(this);
michael@0 3779 NS_ADDREF(*aParent);
michael@0 3780 }
michael@0 3781 return NS_OK;
michael@0 3782 }
michael@0 3783
michael@0 3784 static nsresult
michael@0 3785 GetTopImpl(nsGlobalWindow* aWin, nsIDOMWindow** aTop, bool aScriptable)
michael@0 3786 {
michael@0 3787 *aTop = nullptr;
michael@0 3788
michael@0 3789 // Walk up the parent chain.
michael@0 3790
michael@0 3791 nsCOMPtr<nsIDOMWindow> prevParent = aWin;
michael@0 3792 nsCOMPtr<nsIDOMWindow> parent = aWin;
michael@0 3793 do {
michael@0 3794 if (!parent) {
michael@0 3795 break;
michael@0 3796 }
michael@0 3797
michael@0 3798 prevParent = parent;
michael@0 3799
michael@0 3800 nsCOMPtr<nsIDOMWindow> newParent;
michael@0 3801 nsresult rv;
michael@0 3802 if (aScriptable) {
michael@0 3803 rv = parent->GetScriptableParent(getter_AddRefs(newParent));
michael@0 3804 }
michael@0 3805 else {
michael@0 3806 rv = parent->GetParent(getter_AddRefs(newParent));
michael@0 3807 }
michael@0 3808 NS_ENSURE_SUCCESS(rv, rv);
michael@0 3809
michael@0 3810 parent = newParent;
michael@0 3811
michael@0 3812 } while (parent != prevParent);
michael@0 3813
michael@0 3814 if (parent) {
michael@0 3815 parent.swap(*aTop);
michael@0 3816 }
michael@0 3817
michael@0 3818 return NS_OK;
michael@0 3819 }
michael@0 3820
michael@0 3821 /**
michael@0 3822 * GetScriptableTop is called when script reads window.top.
michael@0 3823 *
michael@0 3824 * In contrast to GetRealTop, GetScriptableTop respects <iframe mozbrowser>
michael@0 3825 * boundaries. If we encounter a window owned by an <iframe mozbrowser> while
michael@0 3826 * walking up the window hierarchy, we'll stop and return that window.
michael@0 3827 */
michael@0 3828 NS_IMETHODIMP
michael@0 3829 nsGlobalWindow::GetScriptableTop(nsIDOMWindow **aTop)
michael@0 3830 {
michael@0 3831 FORWARD_TO_OUTER(GetScriptableTop, (aTop), NS_ERROR_NOT_INITIALIZED);
michael@0 3832 return GetTopImpl(this, aTop, /* aScriptable = */ true);
michael@0 3833 }
michael@0 3834
michael@0 3835 /**
michael@0 3836 * nsIDOMWindow::GetTop (when called from C++) is just a wrapper around
michael@0 3837 * GetRealTop.
michael@0 3838 */
michael@0 3839 NS_IMETHODIMP
michael@0 3840 nsGlobalWindow::GetRealTop(nsIDOMWindow** aTop)
michael@0 3841 {
michael@0 3842 nsGlobalWindow* outer;
michael@0 3843 if (IsInnerWindow()) {
michael@0 3844 outer = GetOuterWindowInternal();
michael@0 3845 if (!outer) {
michael@0 3846 NS_WARNING("No outer window available!");
michael@0 3847 return NS_ERROR_NOT_INITIALIZED;
michael@0 3848 }
michael@0 3849 } else {
michael@0 3850 outer = this;
michael@0 3851 }
michael@0 3852 return GetTopImpl(outer, aTop, /* aScriptable = */ false);
michael@0 3853 }
michael@0 3854
michael@0 3855 void
michael@0 3856 nsGlobalWindow::GetContent(JSContext* aCx,
michael@0 3857 JS::MutableHandle<JSObject*> aRetval,
michael@0 3858 ErrorResult& aError)
michael@0 3859 {
michael@0 3860 FORWARD_TO_OUTER_OR_THROW(GetContent, (aCx, aRetval, aError), aError, );
michael@0 3861
michael@0 3862 nsCOMPtr<nsIDOMWindow> content = GetContentInternal(aError);
michael@0 3863 if (aError.Failed()) {
michael@0 3864 return;
michael@0 3865 }
michael@0 3866
michael@0 3867 if (content) {
michael@0 3868 JS::Rooted<JS::Value> val(aCx);
michael@0 3869 aError = nsContentUtils::WrapNative(aCx, content, &val);
michael@0 3870 if (aError.Failed()) {
michael@0 3871 return;
michael@0 3872 }
michael@0 3873
michael@0 3874 aRetval.set(&val.toObject());
michael@0 3875 return;
michael@0 3876 }
michael@0 3877
michael@0 3878 if (!nsContentUtils::IsCallerChrome() || !IsChromeWindow()) {
michael@0 3879 aError.Throw(NS_ERROR_FAILURE);
michael@0 3880 return;
michael@0 3881 }
michael@0 3882
michael@0 3883 // Something tries to get .content on a ChromeWindow, try to fetch the CPOW.
michael@0 3884 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
michael@0 3885 if (!treeOwner) {
michael@0 3886 aError.Throw(NS_ERROR_FAILURE);
michael@0 3887 return;
michael@0 3888 }
michael@0 3889
michael@0 3890 JS::Rooted<JS::Value> val(aCx, JS::NullValue());
michael@0 3891 aError = treeOwner->GetContentWindow(aCx, &val);
michael@0 3892 if (aError.Failed()) {
michael@0 3893 return;
michael@0 3894 }
michael@0 3895
michael@0 3896 aRetval.set(val.toObjectOrNull());
michael@0 3897 }
michael@0 3898
michael@0 3899 already_AddRefed<nsIDOMWindow>
michael@0 3900 nsGlobalWindow::GetContentInternal(ErrorResult& aError)
michael@0 3901 {
michael@0 3902 // First check for a named frame named "content"
michael@0 3903 nsCOMPtr<nsIDOMWindow> domWindow =
michael@0 3904 GetChildWindow(NS_LITERAL_STRING("content"));
michael@0 3905 if (domWindow) {
michael@0 3906 return domWindow.forget();
michael@0 3907 }
michael@0 3908
michael@0 3909 // If we're contained in <iframe mozbrowser> or <iframe mozapp>, then
michael@0 3910 // GetContent is the same as window.top.
michael@0 3911 if (mDocShell && mDocShell->GetIsInBrowserOrApp()) {
michael@0 3912 return GetTop(aError);
michael@0 3913 }
michael@0 3914
michael@0 3915 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
michael@0 3916 if (!nsContentUtils::IsCallerChrome()) {
michael@0 3917 // If we're called by non-chrome code, make sure we don't return
michael@0 3918 // the primary content window if the calling tab is hidden. In
michael@0 3919 // such a case we return the same-type root in the hidden tab,
michael@0 3920 // which is "good enough", for now.
michael@0 3921 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
michael@0 3922
michael@0 3923 if (baseWin) {
michael@0 3924 bool visible = false;
michael@0 3925 baseWin->GetVisibility(&visible);
michael@0 3926
michael@0 3927 if (!visible) {
michael@0 3928 mDocShell->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
michael@0 3929 }
michael@0 3930 }
michael@0 3931 }
michael@0 3932
michael@0 3933 if (!primaryContent) {
michael@0 3934 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
michael@0 3935 if (!treeOwner) {
michael@0 3936 aError.Throw(NS_ERROR_FAILURE);
michael@0 3937 return nullptr;
michael@0 3938 }
michael@0 3939
michael@0 3940 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
michael@0 3941 }
michael@0 3942
michael@0 3943 domWindow = do_GetInterface(primaryContent);
michael@0 3944 return domWindow.forget();
michael@0 3945 }
michael@0 3946
michael@0 3947 NS_IMETHODIMP
michael@0 3948 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
michael@0 3949 {
michael@0 3950 ErrorResult rv;
michael@0 3951 *aContent = GetContentInternal(rv).take();
michael@0 3952
michael@0 3953 return rv.ErrorCode();
michael@0 3954 }
michael@0 3955
michael@0 3956 NS_IMETHODIMP
michael@0 3957 nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
michael@0 3958 {
michael@0 3959 ErrorResult rv;
michael@0 3960 JS::Rooted<JSObject*> content(aCx);
michael@0 3961 GetContent(aCx, &content, rv);
michael@0 3962 if (!rv.Failed()) {
michael@0 3963 aVal.setObjectOrNull(content);
michael@0 3964 }
michael@0 3965
michael@0 3966 return rv.ErrorCode();
michael@0 3967 }
michael@0 3968
michael@0 3969 NS_IMETHODIMP
michael@0 3970 nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
michael@0 3971 {
michael@0 3972 if (IsInnerWindow()) {
michael@0 3973 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 3974 if (!outer) {
michael@0 3975 NS_WARNING("No outer window available!");
michael@0 3976 return NS_ERROR_NOT_INITIALIZED;
michael@0 3977 }
michael@0 3978 return outer->GetPrompter(aPrompt);
michael@0 3979 }
michael@0 3980
michael@0 3981 if (!mDocShell)
michael@0 3982 return NS_ERROR_FAILURE;
michael@0 3983
michael@0 3984 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
michael@0 3985 NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
michael@0 3986
michael@0 3987 NS_ADDREF(*aPrompt = prompter);
michael@0 3988 return NS_OK;
michael@0 3989 }
michael@0 3990
michael@0 3991 BarProp*
michael@0 3992 nsGlobalWindow::GetMenubar(ErrorResult& aError)
michael@0 3993 {
michael@0 3994 FORWARD_TO_INNER_OR_THROW(GetMenubar, (aError), aError, nullptr);
michael@0 3995
michael@0 3996 if (!mMenubar) {
michael@0 3997 mMenubar = new MenubarProp(this);
michael@0 3998 }
michael@0 3999
michael@0 4000 return mMenubar;
michael@0 4001 }
michael@0 4002
michael@0 4003 NS_IMETHODIMP
michael@0 4004 nsGlobalWindow::GetMenubar(nsISupports** aMenubar)
michael@0 4005 {
michael@0 4006 ErrorResult rv;
michael@0 4007 nsCOMPtr<nsISupports> menubar = GetMenubar(rv);
michael@0 4008 menubar.forget(aMenubar);
michael@0 4009
michael@0 4010 return rv.ErrorCode();
michael@0 4011 }
michael@0 4012
michael@0 4013 BarProp*
michael@0 4014 nsGlobalWindow::GetToolbar(ErrorResult& aError)
michael@0 4015 {
michael@0 4016 FORWARD_TO_INNER_OR_THROW(GetToolbar, (aError), aError, nullptr);
michael@0 4017
michael@0 4018 if (!mToolbar) {
michael@0 4019 mToolbar = new ToolbarProp(this);
michael@0 4020 }
michael@0 4021
michael@0 4022 return mToolbar;
michael@0 4023 }
michael@0 4024
michael@0 4025 NS_IMETHODIMP
michael@0 4026 nsGlobalWindow::GetToolbar(nsISupports** aToolbar)
michael@0 4027 {
michael@0 4028 ErrorResult rv;
michael@0 4029 nsCOMPtr<nsISupports> toolbar = GetToolbar(rv);
michael@0 4030 toolbar.forget(aToolbar);
michael@0 4031
michael@0 4032 return rv.ErrorCode();
michael@0 4033 }
michael@0 4034
michael@0 4035 BarProp*
michael@0 4036 nsGlobalWindow::GetLocationbar(ErrorResult& aError)
michael@0 4037 {
michael@0 4038 FORWARD_TO_INNER_OR_THROW(GetLocationbar, (aError), aError, nullptr);
michael@0 4039
michael@0 4040 if (!mLocationbar) {
michael@0 4041 mLocationbar = new LocationbarProp(this);
michael@0 4042 }
michael@0 4043 return mLocationbar;
michael@0 4044 }
michael@0 4045
michael@0 4046 NS_IMETHODIMP
michael@0 4047 nsGlobalWindow::GetLocationbar(nsISupports** aLocationbar)
michael@0 4048 {
michael@0 4049 ErrorResult rv;
michael@0 4050 nsCOMPtr<nsISupports> locationbar = GetLocationbar(rv);
michael@0 4051 locationbar.forget(aLocationbar);
michael@0 4052
michael@0 4053 return rv.ErrorCode();
michael@0 4054 }
michael@0 4055
michael@0 4056 BarProp*
michael@0 4057 nsGlobalWindow::GetPersonalbar(ErrorResult& aError)
michael@0 4058 {
michael@0 4059 FORWARD_TO_INNER_OR_THROW(GetPersonalbar, (aError), aError, nullptr);
michael@0 4060
michael@0 4061 if (!mPersonalbar) {
michael@0 4062 mPersonalbar = new PersonalbarProp(this);
michael@0 4063 }
michael@0 4064 return mPersonalbar;
michael@0 4065 }
michael@0 4066
michael@0 4067 NS_IMETHODIMP
michael@0 4068 nsGlobalWindow::GetPersonalbar(nsISupports** aPersonalbar)
michael@0 4069 {
michael@0 4070 ErrorResult rv;
michael@0 4071 nsCOMPtr<nsISupports> personalbar = GetPersonalbar(rv);
michael@0 4072 personalbar.forget(aPersonalbar);
michael@0 4073
michael@0 4074 return rv.ErrorCode();
michael@0 4075 }
michael@0 4076
michael@0 4077 BarProp*
michael@0 4078 nsGlobalWindow::GetStatusbar(ErrorResult& aError)
michael@0 4079 {
michael@0 4080 FORWARD_TO_INNER_OR_THROW(GetStatusbar, (aError), aError, nullptr);
michael@0 4081
michael@0 4082 if (!mStatusbar) {
michael@0 4083 mStatusbar = new StatusbarProp(this);
michael@0 4084 }
michael@0 4085 return mStatusbar;
michael@0 4086 }
michael@0 4087
michael@0 4088 NS_IMETHODIMP
michael@0 4089 nsGlobalWindow::GetStatusbar(nsISupports** aStatusbar)
michael@0 4090 {
michael@0 4091 ErrorResult rv;
michael@0 4092 nsCOMPtr<nsISupports> statusbar = GetStatusbar(rv);
michael@0 4093 statusbar.forget(aStatusbar);
michael@0 4094
michael@0 4095 return rv.ErrorCode();
michael@0 4096 }
michael@0 4097
michael@0 4098 BarProp*
michael@0 4099 nsGlobalWindow::GetScrollbars(ErrorResult& aError)
michael@0 4100 {
michael@0 4101 FORWARD_TO_INNER_OR_THROW(GetScrollbars, (aError), aError, nullptr);
michael@0 4102
michael@0 4103 if (!mScrollbars) {
michael@0 4104 mScrollbars = new ScrollbarsProp(this);
michael@0 4105 }
michael@0 4106
michael@0 4107 return mScrollbars;
michael@0 4108 }
michael@0 4109
michael@0 4110 NS_IMETHODIMP
michael@0 4111 nsGlobalWindow::GetScrollbars(nsISupports** aScrollbars)
michael@0 4112 {
michael@0 4113 ErrorResult rv;
michael@0 4114 nsCOMPtr<nsISupports> scrollbars = GetScrollbars(rv);
michael@0 4115 scrollbars.forget(aScrollbars);
michael@0 4116
michael@0 4117 return rv.ErrorCode();
michael@0 4118 }
michael@0 4119
michael@0 4120 bool
michael@0 4121 nsGlobalWindow::GetClosed(ErrorResult& aError)
michael@0 4122 {
michael@0 4123 FORWARD_TO_OUTER_OR_THROW(GetClosed, (aError), aError, false);
michael@0 4124
michael@0 4125 // If someone called close(), or if we don't have a docshell, we're closed.
michael@0 4126 return mIsClosed || !mDocShell;
michael@0 4127 }
michael@0 4128
michael@0 4129 NS_IMETHODIMP
michael@0 4130 nsGlobalWindow::GetClosed(bool* aClosed)
michael@0 4131 {
michael@0 4132 ErrorResult rv;
michael@0 4133 *aClosed = GetClosed(rv);
michael@0 4134
michael@0 4135 return rv.ErrorCode();
michael@0 4136 }
michael@0 4137
michael@0 4138 nsDOMWindowList*
michael@0 4139 nsGlobalWindow::GetWindowList()
michael@0 4140 {
michael@0 4141 MOZ_ASSERT(IsOuterWindow());
michael@0 4142
michael@0 4143 if (!mFrames && mDocShell) {
michael@0 4144 mFrames = new nsDOMWindowList(mDocShell);
michael@0 4145 }
michael@0 4146
michael@0 4147 return mFrames;
michael@0 4148 }
michael@0 4149
michael@0 4150 NS_IMETHODIMP
michael@0 4151 nsGlobalWindow::GetFrames(nsIDOMWindowCollection** aFrames)
michael@0 4152 {
michael@0 4153 FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
michael@0 4154
michael@0 4155 *aFrames = GetWindowList();
michael@0 4156 NS_IF_ADDREF(*aFrames);
michael@0 4157 return NS_OK;
michael@0 4158 }
michael@0 4159
michael@0 4160 already_AddRefed<nsIDOMWindow>
michael@0 4161 nsGlobalWindow::IndexedGetter(uint32_t aIndex, bool& aFound)
michael@0 4162 {
michael@0 4163 aFound = false;
michael@0 4164
michael@0 4165 FORWARD_TO_OUTER(IndexedGetter, (aIndex, aFound), nullptr);
michael@0 4166
michael@0 4167 nsDOMWindowList* windows = GetWindowList();
michael@0 4168 NS_ENSURE_TRUE(windows, nullptr);
michael@0 4169
michael@0 4170 return windows->IndexedGetter(aIndex, aFound);
michael@0 4171 }
michael@0 4172
michael@0 4173 void
michael@0 4174 nsGlobalWindow::GetSupportedNames(nsTArray<nsString>& aNames)
michael@0 4175 {
michael@0 4176 FORWARD_TO_OUTER_VOID(GetSupportedNames, (aNames));
michael@0 4177
michael@0 4178 nsDOMWindowList* windows = GetWindowList();
michael@0 4179 if (windows) {
michael@0 4180 uint32_t length = windows->GetLength();
michael@0 4181 nsString* name = aNames.AppendElements(length);
michael@0 4182 for (uint32_t i = 0; i < length; ++i, ++name) {
michael@0 4183 nsCOMPtr<nsIDocShellTreeItem> item =
michael@0 4184 windows->GetDocShellTreeItemAt(i);
michael@0 4185 item->GetName(*name);
michael@0 4186 }
michael@0 4187 }
michael@0 4188 }
michael@0 4189
michael@0 4190 bool
michael@0 4191 nsGlobalWindow::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
michael@0 4192 JS::Handle<jsid> aId,
michael@0 4193 JS::MutableHandle<JSPropertyDescriptor> aDesc)
michael@0 4194 {
michael@0 4195 MOZ_ASSERT(IsInnerWindow());
michael@0 4196
michael@0 4197 if (!JSID_IS_STRING(aId)) {
michael@0 4198 return true;
michael@0 4199 }
michael@0 4200
michael@0 4201 nsresult rv = nsWindowSH::GlobalResolve(this, aCx, aObj, aId, aDesc);
michael@0 4202 if (NS_FAILED(rv)) {
michael@0 4203 return Throw(aCx, rv);
michael@0 4204 }
michael@0 4205
michael@0 4206 return true;
michael@0 4207 }
michael@0 4208
michael@0 4209 struct GlobalNameEnumeratorClosure
michael@0 4210 {
michael@0 4211 GlobalNameEnumeratorClosure(JSContext* aCx, nsGlobalWindow* aWindow,
michael@0 4212 nsTArray<nsString>& aNames)
michael@0 4213 : mCx(aCx),
michael@0 4214 mWindow(aWindow),
michael@0 4215 mWrapper(aCx, aWindow->GetWrapper()),
michael@0 4216 mNames(aNames)
michael@0 4217 {
michael@0 4218 }
michael@0 4219
michael@0 4220 JSContext* mCx;
michael@0 4221 nsGlobalWindow* mWindow;
michael@0 4222 JS::Rooted<JSObject*> mWrapper;
michael@0 4223 nsTArray<nsString>& mNames;
michael@0 4224 };
michael@0 4225
michael@0 4226 static PLDHashOperator
michael@0 4227 EnumerateGlobalName(const nsAString& aName,
michael@0 4228 const nsGlobalNameStruct& aNameStruct,
michael@0 4229 void* aClosure)
michael@0 4230 {
michael@0 4231 GlobalNameEnumeratorClosure* closure =
michael@0 4232 static_cast<GlobalNameEnumeratorClosure*>(aClosure);
michael@0 4233
michael@0 4234 if (aNameStruct.mType == nsGlobalNameStruct::eTypeStaticNameSet) {
michael@0 4235 // We have no idea what names this might install.
michael@0 4236 return PL_DHASH_NEXT;
michael@0 4237 }
michael@0 4238
michael@0 4239 if (nsWindowSH::NameStructEnabled(closure->mCx, closure->mWindow, aName,
michael@0 4240 aNameStruct) &&
michael@0 4241 (!aNameStruct.mConstructorEnabled ||
michael@0 4242 aNameStruct.mConstructorEnabled(closure->mCx, closure->mWrapper))) {
michael@0 4243 closure->mNames.AppendElement(aName);
michael@0 4244 }
michael@0 4245 return PL_DHASH_NEXT;
michael@0 4246 }
michael@0 4247
michael@0 4248 void
michael@0 4249 nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
michael@0 4250 ErrorResult& aRv)
michael@0 4251 {
michael@0 4252 // "Components" is marked as enumerable but only resolved on demand :-/.
michael@0 4253 //aNames.AppendElement(NS_LITERAL_STRING("Components"));
michael@0 4254
michael@0 4255 nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
michael@0 4256 if (nameSpaceManager) {
michael@0 4257 GlobalNameEnumeratorClosure closure(aCx, this, aNames);
michael@0 4258 nameSpaceManager->EnumerateGlobalNames(EnumerateGlobalName, &closure);
michael@0 4259 }
michael@0 4260 }
michael@0 4261
michael@0 4262 /* static */ bool
michael@0 4263 nsGlobalWindow::IsChromeWindow(JSContext* aCx, JSObject* aObj)
michael@0 4264 {
michael@0 4265 // For now, have to deal with XPConnect objects here.
michael@0 4266 return xpc::WindowOrNull(aObj)->IsChromeWindow();
michael@0 4267 }
michael@0 4268
michael@0 4269 nsIDOMOfflineResourceList*
michael@0 4270 nsGlobalWindow::GetApplicationCache(ErrorResult& aError)
michael@0 4271 {
michael@0 4272 FORWARD_TO_INNER_OR_THROW(GetApplicationCache, (aError), aError, nullptr);
michael@0 4273
michael@0 4274 if (!mApplicationCache) {
michael@0 4275 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
michael@0 4276 if (!webNav) {
michael@0 4277 aError.Throw(NS_ERROR_FAILURE);
michael@0 4278 return nullptr;
michael@0 4279 }
michael@0 4280
michael@0 4281 nsCOMPtr<nsIURI> uri;
michael@0 4282 aError = webNav->GetCurrentURI(getter_AddRefs(uri));
michael@0 4283 if (aError.Failed()) {
michael@0 4284 return nullptr;
michael@0 4285 }
michael@0 4286
michael@0 4287 nsCOMPtr<nsIURI> manifestURI;
michael@0 4288 nsContentUtils::GetOfflineAppManifest(mDoc, getter_AddRefs(manifestURI));
michael@0 4289
michael@0 4290 nsRefPtr<nsDOMOfflineResourceList> applicationCache =
michael@0 4291 new nsDOMOfflineResourceList(manifestURI, uri, this);
michael@0 4292
michael@0 4293 applicationCache->Init();
michael@0 4294
michael@0 4295 mApplicationCache = applicationCache;
michael@0 4296 }
michael@0 4297
michael@0 4298 return mApplicationCache;
michael@0 4299 }
michael@0 4300
michael@0 4301 NS_IMETHODIMP
michael@0 4302 nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
michael@0 4303 {
michael@0 4304 ErrorResult rv;
michael@0 4305 nsCOMPtr<nsIDOMOfflineResourceList> applicationCache =
michael@0 4306 GetApplicationCache(rv);
michael@0 4307 applicationCache.forget(aApplicationCache);
michael@0 4308
michael@0 4309 return rv.ErrorCode();
michael@0 4310 }
michael@0 4311
michael@0 4312 nsIDOMCrypto*
michael@0 4313 nsGlobalWindow::GetCrypto(ErrorResult& aError)
michael@0 4314 {
michael@0 4315 FORWARD_TO_INNER_OR_THROW(GetCrypto, (aError), aError, nullptr);
michael@0 4316
michael@0 4317 if (!mCrypto) {
michael@0 4318 #ifndef MOZ_DISABLE_CRYPTOLEGACY
michael@0 4319 if (XRE_GetProcessType() != GeckoProcessType_Content) {
michael@0 4320 nsresult rv;
michael@0 4321 mCrypto = do_CreateInstance(NS_CRYPTO_CONTRACTID, &rv);
michael@0 4322 if (NS_FAILED(rv)) {
michael@0 4323 aError.Throw(rv);
michael@0 4324 return nullptr;
michael@0 4325 }
michael@0 4326 } else
michael@0 4327 #endif
michael@0 4328 {
michael@0 4329 mCrypto = new Crypto();
michael@0 4330 }
michael@0 4331
michael@0 4332 mCrypto->Init(this);
michael@0 4333 }
michael@0 4334 return mCrypto;
michael@0 4335 }
michael@0 4336
michael@0 4337 NS_IMETHODIMP
michael@0 4338 nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
michael@0 4339 {
michael@0 4340 ErrorResult rv;
michael@0 4341 nsCOMPtr<nsIDOMCrypto> crypto = GetCrypto(rv);
michael@0 4342 crypto.forget(aCrypto);
michael@0 4343
michael@0 4344 return rv.ErrorCode();
michael@0 4345 }
michael@0 4346
michael@0 4347 nsIControllers*
michael@0 4348 nsGlobalWindow::GetControllers(ErrorResult& aError)
michael@0 4349 {
michael@0 4350 FORWARD_TO_OUTER_OR_THROW(GetControllers, (aError), aError, nullptr);
michael@0 4351
michael@0 4352 if (!mControllers) {
michael@0 4353 nsresult rv;
michael@0 4354 mControllers = do_CreateInstance(kXULControllersCID, &rv);
michael@0 4355 if (NS_FAILED(rv)) {
michael@0 4356 aError.Throw(rv);
michael@0 4357 return nullptr;
michael@0 4358 }
michael@0 4359
michael@0 4360 // Add in the default controller
michael@0 4361 nsCOMPtr<nsIController> controller = do_CreateInstance(
michael@0 4362 NS_WINDOWCONTROLLER_CONTRACTID, &rv);
michael@0 4363 if (NS_FAILED(rv)) {
michael@0 4364 aError.Throw(rv);
michael@0 4365 return nullptr;
michael@0 4366 }
michael@0 4367
michael@0 4368 mControllers->InsertControllerAt(0, controller);
michael@0 4369 nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
michael@0 4370 if (!controllerContext) {
michael@0 4371 aError.Throw(NS_ERROR_FAILURE);
michael@0 4372 return nullptr;
michael@0 4373 }
michael@0 4374
michael@0 4375 controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
michael@0 4376 }
michael@0 4377
michael@0 4378 return mControllers;
michael@0 4379 }
michael@0 4380
michael@0 4381 NS_IMETHODIMP
michael@0 4382 nsGlobalWindow::GetControllers(nsIControllers** aResult)
michael@0 4383 {
michael@0 4384 ErrorResult rv;
michael@0 4385 nsCOMPtr<nsIControllers> controllers = GetControllers(rv);
michael@0 4386 controllers.forget(aResult);
michael@0 4387
michael@0 4388 return rv.ErrorCode();
michael@0 4389 }
michael@0 4390
michael@0 4391 nsIDOMWindow*
michael@0 4392 nsGlobalWindow::GetOpenerWindow(ErrorResult& aError)
michael@0 4393 {
michael@0 4394 FORWARD_TO_OUTER_OR_THROW(GetOpenerWindow, (aError), aError, nullptr);
michael@0 4395
michael@0 4396 nsCOMPtr<nsPIDOMWindow> opener = do_QueryReferent(mOpener);
michael@0 4397 if (!opener) {
michael@0 4398 return nullptr;
michael@0 4399 }
michael@0 4400
michael@0 4401 // First, check if we were called from a privileged chrome script
michael@0 4402 if (nsContentUtils::IsCallerChrome()) {
michael@0 4403 return opener;
michael@0 4404 }
michael@0 4405
michael@0 4406 // First, ensure that we're not handing back a chrome window.
michael@0 4407 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(opener.get());
michael@0 4408 if (win->IsChromeWindow()) {
michael@0 4409 return nullptr;
michael@0 4410 }
michael@0 4411
michael@0 4412 // We don't want to reveal the opener if the opener is a mail window,
michael@0 4413 // because opener can be used to spoof the contents of a message (bug 105050).
michael@0 4414 // So, we look in the opener's root docshell to see if it's a mail window.
michael@0 4415 nsCOMPtr<nsIDocShell> openerDocShell = opener->GetDocShell();
michael@0 4416
michael@0 4417 if (openerDocShell) {
michael@0 4418 nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
michael@0 4419 openerDocShell->GetRootTreeItem(getter_AddRefs(openerRootItem));
michael@0 4420 nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
michael@0 4421 if (openerRootDocShell) {
michael@0 4422 uint32_t appType;
michael@0 4423 nsresult rv = openerRootDocShell->GetAppType(&appType);
michael@0 4424 if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
michael@0 4425 return opener;
michael@0 4426 }
michael@0 4427 }
michael@0 4428 }
michael@0 4429
michael@0 4430 return nullptr;
michael@0 4431 }
michael@0 4432
michael@0 4433 void
michael@0 4434 nsGlobalWindow::GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
michael@0 4435 ErrorResult& aError)
michael@0 4436 {
michael@0 4437 nsCOMPtr<nsIDOMWindow> opener = GetOpenerWindow(aError);
michael@0 4438 if (aError.Failed() || !opener) {
michael@0 4439 aRetval.setNull();
michael@0 4440 return;
michael@0 4441 }
michael@0 4442
michael@0 4443 aError = nsContentUtils::WrapNative(aCx, opener, aRetval);
michael@0 4444 }
michael@0 4445
michael@0 4446 NS_IMETHODIMP
michael@0 4447 nsGlobalWindow::GetScriptableOpener(JSContext* aCx,
michael@0 4448 JS::MutableHandle<JS::Value> aOpener)
michael@0 4449 {
michael@0 4450 ErrorResult rv;
michael@0 4451 GetOpener(aCx, aOpener, rv);
michael@0 4452
michael@0 4453 return rv.ErrorCode();
michael@0 4454 }
michael@0 4455
michael@0 4456 NS_IMETHODIMP
michael@0 4457 nsGlobalWindow::GetOpener(nsIDOMWindow** aOpener)
michael@0 4458 {
michael@0 4459 ErrorResult rv;
michael@0 4460 nsCOMPtr<nsIDOMWindow> opener = GetOpenerWindow(rv);
michael@0 4461 opener.forget(aOpener);
michael@0 4462 return rv.ErrorCode();
michael@0 4463 }
michael@0 4464
michael@0 4465 void
michael@0 4466 nsGlobalWindow::SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
michael@0 4467 ErrorResult& aError)
michael@0 4468 {
michael@0 4469 // Check if we were called from a privileged chrome script. If not, and if
michael@0 4470 // aOpener is not null, just define aOpener on our inner window's JS object,
michael@0 4471 // wrapped into the current compartment so that for Xrays we define on the
michael@0 4472 // Xray expando object, but don't set it on the outer window, so that it'll
michael@0 4473 // get reset on navigation. This is just like replaceable properties, but
michael@0 4474 // we're not quite readonly.
michael@0 4475 if (!aOpener.isNull() && !nsContentUtils::IsCallerChrome()) {
michael@0 4476 JS::Rooted<JSObject*> thisObj(aCx, GetWrapperPreserveColor());
michael@0 4477 if (!thisObj) {
michael@0 4478 aError.Throw(NS_ERROR_UNEXPECTED);
michael@0 4479 return;
michael@0 4480 }
michael@0 4481
michael@0 4482 if (!JS_WrapObject(aCx, &thisObj) ||
michael@0 4483 !JS_DefineProperty(aCx, thisObj, "opener", aOpener, JSPROP_ENUMERATE,
michael@0 4484 JS_PropertyStub, JS_StrictPropertyStub)) {
michael@0 4485 aError.Throw(NS_ERROR_FAILURE);
michael@0 4486 }
michael@0 4487
michael@0 4488 return;
michael@0 4489 }
michael@0 4490
michael@0 4491 if (!aOpener.isObjectOrNull()) {
michael@0 4492 // Chrome code trying to set some random value as opener
michael@0 4493 aError.Throw(NS_ERROR_INVALID_ARG);
michael@0 4494 return;
michael@0 4495 }
michael@0 4496
michael@0 4497 nsGlobalWindow* win = nullptr;
michael@0 4498 if (aOpener.isObject()) {
michael@0 4499 JSObject* unwrapped = js::CheckedUnwrap(&aOpener.toObject(),
michael@0 4500 /* stopAtOuter = */ false);
michael@0 4501 if (!unwrapped) {
michael@0 4502 aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
michael@0 4503 return;
michael@0 4504 }
michael@0 4505
michael@0 4506 win = xpc::WindowOrNull(unwrapped);
michael@0 4507 if (!win) {
michael@0 4508 // Wasn't a window
michael@0 4509 aError.Throw(NS_ERROR_INVALID_ARG);
michael@0 4510 return;
michael@0 4511 }
michael@0 4512 }
michael@0 4513
michael@0 4514 SetOpenerWindow(win, false);
michael@0 4515 }
michael@0 4516
michael@0 4517 NS_IMETHODIMP
michael@0 4518 nsGlobalWindow::SetScriptableOpener(JSContext* aCx,
michael@0 4519 JS::Handle<JS::Value> aOpener)
michael@0 4520 {
michael@0 4521 ErrorResult rv;
michael@0 4522 SetOpener(aCx, aOpener, rv);
michael@0 4523
michael@0 4524 return rv.ErrorCode();
michael@0 4525 }
michael@0 4526
michael@0 4527 NS_IMETHODIMP
michael@0 4528 nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener)
michael@0 4529 {
michael@0 4530 SetOpenerWindow(aOpener, false);
michael@0 4531 return NS_OK;
michael@0 4532 }
michael@0 4533
michael@0 4534 void
michael@0 4535 nsGlobalWindow::GetStatus(nsAString& aStatus, ErrorResult& aError)
michael@0 4536 {
michael@0 4537 FORWARD_TO_OUTER_OR_THROW(GetStatus, (aStatus, aError), aError, );
michael@0 4538
michael@0 4539 aStatus = mStatus;
michael@0 4540 }
michael@0 4541
michael@0 4542 NS_IMETHODIMP
michael@0 4543 nsGlobalWindow::GetStatus(nsAString& aStatus)
michael@0 4544 {
michael@0 4545 ErrorResult rv;
michael@0 4546 GetStatus(aStatus, rv);
michael@0 4547
michael@0 4548 return rv.ErrorCode();
michael@0 4549 }
michael@0 4550
michael@0 4551 void
michael@0 4552 nsGlobalWindow::SetStatus(const nsAString& aStatus, ErrorResult& aError)
michael@0 4553 {
michael@0 4554 FORWARD_TO_OUTER_OR_THROW(SetStatus, (aStatus, aError), aError, );
michael@0 4555
michael@0 4556 mStatus = aStatus;
michael@0 4557
michael@0 4558 /*
michael@0 4559 * If caller is not chrome and dom.disable_window_status_change is true,
michael@0 4560 * prevent propagating window.status to the UI by exiting early
michael@0 4561 */
michael@0 4562
michael@0 4563 if (!CanSetProperty("dom.disable_window_status_change")) {
michael@0 4564 return;
michael@0 4565 }
michael@0 4566
michael@0 4567 nsCOMPtr<nsIWebBrowserChrome> browserChrome = GetWebBrowserChrome();
michael@0 4568 if (browserChrome) {
michael@0 4569 browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
michael@0 4570 PromiseFlatString(aStatus).get());
michael@0 4571 }
michael@0 4572 }
michael@0 4573
michael@0 4574 NS_IMETHODIMP
michael@0 4575 nsGlobalWindow::SetStatus(const nsAString& aStatus)
michael@0 4576 {
michael@0 4577 ErrorResult rv;
michael@0 4578 SetStatus(aStatus, rv);
michael@0 4579
michael@0 4580 return rv.ErrorCode();
michael@0 4581 }
michael@0 4582
michael@0 4583 void
michael@0 4584 nsGlobalWindow::GetName(nsAString& aName, ErrorResult& aError)
michael@0 4585 {
michael@0 4586 FORWARD_TO_OUTER_OR_THROW(GetName, (aName, aError), aError, );
michael@0 4587
michael@0 4588 if (mDocShell) {
michael@0 4589 mDocShell->GetName(aName);
michael@0 4590 }
michael@0 4591 }
michael@0 4592
michael@0 4593 NS_IMETHODIMP
michael@0 4594 nsGlobalWindow::GetName(nsAString& aName)
michael@0 4595 {
michael@0 4596 ErrorResult rv;
michael@0 4597 GetName(aName, rv);
michael@0 4598
michael@0 4599 return rv.ErrorCode();
michael@0 4600 }
michael@0 4601
michael@0 4602 void
michael@0 4603 nsGlobalWindow::SetName(const nsAString& aName, mozilla::ErrorResult& aError)
michael@0 4604 {
michael@0 4605 FORWARD_TO_OUTER_OR_THROW(SetName, (aName, aError), aError, );
michael@0 4606
michael@0 4607 if (mDocShell) {
michael@0 4608 aError = mDocShell->SetName(aName);
michael@0 4609 }
michael@0 4610 }
michael@0 4611
michael@0 4612 NS_IMETHODIMP
michael@0 4613 nsGlobalWindow::SetName(const nsAString& aName)
michael@0 4614 {
michael@0 4615 ErrorResult rv;
michael@0 4616 SetName(aName, rv);
michael@0 4617
michael@0 4618 return rv.ErrorCode();
michael@0 4619 }
michael@0 4620
michael@0 4621 // Helper functions used by many methods below.
michael@0 4622 int32_t
michael@0 4623 nsGlobalWindow::DevToCSSIntPixels(int32_t px)
michael@0 4624 {
michael@0 4625 if (!mDocShell)
michael@0 4626 return px; // assume 1:1
michael@0 4627
michael@0 4628 nsRefPtr<nsPresContext> presContext;
michael@0 4629 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 4630 if (!presContext)
michael@0 4631 return px;
michael@0 4632
michael@0 4633 return presContext->DevPixelsToIntCSSPixels(px);
michael@0 4634 }
michael@0 4635
michael@0 4636 int32_t
michael@0 4637 nsGlobalWindow::CSSToDevIntPixels(int32_t px)
michael@0 4638 {
michael@0 4639 if (!mDocShell)
michael@0 4640 return px; // assume 1:1
michael@0 4641
michael@0 4642 nsRefPtr<nsPresContext> presContext;
michael@0 4643 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 4644 if (!presContext)
michael@0 4645 return px;
michael@0 4646
michael@0 4647 return presContext->CSSPixelsToDevPixels(px);
michael@0 4648 }
michael@0 4649
michael@0 4650 nsIntSize
michael@0 4651 nsGlobalWindow::DevToCSSIntPixels(nsIntSize px)
michael@0 4652 {
michael@0 4653 if (!mDocShell)
michael@0 4654 return px; // assume 1:1
michael@0 4655
michael@0 4656 nsRefPtr<nsPresContext> presContext;
michael@0 4657 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 4658 if (!presContext)
michael@0 4659 return px;
michael@0 4660
michael@0 4661 return nsIntSize(
michael@0 4662 presContext->DevPixelsToIntCSSPixels(px.width),
michael@0 4663 presContext->DevPixelsToIntCSSPixels(px.height));
michael@0 4664 }
michael@0 4665
michael@0 4666 nsIntSize
michael@0 4667 nsGlobalWindow::CSSToDevIntPixels(nsIntSize px)
michael@0 4668 {
michael@0 4669 if (!mDocShell)
michael@0 4670 return px; // assume 1:1
michael@0 4671
michael@0 4672 nsRefPtr<nsPresContext> presContext;
michael@0 4673 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 4674 if (!presContext)
michael@0 4675 return px;
michael@0 4676
michael@0 4677 return nsIntSize(
michael@0 4678 presContext->CSSPixelsToDevPixels(px.width),
michael@0 4679 presContext->CSSPixelsToDevPixels(px.height));
michael@0 4680 }
michael@0 4681
michael@0 4682 nsresult
michael@0 4683 nsGlobalWindow::GetInnerSize(CSSIntSize& aSize)
michael@0 4684 {
michael@0 4685 MOZ_ASSERT(IsOuterWindow());
michael@0 4686
michael@0 4687 EnsureSizeUpToDate();
michael@0 4688
michael@0 4689 NS_ENSURE_STATE(mDocShell);
michael@0 4690
michael@0 4691 nsRefPtr<nsPresContext> presContext;
michael@0 4692 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 4693 nsRefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 4694
michael@0 4695 if (!presContext || !presShell) {
michael@0 4696 aSize = CSSIntSize(0, 0);
michael@0 4697 return NS_OK;
michael@0 4698 }
michael@0 4699
michael@0 4700 /*
michael@0 4701 * On platforms with resolution-based zooming, the CSS viewport
michael@0 4702 * and visual viewport may not be the same. The inner size should
michael@0 4703 * be the visual viewport, but we fall back to the CSS viewport
michael@0 4704 * if it is not set.
michael@0 4705 */
michael@0 4706 if (presShell->IsScrollPositionClampingScrollPortSizeSet()) {
michael@0 4707 aSize = CSSIntRect::FromAppUnitsRounded(
michael@0 4708 presShell->GetScrollPositionClampingScrollPortSize());
michael@0 4709 } else {
michael@0 4710 nsRefPtr<nsViewManager> viewManager = presShell->GetViewManager();
michael@0 4711 if (viewManager) {
michael@0 4712 viewManager->FlushDelayedResize(false);
michael@0 4713 }
michael@0 4714
michael@0 4715 aSize = CSSIntRect::FromAppUnitsRounded(
michael@0 4716 presContext->GetVisibleArea().Size());
michael@0 4717 }
michael@0 4718 return NS_OK;
michael@0 4719 }
michael@0 4720
michael@0 4721 int32_t
michael@0 4722 nsGlobalWindow::GetInnerWidth(ErrorResult& aError)
michael@0 4723 {
michael@0 4724 FORWARD_TO_OUTER_OR_THROW(GetInnerWidth, (aError), aError, 0);
michael@0 4725
michael@0 4726 CSSIntSize size;
michael@0 4727 aError = GetInnerSize(size);
michael@0 4728 return size.width;
michael@0 4729 }
michael@0 4730
michael@0 4731 NS_IMETHODIMP
michael@0 4732 nsGlobalWindow::GetInnerWidth(int32_t* aInnerWidth)
michael@0 4733 {
michael@0 4734 ErrorResult rv;
michael@0 4735 *aInnerWidth = GetInnerWidth(rv);
michael@0 4736
michael@0 4737 return rv.ErrorCode();
michael@0 4738 }
michael@0 4739
michael@0 4740 void
michael@0 4741 nsGlobalWindow::SetInnerWidth(int32_t aInnerWidth, ErrorResult& aError)
michael@0 4742 {
michael@0 4743 FORWARD_TO_OUTER_OR_THROW(SetInnerWidth, (aInnerWidth, aError), aError, );
michael@0 4744
michael@0 4745 if (!mDocShell) {
michael@0 4746 aError.Throw(NS_ERROR_UNEXPECTED);
michael@0 4747 return;
michael@0 4748 }
michael@0 4749
michael@0 4750 /*
michael@0 4751 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 4752 * prevent setting window.innerWidth by exiting early
michael@0 4753 */
michael@0 4754 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 4755 return;
michael@0 4756 }
michael@0 4757
michael@0 4758 CheckSecurityWidthAndHeight(&aInnerWidth, nullptr);
michael@0 4759
michael@0 4760 nsRefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 4761
michael@0 4762 if (presShell && presShell->GetIsViewportOverridden())
michael@0 4763 {
michael@0 4764 nscoord height = 0;
michael@0 4765
michael@0 4766 nsRefPtr<nsPresContext> presContext;
michael@0 4767 presContext = presShell->GetPresContext();
michael@0 4768
michael@0 4769 nsRect shellArea = presContext->GetVisibleArea();
michael@0 4770 height = shellArea.height;
michael@0 4771 SetCSSViewportWidthAndHeight(nsPresContext::CSSPixelsToAppUnits(aInnerWidth),
michael@0 4772 height);
michael@0 4773 return;
michael@0 4774 }
michael@0 4775
michael@0 4776 int32_t height = 0;
michael@0 4777 int32_t unused = 0;
michael@0 4778
michael@0 4779 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
michael@0 4780 docShellAsWin->GetSize(&unused, &height);
michael@0 4781 aError = SetDocShellWidthAndHeight(CSSToDevIntPixels(aInnerWidth), height);
michael@0 4782 }
michael@0 4783
michael@0 4784 NS_IMETHODIMP
michael@0 4785 nsGlobalWindow::SetInnerWidth(int32_t aInnerWidth)
michael@0 4786 {
michael@0 4787 ErrorResult rv;
michael@0 4788 SetInnerWidth(aInnerWidth, rv);
michael@0 4789
michael@0 4790 return rv.ErrorCode();
michael@0 4791 }
michael@0 4792
michael@0 4793 int32_t
michael@0 4794 nsGlobalWindow::GetInnerHeight(ErrorResult& aError)
michael@0 4795 {
michael@0 4796 FORWARD_TO_OUTER_OR_THROW(GetInnerHeight, (aError), aError, 0);
michael@0 4797
michael@0 4798 CSSIntSize size;
michael@0 4799 aError = GetInnerSize(size);
michael@0 4800 return size.height;
michael@0 4801 }
michael@0 4802
michael@0 4803 NS_IMETHODIMP
michael@0 4804 nsGlobalWindow::GetInnerHeight(int32_t* aInnerHeight)
michael@0 4805 {
michael@0 4806 ErrorResult rv;
michael@0 4807 *aInnerHeight = GetInnerHeight(rv);
michael@0 4808
michael@0 4809 return rv.ErrorCode();
michael@0 4810 }
michael@0 4811
michael@0 4812 void
michael@0 4813 nsGlobalWindow::SetInnerHeight(int32_t aInnerHeight, ErrorResult& aError)
michael@0 4814 {
michael@0 4815 FORWARD_TO_OUTER_OR_THROW(SetInnerHeight, (aInnerHeight, aError), aError, );
michael@0 4816
michael@0 4817 if (!mDocShell) {
michael@0 4818 aError.Throw(NS_ERROR_UNEXPECTED);
michael@0 4819 return;
michael@0 4820 }
michael@0 4821
michael@0 4822 /*
michael@0 4823 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 4824 * prevent setting window.innerHeight by exiting early
michael@0 4825 */
michael@0 4826 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 4827 return;
michael@0 4828 }
michael@0 4829
michael@0 4830 nsRefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 4831
michael@0 4832 if (presShell && presShell->GetIsViewportOverridden())
michael@0 4833 {
michael@0 4834 nsRefPtr<nsPresContext> presContext;
michael@0 4835 presContext = presShell->GetPresContext();
michael@0 4836
michael@0 4837 nsRect shellArea = presContext->GetVisibleArea();
michael@0 4838 nscoord height = aInnerHeight;
michael@0 4839 nscoord width = shellArea.width;
michael@0 4840 CheckSecurityWidthAndHeight(nullptr, &height);
michael@0 4841 SetCSSViewportWidthAndHeight(width,
michael@0 4842 nsPresContext::CSSPixelsToAppUnits(height));
michael@0 4843 return;
michael@0 4844 }
michael@0 4845
michael@0 4846 int32_t height = 0;
michael@0 4847 int32_t width = 0;
michael@0 4848
michael@0 4849 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
michael@0 4850 docShellAsWin->GetSize(&width, &height);
michael@0 4851 CheckSecurityWidthAndHeight(nullptr, &aInnerHeight);
michael@0 4852 aError = SetDocShellWidthAndHeight(width, CSSToDevIntPixels(aInnerHeight));
michael@0 4853 }
michael@0 4854
michael@0 4855 NS_IMETHODIMP
michael@0 4856 nsGlobalWindow::SetInnerHeight(int32_t aInnerHeight)
michael@0 4857 {
michael@0 4858 ErrorResult rv;
michael@0 4859 SetInnerHeight(aInnerHeight, rv);
michael@0 4860
michael@0 4861 return rv.ErrorCode();
michael@0 4862 }
michael@0 4863
michael@0 4864 nsIntSize
michael@0 4865 nsGlobalWindow::GetOuterSize(ErrorResult& aError)
michael@0 4866 {
michael@0 4867 MOZ_ASSERT(IsOuterWindow());
michael@0 4868
michael@0 4869 if (!IsChrome()) {
michael@0 4870 CSSIntSize size;
michael@0 4871 aError = GetInnerSize(size);
michael@0 4872 return nsIntSize(size.width, size.height);
michael@0 4873 }
michael@0 4874
michael@0 4875 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 4876 if (!treeOwnerAsWin) {
michael@0 4877 aError.Throw(NS_ERROR_FAILURE);
michael@0 4878 return nsIntSize(0, 0);
michael@0 4879 }
michael@0 4880
michael@0 4881 nsGlobalWindow* rootWindow =
michael@0 4882 static_cast<nsGlobalWindow *>(GetPrivateRoot());
michael@0 4883 if (rootWindow) {
michael@0 4884 rootWindow->FlushPendingNotifications(Flush_Layout);
michael@0 4885 }
michael@0 4886
michael@0 4887 nsIntSize sizeDevPixels;
michael@0 4888 aError = treeOwnerAsWin->GetSize(&sizeDevPixels.width, &sizeDevPixels.height);
michael@0 4889 if (aError.Failed()) {
michael@0 4890 return nsIntSize();
michael@0 4891 }
michael@0 4892
michael@0 4893 return DevToCSSIntPixels(sizeDevPixels);
michael@0 4894 }
michael@0 4895
michael@0 4896 int32_t
michael@0 4897 nsGlobalWindow::GetOuterWidth(ErrorResult& aError)
michael@0 4898 {
michael@0 4899 FORWARD_TO_OUTER_OR_THROW(GetOuterWidth, (aError), aError, 0);
michael@0 4900 return GetOuterSize(aError).width;
michael@0 4901 }
michael@0 4902
michael@0 4903 NS_IMETHODIMP
michael@0 4904 nsGlobalWindow::GetOuterWidth(int32_t* aOuterWidth)
michael@0 4905 {
michael@0 4906 ErrorResult rv;
michael@0 4907 *aOuterWidth = GetOuterWidth(rv);
michael@0 4908
michael@0 4909 return rv.ErrorCode();
michael@0 4910 }
michael@0 4911
michael@0 4912 int32_t
michael@0 4913 nsGlobalWindow::GetOuterHeight(ErrorResult& aError)
michael@0 4914 {
michael@0 4915 FORWARD_TO_OUTER_OR_THROW(GetOuterHeight, (aError), aError, 0);
michael@0 4916 return GetOuterSize(aError).height;
michael@0 4917 }
michael@0 4918
michael@0 4919 NS_IMETHODIMP
michael@0 4920 nsGlobalWindow::GetOuterHeight(int32_t* aOuterHeight)
michael@0 4921 {
michael@0 4922 ErrorResult rv;
michael@0 4923 *aOuterHeight = GetOuterHeight(rv);
michael@0 4924
michael@0 4925 return rv.ErrorCode();
michael@0 4926 }
michael@0 4927
michael@0 4928 void
michael@0 4929 nsGlobalWindow::SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth,
michael@0 4930 ErrorResult& aError)
michael@0 4931 {
michael@0 4932 MOZ_ASSERT(IsOuterWindow());
michael@0 4933
michael@0 4934 /*
michael@0 4935 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 4936 * prevent setting window.outerWidth by exiting early
michael@0 4937 */
michael@0 4938
michael@0 4939 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 4940 return;
michael@0 4941 }
michael@0 4942
michael@0 4943 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 4944 if (!treeOwnerAsWin) {
michael@0 4945 aError.Throw(NS_ERROR_FAILURE);
michael@0 4946 return;
michael@0 4947 }
michael@0 4948
michael@0 4949 CheckSecurityWidthAndHeight(aIsWidth ? &aLengthCSSPixels : nullptr,
michael@0 4950 aIsWidth ? nullptr : &aLengthCSSPixels);
michael@0 4951
michael@0 4952 int32_t width, height;
michael@0 4953 aError = treeOwnerAsWin->GetSize(&width, &height);
michael@0 4954 if (aError.Failed()) {
michael@0 4955 return;
michael@0 4956 }
michael@0 4957
michael@0 4958 int32_t lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
michael@0 4959 if (aIsWidth) {
michael@0 4960 width = lengthDevPixels;
michael@0 4961 } else {
michael@0 4962 height = lengthDevPixels;
michael@0 4963 }
michael@0 4964 aError = treeOwnerAsWin->SetSize(width, height, true);
michael@0 4965 }
michael@0 4966
michael@0 4967 void
michael@0 4968 nsGlobalWindow::SetOuterWidth(int32_t aOuterWidth, ErrorResult& aError)
michael@0 4969 {
michael@0 4970 FORWARD_TO_OUTER_OR_THROW(SetOuterWidth, (aOuterWidth, aError), aError, );
michael@0 4971
michael@0 4972 SetOuterSize(aOuterWidth, true, aError);
michael@0 4973 }
michael@0 4974
michael@0 4975 NS_IMETHODIMP
michael@0 4976 nsGlobalWindow::SetOuterWidth(int32_t aOuterWidth)
michael@0 4977 {
michael@0 4978 ErrorResult rv;
michael@0 4979 SetOuterWidth(aOuterWidth, rv);
michael@0 4980
michael@0 4981 return rv.ErrorCode();
michael@0 4982 }
michael@0 4983
michael@0 4984 void
michael@0 4985 nsGlobalWindow::SetOuterHeight(int32_t aOuterHeight, ErrorResult& aError)
michael@0 4986 {
michael@0 4987 FORWARD_TO_OUTER_OR_THROW(SetOuterHeight, (aOuterHeight, aError), aError, );
michael@0 4988
michael@0 4989 SetOuterSize(aOuterHeight, false, aError);
michael@0 4990 }
michael@0 4991
michael@0 4992 NS_IMETHODIMP
michael@0 4993 nsGlobalWindow::SetOuterHeight(int32_t aOuterHeight)
michael@0 4994 {
michael@0 4995 ErrorResult rv;
michael@0 4996 SetOuterHeight(aOuterHeight, rv);
michael@0 4997
michael@0 4998 return rv.ErrorCode();
michael@0 4999 }
michael@0 5000
michael@0 5001 nsIntPoint
michael@0 5002 nsGlobalWindow::GetScreenXY(ErrorResult& aError)
michael@0 5003 {
michael@0 5004 MOZ_ASSERT(IsOuterWindow());
michael@0 5005
michael@0 5006 // For non-chrome callers, always return (0,0) to prevent fingerprinting.
michael@0 5007 if (!IsChrome()) {
michael@0 5008 return nsIntPoint(0, 0);
michael@0 5009 }
michael@0 5010
michael@0 5011 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 5012 if (!treeOwnerAsWin) {
michael@0 5013 aError.Throw(NS_ERROR_FAILURE);
michael@0 5014 return nsIntPoint(0, 0);
michael@0 5015 }
michael@0 5016
michael@0 5017 int32_t x = 0, y = 0;
michael@0 5018 aError = treeOwnerAsWin->GetPosition(&x, &y);
michael@0 5019 return nsIntPoint(x, y);
michael@0 5020 }
michael@0 5021
michael@0 5022 int32_t
michael@0 5023 nsGlobalWindow::GetScreenX(ErrorResult& aError)
michael@0 5024 {
michael@0 5025 FORWARD_TO_OUTER_OR_THROW(GetScreenX, (aError), aError, 0);
michael@0 5026
michael@0 5027 return DevToCSSIntPixels(GetScreenXY(aError).x);
michael@0 5028 }
michael@0 5029
michael@0 5030 NS_IMETHODIMP
michael@0 5031 nsGlobalWindow::GetScreenX(int32_t* aScreenX)
michael@0 5032 {
michael@0 5033 ErrorResult rv;
michael@0 5034 *aScreenX = GetScreenX(rv);
michael@0 5035
michael@0 5036 return rv.ErrorCode();
michael@0 5037 }
michael@0 5038
michael@0 5039 nsRect
michael@0 5040 nsGlobalWindow::GetInnerScreenRect()
michael@0 5041 {
michael@0 5042 MOZ_ASSERT(IsOuterWindow());
michael@0 5043
michael@0 5044 if (!mDocShell) {
michael@0 5045 return nsRect();
michael@0 5046 }
michael@0 5047
michael@0 5048 nsGlobalWindow* rootWindow =
michael@0 5049 static_cast<nsGlobalWindow*>(GetPrivateRoot());
michael@0 5050 if (rootWindow) {
michael@0 5051 rootWindow->FlushPendingNotifications(Flush_Layout);
michael@0 5052 }
michael@0 5053
michael@0 5054 if (!mDocShell) {
michael@0 5055 return nsRect();
michael@0 5056 }
michael@0 5057
michael@0 5058 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 5059 if (!presShell) {
michael@0 5060 return nsRect();
michael@0 5061 }
michael@0 5062 nsIFrame* rootFrame = presShell->GetRootFrame();
michael@0 5063 if (!rootFrame) {
michael@0 5064 return nsRect();
michael@0 5065 }
michael@0 5066
michael@0 5067 return rootFrame->GetScreenRectInAppUnits();
michael@0 5068 }
michael@0 5069
michael@0 5070 float
michael@0 5071 nsGlobalWindow::GetMozInnerScreenX(ErrorResult& aError)
michael@0 5072 {
michael@0 5073 FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenX, (aError), aError, 0);
michael@0 5074
michael@0 5075 // For non-chrome callers, always return 0 to prevent fingerprinting.
michael@0 5076 if (!IsChrome()) return 0.0;
michael@0 5077
michael@0 5078 nsRect r = GetInnerScreenRect();
michael@0 5079 return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
michael@0 5080 }
michael@0 5081
michael@0 5082 NS_IMETHODIMP
michael@0 5083 nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
michael@0 5084 {
michael@0 5085 ErrorResult rv;
michael@0 5086 *aScreenX = GetMozInnerScreenX(rv);
michael@0 5087
michael@0 5088 return rv.ErrorCode();
michael@0 5089 }
michael@0 5090
michael@0 5091 float
michael@0 5092 nsGlobalWindow::GetMozInnerScreenY(ErrorResult& aError)
michael@0 5093 {
michael@0 5094 FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenY, (aError), aError, 0);
michael@0 5095
michael@0 5096 // For non-chrome callers, always return 0 to prevent fingerprinting.
michael@0 5097 if (!IsChrome()) return 0.0;
michael@0 5098
michael@0 5099 nsRect r = GetInnerScreenRect();
michael@0 5100 return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
michael@0 5101 }
michael@0 5102
michael@0 5103 NS_IMETHODIMP
michael@0 5104 nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
michael@0 5105 {
michael@0 5106 ErrorResult rv;
michael@0 5107 *aScreenY = GetMozInnerScreenY(rv);
michael@0 5108
michael@0 5109 return rv.ErrorCode();
michael@0 5110 }
michael@0 5111
michael@0 5112 float
michael@0 5113 nsGlobalWindow::GetDevicePixelRatio(ErrorResult& aError)
michael@0 5114 {
michael@0 5115 FORWARD_TO_OUTER_OR_THROW(GetDevicePixelRatio, (aError), aError, 0.0);
michael@0 5116
michael@0 5117 if (!mDocShell) {
michael@0 5118 return 1.0;
michael@0 5119 }
michael@0 5120
michael@0 5121 nsRefPtr<nsPresContext> presContext;
michael@0 5122 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 5123 if (!presContext) {
michael@0 5124 return 1.0;
michael@0 5125 }
michael@0 5126
michael@0 5127 return float(nsPresContext::AppUnitsPerCSSPixel())/
michael@0 5128 presContext->AppUnitsPerDevPixel();
michael@0 5129 }
michael@0 5130
michael@0 5131 NS_IMETHODIMP
michael@0 5132 nsGlobalWindow::GetDevicePixelRatio(float* aRatio)
michael@0 5133 {
michael@0 5134 ErrorResult rv;
michael@0 5135 *aRatio = GetDevicePixelRatio(rv);
michael@0 5136
michael@0 5137 return rv.ErrorCode();
michael@0 5138 }
michael@0 5139
michael@0 5140 uint64_t
michael@0 5141 nsGlobalWindow::GetMozPaintCount(ErrorResult& aError)
michael@0 5142 {
michael@0 5143 FORWARD_TO_OUTER_OR_THROW(GetMozPaintCount, (aError), aError, 0);
michael@0 5144
michael@0 5145 if (!mDocShell) {
michael@0 5146 return 0;
michael@0 5147 }
michael@0 5148
michael@0 5149 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 5150 return presShell ? presShell->GetPaintCount() : 0;
michael@0 5151 }
michael@0 5152
michael@0 5153 NS_IMETHODIMP
michael@0 5154 nsGlobalWindow::GetMozPaintCount(uint64_t* aResult)
michael@0 5155 {
michael@0 5156 ErrorResult rv;
michael@0 5157 *aResult = GetMozPaintCount(rv);
michael@0 5158
michael@0 5159 return rv.ErrorCode();
michael@0 5160 }
michael@0 5161
michael@0 5162 NS_IMETHODIMP
michael@0 5163 nsGlobalWindow::MozRequestAnimationFrame(nsIFrameRequestCallback* aCallback,
michael@0 5164 int32_t *aHandle)
michael@0 5165 {
michael@0 5166 if (!aCallback) {
michael@0 5167 if (mDoc) {
michael@0 5168 mDoc->WarnOnceAbout(nsIDocument::eMozBeforePaint);
michael@0 5169 }
michael@0 5170 return NS_ERROR_XPC_BAD_CONVERT_JS;
michael@0 5171 }
michael@0 5172
michael@0 5173 ErrorResult rv;
michael@0 5174 nsIDocument::FrameRequestCallbackHolder holder(aCallback);
michael@0 5175 *aHandle = RequestAnimationFrame(holder, rv);
michael@0 5176
michael@0 5177 return rv.ErrorCode();
michael@0 5178 }
michael@0 5179
michael@0 5180 int32_t
michael@0 5181 nsGlobalWindow::RequestAnimationFrame(FrameRequestCallback& aCallback,
michael@0 5182 ErrorResult& aError)
michael@0 5183 {
michael@0 5184 nsIDocument::FrameRequestCallbackHolder holder(&aCallback);
michael@0 5185 return RequestAnimationFrame(holder, aError);
michael@0 5186 }
michael@0 5187
michael@0 5188 int32_t
michael@0 5189 nsGlobalWindow::MozRequestAnimationFrame(nsIFrameRequestCallback* aCallback,
michael@0 5190 ErrorResult& aError)
michael@0 5191 {
michael@0 5192 nsIDocument::FrameRequestCallbackHolder holder(aCallback);
michael@0 5193 return RequestAnimationFrame(holder, aError);
michael@0 5194 }
michael@0 5195
michael@0 5196 int32_t
michael@0 5197 nsGlobalWindow::RequestAnimationFrame(const nsIDocument::FrameRequestCallbackHolder& aCallback,
michael@0 5198 ErrorResult& aError)
michael@0 5199 {
michael@0 5200 FORWARD_TO_INNER_OR_THROW(RequestAnimationFrame, (aCallback, aError), aError,
michael@0 5201 0);
michael@0 5202
michael@0 5203 if (!mDoc) {
michael@0 5204 return 0;
michael@0 5205 }
michael@0 5206
michael@0 5207 if (GetWrapperPreserveColor()) {
michael@0 5208 js::NotifyAnimationActivity(GetWrapperPreserveColor());
michael@0 5209 }
michael@0 5210
michael@0 5211 int32_t handle;
michael@0 5212 aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle);
michael@0 5213 return handle;
michael@0 5214 }
michael@0 5215
michael@0 5216 NS_IMETHODIMP
michael@0 5217 nsGlobalWindow::RequestAnimationFrame(JS::Handle<JS::Value> aCallback,
michael@0 5218 JSContext* cx,
michael@0 5219 int32_t* aHandle)
michael@0 5220 {
michael@0 5221 if (!aCallback.isObject() || !JS_ObjectIsCallable(cx, &aCallback.toObject())) {
michael@0 5222 return NS_ERROR_INVALID_ARG;
michael@0 5223 }
michael@0 5224
michael@0 5225 JS::Rooted<JSObject*> callbackObj(cx, &aCallback.toObject());
michael@0 5226 nsRefPtr<FrameRequestCallback> callback =
michael@0 5227 new FrameRequestCallback(callbackObj, GetIncumbentGlobal());
michael@0 5228
michael@0 5229 ErrorResult rv;
michael@0 5230 *aHandle = RequestAnimationFrame(*callback, rv);
michael@0 5231
michael@0 5232 return rv.ErrorCode();
michael@0 5233 }
michael@0 5234
michael@0 5235 NS_IMETHODIMP
michael@0 5236 nsGlobalWindow::MozCancelRequestAnimationFrame(int32_t aHandle)
michael@0 5237 {
michael@0 5238 return CancelAnimationFrame(aHandle);
michael@0 5239 }
michael@0 5240
michael@0 5241 NS_IMETHODIMP
michael@0 5242 nsGlobalWindow::MozCancelAnimationFrame(int32_t aHandle)
michael@0 5243 {
michael@0 5244 return CancelAnimationFrame(aHandle);
michael@0 5245 }
michael@0 5246
michael@0 5247 void
michael@0 5248 nsGlobalWindow::CancelAnimationFrame(int32_t aHandle, ErrorResult& aError)
michael@0 5249 {
michael@0 5250 FORWARD_TO_INNER_OR_THROW(CancelAnimationFrame, (aHandle, aError), aError, );
michael@0 5251
michael@0 5252 if (!mDoc) {
michael@0 5253 return;
michael@0 5254 }
michael@0 5255
michael@0 5256 mDoc->CancelFrameRequestCallback(aHandle);
michael@0 5257 }
michael@0 5258
michael@0 5259 NS_IMETHODIMP
michael@0 5260 nsGlobalWindow::CancelAnimationFrame(int32_t aHandle)
michael@0 5261 {
michael@0 5262 ErrorResult rv;
michael@0 5263 CancelAnimationFrame(aHandle, rv);
michael@0 5264
michael@0 5265 return rv.ErrorCode();
michael@0 5266 }
michael@0 5267
michael@0 5268 int64_t
michael@0 5269 nsGlobalWindow::GetMozAnimationStartTime(ErrorResult& aError)
michael@0 5270 {
michael@0 5271 FORWARD_TO_INNER_OR_THROW(GetMozAnimationStartTime, (aError), aError, 0);
michael@0 5272
michael@0 5273 if (mDoc) {
michael@0 5274 nsIPresShell* presShell = mDoc->GetShell();
michael@0 5275 if (presShell) {
michael@0 5276 return presShell->GetPresContext()->RefreshDriver()->
michael@0 5277 MostRecentRefreshEpochTime() / PR_USEC_PER_MSEC;
michael@0 5278 }
michael@0 5279 }
michael@0 5280
michael@0 5281 // If all else fails, just be compatible with Date.now()
michael@0 5282 return JS_Now() / PR_USEC_PER_MSEC;
michael@0 5283 }
michael@0 5284
michael@0 5285 NS_IMETHODIMP
michael@0 5286 nsGlobalWindow::GetMozAnimationStartTime(int64_t *aTime)
michael@0 5287 {
michael@0 5288 ErrorResult rv;
michael@0 5289 *aTime = GetMozAnimationStartTime(rv);
michael@0 5290
michael@0 5291 return rv.ErrorCode();
michael@0 5292 }
michael@0 5293
michael@0 5294 already_AddRefed<MediaQueryList>
michael@0 5295 nsGlobalWindow::MatchMedia(const nsAString& aMediaQueryList,
michael@0 5296 ErrorResult& aError)
michael@0 5297 {
michael@0 5298 // FIXME: This whole forward-to-outer and then get a pres
michael@0 5299 // shell/context off the docshell dance is sort of silly; it'd make
michael@0 5300 // more sense to forward to the inner, but it's what everyone else
michael@0 5301 // (GetSelection, GetScrollXY, etc.) does around here.
michael@0 5302 FORWARD_TO_OUTER_OR_THROW(MatchMedia, (aMediaQueryList, aError), aError,
michael@0 5303 nullptr);
michael@0 5304
michael@0 5305 // We need this now to ensure that we have a non-null |presContext|
michael@0 5306 // when we ought to.
michael@0 5307 // This is similar to EnsureSizeUpToDate, but only flushes frames.
michael@0 5308 nsGlobalWindow *parent = static_cast<nsGlobalWindow*>(GetPrivateParent());
michael@0 5309 if (parent) {
michael@0 5310 parent->FlushPendingNotifications(Flush_Frames);
michael@0 5311 }
michael@0 5312
michael@0 5313 if (!mDocShell) {
michael@0 5314 return nullptr;
michael@0 5315 }
michael@0 5316
michael@0 5317 nsRefPtr<nsPresContext> presContext;
michael@0 5318 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 5319
michael@0 5320 if (!presContext) {
michael@0 5321 return nullptr;
michael@0 5322 }
michael@0 5323
michael@0 5324 return presContext->MatchMedia(aMediaQueryList);
michael@0 5325 }
michael@0 5326
michael@0 5327 NS_IMETHODIMP
michael@0 5328 nsGlobalWindow::MatchMedia(const nsAString& aMediaQueryList,
michael@0 5329 nsISupports** aResult)
michael@0 5330 {
michael@0 5331 ErrorResult rv;
michael@0 5332 nsRefPtr<MediaQueryList> mediaQueryList = MatchMedia(aMediaQueryList, rv);
michael@0 5333 mediaQueryList.forget(aResult);
michael@0 5334
michael@0 5335 return rv.ErrorCode();
michael@0 5336 }
michael@0 5337
michael@0 5338 void
michael@0 5339 nsGlobalWindow::SetScreenX(int32_t aScreenX, ErrorResult& aError)
michael@0 5340 {
michael@0 5341 FORWARD_TO_OUTER_OR_THROW(SetScreenX, (aScreenX, aError), aError, );
michael@0 5342
michael@0 5343 /*
michael@0 5344 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 5345 * prevent setting window.screenX by exiting early
michael@0 5346 */
michael@0 5347
michael@0 5348 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 5349 return;
michael@0 5350 }
michael@0 5351
michael@0 5352 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 5353 if (!treeOwnerAsWin) {
michael@0 5354 aError.Throw(NS_ERROR_FAILURE);
michael@0 5355 return;
michael@0 5356 }
michael@0 5357
michael@0 5358 int32_t x, y;
michael@0 5359 aError = treeOwnerAsWin->GetPosition(&x, &y);
michael@0 5360 if (aError.Failed()) {
michael@0 5361 return;
michael@0 5362 }
michael@0 5363
michael@0 5364 CheckSecurityLeftAndTop(&aScreenX, nullptr);
michael@0 5365 x = CSSToDevIntPixels(aScreenX);
michael@0 5366
michael@0 5367 aError = treeOwnerAsWin->SetPosition(x, y);
michael@0 5368 }
michael@0 5369
michael@0 5370 NS_IMETHODIMP
michael@0 5371 nsGlobalWindow::SetScreenX(int32_t aScreenX)
michael@0 5372 {
michael@0 5373 ErrorResult rv;
michael@0 5374 SetScreenX(aScreenX, rv);
michael@0 5375
michael@0 5376 return rv.ErrorCode();
michael@0 5377 }
michael@0 5378
michael@0 5379 int32_t
michael@0 5380 nsGlobalWindow::GetScreenY(ErrorResult& aError)
michael@0 5381 {
michael@0 5382 FORWARD_TO_OUTER_OR_THROW(GetScreenY, (aError), aError, 0);
michael@0 5383
michael@0 5384 return DevToCSSIntPixels(GetScreenXY(aError).y);
michael@0 5385 }
michael@0 5386
michael@0 5387 NS_IMETHODIMP
michael@0 5388 nsGlobalWindow::GetScreenY(int32_t* aScreenY)
michael@0 5389 {
michael@0 5390 ErrorResult rv;
michael@0 5391 *aScreenY = GetScreenY(rv);
michael@0 5392
michael@0 5393 return rv.ErrorCode();
michael@0 5394 }
michael@0 5395
michael@0 5396 void
michael@0 5397 nsGlobalWindow::SetScreenY(int32_t aScreenY, ErrorResult& aError)
michael@0 5398 {
michael@0 5399 FORWARD_TO_OUTER_OR_THROW(SetScreenY, (aScreenY, aError), aError, );
michael@0 5400
michael@0 5401 /*
michael@0 5402 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 5403 * prevent setting window.screenY by exiting early
michael@0 5404 */
michael@0 5405
michael@0 5406 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 5407 return;
michael@0 5408 }
michael@0 5409
michael@0 5410 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 5411 if (!treeOwnerAsWin) {
michael@0 5412 aError.Throw(NS_ERROR_FAILURE);
michael@0 5413 return;
michael@0 5414 }
michael@0 5415
michael@0 5416 int32_t x, y;
michael@0 5417 aError = treeOwnerAsWin->GetPosition(&x, &y);
michael@0 5418 if (aError.Failed()) {
michael@0 5419 return;
michael@0 5420 }
michael@0 5421
michael@0 5422 CheckSecurityLeftAndTop(nullptr, &aScreenY);
michael@0 5423 y = CSSToDevIntPixels(aScreenY);
michael@0 5424
michael@0 5425 aError = treeOwnerAsWin->SetPosition(x, y);
michael@0 5426 }
michael@0 5427
michael@0 5428 NS_IMETHODIMP
michael@0 5429 nsGlobalWindow::SetScreenY(int32_t aScreenY)
michael@0 5430 {
michael@0 5431 ErrorResult rv;
michael@0 5432 SetScreenY(aScreenY, rv);
michael@0 5433
michael@0 5434 return rv.ErrorCode();
michael@0 5435 }
michael@0 5436
michael@0 5437 bool
michael@0 5438 nsGlobalWindow::IsChrome() const
michael@0 5439 {
michael@0 5440 bool isChrome = false;
michael@0 5441
michael@0 5442 if (mDocShell) {
michael@0 5443 nsRefPtr<nsPresContext> presContext;
michael@0 5444 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 5445 isChrome = (presContext && presContext->IsChrome());
michael@0 5446 }
michael@0 5447
michael@0 5448 return isChrome;
michael@0 5449 }
michael@0 5450
michael@0 5451 // NOTE: Arguments to this function should have values scaled to
michael@0 5452 // CSS pixels, not device pixels.
michael@0 5453 void
michael@0 5454 nsGlobalWindow::CheckSecurityWidthAndHeight(int32_t* aWidth, int32_t* aHeight)
michael@0 5455 {
michael@0 5456 MOZ_ASSERT(IsOuterWindow());
michael@0 5457
michael@0 5458 #ifdef MOZ_XUL
michael@0 5459 if (!nsContentUtils::IsCallerChrome()) {
michael@0 5460 // if attempting to resize the window, hide any open popups
michael@0 5461 nsContentUtils::HidePopupsInDocument(mDoc);
michael@0 5462 }
michael@0 5463 #endif
michael@0 5464
michael@0 5465 // This one is easy. Just ensure the variable is greater than 100;
michael@0 5466 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
michael@0 5467 // Check security state for use in determing window dimensions
michael@0 5468
michael@0 5469 if (!nsContentUtils::IsCallerChrome()) {
michael@0 5470 //sec check failed
michael@0 5471 if (aWidth && *aWidth < 100) {
michael@0 5472 *aWidth = 100;
michael@0 5473 }
michael@0 5474 if (aHeight && *aHeight < 100) {
michael@0 5475 *aHeight = 100;
michael@0 5476 }
michael@0 5477 }
michael@0 5478 }
michael@0 5479 }
michael@0 5480
michael@0 5481 // NOTE: Arguments to this function should have values in device pixels
michael@0 5482 nsresult
michael@0 5483 nsGlobalWindow::SetDocShellWidthAndHeight(int32_t aInnerWidth, int32_t aInnerHeight)
michael@0 5484 {
michael@0 5485 MOZ_ASSERT(IsOuterWindow());
michael@0 5486
michael@0 5487 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
michael@0 5488
michael@0 5489 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
michael@0 5490 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
michael@0 5491 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
michael@0 5492
michael@0 5493 NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(mDocShell, aInnerWidth, aInnerHeight),
michael@0 5494 NS_ERROR_FAILURE);
michael@0 5495
michael@0 5496 return NS_OK;
michael@0 5497 }
michael@0 5498
michael@0 5499 // NOTE: Arguments to this function should have values in app units
michael@0 5500 void
michael@0 5501 nsGlobalWindow::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
michael@0 5502 {
michael@0 5503 MOZ_ASSERT(IsOuterWindow());
michael@0 5504
michael@0 5505 nsRefPtr<nsPresContext> presContext;
michael@0 5506 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 5507
michael@0 5508 nsRect shellArea = presContext->GetVisibleArea();
michael@0 5509 shellArea.height = aInnerHeight;
michael@0 5510 shellArea.width = aInnerWidth;
michael@0 5511
michael@0 5512 presContext->SetVisibleArea(shellArea);
michael@0 5513 }
michael@0 5514
michael@0 5515 // NOTE: Arguments to this function should have values scaled to
michael@0 5516 // CSS pixels, not device pixels.
michael@0 5517 void
michael@0 5518 nsGlobalWindow::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop)
michael@0 5519 {
michael@0 5520 MOZ_ASSERT(IsOuterWindow());
michael@0 5521
michael@0 5522 // This one is harder. We have to get the screen size and window dimensions.
michael@0 5523
michael@0 5524 // Check security state for use in determing window dimensions
michael@0 5525
michael@0 5526 if (!nsContentUtils::IsCallerChrome()) {
michael@0 5527 #ifdef MOZ_XUL
michael@0 5528 // if attempting to move the window, hide any open popups
michael@0 5529 nsContentUtils::HidePopupsInDocument(mDoc);
michael@0 5530 #endif
michael@0 5531
michael@0 5532 nsGlobalWindow* rootWindow =
michael@0 5533 static_cast<nsGlobalWindow*>(GetPrivateRoot());
michael@0 5534 if (rootWindow) {
michael@0 5535 rootWindow->FlushPendingNotifications(Flush_Layout);
michael@0 5536 }
michael@0 5537
michael@0 5538 nsCOMPtr<nsIBaseWindow> treeOwner = GetTreeOwnerWindow();
michael@0 5539
michael@0 5540 nsCOMPtr<nsIDOMScreen> screen;
michael@0 5541 GetScreen(getter_AddRefs(screen));
michael@0 5542
michael@0 5543 if (treeOwner && screen) {
michael@0 5544 int32_t screenLeft, screenTop, screenWidth, screenHeight;
michael@0 5545 int32_t winLeft, winTop, winWidth, winHeight;
michael@0 5546
michael@0 5547 // Get the window size
michael@0 5548 treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
michael@0 5549
michael@0 5550 // convert those values to CSS pixels
michael@0 5551 // XXX four separate retrievals of the prescontext
michael@0 5552 winLeft = DevToCSSIntPixels(winLeft);
michael@0 5553 winTop = DevToCSSIntPixels(winTop);
michael@0 5554 winWidth = DevToCSSIntPixels(winWidth);
michael@0 5555 winHeight = DevToCSSIntPixels(winHeight);
michael@0 5556
michael@0 5557 // Get the screen dimensions
michael@0 5558 // XXX This should use nsIScreenManager once it's fully fleshed out.
michael@0 5559 screen->GetAvailLeft(&screenLeft);
michael@0 5560 screen->GetAvailWidth(&screenWidth);
michael@0 5561 screen->GetAvailHeight(&screenHeight);
michael@0 5562 #if defined(XP_MACOSX)
michael@0 5563 /* The mac's coordinate system is different from the assumed Windows'
michael@0 5564 system. It offsets by the height of the menubar so that a window
michael@0 5565 placed at (0,0) will be entirely visible. Unfortunately that
michael@0 5566 correction is made elsewhere (in Widget) and the meaning of
michael@0 5567 the Avail... coordinates is overloaded. Here we allow a window
michael@0 5568 to be placed at (0,0) because it does make sense to do so.
michael@0 5569 */
michael@0 5570 screen->GetTop(&screenTop);
michael@0 5571 #else
michael@0 5572 screen->GetAvailTop(&screenTop);
michael@0 5573 #endif
michael@0 5574
michael@0 5575 if (aLeft) {
michael@0 5576 if (screenLeft+screenWidth < *aLeft+winWidth)
michael@0 5577 *aLeft = screenLeft+screenWidth - winWidth;
michael@0 5578 if (screenLeft > *aLeft)
michael@0 5579 *aLeft = screenLeft;
michael@0 5580 }
michael@0 5581 if (aTop) {
michael@0 5582 if (screenTop+screenHeight < *aTop+winHeight)
michael@0 5583 *aTop = screenTop+screenHeight - winHeight;
michael@0 5584 if (screenTop > *aTop)
michael@0 5585 *aTop = screenTop;
michael@0 5586 }
michael@0 5587 } else {
michael@0 5588 if (aLeft)
michael@0 5589 *aLeft = 0;
michael@0 5590 if (aTop)
michael@0 5591 *aTop = 0;
michael@0 5592 }
michael@0 5593 }
michael@0 5594 }
michael@0 5595
michael@0 5596 NS_IMETHODIMP
michael@0 5597 nsGlobalWindow::GetPageXOffset(int32_t* aPageXOffset)
michael@0 5598 {
michael@0 5599 return GetScrollX(aPageXOffset);
michael@0 5600 }
michael@0 5601
michael@0 5602 NS_IMETHODIMP
michael@0 5603 nsGlobalWindow::GetPageYOffset(int32_t* aPageYOffset)
michael@0 5604 {
michael@0 5605 return GetScrollY(aPageYOffset);
michael@0 5606 }
michael@0 5607
michael@0 5608 void
michael@0 5609 nsGlobalWindow::GetScrollMaxXY(int32_t* aScrollMaxX, int32_t* aScrollMaxY,
michael@0 5610 ErrorResult& aError)
michael@0 5611 {
michael@0 5612 FORWARD_TO_OUTER_OR_THROW(GetScrollMaxXY, (aScrollMaxX, aScrollMaxY, aError),
michael@0 5613 aError, );
michael@0 5614
michael@0 5615 FlushPendingNotifications(Flush_Layout);
michael@0 5616 nsIScrollableFrame *sf = GetScrollFrame();
michael@0 5617 if (!sf) {
michael@0 5618 return;
michael@0 5619 }
michael@0 5620
michael@0 5621 nsRect scrollRange = sf->GetScrollRange();
michael@0 5622
michael@0 5623 if (aScrollMaxX) {
michael@0 5624 *aScrollMaxX = std::max(0,
michael@0 5625 (int32_t)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.XMost())));
michael@0 5626 }
michael@0 5627 if (aScrollMaxY) {
michael@0 5628 *aScrollMaxY = std::max(0,
michael@0 5629 (int32_t)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.YMost())));
michael@0 5630 }
michael@0 5631 }
michael@0 5632
michael@0 5633 int32_t
michael@0 5634 nsGlobalWindow::GetScrollMaxX(ErrorResult& aError)
michael@0 5635 {
michael@0 5636 int32_t scrollMaxX = 0;
michael@0 5637 GetScrollMaxXY(&scrollMaxX, nullptr, aError);
michael@0 5638 return scrollMaxX;
michael@0 5639 }
michael@0 5640
michael@0 5641 NS_IMETHODIMP
michael@0 5642 nsGlobalWindow::GetScrollMaxX(int32_t* aScrollMaxX)
michael@0 5643 {
michael@0 5644 NS_ENSURE_ARG_POINTER(aScrollMaxX);
michael@0 5645 ErrorResult rv;
michael@0 5646 *aScrollMaxX = GetScrollMaxX(rv);
michael@0 5647
michael@0 5648 return rv.ErrorCode();
michael@0 5649 }
michael@0 5650
michael@0 5651 int32_t
michael@0 5652 nsGlobalWindow::GetScrollMaxY(ErrorResult& aError)
michael@0 5653 {
michael@0 5654 int32_t scrollMaxY = 0;
michael@0 5655 GetScrollMaxXY(nullptr, &scrollMaxY, aError);
michael@0 5656 return scrollMaxY;
michael@0 5657 }
michael@0 5658
michael@0 5659 NS_IMETHODIMP
michael@0 5660 nsGlobalWindow::GetScrollMaxY(int32_t* aScrollMaxY)
michael@0 5661 {
michael@0 5662 NS_ENSURE_ARG_POINTER(aScrollMaxY);
michael@0 5663 ErrorResult rv;
michael@0 5664 *aScrollMaxY = GetScrollMaxY(rv);
michael@0 5665
michael@0 5666 return rv.ErrorCode();
michael@0 5667 }
michael@0 5668
michael@0 5669 CSSIntPoint
michael@0 5670 nsGlobalWindow::GetScrollXY(bool aDoFlush, ErrorResult& aError)
michael@0 5671 {
michael@0 5672 FORWARD_TO_OUTER_OR_THROW(GetScrollXY, (aDoFlush, aError), aError,
michael@0 5673 CSSIntPoint(0, 0));
michael@0 5674
michael@0 5675 if (aDoFlush) {
michael@0 5676 FlushPendingNotifications(Flush_Layout);
michael@0 5677 } else {
michael@0 5678 EnsureSizeUpToDate();
michael@0 5679 }
michael@0 5680
michael@0 5681 nsIScrollableFrame *sf = GetScrollFrame();
michael@0 5682 if (!sf) {
michael@0 5683 return CSSIntPoint(0, 0);
michael@0 5684 }
michael@0 5685
michael@0 5686 nsPoint scrollPos = sf->GetScrollPosition();
michael@0 5687 if (scrollPos != nsPoint(0,0) && !aDoFlush) {
michael@0 5688 // Oh, well. This is the expensive case -- the window is scrolled and we
michael@0 5689 // didn't actually flush yet. Repeat, but with a flush, since the content
michael@0 5690 // may get shorter and hence our scroll position may decrease.
michael@0 5691 return GetScrollXY(true, aError);
michael@0 5692 }
michael@0 5693
michael@0 5694 return sf->GetScrollPositionCSSPixels();
michael@0 5695 }
michael@0 5696
michael@0 5697 int32_t
michael@0 5698 nsGlobalWindow::GetScrollX(ErrorResult& aError)
michael@0 5699 {
michael@0 5700 return GetScrollXY(false, aError).x;
michael@0 5701 }
michael@0 5702
michael@0 5703 NS_IMETHODIMP
michael@0 5704 nsGlobalWindow::GetScrollX(int32_t* aScrollX)
michael@0 5705 {
michael@0 5706 NS_ENSURE_ARG_POINTER(aScrollX);
michael@0 5707 ErrorResult rv;
michael@0 5708 *aScrollX = GetScrollXY(false, rv).x;
michael@0 5709 return rv.ErrorCode();
michael@0 5710 }
michael@0 5711
michael@0 5712 int32_t
michael@0 5713 nsGlobalWindow::GetScrollY(ErrorResult& aError)
michael@0 5714 {
michael@0 5715 return GetScrollXY(false, aError).y;
michael@0 5716 }
michael@0 5717
michael@0 5718 NS_IMETHODIMP
michael@0 5719 nsGlobalWindow::GetScrollY(int32_t* aScrollY)
michael@0 5720 {
michael@0 5721 NS_ENSURE_ARG_POINTER(aScrollY);
michael@0 5722 ErrorResult rv;
michael@0 5723 *aScrollY = GetScrollXY(false, rv).y;
michael@0 5724 return rv.ErrorCode();
michael@0 5725 }
michael@0 5726
michael@0 5727 uint32_t
michael@0 5728 nsGlobalWindow::Length()
michael@0 5729 {
michael@0 5730 FORWARD_TO_OUTER(Length, (), 0);
michael@0 5731
michael@0 5732 nsDOMWindowList* windows = GetWindowList();
michael@0 5733
michael@0 5734 return windows ? windows->GetLength() : 0;
michael@0 5735 }
michael@0 5736
michael@0 5737 NS_IMETHODIMP
michael@0 5738 nsGlobalWindow::GetLength(uint32_t* aLength)
michael@0 5739 {
michael@0 5740 *aLength = Length();
michael@0 5741 return NS_OK;
michael@0 5742 }
michael@0 5743
michael@0 5744 already_AddRefed<nsIDOMWindow>
michael@0 5745 nsGlobalWindow::GetChildWindow(const nsAString& aName)
michael@0 5746 {
michael@0 5747 nsCOMPtr<nsIDocShell> docShell(GetDocShell());
michael@0 5748 NS_ENSURE_TRUE(docShell, nullptr);
michael@0 5749
michael@0 5750 nsCOMPtr<nsIDocShellTreeItem> child;
michael@0 5751 docShell->FindChildWithName(PromiseFlatString(aName).get(),
michael@0 5752 false, true, nullptr, nullptr,
michael@0 5753 getter_AddRefs(child));
michael@0 5754
michael@0 5755 nsCOMPtr<nsIDOMWindow> child_win(do_GetInterface(child));
michael@0 5756 return child_win.forget();
michael@0 5757 }
michael@0 5758
michael@0 5759 bool
michael@0 5760 nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
michael@0 5761 {
michael@0 5762 bool defaultActionEnabled = true;
michael@0 5763 nsContentUtils::DispatchTrustedEvent(mDoc,
michael@0 5764 GetOuterWindow(),
michael@0 5765 NS_ConvertASCIItoUTF16(aEventName),
michael@0 5766 true, true, &defaultActionEnabled);
michael@0 5767
michael@0 5768 return defaultActionEnabled;
michael@0 5769 }
michael@0 5770
michael@0 5771 // NOTE: Arguments to this function should be CSS pixels, not device pixels.
michael@0 5772 bool
michael@0 5773 nsGlobalWindow::DispatchResizeEvent(const nsIntSize& aSize)
michael@0 5774 {
michael@0 5775 ErrorResult res;
michael@0 5776 nsRefPtr<Event> domEvent =
michael@0 5777 mDoc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), res);
michael@0 5778 if (res.Failed()) {
michael@0 5779 return false;
michael@0 5780 }
michael@0 5781
michael@0 5782 AutoSafeJSContext cx;
michael@0 5783 JSAutoCompartment ac(cx, GetWrapperPreserveColor());
michael@0 5784 DOMWindowResizeEventDetail detail;
michael@0 5785 detail.mWidth = aSize.width;
michael@0 5786 detail.mHeight = aSize.height;
michael@0 5787 JS::Rooted<JS::Value> detailValue(cx);
michael@0 5788 if (!detail.ToObject(cx, &detailValue)) {
michael@0 5789 return false;
michael@0 5790 }
michael@0 5791
michael@0 5792 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
michael@0 5793 customEvent->InitCustomEvent(cx,
michael@0 5794 NS_LITERAL_STRING("DOMWindowResize"),
michael@0 5795 /* bubbles = */ true,
michael@0 5796 /* cancelable = */ true,
michael@0 5797 detailValue,
michael@0 5798 res);
michael@0 5799 if (res.Failed()) {
michael@0 5800 return false;
michael@0 5801 }
michael@0 5802
michael@0 5803 domEvent->SetTrusted(true);
michael@0 5804 domEvent->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
michael@0 5805
michael@0 5806 nsCOMPtr<EventTarget> target = do_QueryInterface(GetOuterWindow());
michael@0 5807 domEvent->SetTarget(target);
michael@0 5808
michael@0 5809 bool defaultActionEnabled = true;
michael@0 5810 target->DispatchEvent(domEvent, &defaultActionEnabled);
michael@0 5811
michael@0 5812 return defaultActionEnabled;
michael@0 5813 }
michael@0 5814
michael@0 5815 void
michael@0 5816 nsGlobalWindow::RefreshCompartmentPrincipal()
michael@0 5817 {
michael@0 5818 FORWARD_TO_INNER(RefreshCompartmentPrincipal, (), /* void */ );
michael@0 5819
michael@0 5820 JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),
michael@0 5821 nsJSPrincipals::get(mDoc->NodePrincipal()));
michael@0 5822 }
michael@0 5823
michael@0 5824 static already_AddRefed<nsIDocShellTreeItem>
michael@0 5825 GetCallerDocShellTreeItem()
michael@0 5826 {
michael@0 5827 JSContext *cx = nsContentUtils::GetCurrentJSContext();
michael@0 5828 nsCOMPtr<nsIDocShellTreeItem> callerItem;
michael@0 5829
michael@0 5830 if (cx) {
michael@0 5831 nsCOMPtr<nsIWebNavigation> callerWebNav =
michael@0 5832 do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
michael@0 5833
michael@0 5834 callerItem = do_QueryInterface(callerWebNav);
michael@0 5835 }
michael@0 5836
michael@0 5837 return callerItem.forget();
michael@0 5838 }
michael@0 5839
michael@0 5840 bool
michael@0 5841 nsGlobalWindow::WindowExists(const nsAString& aName,
michael@0 5842 bool aLookForCallerOnJSStack)
michael@0 5843 {
michael@0 5844 NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
michael@0 5845 NS_PRECONDITION(mDocShell, "Must have docshell");
michael@0 5846
michael@0 5847 nsCOMPtr<nsIDocShellTreeItem> caller;
michael@0 5848 if (aLookForCallerOnJSStack) {
michael@0 5849 caller = GetCallerDocShellTreeItem();
michael@0 5850 }
michael@0 5851
michael@0 5852 if (!caller) {
michael@0 5853 caller = mDocShell;
michael@0 5854 }
michael@0 5855
michael@0 5856 nsCOMPtr<nsIDocShellTreeItem> namedItem;
michael@0 5857 mDocShell->FindItemWithName(PromiseFlatString(aName).get(), nullptr, caller,
michael@0 5858 getter_AddRefs(namedItem));
michael@0 5859 return namedItem != nullptr;
michael@0 5860 }
michael@0 5861
michael@0 5862 already_AddRefed<nsIWidget>
michael@0 5863 nsGlobalWindow::GetMainWidget()
michael@0 5864 {
michael@0 5865 FORWARD_TO_OUTER(GetMainWidget, (), nullptr);
michael@0 5866
michael@0 5867 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 5868
michael@0 5869 nsCOMPtr<nsIWidget> widget;
michael@0 5870
michael@0 5871 if (treeOwnerAsWin) {
michael@0 5872 treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
michael@0 5873 }
michael@0 5874
michael@0 5875 return widget.forget();
michael@0 5876 }
michael@0 5877
michael@0 5878 nsIWidget*
michael@0 5879 nsGlobalWindow::GetNearestWidget()
michael@0 5880 {
michael@0 5881 nsIDocShell* docShell = GetDocShell();
michael@0 5882 NS_ENSURE_TRUE(docShell, nullptr);
michael@0 5883 nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
michael@0 5884 NS_ENSURE_TRUE(presShell, nullptr);
michael@0 5885 nsIFrame* rootFrame = presShell->GetRootFrame();
michael@0 5886 NS_ENSURE_TRUE(rootFrame, nullptr);
michael@0 5887 return rootFrame->GetView()->GetNearestWidget(nullptr);
michael@0 5888 }
michael@0 5889
michael@0 5890 void
michael@0 5891 nsGlobalWindow::SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError)
michael@0 5892 {
michael@0 5893 aError = SetFullScreenInternal(aFullScreen, true);
michael@0 5894 }
michael@0 5895
michael@0 5896 NS_IMETHODIMP
michael@0 5897 nsGlobalWindow::SetFullScreen(bool aFullScreen)
michael@0 5898 {
michael@0 5899 return SetFullScreenInternal(aFullScreen, true);
michael@0 5900 }
michael@0 5901
michael@0 5902 nsresult
michael@0 5903 nsGlobalWindow::SetFullScreenInternal(bool aFullScreen, bool aRequireTrust)
michael@0 5904 {
michael@0 5905 FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
michael@0 5906
michael@0 5907 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
michael@0 5908
michael@0 5909 bool rootWinFullScreen;
michael@0 5910 GetFullScreen(&rootWinFullScreen);
michael@0 5911 // Only chrome can change our fullScreen mode, unless we're running in
michael@0 5912 // untrusted mode.
michael@0 5913 if (aFullScreen == rootWinFullScreen ||
michael@0 5914 (aRequireTrust && !nsContentUtils::IsCallerChrome())) {
michael@0 5915 return NS_OK;
michael@0 5916 }
michael@0 5917
michael@0 5918 // SetFullScreen needs to be called on the root window, so get that
michael@0 5919 // via the DocShell tree, and if we are not already the root,
michael@0 5920 // call SetFullScreen on that window instead.
michael@0 5921 nsCOMPtr<nsIDocShellTreeItem> rootItem;
michael@0 5922 mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
michael@0 5923 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(rootItem);
michael@0 5924 if (!window)
michael@0 5925 return NS_ERROR_FAILURE;
michael@0 5926 if (rootItem != mDocShell)
michael@0 5927 return window->SetFullScreenInternal(aFullScreen, aRequireTrust);
michael@0 5928
michael@0 5929 // make sure we don't try to set full screen on a non-chrome window,
michael@0 5930 // which might happen in embedding world
michael@0 5931 if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
michael@0 5932 return NS_ERROR_FAILURE;
michael@0 5933
michael@0 5934 // If we are already in full screen mode, just return.
michael@0 5935 if (mFullScreen == aFullScreen)
michael@0 5936 return NS_OK;
michael@0 5937
michael@0 5938 // dispatch a "fullscreen" DOM event so that XUL apps can
michael@0 5939 // respond visually if we are kicked into full screen mode
michael@0 5940 if (!DispatchCustomEvent("fullscreen")) {
michael@0 5941 return NS_OK;
michael@0 5942 }
michael@0 5943
michael@0 5944 // Prevent chrome documents which are still loading from resizing
michael@0 5945 // the window after we set fullscreen mode.
michael@0 5946 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 5947 nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
michael@0 5948 if (aFullScreen && xulWin) {
michael@0 5949 xulWin->SetIntrinsicallySized(false);
michael@0 5950 }
michael@0 5951
michael@0 5952 // Set this before so if widget sends an event indicating its
michael@0 5953 // gone full screen, the state trap above works.
michael@0 5954 mFullScreen = aFullScreen;
michael@0 5955
michael@0 5956 // Sometimes we don't want the top-level widget to actually go fullscreen,
michael@0 5957 // for example in the B2G desktop client, we don't want the emulated screen
michael@0 5958 // dimensions to appear to increase when entering fullscreen mode; we just
michael@0 5959 // want the content to fill the entire client area of the emulator window.
michael@0 5960 if (!Preferences::GetBool("full-screen-api.ignore-widgets", false)) {
michael@0 5961 nsCOMPtr<nsIWidget> widget = GetMainWidget();
michael@0 5962 if (widget)
michael@0 5963 widget->MakeFullScreen(aFullScreen);
michael@0 5964 }
michael@0 5965
michael@0 5966 if (!mFullScreen) {
michael@0 5967 // Force exit from DOM full-screen mode. This is so that if we're in
michael@0 5968 // DOM full-screen mode and the user exits full-screen mode with
michael@0 5969 // the browser full-screen mode toggle keyboard-shortcut, we'll detect
michael@0 5970 // that and leave DOM API full-screen mode too.
michael@0 5971 nsIDocument::ExitFullscreen(mDoc, /* async */ false);
michael@0 5972 }
michael@0 5973
michael@0 5974 if (!mWakeLock && mFullScreen) {
michael@0 5975 nsRefPtr<power::PowerManagerService> pmService =
michael@0 5976 power::PowerManagerService::GetInstance();
michael@0 5977 NS_ENSURE_TRUE(pmService, NS_OK);
michael@0 5978
michael@0 5979 ErrorResult rv;
michael@0 5980 mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"),
michael@0 5981 this, rv);
michael@0 5982 if (rv.Failed()) {
michael@0 5983 return rv.ErrorCode();
michael@0 5984 }
michael@0 5985
michael@0 5986 } else if (mWakeLock && !mFullScreen) {
michael@0 5987 ErrorResult rv;
michael@0 5988 mWakeLock->Unlock(rv);
michael@0 5989 NS_WARN_IF_FALSE(!rv.Failed(), "Failed to unlock the wakelock.");
michael@0 5990 mWakeLock = nullptr;
michael@0 5991 }
michael@0 5992
michael@0 5993 return NS_OK;
michael@0 5994 }
michael@0 5995
michael@0 5996 bool
michael@0 5997 nsGlobalWindow::GetFullScreen(ErrorResult& aError)
michael@0 5998 {
michael@0 5999 FORWARD_TO_OUTER_OR_THROW(GetFullScreen, (aError), aError, false);
michael@0 6000
michael@0 6001 // Get the fullscreen value of the root window, to always have the value
michael@0 6002 // accurate, even when called from content.
michael@0 6003 if (mDocShell) {
michael@0 6004 nsCOMPtr<nsIDocShellTreeItem> rootItem;
michael@0 6005 mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
michael@0 6006 if (rootItem != mDocShell) {
michael@0 6007 nsCOMPtr<nsIDOMWindow> window = do_GetInterface(rootItem);
michael@0 6008 if (window) {
michael@0 6009 bool fullScreen = false;
michael@0 6010 aError = window->GetFullScreen(&fullScreen);
michael@0 6011 return fullScreen;
michael@0 6012 }
michael@0 6013 }
michael@0 6014 }
michael@0 6015
michael@0 6016 // We are the root window, or something went wrong. Return our internal value.
michael@0 6017 return mFullScreen;
michael@0 6018 }
michael@0 6019
michael@0 6020 NS_IMETHODIMP
michael@0 6021 nsGlobalWindow::GetFullScreen(bool* aFullScreen)
michael@0 6022 {
michael@0 6023 ErrorResult rv;
michael@0 6024 *aFullScreen = GetFullScreen(rv);
michael@0 6025
michael@0 6026 return rv.ErrorCode();
michael@0 6027 }
michael@0 6028
michael@0 6029 NS_IMETHODIMP
michael@0 6030 nsGlobalWindow::Dump(const nsAString& aStr)
michael@0 6031 {
michael@0 6032 if (!nsContentUtils::DOMWindowDumpEnabled()) {
michael@0 6033 return NS_OK;
michael@0 6034 }
michael@0 6035
michael@0 6036 char *cstr = ToNewUTF8String(aStr);
michael@0 6037
michael@0 6038 #if defined(XP_MACOSX)
michael@0 6039 // have to convert \r to \n so that printing to the console works
michael@0 6040 char *c = cstr, *cEnd = cstr + strlen(cstr);
michael@0 6041 while (c < cEnd) {
michael@0 6042 if (*c == '\r')
michael@0 6043 *c = '\n';
michael@0 6044 c++;
michael@0 6045 }
michael@0 6046 #endif
michael@0 6047
michael@0 6048 if (cstr) {
michael@0 6049 #ifdef XP_WIN
michael@0 6050 PrintToDebugger(cstr);
michael@0 6051 #endif
michael@0 6052 #ifdef ANDROID
michael@0 6053 __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
michael@0 6054 #endif
michael@0 6055 FILE *fp = gDumpFile ? gDumpFile : stdout;
michael@0 6056 fputs(cstr, fp);
michael@0 6057 fflush(fp);
michael@0 6058 nsMemory::Free(cstr);
michael@0 6059 }
michael@0 6060
michael@0 6061 return NS_OK;
michael@0 6062 }
michael@0 6063
michael@0 6064 void
michael@0 6065 nsGlobalWindow::EnsureReflowFlushAndPaint()
michael@0 6066 {
michael@0 6067 MOZ_ASSERT(IsOuterWindow());
michael@0 6068 NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
michael@0 6069 "docshell!");
michael@0 6070
michael@0 6071 if (!mDocShell)
michael@0 6072 return;
michael@0 6073
michael@0 6074 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 6075
michael@0 6076 if (!presShell)
michael@0 6077 return;
michael@0 6078
michael@0 6079 // Flush pending reflows.
michael@0 6080 if (mDoc) {
michael@0 6081 mDoc->FlushPendingNotifications(Flush_Layout);
michael@0 6082 }
michael@0 6083
michael@0 6084 // Unsuppress painting.
michael@0 6085 presShell->UnsuppressPainting();
michael@0 6086 }
michael@0 6087
michael@0 6088 NS_IMETHODIMP
michael@0 6089 nsGlobalWindow::GetTextZoom(float *aZoom)
michael@0 6090 {
michael@0 6091 FORWARD_TO_OUTER(GetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
michael@0 6092
michael@0 6093 if (mDocShell) {
michael@0 6094 nsCOMPtr<nsIContentViewer> contentViewer;
michael@0 6095 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
michael@0 6096 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
michael@0 6097
michael@0 6098 if (markupViewer) {
michael@0 6099 return markupViewer->GetTextZoom(aZoom);
michael@0 6100 }
michael@0 6101 }
michael@0 6102 return NS_ERROR_FAILURE;
michael@0 6103 }
michael@0 6104
michael@0 6105 NS_IMETHODIMP
michael@0 6106 nsGlobalWindow::SetTextZoom(float aZoom)
michael@0 6107 {
michael@0 6108 FORWARD_TO_OUTER(SetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
michael@0 6109
michael@0 6110 if (mDocShell) {
michael@0 6111 nsCOMPtr<nsIContentViewer> contentViewer;
michael@0 6112 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
michael@0 6113 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
michael@0 6114
michael@0 6115 if (markupViewer)
michael@0 6116 return markupViewer->SetTextZoom(aZoom);
michael@0 6117 }
michael@0 6118 return NS_ERROR_FAILURE;
michael@0 6119 }
michael@0 6120
michael@0 6121 // static
michael@0 6122 void
michael@0 6123 nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
michael@0 6124 {
michael@0 6125 aOutTitle.Truncate();
michael@0 6126
michael@0 6127 // Try to get a host from the running principal -- this will do the
michael@0 6128 // right thing for javascript: and data: documents.
michael@0 6129
michael@0 6130 nsresult rv = NS_OK;
michael@0 6131 NS_ASSERTION(nsContentUtils::GetSecurityManager(),
michael@0 6132 "Global Window has no security manager!");
michael@0 6133 if (nsContentUtils::GetSecurityManager()) {
michael@0 6134 nsCOMPtr<nsIPrincipal> principal;
michael@0 6135 rv = nsContentUtils::GetSecurityManager()->
michael@0 6136 GetSubjectPrincipal(getter_AddRefs(principal));
michael@0 6137
michael@0 6138 if (NS_SUCCEEDED(rv) && principal) {
michael@0 6139 nsCOMPtr<nsIURI> uri;
michael@0 6140 rv = principal->GetURI(getter_AddRefs(uri));
michael@0 6141
michael@0 6142 if (NS_SUCCEEDED(rv) && uri) {
michael@0 6143 // remove user:pass for privacy and spoof prevention
michael@0 6144
michael@0 6145 nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
michael@0 6146 if (fixup) {
michael@0 6147 nsCOMPtr<nsIURI> fixedURI;
michael@0 6148 rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
michael@0 6149 if (NS_SUCCEEDED(rv) && fixedURI) {
michael@0 6150 nsAutoCString host;
michael@0 6151 fixedURI->GetHost(host);
michael@0 6152
michael@0 6153 if (!host.IsEmpty()) {
michael@0 6154 // if this URI has a host we'll show it. For other
michael@0 6155 // schemes (e.g. file:) we fall back to the localized
michael@0 6156 // generic string
michael@0 6157
michael@0 6158 nsAutoCString prepath;
michael@0 6159 fixedURI->GetPrePath(prepath);
michael@0 6160
michael@0 6161 NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
michael@0 6162 const char16_t *formatStrings[] = { ucsPrePath.get() };
michael@0 6163 nsXPIDLString tempString;
michael@0 6164 nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
michael@0 6165 "ScriptDlgHeading",
michael@0 6166 formatStrings,
michael@0 6167 tempString);
michael@0 6168 aOutTitle = tempString;
michael@0 6169 }
michael@0 6170 }
michael@0 6171 }
michael@0 6172 }
michael@0 6173 }
michael@0 6174 else { // failed to get subject principal
michael@0 6175 NS_WARNING("No script principal? Who is calling alert/confirm/prompt?!");
michael@0 6176 }
michael@0 6177 }
michael@0 6178
michael@0 6179 if (aOutTitle.IsEmpty()) {
michael@0 6180 // We didn't find a host so use the generic heading
michael@0 6181 nsXPIDLString tempString;
michael@0 6182 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
michael@0 6183 "ScriptDlgGenericHeading",
michael@0 6184 tempString);
michael@0 6185 aOutTitle = tempString;
michael@0 6186 }
michael@0 6187
michael@0 6188 // Just in case
michael@0 6189 if (aOutTitle.IsEmpty()) {
michael@0 6190 NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
michael@0 6191 aOutTitle.AssignLiteral("[Script]");
michael@0 6192 }
michael@0 6193 }
michael@0 6194
michael@0 6195 bool
michael@0 6196 nsGlobalWindow::CanMoveResizeWindows()
michael@0 6197 {
michael@0 6198 MOZ_ASSERT(IsOuterWindow());
michael@0 6199
michael@0 6200 // When called from chrome, we can avoid the following checks.
michael@0 6201 if (!nsContentUtils::IsCallerChrome()) {
michael@0 6202 // Don't allow scripts to move or resize windows that were not opened by a
michael@0 6203 // script.
michael@0 6204 if (!mHadOriginalOpener) {
michael@0 6205 return false;
michael@0 6206 }
michael@0 6207
michael@0 6208 if (!CanSetProperty("dom.disable_window_move_resize")) {
michael@0 6209 return false;
michael@0 6210 }
michael@0 6211
michael@0 6212 // Ignore the request if we have more than one tab in the window.
michael@0 6213 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
michael@0 6214 if (treeOwner) {
michael@0 6215 uint32_t itemCount;
michael@0 6216 if (NS_SUCCEEDED(treeOwner->GetTargetableShellCount(&itemCount)) &&
michael@0 6217 itemCount > 1) {
michael@0 6218 return false;
michael@0 6219 }
michael@0 6220 }
michael@0 6221 }
michael@0 6222
michael@0 6223 // The preference is useful for the webapp runtime. Webapps should be able
michael@0 6224 // to resize or move their window.
michael@0 6225 if (mDocShell && !Preferences::GetBool("dom.always_allow_move_resize_window",
michael@0 6226 false)) {
michael@0 6227 bool allow;
michael@0 6228 nsresult rv = mDocShell->GetAllowWindowControl(&allow);
michael@0 6229 if (NS_SUCCEEDED(rv) && !allow)
michael@0 6230 return false;
michael@0 6231 }
michael@0 6232
michael@0 6233 if (gMouseDown && !gDragServiceDisabled) {
michael@0 6234 nsCOMPtr<nsIDragService> ds =
michael@0 6235 do_GetService("@mozilla.org/widget/dragservice;1");
michael@0 6236 if (ds) {
michael@0 6237 gDragServiceDisabled = true;
michael@0 6238 ds->Suppress();
michael@0 6239 }
michael@0 6240 }
michael@0 6241 return true;
michael@0 6242 }
michael@0 6243
michael@0 6244 bool
michael@0 6245 nsGlobalWindow::AlertOrConfirm(bool aAlert,
michael@0 6246 const nsAString& aMessage,
michael@0 6247 mozilla::ErrorResult& aError)
michael@0 6248 {
michael@0 6249 // XXX This method is very similar to nsGlobalWindow::Prompt, make
michael@0 6250 // sure any modifications here don't need to happen over there!
michael@0 6251 MOZ_ASSERT(IsOuterWindow());
michael@0 6252
michael@0 6253 if (!AreDialogsEnabled()) {
michael@0 6254 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 6255 return false;
michael@0 6256 }
michael@0 6257
michael@0 6258 // Reset popup state while opening a modal dialog, and firing events
michael@0 6259 // about the dialog, to prevent the current state from being active
michael@0 6260 // the whole time a modal dialog is open.
michael@0 6261 nsAutoPopupStatePusher popupStatePusher(openAbused, true);
michael@0 6262
michael@0 6263 // Before bringing up the window, unsuppress painting and flush
michael@0 6264 // pending reflows.
michael@0 6265 EnsureReflowFlushAndPaint();
michael@0 6266
michael@0 6267 nsAutoString title;
michael@0 6268 MakeScriptDialogTitle(title);
michael@0 6269
michael@0 6270 // Remove non-terminating null characters from the
michael@0 6271 // string. See bug #310037.
michael@0 6272 nsAutoString final;
michael@0 6273 nsContentUtils::StripNullChars(aMessage, final);
michael@0 6274
michael@0 6275 nsresult rv;
michael@0 6276 nsCOMPtr<nsIPromptFactory> promptFac =
michael@0 6277 do_GetService("@mozilla.org/prompter;1", &rv);
michael@0 6278 if (NS_FAILED(rv)) {
michael@0 6279 aError.Throw(rv);
michael@0 6280 return false;
michael@0 6281 }
michael@0 6282
michael@0 6283 nsCOMPtr<nsIPrompt> prompt;
michael@0 6284 aError = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
michael@0 6285 getter_AddRefs(prompt));
michael@0 6286 if (aError.Failed()) {
michael@0 6287 return false;
michael@0 6288 }
michael@0 6289
michael@0 6290 // Always allow tab modal prompts for alert and confirm.
michael@0 6291 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
michael@0 6292 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
michael@0 6293 }
michael@0 6294
michael@0 6295 bool result = false;
michael@0 6296 nsAutoSyncOperation sync(mDoc);
michael@0 6297 if (ShouldPromptToBlockDialogs()) {
michael@0 6298 bool disallowDialog = false;
michael@0 6299 nsXPIDLString label;
michael@0 6300 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
michael@0 6301 "ScriptDialogLabel", label);
michael@0 6302
michael@0 6303 aError = aAlert ?
michael@0 6304 prompt->AlertCheck(title.get(), final.get(), label.get(),
michael@0 6305 &disallowDialog) :
michael@0 6306 prompt->ConfirmCheck(title.get(), final.get(), label.get(),
michael@0 6307 &disallowDialog, &result);
michael@0 6308
michael@0 6309 if (disallowDialog)
michael@0 6310 DisableDialogs();
michael@0 6311 } else {
michael@0 6312 aError = aAlert ?
michael@0 6313 prompt->Alert(title.get(), final.get()) :
michael@0 6314 prompt->Confirm(title.get(), final.get(), &result);
michael@0 6315 }
michael@0 6316
michael@0 6317 return result;
michael@0 6318 }
michael@0 6319
michael@0 6320 void
michael@0 6321 nsGlobalWindow::Alert(const nsAString& aMessage, mozilla::ErrorResult& aError)
michael@0 6322 {
michael@0 6323 FORWARD_TO_OUTER_OR_THROW(Alert, (aMessage, aError), aError, );
michael@0 6324 AlertOrConfirm(/* aAlert = */ true, aMessage, aError);
michael@0 6325 }
michael@0 6326
michael@0 6327 NS_IMETHODIMP
michael@0 6328 nsGlobalWindow::Alert(const nsAString& aString)
michael@0 6329 {
michael@0 6330 ErrorResult rv;
michael@0 6331 Alert(aString, rv);
michael@0 6332
michael@0 6333 return rv.ErrorCode();
michael@0 6334 }
michael@0 6335
michael@0 6336 bool
michael@0 6337 nsGlobalWindow::Confirm(const nsAString& aMessage, ErrorResult& aError)
michael@0 6338 {
michael@0 6339 FORWARD_TO_OUTER_OR_THROW(Confirm, (aMessage, aError), aError, false);
michael@0 6340
michael@0 6341 return AlertOrConfirm(/* aAlert = */ false, aMessage, aError);
michael@0 6342 }
michael@0 6343
michael@0 6344 NS_IMETHODIMP
michael@0 6345 nsGlobalWindow::Confirm(const nsAString& aString, bool* aReturn)
michael@0 6346 {
michael@0 6347 ErrorResult rv;
michael@0 6348 *aReturn = Confirm(aString, rv);
michael@0 6349
michael@0 6350 return rv.ErrorCode();
michael@0 6351 }
michael@0 6352
michael@0 6353 void
michael@0 6354 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
michael@0 6355 nsAString& aReturn, ErrorResult& aError)
michael@0 6356 {
michael@0 6357 // XXX This method is very similar to nsGlobalWindow::AlertOrConfirm, make
michael@0 6358 // sure any modifications here don't need to happen over there!
michael@0 6359 FORWARD_TO_OUTER_OR_THROW(Prompt, (aMessage, aInitial, aReturn, aError),
michael@0 6360 aError, );
michael@0 6361
michael@0 6362 SetDOMStringToNull(aReturn);
michael@0 6363
michael@0 6364 if (!AreDialogsEnabled()) {
michael@0 6365 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 6366 return;
michael@0 6367 }
michael@0 6368
michael@0 6369 // Reset popup state while opening a modal dialog, and firing events
michael@0 6370 // about the dialog, to prevent the current state from being active
michael@0 6371 // the whole time a modal dialog is open.
michael@0 6372 nsAutoPopupStatePusher popupStatePusher(openAbused, true);
michael@0 6373
michael@0 6374 // Before bringing up the window, unsuppress painting and flush
michael@0 6375 // pending reflows.
michael@0 6376 EnsureReflowFlushAndPaint();
michael@0 6377
michael@0 6378 nsAutoString title;
michael@0 6379 MakeScriptDialogTitle(title);
michael@0 6380
michael@0 6381 // Remove non-terminating null characters from the
michael@0 6382 // string. See bug #310037.
michael@0 6383 nsAutoString fixedMessage, fixedInitial;
michael@0 6384 nsContentUtils::StripNullChars(aMessage, fixedMessage);
michael@0 6385 nsContentUtils::StripNullChars(aInitial, fixedInitial);
michael@0 6386
michael@0 6387 nsresult rv;
michael@0 6388 nsCOMPtr<nsIPromptFactory> promptFac =
michael@0 6389 do_GetService("@mozilla.org/prompter;1", &rv);
michael@0 6390 if (NS_FAILED(rv)) {
michael@0 6391 aError.Throw(rv);
michael@0 6392 return;
michael@0 6393 }
michael@0 6394
michael@0 6395 nsCOMPtr<nsIPrompt> prompt;
michael@0 6396 aError = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
michael@0 6397 getter_AddRefs(prompt));
michael@0 6398 if (aError.Failed()) {
michael@0 6399 return;
michael@0 6400 }
michael@0 6401
michael@0 6402 // Always allow tab modal prompts for prompt.
michael@0 6403 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
michael@0 6404 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
michael@0 6405 }
michael@0 6406
michael@0 6407 // Pass in the default value, if any.
michael@0 6408 char16_t *inoutValue = ToNewUnicode(fixedInitial);
michael@0 6409 bool disallowDialog = false;
michael@0 6410
michael@0 6411 nsXPIDLString label;
michael@0 6412 if (ShouldPromptToBlockDialogs()) {
michael@0 6413 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
michael@0 6414 "ScriptDialogLabel", label);
michael@0 6415 }
michael@0 6416
michael@0 6417 nsAutoSyncOperation sync(mDoc);
michael@0 6418 bool ok;
michael@0 6419 aError = prompt->Prompt(title.get(), fixedMessage.get(),
michael@0 6420 &inoutValue, label.get(), &disallowDialog, &ok);
michael@0 6421
michael@0 6422 if (disallowDialog) {
michael@0 6423 DisableDialogs();
michael@0 6424 }
michael@0 6425
michael@0 6426 if (aError.Failed()) {
michael@0 6427 return;
michael@0 6428 }
michael@0 6429
michael@0 6430 nsAdoptingString outValue(inoutValue);
michael@0 6431
michael@0 6432 if (ok && outValue) {
michael@0 6433 aReturn.Assign(outValue);
michael@0 6434 }
michael@0 6435 }
michael@0 6436
michael@0 6437 NS_IMETHODIMP
michael@0 6438 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
michael@0 6439 nsAString& aReturn)
michael@0 6440 {
michael@0 6441 ErrorResult rv;
michael@0 6442 Prompt(aMessage, aInitial, aReturn, rv);
michael@0 6443
michael@0 6444 return rv.ErrorCode();
michael@0 6445 }
michael@0 6446
michael@0 6447 void
michael@0 6448 nsGlobalWindow::Focus(ErrorResult& aError)
michael@0 6449 {
michael@0 6450 FORWARD_TO_OUTER_OR_THROW(Focus, (aError), aError, );
michael@0 6451
michael@0 6452 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
michael@0 6453 if (!fm) {
michael@0 6454 return;
michael@0 6455 }
michael@0 6456
michael@0 6457 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
michael@0 6458
michael@0 6459 bool isVisible = false;
michael@0 6460 if (baseWin) {
michael@0 6461 baseWin->GetVisibility(&isVisible);
michael@0 6462 }
michael@0 6463
michael@0 6464 if (!isVisible) {
michael@0 6465 // A hidden tab is being focused, ignore this call.
michael@0 6466 return;
michael@0 6467 }
michael@0 6468
michael@0 6469 nsIDOMWindow *caller = nsContentUtils::GetWindowFromCaller();
michael@0 6470 nsCOMPtr<nsIDOMWindow> opener;
michael@0 6471 GetOpener(getter_AddRefs(opener));
michael@0 6472
michael@0 6473 // Enforce dom.disable_window_flip (for non-chrome), but still allow the
michael@0 6474 // window which opened us to raise us at times when popups are allowed
michael@0 6475 // (bugs 355482 and 369306).
michael@0 6476 bool canFocus = CanSetProperty("dom.disable_window_flip") ||
michael@0 6477 (opener == caller &&
michael@0 6478 RevisePopupAbuseLevel(gPopupControlState) < openAbused);
michael@0 6479
michael@0 6480 nsCOMPtr<nsIDOMWindow> activeWindow;
michael@0 6481 fm->GetActiveWindow(getter_AddRefs(activeWindow));
michael@0 6482
michael@0 6483 nsCOMPtr<nsIDocShellTreeItem> rootItem;
michael@0 6484 mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
michael@0 6485 nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
michael@0 6486 bool isActive = (rootWin == activeWindow);
michael@0 6487
michael@0 6488 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 6489 if (treeOwnerAsWin && (canFocus || isActive)) {
michael@0 6490 bool isEnabled = true;
michael@0 6491 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
michael@0 6492 NS_WARNING( "Should not try to set the focus on a disabled window" );
michael@0 6493 return;
michael@0 6494 }
michael@0 6495
michael@0 6496 // XXXndeakin not sure what this is for or if it should go somewhere else
michael@0 6497 nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
michael@0 6498 if (embeddingWin)
michael@0 6499 embeddingWin->SetFocus();
michael@0 6500 }
michael@0 6501
michael@0 6502 if (!mDocShell) {
michael@0 6503 return;
michael@0 6504 }
michael@0 6505
michael@0 6506 nsCOMPtr<nsIPresShell> presShell;
michael@0 6507 // Don't look for a presshell if we're a root chrome window that's got
michael@0 6508 // about:blank loaded. We don't want to focus our widget in that case.
michael@0 6509 // XXXbz should we really be checking for IsInitialDocument() instead?
michael@0 6510 bool lookForPresShell = true;
michael@0 6511 if (mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome &&
michael@0 6512 GetPrivateRoot() == static_cast<nsIDOMWindow*>(this) &&
michael@0 6513 mDoc) {
michael@0 6514 nsIURI* ourURI = mDoc->GetDocumentURI();
michael@0 6515 if (ourURI) {
michael@0 6516 lookForPresShell = !NS_IsAboutBlank(ourURI);
michael@0 6517 }
michael@0 6518 }
michael@0 6519
michael@0 6520 if (lookForPresShell) {
michael@0 6521 mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
michael@0 6522 }
michael@0 6523
michael@0 6524 nsCOMPtr<nsIDocShellTreeItem> parentDsti;
michael@0 6525 mDocShell->GetParent(getter_AddRefs(parentDsti));
michael@0 6526
michael@0 6527 // set the parent's current focus to the frame containing this window.
michael@0 6528 nsCOMPtr<nsPIDOMWindow> parent = do_GetInterface(parentDsti);
michael@0 6529 if (parent) {
michael@0 6530 nsCOMPtr<nsIDocument> parentdoc = parent->GetDoc();
michael@0 6531 if (!parentdoc) {
michael@0 6532 return;
michael@0 6533 }
michael@0 6534
michael@0 6535 nsIContent* frame = parentdoc->FindContentForSubDocument(mDoc);
michael@0 6536 nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
michael@0 6537 if (frameElement) {
michael@0 6538 uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
michael@0 6539 if (canFocus)
michael@0 6540 flags |= nsIFocusManager::FLAG_RAISE;
michael@0 6541 aError = fm->SetFocus(frameElement, flags);
michael@0 6542 }
michael@0 6543 return;
michael@0 6544 }
michael@0 6545 if (nsCOMPtr<nsITabChild> child = do_GetInterface(mDocShell)) {
michael@0 6546 child->SendRequestFocus(canFocus);
michael@0 6547 return;
michael@0 6548 }
michael@0 6549 if (canFocus) {
michael@0 6550 // if there is no parent, this must be a toplevel window, so raise the
michael@0 6551 // window if canFocus is true
michael@0 6552 aError = fm->SetActiveWindow(this);
michael@0 6553 }
michael@0 6554 }
michael@0 6555
michael@0 6556 NS_IMETHODIMP
michael@0 6557 nsGlobalWindow::Focus()
michael@0 6558 {
michael@0 6559 ErrorResult rv;
michael@0 6560 Focus(rv);
michael@0 6561
michael@0 6562 return rv.ErrorCode();
michael@0 6563 }
michael@0 6564
michael@0 6565 void
michael@0 6566 nsGlobalWindow::Blur(ErrorResult& aError)
michael@0 6567 {
michael@0 6568 FORWARD_TO_OUTER_OR_THROW(Blur, (aError), aError, );
michael@0 6569
michael@0 6570 // If dom.disable_window_flip == true, then content should not be allowed
michael@0 6571 // to call this function (this would allow popunders, bug 369306)
michael@0 6572 if (!CanSetProperty("dom.disable_window_flip")) {
michael@0 6573 return;
michael@0 6574 }
michael@0 6575
michael@0 6576 // If embedding apps don't implement nsIEmbeddingSiteWindow, we
michael@0 6577 // shouldn't throw exceptions to web content.
michael@0 6578
michael@0 6579 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
michael@0 6580 nsCOMPtr<nsIEmbeddingSiteWindow> siteWindow(do_GetInterface(treeOwner));
michael@0 6581 if (siteWindow) {
michael@0 6582 // This method call may cause mDocShell to become nullptr.
michael@0 6583 siteWindow->Blur();
michael@0 6584
michael@0 6585 // if the root is focused, clear the focus
michael@0 6586 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
michael@0 6587 if (fm && mDoc) {
michael@0 6588 nsCOMPtr<nsIDOMElement> element;
michael@0 6589 fm->GetFocusedElementForWindow(this, false, nullptr, getter_AddRefs(element));
michael@0 6590 nsCOMPtr<nsIContent> content = do_QueryInterface(element);
michael@0 6591 if (content == mDoc->GetRootElement())
michael@0 6592 fm->ClearFocus(this);
michael@0 6593 }
michael@0 6594 }
michael@0 6595 }
michael@0 6596
michael@0 6597 NS_IMETHODIMP
michael@0 6598 nsGlobalWindow::Blur()
michael@0 6599 {
michael@0 6600 ErrorResult rv;
michael@0 6601 Blur(rv);
michael@0 6602
michael@0 6603 return rv.ErrorCode();
michael@0 6604 }
michael@0 6605
michael@0 6606 void
michael@0 6607 nsGlobalWindow::Back(ErrorResult& aError)
michael@0 6608 {
michael@0 6609 FORWARD_TO_OUTER_OR_THROW(Back, (aError), aError, );
michael@0 6610
michael@0 6611 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
michael@0 6612 if (!webNav) {
michael@0 6613 aError.Throw(NS_ERROR_FAILURE);
michael@0 6614 return;
michael@0 6615 }
michael@0 6616
michael@0 6617 aError = webNav->GoBack();
michael@0 6618 }
michael@0 6619
michael@0 6620 NS_IMETHODIMP
michael@0 6621 nsGlobalWindow::Back()
michael@0 6622 {
michael@0 6623 ErrorResult rv;
michael@0 6624 Back(rv);
michael@0 6625
michael@0 6626 return rv.ErrorCode();
michael@0 6627 }
michael@0 6628
michael@0 6629 void
michael@0 6630 nsGlobalWindow::Forward(ErrorResult& aError)
michael@0 6631 {
michael@0 6632 FORWARD_TO_OUTER_OR_THROW(Forward, (aError), aError, );
michael@0 6633
michael@0 6634 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
michael@0 6635 if (!webNav) {
michael@0 6636 aError.Throw(NS_ERROR_FAILURE);
michael@0 6637 return;
michael@0 6638 }
michael@0 6639
michael@0 6640 aError = webNav->GoForward();
michael@0 6641 }
michael@0 6642
michael@0 6643 NS_IMETHODIMP
michael@0 6644 nsGlobalWindow::Forward()
michael@0 6645 {
michael@0 6646 ErrorResult rv;
michael@0 6647 Forward(rv);
michael@0 6648
michael@0 6649 return rv.ErrorCode();
michael@0 6650 }
michael@0 6651
michael@0 6652 void
michael@0 6653 nsGlobalWindow::Home(ErrorResult& aError)
michael@0 6654 {
michael@0 6655 FORWARD_TO_OUTER_OR_THROW(Home, (aError), aError, );
michael@0 6656
michael@0 6657 if (!mDocShell) {
michael@0 6658 return;
michael@0 6659 }
michael@0 6660
michael@0 6661 nsAdoptingString homeURL =
michael@0 6662 Preferences::GetLocalizedString(PREF_BROWSER_STARTUP_HOMEPAGE);
michael@0 6663
michael@0 6664 if (homeURL.IsEmpty()) {
michael@0 6665 // if all else fails, use this
michael@0 6666 #ifdef DEBUG_seth
michael@0 6667 printf("all else failed. using %s as the home page\n", DEFAULT_HOME_PAGE);
michael@0 6668 #endif
michael@0 6669 CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
michael@0 6670 }
michael@0 6671
michael@0 6672 #ifdef MOZ_PHOENIX
michael@0 6673 {
michael@0 6674 // Firefox lets the user specify multiple home pages to open in
michael@0 6675 // individual tabs by separating them with '|'. Since we don't
michael@0 6676 // have the machinery in place to easily open new tabs from here,
michael@0 6677 // simply truncate the homeURL at the first '|' character to
michael@0 6678 // prevent any possibilities of leaking the users list of home
michael@0 6679 // pages to the first home page.
michael@0 6680 //
michael@0 6681 // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
michael@0 6682 // fixed we can revisit this.
michael@0 6683 int32_t firstPipe = homeURL.FindChar('|');
michael@0 6684
michael@0 6685 if (firstPipe > 0) {
michael@0 6686 homeURL.Truncate(firstPipe);
michael@0 6687 }
michael@0 6688 }
michael@0 6689 #endif
michael@0 6690
michael@0 6691 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
michael@0 6692 if (!webNav) {
michael@0 6693 aError.Throw(NS_ERROR_FAILURE);
michael@0 6694 return;
michael@0 6695 }
michael@0 6696
michael@0 6697 aError = webNav->LoadURI(homeURL.get(),
michael@0 6698 nsIWebNavigation::LOAD_FLAGS_NONE,
michael@0 6699 nullptr,
michael@0 6700 nullptr,
michael@0 6701 nullptr);
michael@0 6702 }
michael@0 6703
michael@0 6704 NS_IMETHODIMP
michael@0 6705 nsGlobalWindow::Home()
michael@0 6706 {
michael@0 6707 ErrorResult rv;
michael@0 6708 Home(rv);
michael@0 6709
michael@0 6710 return rv.ErrorCode();
michael@0 6711 }
michael@0 6712
michael@0 6713 void
michael@0 6714 nsGlobalWindow::Stop(ErrorResult& aError)
michael@0 6715 {
michael@0 6716 FORWARD_TO_OUTER_OR_THROW(Stop, (aError), aError, );
michael@0 6717
michael@0 6718 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
michael@0 6719 if (webNav) {
michael@0 6720 aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
michael@0 6721 }
michael@0 6722 }
michael@0 6723
michael@0 6724 NS_IMETHODIMP
michael@0 6725 nsGlobalWindow::Stop()
michael@0 6726 {
michael@0 6727 ErrorResult rv;
michael@0 6728 Stop(rv);
michael@0 6729
michael@0 6730 return rv.ErrorCode();
michael@0 6731 }
michael@0 6732
michael@0 6733 void
michael@0 6734 nsGlobalWindow::Print(ErrorResult& aError)
michael@0 6735 {
michael@0 6736 #ifdef NS_PRINTING
michael@0 6737 FORWARD_TO_OUTER_OR_THROW(Print, (aError), aError, );
michael@0 6738
michael@0 6739 if (Preferences::GetBool("dom.disable_window_print", false)) {
michael@0 6740 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 6741 return;
michael@0 6742 }
michael@0 6743
michael@0 6744 if (!AreDialogsEnabled()) {
michael@0 6745 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 6746 return;
michael@0 6747 }
michael@0 6748
michael@0 6749 if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
michael@0 6750 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 6751 return;
michael@0 6752 }
michael@0 6753
michael@0 6754 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
michael@0 6755 if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
michael@0 6756 getter_AddRefs(webBrowserPrint)))) {
michael@0 6757 nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ?
michael@0 6758 GetCurrentInnerWindowInternal()->mDoc :
michael@0 6759 nullptr);
michael@0 6760
michael@0 6761 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
michael@0 6762 do_GetService("@mozilla.org/gfx/printsettings-service;1");
michael@0 6763
michael@0 6764 nsCOMPtr<nsIPrintSettings> printSettings;
michael@0 6765 if (printSettingsService) {
michael@0 6766 bool printSettingsAreGlobal =
michael@0 6767 Preferences::GetBool("print.use_global_printsettings", false);
michael@0 6768
michael@0 6769 if (printSettingsAreGlobal) {
michael@0 6770 printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
michael@0 6771
michael@0 6772 nsXPIDLString printerName;
michael@0 6773 printSettings->GetPrinterName(getter_Copies(printerName));
michael@0 6774 if (printerName.IsEmpty()) {
michael@0 6775 printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
michael@0 6776 printSettings->SetPrinterName(printerName);
michael@0 6777 }
michael@0 6778 printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
michael@0 6779 printSettingsService->InitPrintSettingsFromPrefs(printSettings,
michael@0 6780 true,
michael@0 6781 nsIPrintSettings::kInitSaveAll);
michael@0 6782 } else {
michael@0 6783 printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
michael@0 6784 }
michael@0 6785
michael@0 6786 EnterModalState();
michael@0 6787 webBrowserPrint->Print(printSettings, nullptr);
michael@0 6788 LeaveModalState();
michael@0 6789
michael@0 6790 bool savePrintSettings =
michael@0 6791 Preferences::GetBool("print.save_print_settings", false);
michael@0 6792 if (printSettingsAreGlobal && savePrintSettings) {
michael@0 6793 printSettingsService->
michael@0 6794 SavePrintSettingsToPrefs(printSettings,
michael@0 6795 true,
michael@0 6796 nsIPrintSettings::kInitSaveAll);
michael@0 6797 printSettingsService->
michael@0 6798 SavePrintSettingsToPrefs(printSettings,
michael@0 6799 false,
michael@0 6800 nsIPrintSettings::kInitSavePrinterName);
michael@0 6801 }
michael@0 6802 } else {
michael@0 6803 webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
michael@0 6804 webBrowserPrint->Print(printSettings, nullptr);
michael@0 6805 }
michael@0 6806 }
michael@0 6807 #endif //NS_PRINTING
michael@0 6808 }
michael@0 6809
michael@0 6810 NS_IMETHODIMP
michael@0 6811 nsGlobalWindow::Print()
michael@0 6812 {
michael@0 6813 ErrorResult rv;
michael@0 6814 Print(rv);
michael@0 6815
michael@0 6816 return rv.ErrorCode();
michael@0 6817 }
michael@0 6818
michael@0 6819 void
michael@0 6820 nsGlobalWindow::MoveTo(int32_t aXPos, int32_t aYPos, ErrorResult& aError)
michael@0 6821 {
michael@0 6822 FORWARD_TO_OUTER_OR_THROW(MoveTo, (aXPos, aYPos, aError), aError, );
michael@0 6823
michael@0 6824 /*
michael@0 6825 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 6826 * prevent window.moveTo() by exiting early
michael@0 6827 */
michael@0 6828
michael@0 6829 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 6830 return;
michael@0 6831 }
michael@0 6832
michael@0 6833 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 6834 if (!treeOwnerAsWin) {
michael@0 6835 aError.Throw(NS_ERROR_FAILURE);
michael@0 6836 return;
michael@0 6837 }
michael@0 6838
michael@0 6839 // Mild abuse of a "size" object so we don't need more helper functions.
michael@0 6840 nsIntSize cssPos(aXPos, aYPos);
michael@0 6841 CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height);
michael@0 6842
michael@0 6843 nsIntSize devPos = CSSToDevIntPixels(cssPos);
michael@0 6844
michael@0 6845 aError = treeOwnerAsWin->SetPosition(devPos.width, devPos.height);
michael@0 6846 }
michael@0 6847
michael@0 6848 NS_IMETHODIMP
michael@0 6849 nsGlobalWindow::MoveTo(int32_t aXPos, int32_t aYPos)
michael@0 6850 {
michael@0 6851 ErrorResult rv;
michael@0 6852 MoveTo(aXPos, aYPos, rv);
michael@0 6853
michael@0 6854 return rv.ErrorCode();
michael@0 6855 }
michael@0 6856
michael@0 6857 void
michael@0 6858 nsGlobalWindow::MoveBy(int32_t aXDif, int32_t aYDif, ErrorResult& aError)
michael@0 6859 {
michael@0 6860 FORWARD_TO_OUTER_OR_THROW(MoveBy, (aXDif, aYDif, aError), aError, );
michael@0 6861
michael@0 6862 /*
michael@0 6863 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 6864 * prevent window.moveBy() by exiting early
michael@0 6865 */
michael@0 6866
michael@0 6867 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 6868 return;
michael@0 6869 }
michael@0 6870
michael@0 6871 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 6872 if (!treeOwnerAsWin) {
michael@0 6873 aError.Throw(NS_ERROR_FAILURE);
michael@0 6874 return;
michael@0 6875 }
michael@0 6876
michael@0 6877 // To do this correctly we have to convert what we get from GetPosition
michael@0 6878 // into CSS pixels, add the arguments, do the security check, and
michael@0 6879 // then convert back to device pixels for the call to SetPosition.
michael@0 6880
michael@0 6881 int32_t x, y;
michael@0 6882 aError = treeOwnerAsWin->GetPosition(&x, &y);
michael@0 6883 if (aError.Failed()) {
michael@0 6884 return;
michael@0 6885 }
michael@0 6886
michael@0 6887 // mild abuse of a "size" object so we don't need more helper functions
michael@0 6888 nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
michael@0 6889
michael@0 6890 cssPos.width += aXDif;
michael@0 6891 cssPos.height += aYDif;
michael@0 6892
michael@0 6893 CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height);
michael@0 6894
michael@0 6895 nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
michael@0 6896
michael@0 6897 aError = treeOwnerAsWin->SetPosition(newDevPos.width, newDevPos.height);
michael@0 6898 }
michael@0 6899
michael@0 6900 NS_IMETHODIMP
michael@0 6901 nsGlobalWindow::MoveBy(int32_t aXDif, int32_t aYDif)
michael@0 6902 {
michael@0 6903 ErrorResult rv;
michael@0 6904 MoveBy(aXDif, aYDif, rv);
michael@0 6905
michael@0 6906 return rv.ErrorCode();
michael@0 6907 }
michael@0 6908
michael@0 6909 void
michael@0 6910 nsGlobalWindow::ResizeTo(int32_t aWidth, int32_t aHeight, ErrorResult& aError)
michael@0 6911 {
michael@0 6912 FORWARD_TO_OUTER_OR_THROW(ResizeTo, (aWidth, aHeight, aError), aError, );
michael@0 6913
michael@0 6914 /*
michael@0 6915 * If caller is a browser-element then dispatch a resize event to
michael@0 6916 * the embedder.
michael@0 6917 */
michael@0 6918 if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
michael@0 6919 nsIntSize size(aWidth, aHeight);
michael@0 6920 if (!DispatchResizeEvent(size)) {
michael@0 6921 // The embedder chose to prevent the default action for this
michael@0 6922 // event, so let's not resize this window after all...
michael@0 6923 return;
michael@0 6924 }
michael@0 6925 }
michael@0 6926
michael@0 6927 /*
michael@0 6928 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 6929 * prevent window.resizeTo() by exiting early
michael@0 6930 */
michael@0 6931
michael@0 6932 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 6933 return;
michael@0 6934 }
michael@0 6935
michael@0 6936 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 6937 if (!treeOwnerAsWin) {
michael@0 6938 aError.Throw(NS_ERROR_FAILURE);
michael@0 6939 return;
michael@0 6940 }
michael@0 6941
michael@0 6942 nsIntSize cssSize(aWidth, aHeight);
michael@0 6943 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height);
michael@0 6944
michael@0 6945 nsIntSize devSz(CSSToDevIntPixels(cssSize));
michael@0 6946
michael@0 6947 aError = treeOwnerAsWin->SetSize(devSz.width, devSz.height, true);
michael@0 6948 }
michael@0 6949
michael@0 6950 NS_IMETHODIMP
michael@0 6951 nsGlobalWindow::ResizeTo(int32_t aWidth, int32_t aHeight)
michael@0 6952 {
michael@0 6953 ErrorResult rv;
michael@0 6954 ResizeTo(aWidth, aHeight, rv);
michael@0 6955
michael@0 6956 return rv.ErrorCode();
michael@0 6957 }
michael@0 6958
michael@0 6959 void
michael@0 6960 nsGlobalWindow::ResizeBy(int32_t aWidthDif, int32_t aHeightDif,
michael@0 6961 ErrorResult& aError)
michael@0 6962 {
michael@0 6963 FORWARD_TO_OUTER_OR_THROW(ResizeBy, (aWidthDif, aHeightDif, aError), aError, );
michael@0 6964
michael@0 6965 /*
michael@0 6966 * If caller is a browser-element then dispatch a resize event to
michael@0 6967 * parent.
michael@0 6968 */
michael@0 6969 if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
michael@0 6970 CSSIntSize size;
michael@0 6971 if (NS_FAILED(GetInnerSize(size))) {
michael@0 6972 return;
michael@0 6973 }
michael@0 6974
michael@0 6975 size.width += aWidthDif;
michael@0 6976 size.height += aHeightDif;
michael@0 6977
michael@0 6978 if (!DispatchResizeEvent(nsIntSize(size.width, size.height))) {
michael@0 6979 // The embedder chose to prevent the default action for this
michael@0 6980 // event, so let's not resize this window after all...
michael@0 6981 return;
michael@0 6982 }
michael@0 6983 }
michael@0 6984
michael@0 6985 /*
michael@0 6986 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 6987 * prevent window.resizeBy() by exiting early
michael@0 6988 */
michael@0 6989
michael@0 6990 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 6991 return;
michael@0 6992 }
michael@0 6993
michael@0 6994 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 6995 if (!treeOwnerAsWin) {
michael@0 6996 aError.Throw(NS_ERROR_FAILURE);
michael@0 6997 return;
michael@0 6998 }
michael@0 6999
michael@0 7000 int32_t width, height;
michael@0 7001 aError = treeOwnerAsWin->GetSize(&width, &height);
michael@0 7002 if (aError.Failed()) {
michael@0 7003 return;
michael@0 7004 }
michael@0 7005
michael@0 7006 // To do this correctly we have to convert what we got from GetSize
michael@0 7007 // into CSS pixels, add the arguments, do the security check, and
michael@0 7008 // then convert back to device pixels for the call to SetSize.
michael@0 7009
michael@0 7010 nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
michael@0 7011
michael@0 7012 cssSize.width += aWidthDif;
michael@0 7013 cssSize.height += aHeightDif;
michael@0 7014
michael@0 7015 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height);
michael@0 7016
michael@0 7017 nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
michael@0 7018
michael@0 7019 aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
michael@0 7020 }
michael@0 7021
michael@0 7022 NS_IMETHODIMP
michael@0 7023 nsGlobalWindow::ResizeBy(int32_t aWidthDif, int32_t aHeightDif)
michael@0 7024 {
michael@0 7025 ErrorResult rv;
michael@0 7026 ResizeBy(aWidthDif, aHeightDif, rv);
michael@0 7027
michael@0 7028 return rv.ErrorCode();
michael@0 7029 }
michael@0 7030
michael@0 7031 void
michael@0 7032 nsGlobalWindow::SizeToContent(ErrorResult& aError)
michael@0 7033 {
michael@0 7034 FORWARD_TO_OUTER_OR_THROW(SizeToContent, (aError), aError, );
michael@0 7035
michael@0 7036 if (!mDocShell) {
michael@0 7037 return;
michael@0 7038 }
michael@0 7039
michael@0 7040 /*
michael@0 7041 * If caller is not chrome and the user has not explicitly exempted the site,
michael@0 7042 * prevent window.sizeToContent() by exiting early
michael@0 7043 */
michael@0 7044
michael@0 7045 if (!CanMoveResizeWindows() || IsFrame()) {
michael@0 7046 return;
michael@0 7047 }
michael@0 7048
michael@0 7049 // The content viewer does a check to make sure that it's a content
michael@0 7050 // viewer for a toplevel docshell.
michael@0 7051 nsCOMPtr<nsIContentViewer> cv;
michael@0 7052 mDocShell->GetContentViewer(getter_AddRefs(cv));
michael@0 7053 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
michael@0 7054 if (!markupViewer) {
michael@0 7055 aError.Throw(NS_ERROR_FAILURE);
michael@0 7056 return;
michael@0 7057 }
michael@0 7058
michael@0 7059 int32_t width, height;
michael@0 7060 aError = markupViewer->GetContentSize(&width, &height);
michael@0 7061 if (aError.Failed()) {
michael@0 7062 return;
michael@0 7063 }
michael@0 7064
michael@0 7065 // Make sure the new size is following the CheckSecurityWidthAndHeight
michael@0 7066 // rules.
michael@0 7067 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
michael@0 7068 if (!treeOwner) {
michael@0 7069 aError.Throw(NS_ERROR_FAILURE);
michael@0 7070 return;
michael@0 7071 }
michael@0 7072
michael@0 7073 nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
michael@0 7074 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height);
michael@0 7075
michael@0 7076 nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
michael@0 7077
michael@0 7078 aError = treeOwner->SizeShellTo(mDocShell, newDevSize.width,
michael@0 7079 newDevSize.height);
michael@0 7080 }
michael@0 7081
michael@0 7082 NS_IMETHODIMP
michael@0 7083 nsGlobalWindow::SizeToContent()
michael@0 7084 {
michael@0 7085 ErrorResult rv;
michael@0 7086 SizeToContent(rv);
michael@0 7087
michael@0 7088 return rv.ErrorCode();
michael@0 7089 }
michael@0 7090
michael@0 7091 NS_IMETHODIMP
michael@0 7092 nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
michael@0 7093 {
michael@0 7094 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
michael@0 7095 return CallQueryInterface(root, aWindowRoot);
michael@0 7096 }
michael@0 7097
michael@0 7098 already_AddRefed<nsPIWindowRoot>
michael@0 7099 nsGlobalWindow::GetTopWindowRoot()
michael@0 7100 {
michael@0 7101 nsPIDOMWindow* piWin = GetPrivateRoot();
michael@0 7102 if (!piWin) {
michael@0 7103 return nullptr;
michael@0 7104 }
michael@0 7105
michael@0 7106 nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
michael@0 7107 return window.forget();
michael@0 7108 }
michael@0 7109
michael@0 7110 NS_IMETHODIMP
michael@0 7111 nsGlobalWindow::Scroll(int32_t aXScroll, int32_t aYScroll)
michael@0 7112 {
michael@0 7113 ScrollTo(CSSIntPoint(aXScroll, aYScroll));
michael@0 7114 return NS_OK;
michael@0 7115 }
michael@0 7116
michael@0 7117 NS_IMETHODIMP
michael@0 7118 nsGlobalWindow::ScrollTo(int32_t aXScroll, int32_t aYScroll)
michael@0 7119 {
michael@0 7120 ScrollTo(CSSIntPoint(aXScroll, aYScroll));
michael@0 7121 return NS_OK;
michael@0 7122 }
michael@0 7123
michael@0 7124 void
michael@0 7125 nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll)
michael@0 7126 {
michael@0 7127 FlushPendingNotifications(Flush_Layout);
michael@0 7128 nsIScrollableFrame *sf = GetScrollFrame();
michael@0 7129
michael@0 7130 if (sf) {
michael@0 7131 // Here we calculate what the max pixel value is that we can
michael@0 7132 // scroll to, we do this by dividing maxint with the pixel to
michael@0 7133 // twips conversion factor, and subtracting 4, the 4 comes from
michael@0 7134 // experimenting with this value, anything less makes the view
michael@0 7135 // code not scroll correctly, I have no idea why. -- jst
michael@0 7136 const int32_t maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
michael@0 7137
michael@0 7138 CSSIntPoint scroll(aScroll);
michael@0 7139 if (scroll.x > maxpx) {
michael@0 7140 scroll.x = maxpx;
michael@0 7141 }
michael@0 7142
michael@0 7143 if (scroll.y > maxpx) {
michael@0 7144 scroll.y = maxpx;
michael@0 7145 }
michael@0 7146 sf->ScrollToCSSPixels(scroll);
michael@0 7147 }
michael@0 7148 }
michael@0 7149
michael@0 7150 NS_IMETHODIMP
michael@0 7151 nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif)
michael@0 7152 {
michael@0 7153 FlushPendingNotifications(Flush_Layout);
michael@0 7154 nsIScrollableFrame *sf = GetScrollFrame();
michael@0 7155
michael@0 7156 if (sf) {
michael@0 7157 CSSIntPoint scrollPos =
michael@0 7158 sf->GetScrollPositionCSSPixels() + CSSIntPoint(aXScrollDif, aYScrollDif);
michael@0 7159 // It seems like it would make more sense for ScrollBy to use
michael@0 7160 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
michael@0 7161 // Perhaps Web content does too.
michael@0 7162 ScrollTo(scrollPos);
michael@0 7163 }
michael@0 7164
michael@0 7165 return NS_OK;
michael@0 7166 }
michael@0 7167
michael@0 7168 NS_IMETHODIMP
michael@0 7169 nsGlobalWindow::ScrollByLines(int32_t numLines)
michael@0 7170 {
michael@0 7171 FlushPendingNotifications(Flush_Layout);
michael@0 7172 nsIScrollableFrame *sf = GetScrollFrame();
michael@0 7173 if (sf) {
michael@0 7174 // It seems like it would make more sense for ScrollByLines to use
michael@0 7175 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
michael@0 7176 // Perhaps Web content does too.
michael@0 7177 sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
michael@0 7178 nsIScrollableFrame::INSTANT);
michael@0 7179 }
michael@0 7180
michael@0 7181 return NS_OK;
michael@0 7182 }
michael@0 7183
michael@0 7184 NS_IMETHODIMP
michael@0 7185 nsGlobalWindow::ScrollByPages(int32_t numPages)
michael@0 7186 {
michael@0 7187 FlushPendingNotifications(Flush_Layout);
michael@0 7188 nsIScrollableFrame *sf = GetScrollFrame();
michael@0 7189 if (sf) {
michael@0 7190 // It seems like it would make more sense for ScrollByPages to use
michael@0 7191 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
michael@0 7192 // Perhaps Web content does too.
michael@0 7193 sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
michael@0 7194 nsIScrollableFrame::INSTANT);
michael@0 7195 }
michael@0 7196
michael@0 7197 return NS_OK;
michael@0 7198 }
michael@0 7199
michael@0 7200 void
michael@0 7201 nsGlobalWindow::ClearTimeout(int32_t aHandle, ErrorResult& aError)
michael@0 7202 {
michael@0 7203 if (aHandle > 0) {
michael@0 7204 ClearTimeoutOrInterval(aHandle, aError);
michael@0 7205 }
michael@0 7206 }
michael@0 7207
michael@0 7208 NS_IMETHODIMP
michael@0 7209 nsGlobalWindow::ClearTimeout(int32_t aHandle)
michael@0 7210 {
michael@0 7211 ErrorResult rv;
michael@0 7212 ClearTimeout(aHandle, rv);
michael@0 7213
michael@0 7214 return rv.ErrorCode();
michael@0 7215 }
michael@0 7216
michael@0 7217 void
michael@0 7218 nsGlobalWindow::ClearInterval(int32_t aHandle, ErrorResult& aError)
michael@0 7219 {
michael@0 7220 if (aHandle > 0) {
michael@0 7221 ClearTimeoutOrInterval(aHandle, aError);
michael@0 7222 }
michael@0 7223 }
michael@0 7224
michael@0 7225 NS_IMETHODIMP
michael@0 7226 nsGlobalWindow::ClearInterval(int32_t aHandle)
michael@0 7227 {
michael@0 7228 ErrorResult rv;
michael@0 7229 ClearInterval(aHandle, rv);
michael@0 7230
michael@0 7231 return rv.ErrorCode();
michael@0 7232 }
michael@0 7233
michael@0 7234 NS_IMETHODIMP
michael@0 7235 nsGlobalWindow::SetTimeout(int32_t *_retval)
michael@0 7236 {
michael@0 7237 return SetTimeoutOrInterval(false, _retval);
michael@0 7238 }
michael@0 7239
michael@0 7240 NS_IMETHODIMP
michael@0 7241 nsGlobalWindow::SetInterval(int32_t *_retval)
michael@0 7242 {
michael@0 7243 return SetTimeoutOrInterval(true, _retval);
michael@0 7244 }
michael@0 7245
michael@0 7246 NS_IMETHODIMP
michael@0 7247 nsGlobalWindow::SetResizable(bool aResizable)
michael@0 7248 {
michael@0 7249 // nop
michael@0 7250
michael@0 7251 return NS_OK;
michael@0 7252 }
michael@0 7253
michael@0 7254 NS_IMETHODIMP
michael@0 7255 nsGlobalWindow::CaptureEvents()
michael@0 7256 {
michael@0 7257 if (mDoc) {
michael@0 7258 mDoc->WarnOnceAbout(nsIDocument::eUseOfCaptureEvents);
michael@0 7259 }
michael@0 7260
michael@0 7261 return NS_OK;
michael@0 7262 }
michael@0 7263
michael@0 7264 NS_IMETHODIMP
michael@0 7265 nsGlobalWindow::ReleaseEvents()
michael@0 7266 {
michael@0 7267 if (mDoc) {
michael@0 7268 mDoc->WarnOnceAbout(nsIDocument::eUseOfReleaseEvents);
michael@0 7269 }
michael@0 7270
michael@0 7271 return NS_OK;
michael@0 7272 }
michael@0 7273
michael@0 7274 static
michael@0 7275 bool IsPopupBlocked(nsIDocument* aDoc)
michael@0 7276 {
michael@0 7277 nsCOMPtr<nsIPopupWindowManager> pm =
michael@0 7278 do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
michael@0 7279
michael@0 7280 if (!pm) {
michael@0 7281 return false;
michael@0 7282 }
michael@0 7283
michael@0 7284 if (!aDoc) {
michael@0 7285 return true;
michael@0 7286 }
michael@0 7287
michael@0 7288 uint32_t permission = nsIPopupWindowManager::ALLOW_POPUP;
michael@0 7289 pm->TestPermission(aDoc->NodePrincipal(), &permission);
michael@0 7290 return permission == nsIPopupWindowManager::DENY_POPUP;
michael@0 7291 }
michael@0 7292
michael@0 7293 /* static */
michael@0 7294 void
michael@0 7295 nsGlobalWindow::FirePopupBlockedEvent(nsIDocument* aDoc,
michael@0 7296 nsIDOMWindow *aRequestingWindow, nsIURI *aPopupURI,
michael@0 7297 const nsAString &aPopupWindowName,
michael@0 7298 const nsAString &aPopupWindowFeatures)
michael@0 7299 {
michael@0 7300 if (aDoc) {
michael@0 7301 // Fire a "DOMPopupBlocked" event so that the UI can hear about
michael@0 7302 // blocked popups.
michael@0 7303 nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDoc);
michael@0 7304 nsCOMPtr<nsIDOMEvent> event;
michael@0 7305 doc->CreateEvent(NS_LITERAL_STRING("PopupBlockedEvents"), getter_AddRefs(event));
michael@0 7306 if (event) {
michael@0 7307 nsCOMPtr<nsIDOMPopupBlockedEvent> pbev(do_QueryInterface(event));
michael@0 7308 pbev->InitPopupBlockedEvent(NS_LITERAL_STRING("DOMPopupBlocked"),
michael@0 7309 true, true, aRequestingWindow,
michael@0 7310 aPopupURI, aPopupWindowName,
michael@0 7311 aPopupWindowFeatures);
michael@0 7312 event->SetTrusted(true);
michael@0 7313
michael@0 7314 bool defaultActionEnabled;
michael@0 7315 aDoc->DispatchEvent(event, &defaultActionEnabled);
michael@0 7316 }
michael@0 7317 }
michael@0 7318 }
michael@0 7319
michael@0 7320 static void FirePopupWindowEvent(nsIDocument* aDoc)
michael@0 7321 {
michael@0 7322 // Fire a "PopupWindow" event
michael@0 7323 nsContentUtils::DispatchTrustedEvent(aDoc, aDoc,
michael@0 7324 NS_LITERAL_STRING("PopupWindow"),
michael@0 7325 true, true);
michael@0 7326 }
michael@0 7327
michael@0 7328 // static
michael@0 7329 bool
michael@0 7330 nsGlobalWindow::CanSetProperty(const char *aPrefName)
michael@0 7331 {
michael@0 7332 // Chrome can set any property.
michael@0 7333 if (nsContentUtils::IsCallerChrome()) {
michael@0 7334 return true;
michael@0 7335 }
michael@0 7336
michael@0 7337 // If the pref is set to true, we can not set the property
michael@0 7338 // and vice versa.
michael@0 7339 return !Preferences::GetBool(aPrefName, true);
michael@0 7340 }
michael@0 7341
michael@0 7342 bool
michael@0 7343 nsGlobalWindow::PopupWhitelisted()
michael@0 7344 {
michael@0 7345 if (!IsPopupBlocked(mDoc))
michael@0 7346 return true;
michael@0 7347
michael@0 7348 nsCOMPtr<nsIDOMWindow> parent;
michael@0 7349
michael@0 7350 if (NS_FAILED(GetParent(getter_AddRefs(parent))) ||
michael@0 7351 parent == static_cast<nsIDOMWindow*>(this))
michael@0 7352 {
michael@0 7353 return false;
michael@0 7354 }
michael@0 7355
michael@0 7356 return static_cast<nsGlobalWindow*>
michael@0 7357 (static_cast<nsIDOMWindow*>
michael@0 7358 (parent.get()))->PopupWhitelisted();
michael@0 7359 }
michael@0 7360
michael@0 7361 /*
michael@0 7362 * Examine the current document state to see if we're in a way that is
michael@0 7363 * typically abused by web designers. The window.open code uses this
michael@0 7364 * routine to determine whether to allow the new window.
michael@0 7365 * Returns a value from the PopupControlState enum.
michael@0 7366 */
michael@0 7367 PopupControlState
michael@0 7368 nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
michael@0 7369 {
michael@0 7370 MOZ_ASSERT(IsOuterWindow());
michael@0 7371
michael@0 7372 NS_ASSERTION(mDocShell, "Must have docshell");
michael@0 7373
michael@0 7374 if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
michael@0 7375 return openAllowed;
michael@0 7376 }
michael@0 7377
michael@0 7378 PopupControlState abuse = aControl;
michael@0 7379 switch (abuse) {
michael@0 7380 case openControlled:
michael@0 7381 case openAbused:
michael@0 7382 case openOverridden:
michael@0 7383 if (PopupWhitelisted())
michael@0 7384 abuse = PopupControlState(abuse - 1);
michael@0 7385 case openAllowed: break;
michael@0 7386 default:
michael@0 7387 NS_WARNING("Strange PopupControlState!");
michael@0 7388 }
michael@0 7389
michael@0 7390 // limit the number of simultaneously open popups
michael@0 7391 if (abuse == openAbused || abuse == openControlled) {
michael@0 7392 int32_t popupMax = Preferences::GetInt("dom.popup_maximum", -1);
michael@0 7393 if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
michael@0 7394 abuse = openOverridden;
michael@0 7395 }
michael@0 7396
michael@0 7397 return abuse;
michael@0 7398 }
michael@0 7399
michael@0 7400 /* If a window open is blocked, fire the appropriate DOM events.
michael@0 7401 aBlocked signifies we just blocked a popup.
michael@0 7402 aWindow signifies we just opened what is probably a popup.
michael@0 7403 */
michael@0 7404 void
michael@0 7405 nsGlobalWindow::FireAbuseEvents(bool aBlocked, bool aWindow,
michael@0 7406 const nsAString &aPopupURL,
michael@0 7407 const nsAString &aPopupWindowName,
michael@0 7408 const nsAString &aPopupWindowFeatures)
michael@0 7409 {
michael@0 7410 // fetch the URI of the window requesting the opened window
michael@0 7411
michael@0 7412 nsCOMPtr<nsIDOMWindow> topWindow;
michael@0 7413 GetTop(getter_AddRefs(topWindow));
michael@0 7414 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(topWindow);
michael@0 7415 if (!window) {
michael@0 7416 return;
michael@0 7417 }
michael@0 7418
michael@0 7419 nsCOMPtr<nsIDocument> topDoc = window->GetDoc();
michael@0 7420 nsCOMPtr<nsIURI> popupURI;
michael@0 7421
michael@0 7422 // build the URI of the would-have-been popup window
michael@0 7423 // (see nsWindowWatcher::URIfromURL)
michael@0 7424
michael@0 7425 // first, fetch the opener's base URI
michael@0 7426
michael@0 7427 nsIURI *baseURL = nullptr;
michael@0 7428
michael@0 7429 JSContext *cx = nsContentUtils::GetCurrentJSContext();
michael@0 7430 nsCOMPtr<nsPIDOMWindow> contextWindow;
michael@0 7431
michael@0 7432 if (cx) {
michael@0 7433 nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
michael@0 7434 if (currentCX) {
michael@0 7435 contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
michael@0 7436 }
michael@0 7437 }
michael@0 7438 if (!contextWindow) {
michael@0 7439 contextWindow = this;
michael@0 7440 }
michael@0 7441
michael@0 7442 nsCOMPtr<nsIDocument> doc = contextWindow->GetDoc();
michael@0 7443 if (doc)
michael@0 7444 baseURL = doc->GetDocBaseURI();
michael@0 7445
michael@0 7446 // use the base URI to build what would have been the popup's URI
michael@0 7447 nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
michael@0 7448 if (ios)
michael@0 7449 ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
michael@0 7450 getter_AddRefs(popupURI));
michael@0 7451
michael@0 7452 // fire an event chock full of informative URIs
michael@0 7453 if (aBlocked) {
michael@0 7454 FirePopupBlockedEvent(topDoc, this, popupURI, aPopupWindowName,
michael@0 7455 aPopupWindowFeatures);
michael@0 7456 }
michael@0 7457 if (aWindow)
michael@0 7458 FirePopupWindowEvent(topDoc);
michael@0 7459 }
michael@0 7460
michael@0 7461 already_AddRefed<nsIDOMWindow>
michael@0 7462 nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
michael@0 7463 const nsAString& aOptions, ErrorResult& aError)
michael@0 7464 {
michael@0 7465 nsCOMPtr<nsIDOMWindow> window;
michael@0 7466 aError = OpenJS(aUrl, aName, aOptions, getter_AddRefs(window));
michael@0 7467 return window.forget();
michael@0 7468 }
michael@0 7469
michael@0 7470 NS_IMETHODIMP
michael@0 7471 nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
michael@0 7472 const nsAString& aOptions, nsIDOMWindow **_retval)
michael@0 7473 {
michael@0 7474 return OpenInternal(aUrl, aName, aOptions,
michael@0 7475 false, // aDialog
michael@0 7476 false, // aContentModal
michael@0 7477 true, // aCalledNoScript
michael@0 7478 false, // aDoJSFixups
michael@0 7479 true, // aNavigate
michael@0 7480 nullptr, nullptr, // No args
michael@0 7481 GetPrincipal(), // aCalleePrincipal
michael@0 7482 nullptr, // aJSCallerContext
michael@0 7483 _retval);
michael@0 7484 }
michael@0 7485
michael@0 7486 NS_IMETHODIMP
michael@0 7487 nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
michael@0 7488 const nsAString& aOptions, nsIDOMWindow **_retval)
michael@0 7489 {
michael@0 7490 return OpenInternal(aUrl, aName, aOptions,
michael@0 7491 false, // aDialog
michael@0 7492 false, // aContentModal
michael@0 7493 false, // aCalledNoScript
michael@0 7494 true, // aDoJSFixups
michael@0 7495 true, // aNavigate
michael@0 7496 nullptr, nullptr, // No args
michael@0 7497 GetPrincipal(), // aCalleePrincipal
michael@0 7498 nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
michael@0 7499 _retval);
michael@0 7500 }
michael@0 7501
michael@0 7502 // like Open, but attaches to the new window any extra parameters past
michael@0 7503 // [features] as a JS property named "arguments"
michael@0 7504 NS_IMETHODIMP
michael@0 7505 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
michael@0 7506 const nsAString& aOptions,
michael@0 7507 nsISupports* aExtraArgument, nsIDOMWindow** _retval)
michael@0 7508 {
michael@0 7509 return OpenInternal(aUrl, aName, aOptions,
michael@0 7510 true, // aDialog
michael@0 7511 false, // aContentModal
michael@0 7512 true, // aCalledNoScript
michael@0 7513 false, // aDoJSFixups
michael@0 7514 true, // aNavigate
michael@0 7515 nullptr, aExtraArgument, // Arguments
michael@0 7516 GetPrincipal(), // aCalleePrincipal
michael@0 7517 nullptr, // aJSCallerContext
michael@0 7518 _retval);
michael@0 7519 }
michael@0 7520
michael@0 7521 // Like Open, but passes aNavigate=false.
michael@0 7522 /* virtual */ nsresult
michael@0 7523 nsGlobalWindow::OpenNoNavigate(const nsAString& aUrl,
michael@0 7524 const nsAString& aName,
michael@0 7525 const nsAString& aOptions,
michael@0 7526 nsIDOMWindow **_retval)
michael@0 7527 {
michael@0 7528 return OpenInternal(aUrl, aName, aOptions,
michael@0 7529 false, // aDialog
michael@0 7530 false, // aContentModal
michael@0 7531 true, // aCalledNoScript
michael@0 7532 false, // aDoJSFixups
michael@0 7533 false, // aNavigate
michael@0 7534 nullptr, nullptr, // No args
michael@0 7535 GetPrincipal(), // aCalleePrincipal
michael@0 7536 nullptr, // aJSCallerContext
michael@0 7537 _retval);
michael@0 7538
michael@0 7539 }
michael@0 7540
michael@0 7541 already_AddRefed<nsIDOMWindow>
michael@0 7542 nsGlobalWindow::OpenDialog(JSContext* aCx, const nsAString& aUrl,
michael@0 7543 const nsAString& aName, const nsAString& aOptions,
michael@0 7544 const Sequence<JS::Value>& aExtraArgument,
michael@0 7545 ErrorResult& aError)
michael@0 7546 {
michael@0 7547 nsCOMPtr<nsIJSArgArray> argvArray;
michael@0 7548 aError = NS_CreateJSArgv(aCx, aExtraArgument.Length(),
michael@0 7549 const_cast<JS::Value*>(aExtraArgument.Elements()),
michael@0 7550 getter_AddRefs(argvArray));
michael@0 7551 if (aError.Failed()) {
michael@0 7552 return nullptr;
michael@0 7553 }
michael@0 7554
michael@0 7555 nsCOMPtr<nsIDOMWindow> dialog;
michael@0 7556 aError = OpenInternal(aUrl, aName, aOptions,
michael@0 7557 true, // aDialog
michael@0 7558 false, // aContentModal
michael@0 7559 false, // aCalledNoScript
michael@0 7560 false, // aDoJSFixups
michael@0 7561 true, // aNavigate
michael@0 7562 argvArray, nullptr, // Arguments
michael@0 7563 GetPrincipal(), // aCalleePrincipal
michael@0 7564 aCx, // aJSCallerContext
michael@0 7565 getter_AddRefs(dialog));
michael@0 7566 return dialog.forget();
michael@0 7567 }
michael@0 7568
michael@0 7569 NS_IMETHODIMP
michael@0 7570 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
michael@0 7571 const nsAString& aOptions, nsIDOMWindow** _retval)
michael@0 7572 {
michael@0 7573 if (!nsContentUtils::IsCallerChrome()) {
michael@0 7574 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 7575 }
michael@0 7576
michael@0 7577 nsAXPCNativeCallContext *ncc = nullptr;
michael@0 7578 nsresult rv = nsContentUtils::XPConnect()->
michael@0 7579 GetCurrentNativeCallContext(&ncc);
michael@0 7580 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7581
michael@0 7582 if (!ncc)
michael@0 7583 return NS_ERROR_NOT_AVAILABLE;
michael@0 7584
michael@0 7585 JSContext *cx = nullptr;
michael@0 7586
michael@0 7587 rv = ncc->GetJSContext(&cx);
michael@0 7588 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7589
michael@0 7590 uint32_t argc;
michael@0 7591 JS::Value *argv = nullptr;
michael@0 7592
michael@0 7593 // XXX - need to get this as nsISupports?
michael@0 7594 ncc->GetArgc(&argc);
michael@0 7595 ncc->GetArgvPtr(&argv);
michael@0 7596
michael@0 7597 // Strip the url, name and options from the args seen by scripts.
michael@0 7598 uint32_t argOffset = argc < 3 ? argc : 3;
michael@0 7599 nsCOMPtr<nsIJSArgArray> argvArray;
michael@0 7600 rv = NS_CreateJSArgv(cx, argc - argOffset, argv + argOffset,
michael@0 7601 getter_AddRefs(argvArray));
michael@0 7602 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7603
michael@0 7604 return OpenInternal(aUrl, aName, aOptions,
michael@0 7605 true, // aDialog
michael@0 7606 false, // aContentModal
michael@0 7607 false, // aCalledNoScript
michael@0 7608 false, // aDoJSFixups
michael@0 7609 true, // aNavigate
michael@0 7610 argvArray, nullptr, // Arguments
michael@0 7611 GetPrincipal(), // aCalleePrincipal
michael@0 7612 cx, // aJSCallerContext
michael@0 7613 _retval);
michael@0 7614 }
michael@0 7615
michael@0 7616 already_AddRefed<nsIDOMWindow>
michael@0 7617 nsGlobalWindow::GetFrames(ErrorResult& aError)
michael@0 7618 {
michael@0 7619 FORWARD_TO_OUTER_OR_THROW(GetFrames, (aError), aError, nullptr);
michael@0 7620
michael@0 7621 nsRefPtr<nsGlobalWindow> frames(this);
michael@0 7622 FlushPendingNotifications(Flush_ContentAndNotify);
michael@0 7623 return frames.forget();
michael@0 7624 }
michael@0 7625
michael@0 7626 NS_IMETHODIMP
michael@0 7627 nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
michael@0 7628 {
michael@0 7629 ErrorResult rv;
michael@0 7630 nsCOMPtr<nsIDOMWindow> frames = GetFrames(rv);
michael@0 7631 frames.forget(aFrames);
michael@0 7632
michael@0 7633 return rv.ErrorCode();
michael@0 7634 }
michael@0 7635
michael@0 7636 JSObject* nsGlobalWindow::CallerGlobal()
michael@0 7637 {
michael@0 7638 JSContext *cx = nsContentUtils::GetCurrentJSContext();
michael@0 7639 if (!cx) {
michael@0 7640 NS_ERROR("Please don't call this method from C++!");
michael@0 7641
michael@0 7642 return nullptr;
michael@0 7643 }
michael@0 7644
michael@0 7645 // If somebody does sameOriginIframeWindow.postMessage(...), they probably
michael@0 7646 // expect the .source attribute of the resulting message event to be |window|
michael@0 7647 // rather than |sameOriginIframeWindow|, even though the transparent wrapper
michael@0 7648 // semantics of same-origin access will cause us to be in the iframe's
michael@0 7649 // compartment at the time of the call. This means that we want the incumbent
michael@0 7650 // global here, rather than the global of the current compartment.
michael@0 7651 //
michael@0 7652 // There are various edge cases in which the incumbent global and the current
michael@0 7653 // global would not be same-origin. They include:
michael@0 7654 // * A privileged caller (System Principal or Expanded Principal) manipulating
michael@0 7655 // less-privileged content via Xray Waivers.
michael@0 7656 // * An unprivileged caller invoking a cross-origin function that was exposed
michael@0 7657 // to it by privileged code (i.e. Sandbox.importFunction).
michael@0 7658 //
michael@0 7659 // In these cases, we probably don't want the privileged global appearing in the
michael@0 7660 // .source attribute. So we fall back to the compartment global there.
michael@0 7661 JS::Rooted<JSObject*> incumbentGlobal(cx, &IncumbentJSGlobal());
michael@0 7662 JS::Rooted<JSObject*> compartmentGlobal(cx, JS::CurrentGlobalOrNull(cx));
michael@0 7663 nsIPrincipal* incumbentPrin = nsContentUtils::GetObjectPrincipal(incumbentGlobal);
michael@0 7664 nsIPrincipal* compartmentPrin = nsContentUtils::GetObjectPrincipal(compartmentGlobal);
michael@0 7665 return incumbentPrin->EqualsConsideringDomain(compartmentPrin) ? incumbentGlobal
michael@0 7666 : compartmentGlobal;
michael@0 7667 }
michael@0 7668
michael@0 7669
michael@0 7670 nsGlobalWindow*
michael@0 7671 nsGlobalWindow::CallerInnerWindow()
michael@0 7672 {
michael@0 7673 JSContext *cx = nsContentUtils::GetCurrentJSContext();
michael@0 7674 NS_ENSURE_TRUE(cx, nullptr);
michael@0 7675 JS::Rooted<JSObject*> scope(cx, CallerGlobal());
michael@0 7676
michael@0 7677 // When Jetpack runs content scripts inside a sandbox, it uses
michael@0 7678 // sandboxPrototype to make them appear as though they're running in the
michael@0 7679 // scope of the page. So when a content script invokes postMessage, it expects
michael@0 7680 // the |source| of the received message to be the window set as the
michael@0 7681 // sandboxPrototype. This used to work incidentally for unrelated reasons, but
michael@0 7682 // now we need to do some special handling to support it.
michael@0 7683 {
michael@0 7684 JSAutoCompartment ac(cx, scope);
michael@0 7685 JS::Rooted<JSObject*> scopeProto(cx);
michael@0 7686 bool ok = JS_GetPrototype(cx, scope, &scopeProto);
michael@0 7687 NS_ENSURE_TRUE(ok, nullptr);
michael@0 7688 if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
michael@0 7689 (scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtOuter = */ false)))
michael@0 7690 {
michael@0 7691 scope = scopeProto;
michael@0 7692 }
michael@0 7693 }
michael@0 7694 JSAutoCompartment ac(cx, scope);
michael@0 7695
michael@0 7696 // We don't use xpc::WindowOrNull here because we want to be able to tell
michael@0 7697 // apart the cases of "scope is not an nsISupports at all" and "scope is an
michael@0 7698 // nsISupports that's not a window". It's not clear whether that's desirable,
michael@0 7699 // see bug 984467.
michael@0 7700 nsISupports* native =
michael@0 7701 nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, scope);
michael@0 7702 if (!native)
michael@0 7703 return nullptr;
michael@0 7704
michael@0 7705 // The calling window must be holding a reference, so we can just return a
michael@0 7706 // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
michael@0 7707 // destructor's release.
michael@0 7708 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(native);
michael@0 7709 if (!win)
michael@0 7710 return GetCurrentInnerWindowInternal();
michael@0 7711 return static_cast<nsGlobalWindow*>(win.get());
michael@0 7712 }
michael@0 7713
michael@0 7714 nsresult
michael@0 7715 nsGlobalWindow::GetFirstPartyIsolationURI(nsIURI** aFirstPartyIsolationURI)
michael@0 7716 {
michael@0 7717 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
michael@0 7718 do_GetService(THIRDPARTYUTIL_CONTRACTID);
michael@0 7719 if (!thirdPartyUtil)
michael@0 7720 return NS_ERROR_FAILURE;
michael@0 7721
michael@0 7722 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDoc);
michael@0 7723 return thirdPartyUtil->GetFirstPartyIsolationURI(NULL, doc, aFirstPartyIsolationURI);
michael@0 7724 }
michael@0 7725
michael@0 7726
michael@0 7727 /**
michael@0 7728 * Class used to represent events generated by calls to Window.postMessage,
michael@0 7729 * which asynchronously creates and dispatches events.
michael@0 7730 */
michael@0 7731 class PostMessageEvent : public nsRunnable
michael@0 7732 {
michael@0 7733 public:
michael@0 7734 NS_DECL_NSIRUNNABLE
michael@0 7735
michael@0 7736 PostMessageEvent(nsGlobalWindow* aSource,
michael@0 7737 const nsAString& aCallerOrigin,
michael@0 7738 nsGlobalWindow* aTargetWindow,
michael@0 7739 nsIPrincipal* aProvidedPrincipal,
michael@0 7740 bool aTrustedCaller)
michael@0 7741 : mSource(aSource),
michael@0 7742 mCallerOrigin(aCallerOrigin),
michael@0 7743 mTargetWindow(aTargetWindow),
michael@0 7744 mProvidedPrincipal(aProvidedPrincipal),
michael@0 7745 mTrustedCaller(aTrustedCaller)
michael@0 7746 {
michael@0 7747 MOZ_COUNT_CTOR(PostMessageEvent);
michael@0 7748 }
michael@0 7749
michael@0 7750 ~PostMessageEvent()
michael@0 7751 {
michael@0 7752 MOZ_COUNT_DTOR(PostMessageEvent);
michael@0 7753 }
michael@0 7754
michael@0 7755 JSAutoStructuredCloneBuffer& Buffer()
michael@0 7756 {
michael@0 7757 return mBuffer;
michael@0 7758 }
michael@0 7759
michael@0 7760 bool StoreISupports(nsISupports* aSupports)
michael@0 7761 {
michael@0 7762 mSupportsArray.AppendElement(aSupports);
michael@0 7763 return true;
michael@0 7764 }
michael@0 7765
michael@0 7766 private:
michael@0 7767 JSAutoStructuredCloneBuffer mBuffer;
michael@0 7768 nsRefPtr<nsGlobalWindow> mSource;
michael@0 7769 nsString mCallerOrigin;
michael@0 7770 nsRefPtr<nsGlobalWindow> mTargetWindow;
michael@0 7771 nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
michael@0 7772 bool mTrustedCaller;
michael@0 7773 nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
michael@0 7774 };
michael@0 7775
michael@0 7776 namespace {
michael@0 7777
michael@0 7778 struct StructuredCloneInfo {
michael@0 7779 PostMessageEvent* event;
michael@0 7780 bool subsumes;
michael@0 7781 nsPIDOMWindow* window;
michael@0 7782 nsRefPtrHashtable<nsRefPtrHashKey<MessagePortBase>, MessagePortBase> ports;
michael@0 7783 };
michael@0 7784
michael@0 7785 static JSObject*
michael@0 7786 PostMessageReadStructuredClone(JSContext* cx,
michael@0 7787 JSStructuredCloneReader* reader,
michael@0 7788 uint32_t tag,
michael@0 7789 uint32_t data,
michael@0 7790 void* closure)
michael@0 7791 {
michael@0 7792 if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
michael@0 7793 NS_ASSERTION(!data, "Data should be empty");
michael@0 7794
michael@0 7795 nsISupports* supports;
michael@0 7796 if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
michael@0 7797 JS::Rooted<JS::Value> val(cx);
michael@0 7798 if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
michael@0 7799 return val.toObjectOrNull();
michael@0 7800 }
michael@0 7801 }
michael@0 7802 }
michael@0 7803
michael@0 7804 const JSStructuredCloneCallbacks* runtimeCallbacks =
michael@0 7805 js::GetContextStructuredCloneCallbacks(cx);
michael@0 7806
michael@0 7807 if (runtimeCallbacks) {
michael@0 7808 return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
michael@0 7809 }
michael@0 7810
michael@0 7811 return nullptr;
michael@0 7812 }
michael@0 7813
michael@0 7814 static bool
michael@0 7815 PostMessageWriteStructuredClone(JSContext* cx,
michael@0 7816 JSStructuredCloneWriter* writer,
michael@0 7817 JS::Handle<JSObject*> obj,
michael@0 7818 void *closure)
michael@0 7819 {
michael@0 7820 StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
michael@0 7821 NS_ASSERTION(scInfo, "Must have scInfo!");
michael@0 7822
michael@0 7823 nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
michael@0 7824 nsContentUtils::XPConnect()->
michael@0 7825 GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
michael@0 7826 if (wrappedNative) {
michael@0 7827 uint32_t scTag = 0;
michael@0 7828 nsISupports* supports = wrappedNative->Native();
michael@0 7829
michael@0 7830 nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
michael@0 7831 if (blob && scInfo->subsumes)
michael@0 7832 scTag = SCTAG_DOM_BLOB;
michael@0 7833
michael@0 7834 nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
michael@0 7835 if (list && scInfo->subsumes)
michael@0 7836 scTag = SCTAG_DOM_FILELIST;
michael@0 7837
michael@0 7838 if (scTag)
michael@0 7839 return JS_WriteUint32Pair(writer, scTag, 0) &&
michael@0 7840 JS_WriteBytes(writer, &supports, sizeof(supports)) &&
michael@0 7841 scInfo->event->StoreISupports(supports);
michael@0 7842 }
michael@0 7843
michael@0 7844 const JSStructuredCloneCallbacks* runtimeCallbacks =
michael@0 7845 js::GetContextStructuredCloneCallbacks(cx);
michael@0 7846
michael@0 7847 if (runtimeCallbacks) {
michael@0 7848 return runtimeCallbacks->write(cx, writer, obj, nullptr);
michael@0 7849 }
michael@0 7850
michael@0 7851 return false;
michael@0 7852 }
michael@0 7853
michael@0 7854 static bool
michael@0 7855 PostMessageReadTransferStructuredClone(JSContext* aCx,
michael@0 7856 JSStructuredCloneReader* reader,
michael@0 7857 uint32_t tag, void* aData,
michael@0 7858 uint64_t aExtraData,
michael@0 7859 void* aClosure,
michael@0 7860 JS::MutableHandle<JSObject*> returnObject)
michael@0 7861 {
michael@0 7862 StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
michael@0 7863 NS_ASSERTION(scInfo, "Must have scInfo!");
michael@0 7864
michael@0 7865 if (MessageChannel::PrefEnabled() && tag == SCTAG_DOM_MAP_MESSAGEPORT) {
michael@0 7866 MessagePort* port = static_cast<MessagePort*>(aData);
michael@0 7867 port->BindToOwner(scInfo->window);
michael@0 7868 scInfo->ports.Put(port, nullptr);
michael@0 7869
michael@0 7870 JS::Rooted<JSObject*> obj(aCx, port->WrapObject(aCx));
michael@0 7871 if (JS_WrapObject(aCx, &obj)) {
michael@0 7872 MOZ_ASSERT(port->GetOwner() == scInfo->window);
michael@0 7873 returnObject.set(obj);
michael@0 7874 }
michael@0 7875
michael@0 7876 return true;
michael@0 7877 }
michael@0 7878
michael@0 7879 return false;
michael@0 7880 }
michael@0 7881
michael@0 7882 static bool
michael@0 7883 PostMessageTransferStructuredClone(JSContext* aCx,
michael@0 7884 JS::Handle<JSObject*> aObj,
michael@0 7885 void* aClosure,
michael@0 7886 uint32_t* aTag,
michael@0 7887 JS::TransferableOwnership* aOwnership,
michael@0 7888 void** aContent,
michael@0 7889 uint64_t* aExtraData)
michael@0 7890 {
michael@0 7891 StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
michael@0 7892 NS_ASSERTION(scInfo, "Must have scInfo!");
michael@0 7893
michael@0 7894 if (MessageChannel::PrefEnabled()) {
michael@0 7895 MessagePortBase* port = nullptr;
michael@0 7896 nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
michael@0 7897 if (NS_SUCCEEDED(rv)) {
michael@0 7898 nsRefPtr<MessagePortBase> newPort;
michael@0 7899 if (scInfo->ports.Get(port, getter_AddRefs(newPort))) {
michael@0 7900 // No duplicate.
michael@0 7901 return false;
michael@0 7902 }
michael@0 7903
michael@0 7904 newPort = port->Clone();
michael@0 7905 scInfo->ports.Put(port, newPort);
michael@0 7906
michael@0 7907 *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
michael@0 7908 *aOwnership = JS::SCTAG_TMO_CUSTOM;
michael@0 7909 *aContent = newPort;
michael@0 7910 *aExtraData = 0;
michael@0 7911
michael@0 7912 return true;
michael@0 7913 }
michael@0 7914 }
michael@0 7915
michael@0 7916 return false;
michael@0 7917 }
michael@0 7918
michael@0 7919 void
michael@0 7920 PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership,
michael@0 7921 void *aContent, uint64_t aExtraData, void* aClosure)
michael@0 7922 {
michael@0 7923 StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
michael@0 7924 NS_ASSERTION(scInfo, "Must have scInfo!");
michael@0 7925
michael@0 7926 if (MessageChannel::PrefEnabled() && aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
michael@0 7927 nsRefPtr<MessagePortBase> port(static_cast<MessagePort*>(aContent));
michael@0 7928 scInfo->ports.Remove(port);
michael@0 7929 }
michael@0 7930 }
michael@0 7931
michael@0 7932 JSStructuredCloneCallbacks kPostMessageCallbacks = {
michael@0 7933 PostMessageReadStructuredClone,
michael@0 7934 PostMessageWriteStructuredClone,
michael@0 7935 nullptr,
michael@0 7936 PostMessageReadTransferStructuredClone,
michael@0 7937 PostMessageTransferStructuredClone,
michael@0 7938 PostMessageFreeTransferStructuredClone
michael@0 7939 };
michael@0 7940
michael@0 7941 } // anonymous namespace
michael@0 7942
michael@0 7943 static PLDHashOperator
michael@0 7944 PopulateMessagePortList(MessagePortBase* aKey, MessagePortBase* aValue, void* aClosure)
michael@0 7945 {
michael@0 7946 nsTArray<nsRefPtr<MessagePortBase> > *array =
michael@0 7947 static_cast<nsTArray<nsRefPtr<MessagePortBase> > *>(aClosure);
michael@0 7948
michael@0 7949 array->AppendElement(aKey);
michael@0 7950 return PL_DHASH_NEXT;
michael@0 7951 }
michael@0 7952
michael@0 7953 NS_IMETHODIMP
michael@0 7954 PostMessageEvent::Run()
michael@0 7955 {
michael@0 7956 NS_ABORT_IF_FALSE(mTargetWindow->IsOuterWindow(),
michael@0 7957 "should have been passed an outer window!");
michael@0 7958 NS_ABORT_IF_FALSE(!mSource || mSource->IsOuterWindow(),
michael@0 7959 "should have been passed an outer window!");
michael@0 7960
michael@0 7961 AutoJSAPI jsapi;
michael@0 7962 JSContext* cx = jsapi.cx();
michael@0 7963
michael@0 7964 // If we bailed before this point we're going to leak mMessage, but
michael@0 7965 // that's probably better than crashing.
michael@0 7966
michael@0 7967 nsRefPtr<nsGlobalWindow> targetWindow;
michael@0 7968 if (mTargetWindow->IsClosedOrClosing() ||
michael@0 7969 !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
michael@0 7970 targetWindow->IsClosedOrClosing())
michael@0 7971 return NS_OK;
michael@0 7972
michael@0 7973 NS_ABORT_IF_FALSE(targetWindow->IsInnerWindow(),
michael@0 7974 "we ordered an inner window!");
michael@0 7975 JSAutoCompartment ac(cx, targetWindow->GetWrapperPreserveColor());
michael@0 7976
michael@0 7977 // Ensure that any origin which might have been provided is the origin of this
michael@0 7978 // window's document. Note that we do this *now* instead of when postMessage
michael@0 7979 // is called because the target window might have been navigated to a
michael@0 7980 // different location between then and now. If this check happened when
michael@0 7981 // postMessage was called, it would be fairly easy for a malicious webpage to
michael@0 7982 // intercept messages intended for another site by carefully timing navigation
michael@0 7983 // of the target window so it changed location after postMessage but before
michael@0 7984 // now.
michael@0 7985 if (mProvidedPrincipal) {
michael@0 7986 // Get the target's origin either from its principal or, in the case the
michael@0 7987 // principal doesn't carry a URI (e.g. the system principal), the target's
michael@0 7988 // document.
michael@0 7989 nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
michael@0 7990 if (NS_WARN_IF(!targetPrin))
michael@0 7991 return NS_OK;
michael@0 7992
michael@0 7993 // Note: This is contrary to the spec with respect to file: URLs, which
michael@0 7994 // the spec groups into a single origin, but given we intentionally
michael@0 7995 // don't do that in other places it seems better to hold the line for
michael@0 7996 // now. Long-term, we want HTML5 to address this so that we can
michael@0 7997 // be compliant while being safer.
michael@0 7998 if (!targetPrin->Equals(mProvidedPrincipal)) {
michael@0 7999 return NS_OK;
michael@0 8000 }
michael@0 8001 }
michael@0 8002
michael@0 8003 // Deserialize the structured clone data
michael@0 8004 JS::Rooted<JS::Value> messageData(cx);
michael@0 8005 StructuredCloneInfo scInfo;
michael@0 8006 scInfo.event = this;
michael@0 8007 scInfo.window = targetWindow;
michael@0 8008
michael@0 8009 if (!mBuffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo)) {
michael@0 8010 return NS_ERROR_DOM_DATA_CLONE_ERR;
michael@0 8011 }
michael@0 8012
michael@0 8013 // Create the event
michael@0 8014 nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
michael@0 8015 do_QueryInterface(static_cast<nsPIDOMWindow*>(targetWindow.get()));
michael@0 8016 nsRefPtr<MessageEvent> event =
michael@0 8017 new MessageEvent(eventTarget, nullptr, nullptr);
michael@0 8018
michael@0 8019 event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */,
michael@0 8020 false /*cancelable */, messageData, mCallerOrigin,
michael@0 8021 EmptyString(), mSource);
michael@0 8022
michael@0 8023 nsTArray<nsRefPtr<MessagePortBase> > ports;
michael@0 8024 scInfo.ports.EnumerateRead(PopulateMessagePortList, &ports);
michael@0 8025 event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()), ports));
michael@0 8026
michael@0 8027 // We can't simply call dispatchEvent on the window because doing so ends
michael@0 8028 // up flipping the trusted bit on the event, and we don't want that to
michael@0 8029 // happen because then untrusted content can call postMessage on a chrome
michael@0 8030 // window if it can get a reference to it.
michael@0 8031
michael@0 8032 nsIPresShell *shell = targetWindow->mDoc->GetShell();
michael@0 8033 nsRefPtr<nsPresContext> presContext;
michael@0 8034 if (shell)
michael@0 8035 presContext = shell->GetPresContext();
michael@0 8036
michael@0 8037 event->SetTrusted(mTrustedCaller);
michael@0 8038 WidgetEvent* internalEvent = event->GetInternalNSEvent();
michael@0 8039
michael@0 8040 nsEventStatus status = nsEventStatus_eIgnore;
michael@0 8041 EventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
michael@0 8042 presContext,
michael@0 8043 internalEvent,
michael@0 8044 static_cast<dom::Event*>(event.get()),
michael@0 8045 &status);
michael@0 8046 return NS_OK;
michael@0 8047 }
michael@0 8048
michael@0 8049 void
michael@0 8050 nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
michael@0 8051 const nsAString& aTargetOrigin,
michael@0 8052 JS::Handle<JS::Value> aTransfer,
michael@0 8053 ErrorResult& aError)
michael@0 8054 {
michael@0 8055 FORWARD_TO_OUTER_OR_THROW(PostMessageMoz,
michael@0 8056 (aCx, aMessage, aTargetOrigin, aTransfer, aError),
michael@0 8057 aError, );
michael@0 8058
michael@0 8059 //
michael@0 8060 // Window.postMessage is an intentional subversion of the same-origin policy.
michael@0 8061 // As such, this code must be particularly careful in the information it
michael@0 8062 // exposes to calling code.
michael@0 8063 //
michael@0 8064 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
michael@0 8065 //
michael@0 8066
michael@0 8067 // First, get the caller's window
michael@0 8068 nsRefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
michael@0 8069 nsIPrincipal* callerPrin;
michael@0 8070 if (callerInnerWin) {
michael@0 8071 NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(),
michael@0 8072 "should have gotten an inner window here");
michael@0 8073
michael@0 8074 // Compute the caller's origin either from its principal or, in the case the
michael@0 8075 // principal doesn't carry a URI (e.g. the system principal), the caller's
michael@0 8076 // document. We must get this now instead of when the event is created and
michael@0 8077 // dispatched, because ultimately it is the identity of the calling window
michael@0 8078 // *now* that determines who sent the message (and not an identity which might
michael@0 8079 // have changed due to intervening navigations).
michael@0 8080 callerPrin = callerInnerWin->GetPrincipal();
michael@0 8081 }
michael@0 8082 else {
michael@0 8083 // In case the global is not a window, it can be a sandbox, and the sandbox's
michael@0 8084 // principal can be used for the security check.
michael@0 8085 JSObject *global = CallerGlobal();
michael@0 8086 NS_ASSERTION(global, "Why is there no global object?");
michael@0 8087 JSCompartment *compartment = js::GetObjectCompartment(global);
michael@0 8088 callerPrin = xpc::GetCompartmentPrincipal(compartment);
michael@0 8089 }
michael@0 8090 if (!callerPrin) {
michael@0 8091 return;
michael@0 8092 }
michael@0 8093
michael@0 8094 nsCOMPtr<nsIURI> callerOuterURI;
michael@0 8095 if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI)))) {
michael@0 8096 return;
michael@0 8097 }
michael@0 8098
michael@0 8099 nsAutoString origin;
michael@0 8100 if (callerOuterURI) {
michael@0 8101 // if the principal has a URI, use that to generate the origin
michael@0 8102 nsContentUtils::GetUTFOrigin(callerPrin, origin);
michael@0 8103 }
michael@0 8104 else if (callerInnerWin) {
michael@0 8105 // otherwise use the URI of the document to generate origin
michael@0 8106 nsCOMPtr<nsIDocument> doc = callerInnerWin->GetExtantDoc();
michael@0 8107 if (!doc) {
michael@0 8108 return;
michael@0 8109 }
michael@0 8110 callerOuterURI = doc->GetDocumentURI();
michael@0 8111 // if the principal has a URI, use that to generate the origin
michael@0 8112 nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
michael@0 8113 }
michael@0 8114 else {
michael@0 8115 // in case of a sandbox with a system principal origin can be empty
michael@0 8116 if (!nsContentUtils::IsSystemPrincipal(callerPrin)) {
michael@0 8117 return;
michael@0 8118 }
michael@0 8119 }
michael@0 8120
michael@0 8121 // Convert the provided origin string into a URI for comparison purposes.
michael@0 8122 nsCOMPtr<nsIPrincipal> providedPrincipal;
michael@0 8123
michael@0 8124 if (aTargetOrigin.EqualsASCII("/")) {
michael@0 8125 providedPrincipal = BrokenGetEntryGlobal()->PrincipalOrNull();
michael@0 8126 if (NS_WARN_IF(!providedPrincipal))
michael@0 8127 return;
michael@0 8128 }
michael@0 8129
michael@0 8130 // "*" indicates no specific origin is required.
michael@0 8131 else if (!aTargetOrigin.EqualsASCII("*")) {
michael@0 8132 nsCOMPtr<nsIURI> originURI;
michael@0 8133 if (NS_FAILED(NS_NewURI(getter_AddRefs(originURI), aTargetOrigin))) {
michael@0 8134 aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
michael@0 8135 return;
michael@0 8136 }
michael@0 8137
michael@0 8138 if (NS_FAILED(originURI->SetUserPass(EmptyCString())) ||
michael@0 8139 NS_FAILED(originURI->SetPath(EmptyCString()))) {
michael@0 8140 return;
michael@0 8141 }
michael@0 8142
michael@0 8143 nsCOMPtr<nsIScriptSecurityManager> ssm =
michael@0 8144 nsContentUtils::GetSecurityManager();
michael@0 8145 MOZ_ASSERT(ssm);
michael@0 8146
michael@0 8147 nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetSubjectPrincipal();
michael@0 8148 MOZ_ASSERT(principal);
michael@0 8149
michael@0 8150 uint32_t appId;
michael@0 8151 if (NS_WARN_IF(NS_FAILED(principal->GetAppId(&appId))))
michael@0 8152 return;
michael@0 8153
michael@0 8154 bool isInBrowser;
michael@0 8155 if (NS_WARN_IF(NS_FAILED(principal->GetIsInBrowserElement(&isInBrowser))))
michael@0 8156 return;
michael@0 8157
michael@0 8158 // Create a nsIPrincipal inheriting the app/browser attributes from the
michael@0 8159 // caller.
michael@0 8160 nsresult rv = ssm->GetAppCodebasePrincipal(originURI, appId, isInBrowser,
michael@0 8161 getter_AddRefs(providedPrincipal));
michael@0 8162 if (NS_WARN_IF(NS_FAILED(rv))) {
michael@0 8163 return;
michael@0 8164 }
michael@0 8165 }
michael@0 8166
michael@0 8167 // Create and asynchronously dispatch a runnable which will handle actual DOM
michael@0 8168 // event creation and dispatch.
michael@0 8169 nsRefPtr<PostMessageEvent> event =
michael@0 8170 new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin
michael@0 8171 ? nullptr
michael@0 8172 : callerInnerWin->GetOuterWindowInternal(),
michael@0 8173 origin,
michael@0 8174 this,
michael@0 8175 providedPrincipal,
michael@0 8176 nsContentUtils::IsCallerChrome());
michael@0 8177
michael@0 8178 // We *must* clone the data here, or the JS::Value could be modified
michael@0 8179 // by script
michael@0 8180 StructuredCloneInfo scInfo;
michael@0 8181 scInfo.event = event;
michael@0 8182 scInfo.window = this;
michael@0 8183
michael@0 8184 nsIPrincipal* principal = GetPrincipal();
michael@0 8185 JS::Rooted<JS::Value> message(aCx, aMessage);
michael@0 8186 JS::Rooted<JS::Value> transfer(aCx, aTransfer);
michael@0 8187 if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)) ||
michael@0 8188 !event->Buffer().write(aCx, message, transfer, &kPostMessageCallbacks,
michael@0 8189 &scInfo)) {
michael@0 8190 aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
michael@0 8191 return;
michael@0 8192 }
michael@0 8193
michael@0 8194 aError = NS_DispatchToCurrentThread(event);
michael@0 8195 }
michael@0 8196
michael@0 8197 void
michael@0 8198 nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
michael@0 8199 const nsAString& aTargetOrigin,
michael@0 8200 const Optional<Sequence<JS::Value > >& aTransfer,
michael@0 8201 ErrorResult& aError)
michael@0 8202 {
michael@0 8203 JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
michael@0 8204 if (aTransfer.WasPassed()) {
michael@0 8205 const Sequence<JS::Value >& values = aTransfer.Value();
michael@0 8206
michael@0 8207 // The input sequence only comes from the generated bindings code, which
michael@0 8208 // ensures it is rooted.
michael@0 8209 JS::HandleValueArray elements =
michael@0 8210 JS::HandleValueArray::fromMarkedLocation(values.Length(), values.Elements());
michael@0 8211
michael@0 8212 transferArray = JS::ObjectOrNullValue(JS_NewArrayObject(aCx, elements));
michael@0 8213 if (transferArray.isNull()) {
michael@0 8214 aError.Throw(NS_ERROR_OUT_OF_MEMORY);
michael@0 8215 return;
michael@0 8216 }
michael@0 8217 }
michael@0 8218
michael@0 8219 PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray, aError);
michael@0 8220 }
michael@0 8221
michael@0 8222 NS_IMETHODIMP
michael@0 8223 nsGlobalWindow::PostMessageMoz(JS::Handle<JS::Value> aMessage,
michael@0 8224 const nsAString& aOrigin,
michael@0 8225 JS::Handle<JS::Value> aTransfer,
michael@0 8226 JSContext* aCx)
michael@0 8227 {
michael@0 8228 ErrorResult rv;
michael@0 8229 PostMessageMoz(aCx, aMessage, aOrigin, aTransfer, rv);
michael@0 8230
michael@0 8231 return rv.ErrorCode();
michael@0 8232 }
michael@0 8233
michael@0 8234 class nsCloseEvent : public nsRunnable {
michael@0 8235
michael@0 8236 nsRefPtr<nsGlobalWindow> mWindow;
michael@0 8237 bool mIndirect;
michael@0 8238
michael@0 8239 nsCloseEvent(nsGlobalWindow *aWindow, bool aIndirect)
michael@0 8240 : mWindow(aWindow)
michael@0 8241 , mIndirect(aIndirect)
michael@0 8242 {}
michael@0 8243
michael@0 8244 public:
michael@0 8245
michael@0 8246 static nsresult
michael@0 8247 PostCloseEvent(nsGlobalWindow* aWindow, bool aIndirect) {
michael@0 8248 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
michael@0 8249 nsresult rv = NS_DispatchToCurrentThread(ev);
michael@0 8250 if (NS_SUCCEEDED(rv))
michael@0 8251 aWindow->MaybeForgiveSpamCount();
michael@0 8252 return rv;
michael@0 8253 }
michael@0 8254
michael@0 8255 NS_IMETHOD Run() {
michael@0 8256 if (mWindow) {
michael@0 8257 if (mIndirect) {
michael@0 8258 return PostCloseEvent(mWindow, false);
michael@0 8259 }
michael@0 8260 mWindow->ReallyCloseWindow();
michael@0 8261 }
michael@0 8262 return NS_OK;
michael@0 8263 }
michael@0 8264
michael@0 8265 };
michael@0 8266
michael@0 8267 bool
michael@0 8268 nsGlobalWindow::CanClose()
michael@0 8269 {
michael@0 8270 if (!mDocShell)
michael@0 8271 return true;
michael@0 8272
michael@0 8273 // Ask the content viewer whether the toplevel window can close.
michael@0 8274 // If the content viewer returns false, it is responsible for calling
michael@0 8275 // Close() as soon as it is possible for the window to close.
michael@0 8276 // This allows us to not close the window while printing is happening.
michael@0 8277
michael@0 8278 nsCOMPtr<nsIContentViewer> cv;
michael@0 8279 mDocShell->GetContentViewer(getter_AddRefs(cv));
michael@0 8280 if (cv) {
michael@0 8281 bool canClose;
michael@0 8282 nsresult rv = cv->PermitUnload(false, &canClose);
michael@0 8283 if (NS_SUCCEEDED(rv) && !canClose)
michael@0 8284 return false;
michael@0 8285
michael@0 8286 rv = cv->RequestWindowClose(&canClose);
michael@0 8287 if (NS_SUCCEEDED(rv) && !canClose)
michael@0 8288 return false;
michael@0 8289 }
michael@0 8290
michael@0 8291 return true;
michael@0 8292 }
michael@0 8293
michael@0 8294 void
michael@0 8295 nsGlobalWindow::Close(ErrorResult& aError)
michael@0 8296 {
michael@0 8297 FORWARD_TO_OUTER_OR_THROW(Close, (aError), aError, );
michael@0 8298
michael@0 8299 if (!mDocShell || IsInModalState() ||
michael@0 8300 (IsFrame() && !mDocShell->GetIsBrowserOrApp())) {
michael@0 8301 // window.close() is called on a frame in a frameset, on a window
michael@0 8302 // that's already closed, or on a window for which there's
michael@0 8303 // currently a modal dialog open. Ignore such calls.
michael@0 8304 return;
michael@0 8305 }
michael@0 8306
michael@0 8307 if (mHavePendingClose) {
michael@0 8308 // We're going to be closed anyway; do nothing since we don't want
michael@0 8309 // to double-close
michael@0 8310 return;
michael@0 8311 }
michael@0 8312
michael@0 8313 if (mBlockScriptedClosingFlag)
michael@0 8314 {
michael@0 8315 // A script's popup has been blocked and we don't want
michael@0 8316 // the window to be closed directly after this event,
michael@0 8317 // so the user can see that there was a blocked popup.
michael@0 8318 return;
michael@0 8319 }
michael@0 8320
michael@0 8321 // Don't allow scripts from content to close non-app or non-neterror
michael@0 8322 // windows that were not opened by script.
michael@0 8323 nsAutoString url;
michael@0 8324 mDoc->GetURL(url);
michael@0 8325 if (!mDocShell->GetIsApp() &&
michael@0 8326 !StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
michael@0 8327 !mHadOriginalOpener && !nsContentUtils::IsCallerChrome()) {
michael@0 8328 bool allowClose = mAllowScriptsToClose ||
michael@0 8329 Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
michael@0 8330 if (!allowClose) {
michael@0 8331 // We're blocking the close operation
michael@0 8332 // report localized error msg in JS console
michael@0 8333 nsContentUtils::ReportToConsole(
michael@0 8334 nsIScriptError::warningFlag,
michael@0 8335 NS_LITERAL_CSTRING("DOM Window"), mDoc, // Better name for the category?
michael@0 8336 nsContentUtils::eDOM_PROPERTIES,
michael@0 8337 "WindowCloseBlockedWarning");
michael@0 8338
michael@0 8339 return;
michael@0 8340 }
michael@0 8341 }
michael@0 8342
michael@0 8343 if (!mInClose && !mIsClosed && !CanClose()) {
michael@0 8344 return;
michael@0 8345 }
michael@0 8346
michael@0 8347 // Fire a DOM event notifying listeners that this window is about to
michael@0 8348 // be closed. The tab UI code may choose to cancel the default
michael@0 8349 // action for this event, if so, we won't actually close the window
michael@0 8350 // (since the tab UI code will close the tab in stead). Sure, this
michael@0 8351 // could be abused by content code, but do we care? I don't think
michael@0 8352 // so...
michael@0 8353
michael@0 8354 bool wasInClose = mInClose;
michael@0 8355 mInClose = true;
michael@0 8356
michael@0 8357 if (!DispatchCustomEvent("DOMWindowClose")) {
michael@0 8358 // Someone chose to prevent the default action for this event, if
michael@0 8359 // so, let's not close this window after all...
michael@0 8360
michael@0 8361 mInClose = wasInClose;
michael@0 8362 return;
michael@0 8363 }
michael@0 8364
michael@0 8365 aError = FinalClose();
michael@0 8366 }
michael@0 8367
michael@0 8368 NS_IMETHODIMP
michael@0 8369 nsGlobalWindow::Close()
michael@0 8370 {
michael@0 8371 ErrorResult rv;
michael@0 8372 Close(rv);
michael@0 8373
michael@0 8374 return rv.ErrorCode();
michael@0 8375 }
michael@0 8376
michael@0 8377 nsresult
michael@0 8378 nsGlobalWindow::ForceClose()
michael@0 8379 {
michael@0 8380 if (IsFrame() || !mDocShell) {
michael@0 8381 // This may be a frame in a frameset, or a window that's already closed.
michael@0 8382 // Ignore such calls.
michael@0 8383
michael@0 8384 return NS_OK;
michael@0 8385 }
michael@0 8386
michael@0 8387 if (mHavePendingClose) {
michael@0 8388 // We're going to be closed anyway; do nothing since we don't want
michael@0 8389 // to double-close
michael@0 8390 return NS_OK;
michael@0 8391 }
michael@0 8392
michael@0 8393 mInClose = true;
michael@0 8394
michael@0 8395 DispatchCustomEvent("DOMWindowClose");
michael@0 8396
michael@0 8397 return FinalClose();
michael@0 8398 }
michael@0 8399
michael@0 8400 nsresult
michael@0 8401 nsGlobalWindow::FinalClose()
michael@0 8402 {
michael@0 8403 // Flag that we were closed.
michael@0 8404 mIsClosed = true;
michael@0 8405
michael@0 8406 // This stuff is non-sensical but incredibly fragile. The reasons for the
michael@0 8407 // behavior here don't make sense today and may not have ever made sense,
michael@0 8408 // but various bits of frontend code break when you change them. If you need
michael@0 8409 // to fix up this behavior, feel free to. It's a righteous task, but involves
michael@0 8410 // wrestling with various download manager tests, frontend code, and possible
michael@0 8411 // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
michael@0 8412 // testing ground.
michael@0 8413 //
michael@0 8414 // In particular, if |win|'s JSContext is at the top of the stack, we must
michael@0 8415 // complete _two_ round-trips to the event loop before the call to
michael@0 8416 // ReallyCloseWindow. This allows setTimeout handlers that are set after
michael@0 8417 // FinalClose() is called to run before the window is torn down.
michael@0 8418 bool indirect = GetContextInternal() && // Occasionally null. See bug 877390.
michael@0 8419 (nsContentUtils::GetCurrentJSContext() ==
michael@0 8420 GetContextInternal()->GetNativeContext());
michael@0 8421 if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))) {
michael@0 8422 ReallyCloseWindow();
michael@0 8423 } else {
michael@0 8424 mHavePendingClose = true;
michael@0 8425 }
michael@0 8426
michael@0 8427 return NS_OK;
michael@0 8428 }
michael@0 8429
michael@0 8430
michael@0 8431 void
michael@0 8432 nsGlobalWindow::ReallyCloseWindow()
michael@0 8433 {
michael@0 8434 FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
michael@0 8435
michael@0 8436 // Make sure we never reenter this method.
michael@0 8437 mHavePendingClose = true;
michael@0 8438
michael@0 8439 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
michael@0 8440
michael@0 8441 // If there's no treeOwnerAsWin, this window must already be closed.
michael@0 8442
michael@0 8443 if (treeOwnerAsWin) {
michael@0 8444
michael@0 8445 // but if we're a browser window we could be in some nasty
michael@0 8446 // self-destroying cascade that we should mostly ignore
michael@0 8447
michael@0 8448 if (mDocShell) {
michael@0 8449 nsCOMPtr<nsIBrowserDOMWindow> bwin;
michael@0 8450 nsCOMPtr<nsIDocShellTreeItem> rootItem;
michael@0 8451 mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
michael@0 8452 nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
michael@0 8453 nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
michael@0 8454 if (chromeWin)
michael@0 8455 chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
michael@0 8456
michael@0 8457 if (rootWin) {
michael@0 8458 /* Normally we destroy the entire window, but not if
michael@0 8459 this DOM window belongs to a tabbed browser and doesn't
michael@0 8460 correspond to a tab. This allows a well-behaved tab
michael@0 8461 to destroy the container as it should but is a final measure
michael@0 8462 to prevent an errant tab from doing so when it shouldn't.
michael@0 8463 This works because we reach this code when we shouldn't only
michael@0 8464 in the particular circumstance that we belong to a tab
michael@0 8465 that has just been closed (and is therefore already missing
michael@0 8466 from the list of browsers) (and has an unload handler
michael@0 8467 that closes the window). */
michael@0 8468 // XXXbz now that we have mHavePendingClose, is this needed?
michael@0 8469 bool isTab = false;
michael@0 8470 if (rootWin == this ||
michael@0 8471 !bwin || (bwin->IsTabContentWindow(GetOuterWindowInternal(),
michael@0 8472 &isTab), isTab))
michael@0 8473 treeOwnerAsWin->Destroy();
michael@0 8474 }
michael@0 8475 }
michael@0 8476
michael@0 8477 CleanUp();
michael@0 8478 }
michael@0 8479 }
michael@0 8480
michael@0 8481 void
michael@0 8482 nsGlobalWindow::EnterModalState()
michael@0 8483 {
michael@0 8484 MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
michael@0 8485
michael@0 8486 // GetScriptableTop, not GetTop, so that EnterModalState works properly with
michael@0 8487 // <iframe mozbrowser>.
michael@0 8488 nsGlobalWindow* topWin = GetScriptableTop();
michael@0 8489
michael@0 8490 if (!topWin) {
michael@0 8491 NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
michael@0 8492 return;
michael@0 8493 }
michael@0 8494
michael@0 8495 // If there is an active ESM in this window, clear it. Otherwise, this can
michael@0 8496 // cause a problem if a modal state is entered during a mouseup event.
michael@0 8497 EventStateManager* activeESM =
michael@0 8498 static_cast<EventStateManager*>(
michael@0 8499 EventStateManager::GetActiveEventStateManager());
michael@0 8500 if (activeESM && activeESM->GetPresContext()) {
michael@0 8501 nsIPresShell* activeShell = activeESM->GetPresContext()->GetPresShell();
michael@0 8502 if (activeShell && (
michael@0 8503 nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(), mDoc) ||
michael@0 8504 nsContentUtils::ContentIsCrossDocDescendantOf(mDoc, activeShell->GetDocument()))) {
michael@0 8505 EventStateManager::ClearGlobalActiveContent(activeESM);
michael@0 8506
michael@0 8507 activeShell->SetCapturingContent(nullptr, 0);
michael@0 8508
michael@0 8509 if (activeShell) {
michael@0 8510 nsRefPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
michael@0 8511 frameSelection->SetMouseDownState(false);
michael@0 8512 }
michael@0 8513 }
michael@0 8514 }
michael@0 8515
michael@0 8516 // If there are any drag and drop operations in flight, try to end them.
michael@0 8517 nsCOMPtr<nsIDragService> ds =
michael@0 8518 do_GetService("@mozilla.org/widget/dragservice;1");
michael@0 8519 if (ds) {
michael@0 8520 ds->EndDragSession(true);
michael@0 8521 }
michael@0 8522
michael@0 8523 // Clear the capturing content if it is under topDoc.
michael@0 8524 // Usually the activeESM check above does that, but there are cases when
michael@0 8525 // we don't have activeESM, or it is for different document.
michael@0 8526 nsIDocument* topDoc = topWin->GetExtantDoc();
michael@0 8527 nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
michael@0 8528 if (capturingContent && topDoc &&
michael@0 8529 nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
michael@0 8530 nsIPresShell::SetCapturingContent(nullptr, 0);
michael@0 8531 }
michael@0 8532
michael@0 8533 if (topWin->mModalStateDepth == 0) {
michael@0 8534 NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
michael@0 8535
michael@0 8536 mSuspendedDoc = topDoc;
michael@0 8537 if (mSuspendedDoc) {
michael@0 8538 mSuspendedDoc->SuppressEventHandling(nsIDocument::eAnimationsOnly);
michael@0 8539 }
michael@0 8540 }
michael@0 8541 topWin->mModalStateDepth++;
michael@0 8542 }
michael@0 8543
michael@0 8544 // static
michael@0 8545 void
michael@0 8546 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
michael@0 8547 nsGlobalWindow *aWindow)
michael@0 8548 {
michael@0 8549 nsGlobalWindow *inner;
michael@0 8550
michael@0 8551 // Return early if we're frozen or have no inner window.
michael@0 8552 if (!(inner = aWindow->GetCurrentInnerWindowInternal()) ||
michael@0 8553 inner->IsFrozen()) {
michael@0 8554 return;
michael@0 8555 }
michael@0 8556
michael@0 8557 inner->RunTimeout(nullptr);
michael@0 8558
michael@0 8559 // Check again if we're frozen since running pending timeouts
michael@0 8560 // could've frozen us.
michael@0 8561 if (inner->IsFrozen()) {
michael@0 8562 return;
michael@0 8563 }
michael@0 8564
michael@0 8565 nsCOMPtr<nsIDOMWindowCollection> frames;
michael@0 8566 aWindow->GetFrames(getter_AddRefs(frames));
michael@0 8567
michael@0 8568 if (!frames) {
michael@0 8569 return;
michael@0 8570 }
michael@0 8571
michael@0 8572 uint32_t i, length;
michael@0 8573 if (NS_FAILED(frames->GetLength(&length)) || !length) {
michael@0 8574 return;
michael@0 8575 }
michael@0 8576
michael@0 8577 for (i = 0; i < length && aTopWindow->mModalStateDepth == 0; i++) {
michael@0 8578 nsCOMPtr<nsIDOMWindow> child;
michael@0 8579 frames->Item(i, getter_AddRefs(child));
michael@0 8580
michael@0 8581 if (!child) {
michael@0 8582 return;
michael@0 8583 }
michael@0 8584
michael@0 8585 nsGlobalWindow *childWin =
michael@0 8586 static_cast<nsGlobalWindow *>
michael@0 8587 (static_cast<nsIDOMWindow *>
michael@0 8588 (child.get()));
michael@0 8589
michael@0 8590 RunPendingTimeoutsRecursive(aTopWindow, childWin);
michael@0 8591 }
michael@0 8592 }
michael@0 8593
michael@0 8594 class nsPendingTimeoutRunner : public nsRunnable
michael@0 8595 {
michael@0 8596 public:
michael@0 8597 nsPendingTimeoutRunner(nsGlobalWindow *aWindow)
michael@0 8598 : mWindow(aWindow)
michael@0 8599 {
michael@0 8600 NS_ASSERTION(mWindow, "mWindow is null.");
michael@0 8601 }
michael@0 8602
michael@0 8603 NS_IMETHOD Run()
michael@0 8604 {
michael@0 8605 nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow, mWindow);
michael@0 8606
michael@0 8607 return NS_OK;
michael@0 8608 }
michael@0 8609
michael@0 8610 private:
michael@0 8611 nsRefPtr<nsGlobalWindow> mWindow;
michael@0 8612 };
michael@0 8613
michael@0 8614 void
michael@0 8615 nsGlobalWindow::LeaveModalState()
michael@0 8616 {
michael@0 8617 MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
michael@0 8618
michael@0 8619 nsGlobalWindow* topWin = GetScriptableTop();
michael@0 8620
michael@0 8621 if (!topWin) {
michael@0 8622 NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
michael@0 8623 return;
michael@0 8624 }
michael@0 8625
michael@0 8626 topWin->mModalStateDepth--;
michael@0 8627
michael@0 8628 if (topWin->mModalStateDepth == 0) {
michael@0 8629 nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
michael@0 8630 if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
michael@0 8631 NS_WARNING("failed to dispatch pending timeout runnable");
michael@0 8632
michael@0 8633 if (mSuspendedDoc) {
michael@0 8634 nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
michael@0 8635 mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly,
michael@0 8636 currentDoc == mSuspendedDoc);
michael@0 8637 mSuspendedDoc = nullptr;
michael@0 8638 }
michael@0 8639 }
michael@0 8640
michael@0 8641 // Remember the time of the last dialog quit.
michael@0 8642 nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
michael@0 8643 if (inner)
michael@0 8644 inner->mLastDialogQuitTime = TimeStamp::Now();
michael@0 8645 }
michael@0 8646
michael@0 8647 bool
michael@0 8648 nsGlobalWindow::IsInModalState()
michael@0 8649 {
michael@0 8650 nsGlobalWindow *topWin = GetScriptableTop();
michael@0 8651
michael@0 8652 if (!topWin) {
michael@0 8653 NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
michael@0 8654
michael@0 8655 return false;
michael@0 8656 }
michael@0 8657
michael@0 8658 return topWin->mModalStateDepth != 0;
michael@0 8659 }
michael@0 8660
michael@0 8661 // static
michael@0 8662 void
michael@0 8663 nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
michael@0 8664 nsCOMPtr<nsIObserverService> observerService =
michael@0 8665 services::GetObserverService();
michael@0 8666 if (observerService) {
michael@0 8667 observerService->
michael@0 8668 NotifyObservers(ToSupports(aWindow),
michael@0 8669 DOM_WINDOW_DESTROYED_TOPIC, nullptr);
michael@0 8670 }
michael@0 8671 }
michael@0 8672
michael@0 8673 class WindowDestroyedEvent : public nsRunnable
michael@0 8674 {
michael@0 8675 public:
michael@0 8676 WindowDestroyedEvent(nsPIDOMWindow* aWindow, uint64_t aID,
michael@0 8677 const char* aTopic) :
michael@0 8678 mID(aID), mTopic(aTopic)
michael@0 8679 {
michael@0 8680 mWindow = do_GetWeakReference(aWindow);
michael@0 8681 }
michael@0 8682
michael@0 8683 NS_IMETHOD Run()
michael@0 8684 {
michael@0 8685 nsCOMPtr<nsIObserverService> observerService =
michael@0 8686 do_GetService("@mozilla.org/observer-service;1");
michael@0 8687 if (observerService) {
michael@0 8688 nsCOMPtr<nsISupportsPRUint64> wrapper =
michael@0 8689 do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
michael@0 8690 if (wrapper) {
michael@0 8691 wrapper->SetData(mID);
michael@0 8692 observerService->NotifyObservers(wrapper, mTopic.get(), nullptr);
michael@0 8693 }
michael@0 8694 }
michael@0 8695
michael@0 8696 bool skipNukeCrossCompartment = false;
michael@0 8697 #ifndef DEBUG
michael@0 8698 nsCOMPtr<nsIAppStartup> appStartup =
michael@0 8699 do_GetService(NS_APPSTARTUP_CONTRACTID);
michael@0 8700
michael@0 8701 if (appStartup) {
michael@0 8702 appStartup->GetShuttingDown(&skipNukeCrossCompartment);
michael@0 8703 }
michael@0 8704 #endif
michael@0 8705
michael@0 8706 nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
michael@0 8707 if (!skipNukeCrossCompartment && window) {
michael@0 8708 nsGlobalWindow* currentInner =
michael@0 8709 window->IsInnerWindow() ? static_cast<nsGlobalWindow*>(window.get()) :
michael@0 8710 static_cast<nsGlobalWindow*>(window->GetCurrentInnerWindow());
michael@0 8711 NS_ENSURE_TRUE(currentInner, NS_OK);
michael@0 8712
michael@0 8713 AutoSafeJSContext cx;
michael@0 8714 JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
michael@0 8715 // We only want to nuke wrappers for the chrome->content case
michael@0 8716 if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
michael@0 8717 js::NukeCrossCompartmentWrappers(cx,
michael@0 8718 js::ChromeCompartmentsOnly(),
michael@0 8719 js::SingleCompartment(js::GetObjectCompartment(obj)),
michael@0 8720 window->IsInnerWindow() ? js::DontNukeWindowReferences :
michael@0 8721 js::NukeWindowReferences);
michael@0 8722 }
michael@0 8723 }
michael@0 8724
michael@0 8725 return NS_OK;
michael@0 8726 }
michael@0 8727
michael@0 8728 private:
michael@0 8729 uint64_t mID;
michael@0 8730 nsCString mTopic;
michael@0 8731 nsWeakPtr mWindow;
michael@0 8732 };
michael@0 8733
michael@0 8734 void
michael@0 8735 nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
michael@0 8736 {
michael@0 8737 nsRefPtr<nsIRunnable> runnable = new WindowDestroyedEvent(this, mWindowID, aTopic);
michael@0 8738 nsresult rv = NS_DispatchToCurrentThread(runnable);
michael@0 8739 if (NS_SUCCEEDED(rv)) {
michael@0 8740 mNotifiedIDDestroyed = true;
michael@0 8741 }
michael@0 8742 }
michael@0 8743
michael@0 8744 // static
michael@0 8745 void
michael@0 8746 nsGlobalWindow::NotifyDOMWindowFrozen(nsGlobalWindow* aWindow) {
michael@0 8747 if (aWindow && aWindow->IsInnerWindow()) {
michael@0 8748 nsCOMPtr<nsIObserverService> observerService =
michael@0 8749 services::GetObserverService();
michael@0 8750 if (observerService) {
michael@0 8751 observerService->
michael@0 8752 NotifyObservers(ToSupports(aWindow),
michael@0 8753 DOM_WINDOW_FROZEN_TOPIC, nullptr);
michael@0 8754 }
michael@0 8755 }
michael@0 8756 }
michael@0 8757
michael@0 8758 // static
michael@0 8759 void
michael@0 8760 nsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindow* aWindow) {
michael@0 8761 if (aWindow && aWindow->IsInnerWindow()) {
michael@0 8762 nsCOMPtr<nsIObserverService> observerService =
michael@0 8763 services::GetObserverService();
michael@0 8764 if (observerService) {
michael@0 8765 observerService->
michael@0 8766 NotifyObservers(ToSupports(aWindow),
michael@0 8767 DOM_WINDOW_THAWED_TOPIC, nullptr);
michael@0 8768 }
michael@0 8769 }
michael@0 8770 }
michael@0 8771
michael@0 8772 JSObject*
michael@0 8773 nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
michael@0 8774 {
michael@0 8775 AutoSafeJSContext cx;
michael@0 8776 JS::Rooted<JSObject*> handler(cx);
michael@0 8777 if (mCachedXBLPrototypeHandlers) {
michael@0 8778 mCachedXBLPrototypeHandlers->Get(aKey, handler.address());
michael@0 8779 }
michael@0 8780 return handler;
michael@0 8781 }
michael@0 8782
michael@0 8783 void
michael@0 8784 nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
michael@0 8785 JS::Handle<JSObject*> aHandler)
michael@0 8786 {
michael@0 8787 if (!mCachedXBLPrototypeHandlers) {
michael@0 8788 mCachedXBLPrototypeHandlers = new nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>();
michael@0 8789 PreserveWrapper(ToSupports(this));
michael@0 8790 }
michael@0 8791
michael@0 8792 mCachedXBLPrototypeHandlers->Put(aKey, aHandler);
michael@0 8793 }
michael@0 8794
michael@0 8795 /**
michael@0 8796 * GetScriptableFrameElement is called when script reads
michael@0 8797 * nsIGlobalWindow::frameElement.
michael@0 8798 *
michael@0 8799 * In contrast to GetRealFrameElement, GetScriptableFrameElement says that the
michael@0 8800 * window contained by an <iframe mozbrowser> or <iframe mozapp> has no frame
michael@0 8801 * element (effectively treating a mozbrowser the same as a content/chrome
michael@0 8802 * boundary).
michael@0 8803 */
michael@0 8804 NS_IMETHODIMP
michael@0 8805 nsGlobalWindow::GetScriptableFrameElement(nsIDOMElement** aFrameElement)
michael@0 8806 {
michael@0 8807 ErrorResult rv;
michael@0 8808 nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(GetFrameElement(rv));
michael@0 8809 if (rv.Failed()) {
michael@0 8810 return rv.ErrorCode();
michael@0 8811 }
michael@0 8812
michael@0 8813 frameElement.forget(aFrameElement);
michael@0 8814
michael@0 8815 return NS_OK;
michael@0 8816 }
michael@0 8817
michael@0 8818 Element*
michael@0 8819 nsGlobalWindow::GetFrameElement(ErrorResult& aError)
michael@0 8820 {
michael@0 8821 FORWARD_TO_OUTER_OR_THROW(GetFrameElement, (aError), aError, nullptr);
michael@0 8822
michael@0 8823 if (!mDocShell || mDocShell->GetIsBrowserOrApp()) {
michael@0 8824 return nullptr;
michael@0 8825 }
michael@0 8826
michael@0 8827 // Per HTML5, the frameElement getter returns null in cross-origin situations.
michael@0 8828 Element* element = GetRealFrameElement(aError);
michael@0 8829 if (aError.Failed() || !element) {
michael@0 8830 return nullptr;
michael@0 8831 }
michael@0 8832 if (!nsContentUtils::GetSubjectPrincipal()->
michael@0 8833 SubsumesConsideringDomain(element->NodePrincipal())) {
michael@0 8834 return nullptr;
michael@0 8835 }
michael@0 8836 return element;
michael@0 8837 }
michael@0 8838
michael@0 8839 Element*
michael@0 8840 nsGlobalWindow::GetRealFrameElement(ErrorResult& aError)
michael@0 8841 {
michael@0 8842 FORWARD_TO_OUTER_OR_THROW(GetRealFrameElement, (aError), aError, nullptr);
michael@0 8843
michael@0 8844 if (!mDocShell) {
michael@0 8845 return nullptr;
michael@0 8846 }
michael@0 8847
michael@0 8848 nsCOMPtr<nsIDocShell> parent;
michael@0 8849 mDocShell->GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
michael@0 8850
michael@0 8851 if (!parent || parent == mDocShell) {
michael@0 8852 // We're at a chrome boundary, don't expose the chrome iframe
michael@0 8853 // element to content code.
michael@0 8854 return nullptr;
michael@0 8855 }
michael@0 8856
michael@0 8857 return mFrameElement;
michael@0 8858 }
michael@0 8859
michael@0 8860 /**
michael@0 8861 * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper
michael@0 8862 * around GetRealFrameElement.
michael@0 8863 */
michael@0 8864 NS_IMETHODIMP
michael@0 8865 nsGlobalWindow::GetRealFrameElement(nsIDOMElement** aFrameElement)
michael@0 8866 {
michael@0 8867 ErrorResult rv;
michael@0 8868 nsCOMPtr<nsIDOMElement> frameElement =
michael@0 8869 do_QueryInterface(GetRealFrameElement(rv));
michael@0 8870 frameElement.forget(aFrameElement);
michael@0 8871
michael@0 8872 return rv.ErrorCode();
michael@0 8873 }
michael@0 8874
michael@0 8875 // Helper for converting window.showModalDialog() options (list of ';'
michael@0 8876 // separated name (:|=) value pairs) to a format that's parsable by
michael@0 8877 // our normal window opening code.
michael@0 8878
michael@0 8879 void
michael@0 8880 ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult)
michael@0 8881 {
michael@0 8882 nsAString::const_iterator end;
michael@0 8883 aOptions.EndReading(end);
michael@0 8884
michael@0 8885 nsAString::const_iterator iter;
michael@0 8886 aOptions.BeginReading(iter);
michael@0 8887
michael@0 8888 while (iter != end) {
michael@0 8889 // Skip whitespace.
michael@0 8890 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
michael@0 8891 ++iter;
michael@0 8892 }
michael@0 8893
michael@0 8894 nsAString::const_iterator name_start = iter;
michael@0 8895
michael@0 8896 // Skip characters until we find whitespace, ';', ':', or '='
michael@0 8897 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
michael@0 8898 *iter != ';' &&
michael@0 8899 *iter != ':' &&
michael@0 8900 *iter != '=') {
michael@0 8901 ++iter;
michael@0 8902 }
michael@0 8903
michael@0 8904 nsAString::const_iterator name_end = iter;
michael@0 8905
michael@0 8906 // Skip whitespace.
michael@0 8907 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
michael@0 8908 ++iter;
michael@0 8909 }
michael@0 8910
michael@0 8911 if (*iter == ';') {
michael@0 8912 // No value found, skip the ';' and keep going.
michael@0 8913 ++iter;
michael@0 8914
michael@0 8915 continue;
michael@0 8916 }
michael@0 8917
michael@0 8918 nsAString::const_iterator value_start = iter;
michael@0 8919 nsAString::const_iterator value_end = iter;
michael@0 8920
michael@0 8921 if (*iter == ':' || *iter == '=') {
michael@0 8922 // We found name followed by ':' or '='. Look for a value.
michael@0 8923
michael@0 8924 iter++; // Skip the ':' or '='
michael@0 8925
michael@0 8926 // Skip whitespace.
michael@0 8927 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
michael@0 8928 ++iter;
michael@0 8929 }
michael@0 8930
michael@0 8931 value_start = iter;
michael@0 8932
michael@0 8933 // Skip until we find whitespace, or ';'.
michael@0 8934 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
michael@0 8935 *iter != ';') {
michael@0 8936 ++iter;
michael@0 8937 }
michael@0 8938
michael@0 8939 value_end = iter;
michael@0 8940
michael@0 8941 // Skip whitespace.
michael@0 8942 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
michael@0 8943 ++iter;
michael@0 8944 }
michael@0 8945 }
michael@0 8946
michael@0 8947 const nsDependentSubstring& name = Substring(name_start, name_end);
michael@0 8948 const nsDependentSubstring& value = Substring(value_start, value_end);
michael@0 8949
michael@0 8950 if (name.LowerCaseEqualsLiteral("center")) {
michael@0 8951 if (value.LowerCaseEqualsLiteral("on") ||
michael@0 8952 value.LowerCaseEqualsLiteral("yes") ||
michael@0 8953 value.LowerCaseEqualsLiteral("1")) {
michael@0 8954 aResult.AppendLiteral(",centerscreen=1");
michael@0 8955 }
michael@0 8956 } else if (name.LowerCaseEqualsLiteral("dialogwidth")) {
michael@0 8957 if (!value.IsEmpty()) {
michael@0 8958 aResult.AppendLiteral(",width=");
michael@0 8959 aResult.Append(value);
michael@0 8960 }
michael@0 8961 } else if (name.LowerCaseEqualsLiteral("dialogheight")) {
michael@0 8962 if (!value.IsEmpty()) {
michael@0 8963 aResult.AppendLiteral(",height=");
michael@0 8964 aResult.Append(value);
michael@0 8965 }
michael@0 8966 } else if (name.LowerCaseEqualsLiteral("dialogtop")) {
michael@0 8967 if (!value.IsEmpty()) {
michael@0 8968 aResult.AppendLiteral(",top=");
michael@0 8969 aResult.Append(value);
michael@0 8970 }
michael@0 8971 } else if (name.LowerCaseEqualsLiteral("dialogleft")) {
michael@0 8972 if (!value.IsEmpty()) {
michael@0 8973 aResult.AppendLiteral(",left=");
michael@0 8974 aResult.Append(value);
michael@0 8975 }
michael@0 8976 } else if (name.LowerCaseEqualsLiteral("resizable")) {
michael@0 8977 if (value.LowerCaseEqualsLiteral("on") ||
michael@0 8978 value.LowerCaseEqualsLiteral("yes") ||
michael@0 8979 value.LowerCaseEqualsLiteral("1")) {
michael@0 8980 aResult.AppendLiteral(",resizable=1");
michael@0 8981 }
michael@0 8982 } else if (name.LowerCaseEqualsLiteral("scroll")) {
michael@0 8983 if (value.LowerCaseEqualsLiteral("off") ||
michael@0 8984 value.LowerCaseEqualsLiteral("no") ||
michael@0 8985 value.LowerCaseEqualsLiteral("0")) {
michael@0 8986 aResult.AppendLiteral(",scrollbars=0");
michael@0 8987 }
michael@0 8988 }
michael@0 8989
michael@0 8990 if (iter == end) {
michael@0 8991 break;
michael@0 8992 }
michael@0 8993
michael@0 8994 iter++;
michael@0 8995 }
michael@0 8996 }
michael@0 8997
michael@0 8998 already_AddRefed<nsIVariant>
michael@0 8999 nsGlobalWindow::ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument,
michael@0 9000 const nsAString& aOptions, ErrorResult& aError)
michael@0 9001 {
michael@0 9002 if (mDoc) {
michael@0 9003 mDoc->WarnOnceAbout(nsIDocument::eShowModalDialog);
michael@0 9004 }
michael@0 9005
michael@0 9006 FORWARD_TO_OUTER_OR_THROW(ShowModalDialog,
michael@0 9007 (aUrl, aArgument, aOptions, aError), aError,
michael@0 9008 nullptr);
michael@0 9009
michael@0 9010 if (Preferences::GetBool("dom.disable_window_showModalDialog", false)) {
michael@0 9011 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 9012 return nullptr;
michael@0 9013 }
michael@0 9014
michael@0 9015 nsRefPtr<DialogValueHolder> argHolder =
michael@0 9016 new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(), aArgument);
michael@0 9017
michael@0 9018 // Before bringing up the window/dialog, unsuppress painting and flush
michael@0 9019 // pending reflows.
michael@0 9020 EnsureReflowFlushAndPaint();
michael@0 9021
michael@0 9022 if (!AreDialogsEnabled()) {
michael@0 9023 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 9024 return nullptr;
michael@0 9025 }
michael@0 9026
michael@0 9027 if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
michael@0 9028 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 9029 return nullptr;
michael@0 9030 }
michael@0 9031
michael@0 9032 nsCOMPtr<nsIDOMWindow> dlgWin;
michael@0 9033 nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
michael@0 9034
michael@0 9035 ConvertDialogOptions(aOptions, options);
michael@0 9036
michael@0 9037 options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
michael@0 9038
michael@0 9039 EnterModalState();
michael@0 9040 uint32_t oldMicroTaskLevel = nsContentUtils::MicroTaskLevel();
michael@0 9041 nsContentUtils::SetMicroTaskLevel(0);
michael@0 9042 aError = OpenInternal(aUrl, EmptyString(), options,
michael@0 9043 false, // aDialog
michael@0 9044 true, // aContentModal
michael@0 9045 true, // aCalledNoScript
michael@0 9046 true, // aDoJSFixups
michael@0 9047 true, // aNavigate
michael@0 9048 nullptr, argHolder, // args
michael@0 9049 GetPrincipal(), // aCalleePrincipal
michael@0 9050 nullptr, // aJSCallerContext
michael@0 9051 getter_AddRefs(dlgWin));
michael@0 9052 nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel);
michael@0 9053 LeaveModalState();
michael@0 9054 if (aError.Failed()) {
michael@0 9055 return nullptr;
michael@0 9056 }
michael@0 9057
michael@0 9058 nsCOMPtr<nsIDOMModalContentWindow> dialog = do_QueryInterface(dlgWin);
michael@0 9059 if (!dialog) {
michael@0 9060 return nullptr;
michael@0 9061 }
michael@0 9062
michael@0 9063 nsCOMPtr<nsIVariant> retVal;
michael@0 9064 aError = dialog->GetReturnValue(getter_AddRefs(retVal));
michael@0 9065 MOZ_ASSERT(!aError.Failed());
michael@0 9066
michael@0 9067 return retVal.forget();
michael@0 9068 }
michael@0 9069
michael@0 9070 void
michael@0 9071 nsGlobalWindow::ShowModalDialog(JSContext* aCx, const nsAString& aUrl,
michael@0 9072 JS::Handle<JS::Value> aArgument,
michael@0 9073 const nsAString& aOptions,
michael@0 9074 JS::MutableHandle<JS::Value> aRetval,
michael@0 9075 ErrorResult& aError)
michael@0 9076 {
michael@0 9077 nsCOMPtr<nsIVariant> args;
michael@0 9078 aError = nsContentUtils::XPConnect()->JSToVariant(aCx,
michael@0 9079 aArgument,
michael@0 9080 getter_AddRefs(args));
michael@0 9081
michael@0 9082 nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aUrl, args, aOptions, aError);
michael@0 9083 if (aError.Failed()) {
michael@0 9084 return;
michael@0 9085 }
michael@0 9086
michael@0 9087 JS::Rooted<JS::Value> result(aCx);
michael@0 9088 if (retVal) {
michael@0 9089 aError = nsContentUtils::XPConnect()->VariantToJS(aCx,
michael@0 9090 FastGetGlobalJSObject(),
michael@0 9091 retVal, aRetval);
michael@0 9092 } else {
michael@0 9093 aRetval.setNull();
michael@0 9094 }
michael@0 9095 }
michael@0 9096
michael@0 9097 NS_IMETHODIMP
michael@0 9098 nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs_,
michael@0 9099 const nsAString& aOptions, uint8_t aArgc,
michael@0 9100 nsIVariant **aRetVal)
michael@0 9101 {
michael@0 9102 // Per-spec the |arguments| parameter is supposed to pass through unmodified.
michael@0 9103 // However, XPConnect default-initializes variants to null, rather than
michael@0 9104 // undefined. Fix this up here.
michael@0 9105 nsCOMPtr<nsIVariant> aArgs = aArgs_;
michael@0 9106 if (aArgc < 1) {
michael@0 9107 aArgs = CreateVoidVariant();
michael@0 9108 }
michael@0 9109
michael@0 9110 ErrorResult rv;
michael@0 9111 nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aURI, aArgs, aOptions, rv);
michael@0 9112 retVal.forget(aRetVal);
michael@0 9113
michael@0 9114 return rv.ErrorCode();
michael@0 9115 }
michael@0 9116
michael@0 9117 class CommandDispatcher : public nsRunnable
michael@0 9118 {
michael@0 9119 public:
michael@0 9120 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
michael@0 9121 const nsAString& aAction)
michael@0 9122 : mDispatcher(aDispatcher), mAction(aAction) {}
michael@0 9123
michael@0 9124 NS_IMETHOD Run()
michael@0 9125 {
michael@0 9126 return mDispatcher->UpdateCommands(mAction);
michael@0 9127 }
michael@0 9128
michael@0 9129 nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
michael@0 9130 nsString mAction;
michael@0 9131 };
michael@0 9132
michael@0 9133 NS_IMETHODIMP
michael@0 9134 nsGlobalWindow::UpdateCommands(const nsAString& anAction)
michael@0 9135 {
michael@0 9136 nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
michael@0 9137 if (!rootWindow)
michael@0 9138 return NS_OK;
michael@0 9139
michael@0 9140 nsCOMPtr<nsIDOMXULDocument> xulDoc =
michael@0 9141 do_QueryInterface(rootWindow->GetExtantDoc());
michael@0 9142 // See if we contain a XUL document.
michael@0 9143 if (xulDoc) {
michael@0 9144 // Retrieve the command dispatcher and call updateCommands on it.
michael@0 9145 nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
michael@0 9146 xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
michael@0 9147 if (xulCommandDispatcher) {
michael@0 9148 nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
michael@0 9149 anAction));
michael@0 9150 }
michael@0 9151 }
michael@0 9152
michael@0 9153 return NS_OK;
michael@0 9154 }
michael@0 9155
michael@0 9156 Selection*
michael@0 9157 nsGlobalWindow::GetSelection(ErrorResult& aError)
michael@0 9158 {
michael@0 9159 FORWARD_TO_OUTER_OR_THROW(GetSelection, (aError), aError, nullptr);
michael@0 9160
michael@0 9161 if (!mDocShell) {
michael@0 9162 return nullptr;
michael@0 9163 }
michael@0 9164
michael@0 9165 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 9166 if (!presShell) {
michael@0 9167 return nullptr;
michael@0 9168 }
michael@0 9169
michael@0 9170 return static_cast<Selection*>(presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL));
michael@0 9171 }
michael@0 9172
michael@0 9173 NS_IMETHODIMP
michael@0 9174 nsGlobalWindow::GetSelection(nsISelection** aSelection)
michael@0 9175 {
michael@0 9176 ErrorResult rv;
michael@0 9177 nsCOMPtr<nsISelection> selection = GetSelection(rv);
michael@0 9178 selection.forget(aSelection);
michael@0 9179
michael@0 9180 return rv.ErrorCode();
michael@0 9181 }
michael@0 9182
michael@0 9183 bool
michael@0 9184 nsGlobalWindow::Find(const nsAString& aString, bool aCaseSensitive,
michael@0 9185 bool aBackwards, bool aWrapAround, bool aWholeWord,
michael@0 9186 bool aSearchInFrames, bool aShowDialog,
michael@0 9187 ErrorResult& aError)
michael@0 9188 {
michael@0 9189 if (Preferences::GetBool("dom.disable_window_find", false)) {
michael@0 9190 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 9191 return false;
michael@0 9192 }
michael@0 9193
michael@0 9194 FORWARD_TO_OUTER_OR_THROW(Find,
michael@0 9195 (aString, aCaseSensitive, aBackwards, aWrapAround,
michael@0 9196 aWholeWord, aSearchInFrames, aShowDialog, aError),
michael@0 9197 aError, false);
michael@0 9198
michael@0 9199 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
michael@0 9200 if (!finder) {
michael@0 9201 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 9202 return false;
michael@0 9203 }
michael@0 9204
michael@0 9205 // Set the options of the search
michael@0 9206 aError = finder->SetSearchString(PromiseFlatString(aString).get());
michael@0 9207 if (aError.Failed()) {
michael@0 9208 return false;
michael@0 9209 }
michael@0 9210 finder->SetMatchCase(aCaseSensitive);
michael@0 9211 finder->SetFindBackwards(aBackwards);
michael@0 9212 finder->SetWrapFind(aWrapAround);
michael@0 9213 finder->SetEntireWord(aWholeWord);
michael@0 9214 finder->SetSearchFrames(aSearchInFrames);
michael@0 9215
michael@0 9216 // the nsIWebBrowserFind is initialized to use this window
michael@0 9217 // as the search root, but uses focus to set the current search
michael@0 9218 // frame. If we're being called from JS (as here), this window
michael@0 9219 // should be the current search frame.
michael@0 9220 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
michael@0 9221 if (framesFinder) {
michael@0 9222 framesFinder->SetRootSearchFrame(this); // paranoia
michael@0 9223 framesFinder->SetCurrentSearchFrame(this);
michael@0 9224 }
michael@0 9225
michael@0 9226 // The Find API does not accept empty strings. Launch the Find Dialog.
michael@0 9227 if (aString.IsEmpty() || aShowDialog) {
michael@0 9228 // See if the find dialog is already up using nsIWindowMediator
michael@0 9229 nsCOMPtr<nsIWindowMediator> windowMediator =
michael@0 9230 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
michael@0 9231
michael@0 9232 nsCOMPtr<nsIDOMWindow> findDialog;
michael@0 9233
michael@0 9234 if (windowMediator) {
michael@0 9235 windowMediator->GetMostRecentWindow(MOZ_UTF16("findInPage"),
michael@0 9236 getter_AddRefs(findDialog));
michael@0 9237 }
michael@0 9238
michael@0 9239 if (findDialog) {
michael@0 9240 // The Find dialog is already open, bring it to the top.
michael@0 9241 aError = findDialog->Focus();
michael@0 9242 } else if (finder) {
michael@0 9243 // Open a Find dialog
michael@0 9244 nsCOMPtr<nsIDOMWindow> dialog;
michael@0 9245 aError = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
michael@0 9246 NS_LITERAL_STRING("_blank"),
michael@0 9247 NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
michael@0 9248 finder, getter_AddRefs(dialog));
michael@0 9249 }
michael@0 9250
michael@0 9251 return false;
michael@0 9252 }
michael@0 9253
michael@0 9254 // Launch the search with the passed in search string
michael@0 9255 bool didFind = false;
michael@0 9256 aError = finder->FindNext(&didFind);
michael@0 9257 return didFind;
michael@0 9258 }
michael@0 9259
michael@0 9260 NS_IMETHODIMP
michael@0 9261 nsGlobalWindow::Find(const nsAString& aStr, bool aCaseSensitive,
michael@0 9262 bool aBackwards, bool aWrapAround, bool aWholeWord,
michael@0 9263 bool aSearchInFrames, bool aShowDialog,
michael@0 9264 bool *aDidFind)
michael@0 9265 {
michael@0 9266 ErrorResult rv;
michael@0 9267 *aDidFind = Find(aStr, aCaseSensitive, aBackwards, aWrapAround, aWholeWord,
michael@0 9268 aSearchInFrames, aShowDialog, rv);
michael@0 9269
michael@0 9270 return rv.ErrorCode();
michael@0 9271 }
michael@0 9272
michael@0 9273 void
michael@0 9274 nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
michael@0 9275 nsAString& aBinaryData, ErrorResult& aError)
michael@0 9276 {
michael@0 9277 aError = nsContentUtils::Atob(aAsciiBase64String, aBinaryData);
michael@0 9278 }
michael@0 9279
michael@0 9280 NS_IMETHODIMP
michael@0 9281 nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
michael@0 9282 nsAString& aBinaryData)
michael@0 9283 {
michael@0 9284 ErrorResult rv;
michael@0 9285 Atob(aAsciiBase64String, aBinaryData, rv);
michael@0 9286
michael@0 9287 return rv.ErrorCode();
michael@0 9288 }
michael@0 9289
michael@0 9290 void
michael@0 9291 nsGlobalWindow::Btoa(const nsAString& aBinaryData,
michael@0 9292 nsAString& aAsciiBase64String, ErrorResult& aError)
michael@0 9293 {
michael@0 9294 aError = nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
michael@0 9295 }
michael@0 9296
michael@0 9297 NS_IMETHODIMP
michael@0 9298 nsGlobalWindow::Btoa(const nsAString& aBinaryData,
michael@0 9299 nsAString& aAsciiBase64String)
michael@0 9300 {
michael@0 9301 ErrorResult rv;
michael@0 9302 Btoa(aBinaryData, aAsciiBase64String, rv);
michael@0 9303
michael@0 9304 return rv.ErrorCode();
michael@0 9305 }
michael@0 9306
michael@0 9307 //*****************************************************************************
michael@0 9308 // nsGlobalWindow::nsIDOMEventTarget
michael@0 9309 //*****************************************************************************
michael@0 9310
michael@0 9311 NS_IMETHODIMP
michael@0 9312 nsGlobalWindow::RemoveEventListener(const nsAString& aType,
michael@0 9313 nsIDOMEventListener* aListener,
michael@0 9314 bool aUseCapture)
michael@0 9315 {
michael@0 9316 if (nsRefPtr<EventListenerManager> elm = GetExistingListenerManager()) {
michael@0 9317 elm->RemoveEventListener(aType, aListener, aUseCapture);
michael@0 9318 }
michael@0 9319 return NS_OK;
michael@0 9320 }
michael@0 9321
michael@0 9322 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)
michael@0 9323
michael@0 9324 NS_IMETHODIMP
michael@0 9325 nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
michael@0 9326 {
michael@0 9327 FORWARD_TO_INNER(DispatchEvent, (aEvent, aRetVal), NS_OK);
michael@0 9328
michael@0 9329 if (!IsCurrentInnerWindow()) {
michael@0 9330 NS_WARNING("DispatchEvent called on non-current inner window, dropping. "
michael@0 9331 "Please check the window in the caller instead.");
michael@0 9332 return NS_ERROR_FAILURE;
michael@0 9333 }
michael@0 9334
michael@0 9335 if (!mDoc) {
michael@0 9336 return NS_ERROR_FAILURE;
michael@0 9337 }
michael@0 9338
michael@0 9339 // Obtain a presentation shell
michael@0 9340 nsIPresShell *shell = mDoc->GetShell();
michael@0 9341 nsRefPtr<nsPresContext> presContext;
michael@0 9342 if (shell) {
michael@0 9343 // Retrieve the context
michael@0 9344 presContext = shell->GetPresContext();
michael@0 9345 }
michael@0 9346
michael@0 9347 nsEventStatus status = nsEventStatus_eIgnore;
michael@0 9348 nsresult rv =
michael@0 9349 EventDispatcher::DispatchDOMEvent(GetOuterWindow(), nullptr, aEvent,
michael@0 9350 presContext, &status);
michael@0 9351
michael@0 9352 *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
michael@0 9353 return rv;
michael@0 9354 }
michael@0 9355
michael@0 9356 NS_IMETHODIMP
michael@0 9357 nsGlobalWindow::AddEventListener(const nsAString& aType,
michael@0 9358 nsIDOMEventListener *aListener,
michael@0 9359 bool aUseCapture, bool aWantsUntrusted,
michael@0 9360 uint8_t aOptionalArgc)
michael@0 9361 {
michael@0 9362 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
michael@0 9363 "Won't check if this is chrome, you want to set "
michael@0 9364 "aWantsUntrusted to false or make the aWantsUntrusted "
michael@0 9365 "explicit by making optional_argc non-zero.");
michael@0 9366
michael@0 9367 if (IsOuterWindow() && mInnerWindow &&
michael@0 9368 !nsContentUtils::CanCallerAccess(mInnerWindow)) {
michael@0 9369 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 9370 }
michael@0 9371
michael@0 9372 if (!aWantsUntrusted &&
michael@0 9373 (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
michael@0 9374 aWantsUntrusted = true;
michael@0 9375 }
michael@0 9376
michael@0 9377 EventListenerManager* manager = GetOrCreateListenerManager();
michael@0 9378 NS_ENSURE_STATE(manager);
michael@0 9379 manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
michael@0 9380 return NS_OK;
michael@0 9381 }
michael@0 9382
michael@0 9383 void
michael@0 9384 nsGlobalWindow::AddEventListener(const nsAString& aType,
michael@0 9385 EventListener* aListener,
michael@0 9386 bool aUseCapture,
michael@0 9387 const Nullable<bool>& aWantsUntrusted,
michael@0 9388 ErrorResult& aRv)
michael@0 9389 {
michael@0 9390 if (IsOuterWindow() && mInnerWindow &&
michael@0 9391 !nsContentUtils::CanCallerAccess(mInnerWindow)) {
michael@0 9392 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
michael@0 9393 return;
michael@0 9394 }
michael@0 9395
michael@0 9396 bool wantsUntrusted;
michael@0 9397 if (aWantsUntrusted.IsNull()) {
michael@0 9398 wantsUntrusted = !nsContentUtils::IsChromeDoc(mDoc);
michael@0 9399 } else {
michael@0 9400 wantsUntrusted = aWantsUntrusted.Value();
michael@0 9401 }
michael@0 9402
michael@0 9403 EventListenerManager* manager = GetOrCreateListenerManager();
michael@0 9404 if (!manager) {
michael@0 9405 aRv.Throw(NS_ERROR_UNEXPECTED);
michael@0 9406 return;
michael@0 9407 }
michael@0 9408 manager->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
michael@0 9409 }
michael@0 9410
michael@0 9411 NS_IMETHODIMP
michael@0 9412 nsGlobalWindow::AddSystemEventListener(const nsAString& aType,
michael@0 9413 nsIDOMEventListener *aListener,
michael@0 9414 bool aUseCapture,
michael@0 9415 bool aWantsUntrusted,
michael@0 9416 uint8_t aOptionalArgc)
michael@0 9417 {
michael@0 9418 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
michael@0 9419 "Won't check if this is chrome, you want to set "
michael@0 9420 "aWantsUntrusted to false or make the aWantsUntrusted "
michael@0 9421 "explicit by making optional_argc non-zero.");
michael@0 9422
michael@0 9423 if (IsOuterWindow() && mInnerWindow &&
michael@0 9424 !nsContentUtils::CanCallerAccess(mInnerWindow)) {
michael@0 9425 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 9426 }
michael@0 9427
michael@0 9428 if (!aWantsUntrusted &&
michael@0 9429 (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
michael@0 9430 aWantsUntrusted = true;
michael@0 9431 }
michael@0 9432
michael@0 9433 return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
michael@0 9434 aWantsUntrusted);
michael@0 9435 }
michael@0 9436
michael@0 9437 EventListenerManager*
michael@0 9438 nsGlobalWindow::GetOrCreateListenerManager()
michael@0 9439 {
michael@0 9440 FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager, (), nullptr);
michael@0 9441
michael@0 9442 if (!mListenerManager) {
michael@0 9443 mListenerManager =
michael@0 9444 new EventListenerManager(static_cast<EventTarget*>(this));
michael@0 9445 }
michael@0 9446
michael@0 9447 return mListenerManager;
michael@0 9448 }
michael@0 9449
michael@0 9450 EventListenerManager*
michael@0 9451 nsGlobalWindow::GetExistingListenerManager() const
michael@0 9452 {
michael@0 9453 FORWARD_TO_INNER(GetExistingListenerManager, (), nullptr);
michael@0 9454
michael@0 9455 return mListenerManager;
michael@0 9456 }
michael@0 9457
michael@0 9458 nsIScriptContext*
michael@0 9459 nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
michael@0 9460 {
michael@0 9461 *aRv = NS_ERROR_UNEXPECTED;
michael@0 9462 NS_ENSURE_TRUE(!IsInnerWindow() || IsCurrentInnerWindow(), nullptr);
michael@0 9463
michael@0 9464 nsIScriptContext* scx;
michael@0 9465 if ((scx = GetContext())) {
michael@0 9466 *aRv = NS_OK;
michael@0 9467 return scx;
michael@0 9468 }
michael@0 9469 return nullptr;
michael@0 9470 }
michael@0 9471
michael@0 9472 //*****************************************************************************
michael@0 9473 // nsGlobalWindow::nsPIDOMWindow
michael@0 9474 //*****************************************************************************
michael@0 9475
michael@0 9476 nsPIDOMWindow*
michael@0 9477 nsGlobalWindow::GetPrivateParent()
michael@0 9478 {
michael@0 9479 MOZ_ASSERT(IsOuterWindow());
michael@0 9480
michael@0 9481 nsCOMPtr<nsIDOMWindow> parent;
michael@0 9482 GetParent(getter_AddRefs(parent));
michael@0 9483
michael@0 9484 if (static_cast<nsIDOMWindow *>(this) == parent.get()) {
michael@0 9485 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
michael@0 9486 if (!chromeElement)
michael@0 9487 return nullptr; // This is ok, just means a null parent.
michael@0 9488
michael@0 9489 nsIDocument* doc = chromeElement->GetDocument();
michael@0 9490 if (!doc)
michael@0 9491 return nullptr; // This is ok, just means a null parent.
michael@0 9492
michael@0 9493 return doc->GetWindow();
michael@0 9494 }
michael@0 9495
michael@0 9496 if (parent) {
michael@0 9497 return static_cast<nsGlobalWindow *>
michael@0 9498 (static_cast<nsIDOMWindow*>(parent.get()));
michael@0 9499 }
michael@0 9500
michael@0 9501 return nullptr;
michael@0 9502 }
michael@0 9503
michael@0 9504 nsPIDOMWindow*
michael@0 9505 nsGlobalWindow::GetPrivateRoot()
michael@0 9506 {
michael@0 9507 if (IsInnerWindow()) {
michael@0 9508 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 9509 if (!outer) {
michael@0 9510 NS_WARNING("No outer window available!");
michael@0 9511 return nullptr;
michael@0 9512 }
michael@0 9513 return outer->GetPrivateRoot();
michael@0 9514 }
michael@0 9515
michael@0 9516 nsCOMPtr<nsIDOMWindow> top;
michael@0 9517 GetTop(getter_AddRefs(top));
michael@0 9518
michael@0 9519 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
michael@0 9520 if (chromeElement) {
michael@0 9521 nsIDocument* doc = chromeElement->GetDocument();
michael@0 9522 if (doc) {
michael@0 9523 nsIDOMWindow *parent = doc->GetWindow();
michael@0 9524 if (parent) {
michael@0 9525 parent->GetTop(getter_AddRefs(top));
michael@0 9526 }
michael@0 9527 }
michael@0 9528 }
michael@0 9529
michael@0 9530 return static_cast<nsGlobalWindow*>(top.get());
michael@0 9531 }
michael@0 9532
michael@0 9533
michael@0 9534 nsIDOMLocation*
michael@0 9535 nsGlobalWindow::GetLocation(ErrorResult& aError)
michael@0 9536 {
michael@0 9537 FORWARD_TO_INNER_OR_THROW(GetLocation, (aError), aError, nullptr);
michael@0 9538
michael@0 9539 nsIDocShell *docShell = GetDocShell();
michael@0 9540 if (!mLocation && docShell) {
michael@0 9541 mLocation = new nsLocation(docShell);
michael@0 9542 }
michael@0 9543 return mLocation;
michael@0 9544 }
michael@0 9545
michael@0 9546 NS_IMETHODIMP
michael@0 9547 nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
michael@0 9548 {
michael@0 9549 ErrorResult rv;
michael@0 9550 nsCOMPtr<nsIDOMLocation> location = GetLocation(rv);
michael@0 9551 location.forget(aLocation);
michael@0 9552
michael@0 9553 return rv.ErrorCode();
michael@0 9554 }
michael@0 9555
michael@0 9556 void
michael@0 9557 nsGlobalWindow::ActivateOrDeactivate(bool aActivate)
michael@0 9558 {
michael@0 9559 MOZ_ASSERT(IsOuterWindow());
michael@0 9560
michael@0 9561 // Set / unset mIsActive on the top level window, which is used for the
michael@0 9562 // :-moz-window-inactive pseudoclass, and its sheet (if any).
michael@0 9563 nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
michael@0 9564 if (!mainWidget)
michael@0 9565 return;
michael@0 9566
michael@0 9567 // Get the top level widget (if the main widget is a sheet, this will
michael@0 9568 // be the sheet's top (non-sheet) parent).
michael@0 9569 nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
michael@0 9570 if (!topLevelWidget) {
michael@0 9571 topLevelWidget = mainWidget;
michael@0 9572 }
michael@0 9573
michael@0 9574 nsCOMPtr<nsPIDOMWindow> piMainWindow(
michael@0 9575 do_QueryInterface(static_cast<nsIDOMWindow*>(this)));
michael@0 9576 piMainWindow->SetActive(aActivate);
michael@0 9577
michael@0 9578 if (mainWidget != topLevelWidget) {
michael@0 9579 // This is a workaround for the following problem:
michael@0 9580 // When a window with an open sheet gains or loses focus, only the sheet
michael@0 9581 // window receives the NS_ACTIVATE/NS_DEACTIVATE event. However the
michael@0 9582 // styling of the containing top level window also needs to change. We
michael@0 9583 // get around this by calling nsPIDOMWindow::SetActive() on both windows.
michael@0 9584
michael@0 9585 // Get the top level widget's nsGlobalWindow
michael@0 9586 nsCOMPtr<nsIDOMWindow> topLevelWindow;
michael@0 9587
michael@0 9588 // widgetListener should be a nsXULWindow
michael@0 9589 nsIWidgetListener* listener = topLevelWidget->GetWidgetListener();
michael@0 9590 if (listener) {
michael@0 9591 nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
michael@0 9592 nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
michael@0 9593 topLevelWindow = do_GetInterface(req);
michael@0 9594 }
michael@0 9595
michael@0 9596 if (topLevelWindow) {
michael@0 9597 nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
michael@0 9598 piWin->SetActive(aActivate);
michael@0 9599 }
michael@0 9600 }
michael@0 9601 }
michael@0 9602
michael@0 9603 static bool
michael@0 9604 NotifyDocumentTree(nsIDocument* aDocument, void* aData)
michael@0 9605 {
michael@0 9606 aDocument->EnumerateSubDocuments(NotifyDocumentTree, nullptr);
michael@0 9607 aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
michael@0 9608 return true;
michael@0 9609 }
michael@0 9610
michael@0 9611 void
michael@0 9612 nsGlobalWindow::SetActive(bool aActive)
michael@0 9613 {
michael@0 9614 nsPIDOMWindow::SetActive(aActive);
michael@0 9615 NotifyDocumentTree(mDoc, nullptr);
michael@0 9616 }
michael@0 9617
michael@0 9618 void nsGlobalWindow::SetIsBackground(bool aIsBackground)
michael@0 9619 {
michael@0 9620 MOZ_ASSERT(IsOuterWindow());
michael@0 9621
michael@0 9622 bool resetTimers = (!aIsBackground && IsBackground());
michael@0 9623 nsPIDOMWindow::SetIsBackground(aIsBackground);
michael@0 9624 if (resetTimers) {
michael@0 9625 ResetTimersForNonBackgroundWindow();
michael@0 9626 }
michael@0 9627 #ifdef MOZ_GAMEPAD
michael@0 9628 if (!aIsBackground) {
michael@0 9629 nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
michael@0 9630 if (inner) {
michael@0 9631 inner->SyncGamepadState();
michael@0 9632 }
michael@0 9633 }
michael@0 9634 #endif
michael@0 9635 }
michael@0 9636
michael@0 9637 void nsGlobalWindow::MaybeUpdateTouchState()
michael@0 9638 {
michael@0 9639 FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
michael@0 9640
michael@0 9641 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
michael@0 9642
michael@0 9643 nsCOMPtr<nsIDOMWindow> focusedWindow;
michael@0 9644 fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
michael@0 9645
michael@0 9646 if(this == focusedWindow) {
michael@0 9647 UpdateTouchState();
michael@0 9648 }
michael@0 9649
michael@0 9650 if (mMayHaveTouchEventListener) {
michael@0 9651 nsCOMPtr<nsIObserverService> observerService =
michael@0 9652 services::GetObserverService();
michael@0 9653
michael@0 9654 if (observerService) {
michael@0 9655 observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
michael@0 9656 DOM_TOUCH_LISTENER_ADDED,
michael@0 9657 nullptr);
michael@0 9658 }
michael@0 9659 }
michael@0 9660 }
michael@0 9661
michael@0 9662 void nsGlobalWindow::UpdateTouchState()
michael@0 9663 {
michael@0 9664 FORWARD_TO_INNER_VOID(UpdateTouchState, ());
michael@0 9665
michael@0 9666 nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
michael@0 9667 if (!mainWidget) {
michael@0 9668 return;
michael@0 9669 }
michael@0 9670
michael@0 9671 if (mMayHaveTouchEventListener) {
michael@0 9672 mainWidget->RegisterTouchWindow();
michael@0 9673 } else {
michael@0 9674 mainWidget->UnregisterTouchWindow();
michael@0 9675 }
michael@0 9676 }
michael@0 9677
michael@0 9678 void
michael@0 9679 nsGlobalWindow::EnableGamepadUpdates()
michael@0 9680 {
michael@0 9681 FORWARD_TO_INNER_VOID(EnableGamepadUpdates, ());
michael@0 9682 if (mHasGamepad) {
michael@0 9683 #ifdef MOZ_GAMEPAD
michael@0 9684 nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
michael@0 9685 if (gamepadsvc) {
michael@0 9686 gamepadsvc->AddListener(this);
michael@0 9687 }
michael@0 9688 #endif
michael@0 9689 }
michael@0 9690 }
michael@0 9691
michael@0 9692 void
michael@0 9693 nsGlobalWindow::DisableGamepadUpdates()
michael@0 9694 {
michael@0 9695 FORWARD_TO_INNER_VOID(DisableGamepadUpdates, ());
michael@0 9696 if (mHasGamepad) {
michael@0 9697 #ifdef MOZ_GAMEPAD
michael@0 9698 nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
michael@0 9699 if (gamepadsvc) {
michael@0 9700 gamepadsvc->RemoveListener(this);
michael@0 9701 }
michael@0 9702 #endif
michael@0 9703 }
michael@0 9704 }
michael@0 9705
michael@0 9706 void
michael@0 9707 nsGlobalWindow::SetChromeEventHandler(EventTarget* aChromeEventHandler)
michael@0 9708 {
michael@0 9709 MOZ_ASSERT(IsOuterWindow());
michael@0 9710
michael@0 9711 SetChromeEventHandlerInternal(aChromeEventHandler);
michael@0 9712 // update the chrome event handler on all our inner windows
michael@0 9713 for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
michael@0 9714 inner != this;
michael@0 9715 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
michael@0 9716 NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
michael@0 9717 "bad outer window pointer");
michael@0 9718 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
michael@0 9719 }
michael@0 9720 }
michael@0 9721
michael@0 9722 static bool IsLink(nsIContent* aContent)
michael@0 9723 {
michael@0 9724 return aContent && (aContent->IsHTML(nsGkAtoms::a) ||
michael@0 9725 aContent->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
michael@0 9726 nsGkAtoms::simple, eCaseMatters));
michael@0 9727 }
michael@0 9728
michael@0 9729 void
michael@0 9730 nsGlobalWindow::SetFocusedNode(nsIContent* aNode,
michael@0 9731 uint32_t aFocusMethod,
michael@0 9732 bool aNeedsFocus)
michael@0 9733 {
michael@0 9734 FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
michael@0 9735
michael@0 9736 if (aNode && aNode->GetCurrentDoc() != mDoc) {
michael@0 9737 NS_WARNING("Trying to set focus to a node from a wrong document");
michael@0 9738 return;
michael@0 9739 }
michael@0 9740
michael@0 9741 if (mCleanedUp) {
michael@0 9742 NS_ASSERTION(!aNode, "Trying to focus cleaned up window!");
michael@0 9743 aNode = nullptr;
michael@0 9744 aNeedsFocus = false;
michael@0 9745 }
michael@0 9746 if (mFocusedNode != aNode) {
michael@0 9747 UpdateCanvasFocus(false, aNode);
michael@0 9748 mFocusedNode = aNode;
michael@0 9749 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
michael@0 9750 mShowFocusRingForContent = false;
michael@0 9751 }
michael@0 9752
michael@0 9753 if (mFocusedNode) {
michael@0 9754 // if a node was focused by a keypress, turn on focus rings for the
michael@0 9755 // window.
michael@0 9756 if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
michael@0 9757 mFocusByKeyOccurred = true;
michael@0 9758 } else if (
michael@0 9759 // otherwise, we set mShowFocusRingForContent, as we don't want this to
michael@0 9760 // be permanent for the window. On Windows, focus rings are only shown
michael@0 9761 // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
michael@0 9762 // are only hidden for clicks on links.
michael@0 9763 #ifndef XP_WIN
michael@0 9764 !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) || !IsLink(aNode) ||
michael@0 9765 #endif
michael@0 9766 aFocusMethod & nsIFocusManager::FLAG_SHOWRING) {
michael@0 9767 mShowFocusRingForContent = true;
michael@0 9768 }
michael@0 9769 }
michael@0 9770
michael@0 9771 if (aNeedsFocus)
michael@0 9772 mNeedsFocus = aNeedsFocus;
michael@0 9773 }
michael@0 9774
michael@0 9775 uint32_t
michael@0 9776 nsGlobalWindow::GetFocusMethod()
michael@0 9777 {
michael@0 9778 FORWARD_TO_INNER(GetFocusMethod, (), 0);
michael@0 9779
michael@0 9780 return mFocusMethod;
michael@0 9781 }
michael@0 9782
michael@0 9783 bool
michael@0 9784 nsGlobalWindow::ShouldShowFocusRing()
michael@0 9785 {
michael@0 9786 FORWARD_TO_INNER(ShouldShowFocusRing, (), false);
michael@0 9787
michael@0 9788 return mShowFocusRings || mShowFocusRingForContent || mFocusByKeyOccurred;
michael@0 9789 }
michael@0 9790
michael@0 9791 void
michael@0 9792 nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
michael@0 9793 UIStateChangeType aShowFocusRings)
michael@0 9794 {
michael@0 9795 FORWARD_TO_INNER_VOID(SetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
michael@0 9796
michael@0 9797 bool oldShouldShowFocusRing = ShouldShowFocusRing();
michael@0 9798
michael@0 9799 // only change the flags that have been modified
michael@0 9800 if (aShowAccelerators != UIStateChangeType_NoChange)
michael@0 9801 mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
michael@0 9802 if (aShowFocusRings != UIStateChangeType_NoChange)
michael@0 9803 mShowFocusRings = aShowFocusRings == UIStateChangeType_Set;
michael@0 9804
michael@0 9805 // propagate the indicators to child windows
michael@0 9806 nsCOMPtr<nsIDocShell> docShell = GetDocShell();
michael@0 9807 if (docShell) {
michael@0 9808 int32_t childCount = 0;
michael@0 9809 docShell->GetChildCount(&childCount);
michael@0 9810
michael@0 9811 for (int32_t i = 0; i < childCount; ++i) {
michael@0 9812 nsCOMPtr<nsIDocShellTreeItem> childShell;
michael@0 9813 docShell->GetChildAt(i, getter_AddRefs(childShell));
michael@0 9814 nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(childShell);
michael@0 9815 if (childWindow) {
michael@0 9816 childWindow->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
michael@0 9817 }
michael@0 9818 }
michael@0 9819 }
michael@0 9820
michael@0 9821 bool newShouldShowFocusRing = ShouldShowFocusRing();
michael@0 9822 if (mHasFocus && mFocusedNode &&
michael@0 9823 oldShouldShowFocusRing != newShouldShowFocusRing &&
michael@0 9824 mFocusedNode->IsElement()) {
michael@0 9825 // Update mFocusedNode's state.
michael@0 9826 if (newShouldShowFocusRing) {
michael@0 9827 mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);
michael@0 9828 } else {
michael@0 9829 mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);
michael@0 9830 }
michael@0 9831 }
michael@0 9832 }
michael@0 9833
michael@0 9834 void
michael@0 9835 nsGlobalWindow::GetKeyboardIndicators(bool* aShowAccelerators,
michael@0 9836 bool* aShowFocusRings)
michael@0 9837 {
michael@0 9838 FORWARD_TO_INNER_VOID(GetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
michael@0 9839
michael@0 9840 *aShowAccelerators = mShowAccelerators;
michael@0 9841 *aShowFocusRings = mShowFocusRings;
michael@0 9842 }
michael@0 9843
michael@0 9844 bool
michael@0 9845 nsGlobalWindow::TakeFocus(bool aFocus, uint32_t aFocusMethod)
michael@0 9846 {
michael@0 9847 FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false);
michael@0 9848
michael@0 9849 if (mCleanedUp) {
michael@0 9850 return false;
michael@0 9851 }
michael@0 9852
michael@0 9853 if (aFocus)
michael@0 9854 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
michael@0 9855
michael@0 9856 if (mHasFocus != aFocus) {
michael@0 9857 mHasFocus = aFocus;
michael@0 9858 UpdateCanvasFocus(true, mFocusedNode);
michael@0 9859 }
michael@0 9860
michael@0 9861 // if mNeedsFocus is true, then the document has not yet received a
michael@0 9862 // document-level focus event. If there is a root content node, then return
michael@0 9863 // true to tell the calling focus manager that a focus event is expected. If
michael@0 9864 // there is no root content node, the document hasn't loaded enough yet, or
michael@0 9865 // there isn't one and there is no point in firing a focus event.
michael@0 9866 if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nullptr) {
michael@0 9867 mNeedsFocus = false;
michael@0 9868 return true;
michael@0 9869 }
michael@0 9870
michael@0 9871 mNeedsFocus = false;
michael@0 9872 return false;
michael@0 9873 }
michael@0 9874
michael@0 9875 void
michael@0 9876 nsGlobalWindow::SetReadyForFocus()
michael@0 9877 {
michael@0 9878 FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
michael@0 9879
michael@0 9880 bool oldNeedsFocus = mNeedsFocus;
michael@0 9881 mNeedsFocus = false;
michael@0 9882
michael@0 9883 // update whether focus rings need to be shown using the state from the
michael@0 9884 // root window
michael@0 9885 nsPIDOMWindow* root = GetPrivateRoot();
michael@0 9886 if (root) {
michael@0 9887 bool showAccelerators, showFocusRings;
michael@0 9888 root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
michael@0 9889 mShowFocusRings = showFocusRings;
michael@0 9890 }
michael@0 9891
michael@0 9892 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
michael@0 9893 if (fm)
michael@0 9894 fm->WindowShown(this, oldNeedsFocus);
michael@0 9895 }
michael@0 9896
michael@0 9897 void
michael@0 9898 nsGlobalWindow::PageHidden()
michael@0 9899 {
michael@0 9900 FORWARD_TO_INNER_VOID(PageHidden, ());
michael@0 9901
michael@0 9902 // the window is being hidden, so tell the focus manager that the frame is
michael@0 9903 // no longer valid. Use the persisted field to determine if the document
michael@0 9904 // is being destroyed.
michael@0 9905
michael@0 9906 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
michael@0 9907 if (fm)
michael@0 9908 fm->WindowHidden(this);
michael@0 9909
michael@0 9910 mNeedsFocus = true;
michael@0 9911 }
michael@0 9912
michael@0 9913 class HashchangeCallback : public nsRunnable
michael@0 9914 {
michael@0 9915 public:
michael@0 9916 HashchangeCallback(const nsAString &aOldURL,
michael@0 9917 const nsAString &aNewURL,
michael@0 9918 nsGlobalWindow* aWindow)
michael@0 9919 : mWindow(aWindow)
michael@0 9920 {
michael@0 9921 MOZ_ASSERT(mWindow);
michael@0 9922 MOZ_ASSERT(mWindow->IsInnerWindow());
michael@0 9923 mOldURL.Assign(aOldURL);
michael@0 9924 mNewURL.Assign(aNewURL);
michael@0 9925 }
michael@0 9926
michael@0 9927 NS_IMETHOD Run()
michael@0 9928 {
michael@0 9929 NS_PRECONDITION(NS_IsMainThread(), "Should be called on the main thread.");
michael@0 9930 return mWindow->FireHashchange(mOldURL, mNewURL);
michael@0 9931 }
michael@0 9932
michael@0 9933 private:
michael@0 9934 nsString mOldURL;
michael@0 9935 nsString mNewURL;
michael@0 9936 nsRefPtr<nsGlobalWindow> mWindow;
michael@0 9937 };
michael@0 9938
michael@0 9939 nsresult
michael@0 9940 nsGlobalWindow::DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI)
michael@0 9941 {
michael@0 9942 FORWARD_TO_INNER(DispatchAsyncHashchange, (aOldURI, aNewURI), NS_OK);
michael@0 9943
michael@0 9944 // Make sure that aOldURI and aNewURI are identical up to the '#', and that
michael@0 9945 // their hashes are different.
michael@0 9946 nsAutoCString oldBeforeHash, oldHash, newBeforeHash, newHash;
michael@0 9947 nsContentUtils::SplitURIAtHash(aOldURI, oldBeforeHash, oldHash);
michael@0 9948 nsContentUtils::SplitURIAtHash(aNewURI, newBeforeHash, newHash);
michael@0 9949
michael@0 9950 NS_ENSURE_STATE(oldBeforeHash.Equals(newBeforeHash));
michael@0 9951 NS_ENSURE_STATE(!oldHash.Equals(newHash));
michael@0 9952
michael@0 9953 nsAutoCString oldSpec, newSpec;
michael@0 9954 aOldURI->GetSpec(oldSpec);
michael@0 9955 aNewURI->GetSpec(newSpec);
michael@0 9956
michael@0 9957 NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
michael@0 9958 NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
michael@0 9959
michael@0 9960 nsCOMPtr<nsIRunnable> callback =
michael@0 9961 new HashchangeCallback(oldWideSpec, newWideSpec, this);
michael@0 9962 return NS_DispatchToMainThread(callback);
michael@0 9963 }
michael@0 9964
michael@0 9965 nsresult
michael@0 9966 nsGlobalWindow::FireHashchange(const nsAString &aOldURL,
michael@0 9967 const nsAString &aNewURL)
michael@0 9968 {
michael@0 9969 MOZ_ASSERT(IsInnerWindow());
michael@0 9970
michael@0 9971 // Don't do anything if the window is frozen.
michael@0 9972 if (IsFrozen())
michael@0 9973 return NS_OK;
michael@0 9974
michael@0 9975 // Get a presentation shell for use in creating the hashchange event.
michael@0 9976 NS_ENSURE_STATE(IsCurrentInnerWindow());
michael@0 9977
michael@0 9978 nsIPresShell *shell = mDoc->GetShell();
michael@0 9979 nsRefPtr<nsPresContext> presContext;
michael@0 9980 if (shell) {
michael@0 9981 presContext = shell->GetPresContext();
michael@0 9982 }
michael@0 9983
michael@0 9984 // Create a new hashchange event.
michael@0 9985 nsCOMPtr<nsIDOMEvent> domEvent;
michael@0 9986 nsresult rv =
michael@0 9987 EventDispatcher::CreateEvent(this, presContext, nullptr,
michael@0 9988 NS_LITERAL_STRING("hashchangeevent"),
michael@0 9989 getter_AddRefs(domEvent));
michael@0 9990 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9991
michael@0 9992 nsCOMPtr<nsIDOMHashChangeEvent> hashchangeEvent = do_QueryInterface(domEvent);
michael@0 9993 NS_ENSURE_TRUE(hashchangeEvent, NS_ERROR_UNEXPECTED);
michael@0 9994
michael@0 9995 // The hashchange event bubbles and isn't cancellable.
michael@0 9996 rv = hashchangeEvent->InitHashChangeEvent(NS_LITERAL_STRING("hashchange"),
michael@0 9997 true, false,
michael@0 9998 aOldURL, aNewURL);
michael@0 9999 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10000
michael@0 10001 domEvent->SetTrusted(true);
michael@0 10002
michael@0 10003 bool dummy;
michael@0 10004 return DispatchEvent(hashchangeEvent, &dummy);
michael@0 10005 }
michael@0 10006
michael@0 10007 nsresult
michael@0 10008 nsGlobalWindow::DispatchSyncPopState()
michael@0 10009 {
michael@0 10010 FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK);
michael@0 10011
michael@0 10012 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
michael@0 10013 "Must be safe to run script here.");
michael@0 10014
michael@0 10015 // Check that PopState hasn't been pref'ed off.
michael@0 10016 if (!Preferences::GetBool(sPopStatePrefStr, false)) {
michael@0 10017 return NS_OK;
michael@0 10018 }
michael@0 10019
michael@0 10020 nsresult rv = NS_OK;
michael@0 10021
michael@0 10022 // Bail if the window is frozen.
michael@0 10023 if (IsFrozen()) {
michael@0 10024 return NS_OK;
michael@0 10025 }
michael@0 10026
michael@0 10027 // Get the document's pending state object -- it contains the data we're
michael@0 10028 // going to send along with the popstate event. The object is serialized
michael@0 10029 // using structured clone.
michael@0 10030 nsCOMPtr<nsIVariant> stateObj;
michael@0 10031 rv = mDoc->GetStateObject(getter_AddRefs(stateObj));
michael@0 10032 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10033
michael@0 10034 // Obtain a presentation shell for use in creating a popstate event.
michael@0 10035 nsIPresShell *shell = mDoc->GetShell();
michael@0 10036 nsRefPtr<nsPresContext> presContext;
michael@0 10037 if (shell) {
michael@0 10038 presContext = shell->GetPresContext();
michael@0 10039 }
michael@0 10040
michael@0 10041 // Create a new popstate event
michael@0 10042 nsCOMPtr<nsIDOMEvent> domEvent;
michael@0 10043 rv = EventDispatcher::CreateEvent(this, presContext, nullptr,
michael@0 10044 NS_LITERAL_STRING("popstateevent"),
michael@0 10045 getter_AddRefs(domEvent));
michael@0 10046 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10047
michael@0 10048 // Initialize the popstate event, which does bubble but isn't cancellable.
michael@0 10049 nsCOMPtr<nsIDOMPopStateEvent> popstateEvent = do_QueryInterface(domEvent);
michael@0 10050 rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"),
michael@0 10051 true, false,
michael@0 10052 stateObj);
michael@0 10053 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10054
michael@0 10055 domEvent->SetTrusted(true);
michael@0 10056
michael@0 10057 nsCOMPtr<EventTarget> outerWindow =
michael@0 10058 do_QueryInterface(GetOuterWindow());
michael@0 10059 NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
michael@0 10060
michael@0 10061 rv = domEvent->SetTarget(outerWindow);
michael@0 10062 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10063
michael@0 10064 bool dummy; // default action
michael@0 10065 return DispatchEvent(popstateEvent, &dummy);
michael@0 10066 }
michael@0 10067
michael@0 10068 // Find an nsICanvasFrame under aFrame. Only search the principal
michael@0 10069 // child lists. aFrame must be non-null.
michael@0 10070 static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
michael@0 10071 {
michael@0 10072 nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
michael@0 10073 if (canvasFrame) {
michael@0 10074 return canvasFrame;
michael@0 10075 }
michael@0 10076
michael@0 10077 nsIFrame* kid = aFrame->GetFirstPrincipalChild();
michael@0 10078 while (kid) {
michael@0 10079 canvasFrame = FindCanvasFrame(kid);
michael@0 10080 if (canvasFrame) {
michael@0 10081 return canvasFrame;
michael@0 10082 }
michael@0 10083 kid = kid->GetNextSibling();
michael@0 10084 }
michael@0 10085
michael@0 10086 return nullptr;
michael@0 10087 }
michael@0 10088
michael@0 10089 //-------------------------------------------------------
michael@0 10090 // Tells the HTMLFrame/CanvasFrame that is now has focus
michael@0 10091 void
michael@0 10092 nsGlobalWindow::UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent)
michael@0 10093 {
michael@0 10094 MOZ_ASSERT(IsInnerWindow());
michael@0 10095
michael@0 10096 // this is called from the inner window so use GetDocShell
michael@0 10097 nsIDocShell* docShell = GetDocShell();
michael@0 10098 if (!docShell)
michael@0 10099 return;
michael@0 10100
michael@0 10101 bool editable;
michael@0 10102 docShell->GetEditable(&editable);
michael@0 10103 if (editable)
michael@0 10104 return;
michael@0 10105
michael@0 10106 nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
michael@0 10107 if (!presShell || !mDoc)
michael@0 10108 return;
michael@0 10109
michael@0 10110 Element *rootElement = mDoc->GetRootElement();
michael@0 10111 if (rootElement) {
michael@0 10112 if ((mHasFocus || aFocusChanged) &&
michael@0 10113 (mFocusedNode == rootElement || aNewContent == rootElement)) {
michael@0 10114 nsIFrame* frame = rootElement->GetPrimaryFrame();
michael@0 10115 if (frame) {
michael@0 10116 frame = frame->GetParent();
michael@0 10117 nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
michael@0 10118 if (canvasFrame) {
michael@0 10119 canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
michael@0 10120 }
michael@0 10121 }
michael@0 10122 }
michael@0 10123 } else {
michael@0 10124 // Look for the frame the hard way
michael@0 10125 nsIFrame* frame = presShell->GetRootFrame();
michael@0 10126 if (frame) {
michael@0 10127 nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
michael@0 10128 if (canvasFrame) {
michael@0 10129 canvasFrame->SetHasFocus(false);
michael@0 10130 }
michael@0 10131 }
michael@0 10132 }
michael@0 10133 }
michael@0 10134
michael@0 10135 already_AddRefed<nsICSSDeclaration>
michael@0 10136 nsGlobalWindow::GetComputedStyle(Element& aElt, const nsAString& aPseudoElt,
michael@0 10137 ErrorResult& aError)
michael@0 10138 {
michael@0 10139 return GetComputedStyleHelper(aElt, aPseudoElt, false, aError);
michael@0 10140 }
michael@0 10141
michael@0 10142 NS_IMETHODIMP
michael@0 10143 nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
michael@0 10144 const nsAString& aPseudoElt,
michael@0 10145 nsIDOMCSSStyleDeclaration** aReturn)
michael@0 10146 {
michael@0 10147 return GetComputedStyleHelper(aElt, aPseudoElt, false, aReturn);
michael@0 10148 }
michael@0 10149
michael@0 10150 already_AddRefed<nsICSSDeclaration>
michael@0 10151 nsGlobalWindow::GetDefaultComputedStyle(Element& aElt,
michael@0 10152 const nsAString& aPseudoElt,
michael@0 10153 ErrorResult& aError)
michael@0 10154 {
michael@0 10155 return GetComputedStyleHelper(aElt, aPseudoElt, true, aError);
michael@0 10156 }
michael@0 10157
michael@0 10158 NS_IMETHODIMP
michael@0 10159 nsGlobalWindow::GetDefaultComputedStyle(nsIDOMElement* aElt,
michael@0 10160 const nsAString& aPseudoElt,
michael@0 10161 nsIDOMCSSStyleDeclaration** aReturn)
michael@0 10162 {
michael@0 10163 return GetComputedStyleHelper(aElt, aPseudoElt, true, aReturn);
michael@0 10164 }
michael@0 10165
michael@0 10166 nsresult
michael@0 10167 nsGlobalWindow::GetComputedStyleHelper(nsIDOMElement* aElt,
michael@0 10168 const nsAString& aPseudoElt,
michael@0 10169 bool aDefaultStylesOnly,
michael@0 10170 nsIDOMCSSStyleDeclaration** aReturn)
michael@0 10171 {
michael@0 10172 NS_ENSURE_ARG_POINTER(aReturn);
michael@0 10173 *aReturn = nullptr;
michael@0 10174
michael@0 10175 nsCOMPtr<dom::Element> element = do_QueryInterface(aElt);
michael@0 10176 if (!element) {
michael@0 10177 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
michael@0 10178 }
michael@0 10179
michael@0 10180 ErrorResult rv;
michael@0 10181 nsCOMPtr<nsIDOMCSSStyleDeclaration> declaration =
michael@0 10182 GetComputedStyleHelper(*element, aPseudoElt, aDefaultStylesOnly, rv);
michael@0 10183 declaration.forget(aReturn);
michael@0 10184
michael@0 10185 return rv.ErrorCode();
michael@0 10186 }
michael@0 10187
michael@0 10188 already_AddRefed<nsICSSDeclaration>
michael@0 10189 nsGlobalWindow::GetComputedStyleHelper(Element& aElt,
michael@0 10190 const nsAString& aPseudoElt,
michael@0 10191 bool aDefaultStylesOnly,
michael@0 10192 ErrorResult& aError)
michael@0 10193 {
michael@0 10194 FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelper,
michael@0 10195 (aElt, aPseudoElt, aDefaultStylesOnly, aError),
michael@0 10196 aError, nullptr);
michael@0 10197
michael@0 10198 if (!mDocShell) {
michael@0 10199 return nullptr;
michael@0 10200 }
michael@0 10201
michael@0 10202 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 10203
michael@0 10204 if (!presShell) {
michael@0 10205 // Try flushing frames on our parent in case there's a pending
michael@0 10206 // style change that will create the presshell.
michael@0 10207 nsGlobalWindow *parent =
michael@0 10208 static_cast<nsGlobalWindow *>(GetPrivateParent());
michael@0 10209 if (!parent) {
michael@0 10210 return nullptr;
michael@0 10211 }
michael@0 10212
michael@0 10213 parent->FlushPendingNotifications(Flush_Frames);
michael@0 10214
michael@0 10215 // Might have killed mDocShell
michael@0 10216 if (!mDocShell) {
michael@0 10217 return nullptr;
michael@0 10218 }
michael@0 10219
michael@0 10220 presShell = mDocShell->GetPresShell();
michael@0 10221 if (!presShell) {
michael@0 10222 return nullptr;
michael@0 10223 }
michael@0 10224 }
michael@0 10225
michael@0 10226 nsRefPtr<nsComputedDOMStyle> compStyle =
michael@0 10227 NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell,
michael@0 10228 aDefaultStylesOnly ? nsComputedDOMStyle::eDefaultOnly :
michael@0 10229 nsComputedDOMStyle::eAll);
michael@0 10230
michael@0 10231 return compStyle.forget();
michael@0 10232 }
michael@0 10233
michael@0 10234 nsIDOMStorage*
michael@0 10235 nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
michael@0 10236 {
michael@0 10237 FORWARD_TO_INNER_OR_THROW(GetSessionStorage, (aError), aError, nullptr);
michael@0 10238
michael@0 10239 nsIPrincipal *principal = GetPrincipal();
michael@0 10240 nsIDocShell* docShell = GetDocShell();
michael@0 10241
michael@0 10242 if (!principal || !docShell || !Preferences::GetBool(kStorageEnabled)) {
michael@0 10243 return nullptr;
michael@0 10244 }
michael@0 10245
michael@0 10246 if (mSessionStorage) {
michael@0 10247 #ifdef PR_LOGGING
michael@0 10248 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
michael@0 10249 PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get());
michael@0 10250 }
michael@0 10251 #endif
michael@0 10252 nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(mSessionStorage);
michael@0 10253 if (piStorage) {
michael@0 10254 bool canAccess = piStorage->CanAccess(principal);
michael@0 10255 NS_ASSERTION(canAccess,
michael@0 10256 "window %x owned sessionStorage "
michael@0 10257 "that could not be accessed!");
michael@0 10258 if (!canAccess) {
michael@0 10259 mSessionStorage = nullptr;
michael@0 10260 }
michael@0 10261 }
michael@0 10262 }
michael@0 10263
michael@0 10264 if (!mSessionStorage) {
michael@0 10265 nsString documentURI;
michael@0 10266 if (mDoc) {
michael@0 10267 mDoc->GetDocumentURI(documentURI);
michael@0 10268 }
michael@0 10269
michael@0 10270 // If the document has the sandboxed origin flag set
michael@0 10271 // don't allow access to sessionStorage.
michael@0 10272 if (!mDoc) {
michael@0 10273 aError.Throw(NS_ERROR_FAILURE);
michael@0 10274 return nullptr;
michael@0 10275 }
michael@0 10276
michael@0 10277 if (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
michael@0 10278 aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
michael@0 10279 return nullptr;
michael@0 10280 }
michael@0 10281
michael@0 10282 nsresult rv;
michael@0 10283
michael@0 10284 nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(docShell, &rv);
michael@0 10285 if (NS_FAILED(rv)) {
michael@0 10286 aError.Throw(rv);
michael@0 10287 return nullptr;
michael@0 10288 }
michael@0 10289
michael@0 10290 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
michael@0 10291
michael@0 10292 nsCOMPtr<nsIURI> firstPartyIsolationURI;
michael@0 10293 rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
michael@0 10294 if (NS_FAILED(rv)) {
michael@0 10295 aError.Throw(rv);
michael@0 10296 return nullptr;
michael@0 10297 }
michael@0 10298
michael@0 10299 aError = storageManager->CreateStorageForFirstParty(firstPartyIsolationURI, principal,
michael@0 10300 documentURI,
michael@0 10301 loadContext && loadContext->UsePrivateBrowsing(),
michael@0 10302 getter_AddRefs(mSessionStorage));
michael@0 10303 if (aError.Failed()) {
michael@0 10304 return nullptr;
michael@0 10305 }
michael@0 10306
michael@0 10307 #ifdef PR_LOGGING
michael@0 10308 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
michael@0 10309 PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
michael@0 10310 }
michael@0 10311 #endif
michael@0 10312
michael@0 10313 if (!mSessionStorage) {
michael@0 10314 aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
michael@0 10315 return nullptr;
michael@0 10316 }
michael@0 10317 }
michael@0 10318
michael@0 10319 #ifdef PR_LOGGING
michael@0 10320 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
michael@0 10321 PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get());
michael@0 10322 }
michael@0 10323 #endif
michael@0 10324
michael@0 10325 return mSessionStorage;
michael@0 10326 }
michael@0 10327
michael@0 10328 NS_IMETHODIMP
michael@0 10329 nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
michael@0 10330 {
michael@0 10331 ErrorResult rv;
michael@0 10332 nsCOMPtr<nsIDOMStorage> storage = GetSessionStorage(rv);
michael@0 10333 storage.forget(aSessionStorage);
michael@0 10334
michael@0 10335 return rv.ErrorCode();
michael@0 10336 }
michael@0 10337
michael@0 10338 nsIDOMStorage*
michael@0 10339 nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
michael@0 10340 {
michael@0 10341 FORWARD_TO_INNER_OR_THROW(GetLocalStorage, (aError), aError, nullptr);
michael@0 10342
michael@0 10343 if (!Preferences::GetBool(kStorageEnabled)) {
michael@0 10344 return nullptr;
michael@0 10345 }
michael@0 10346
michael@0 10347 if (!mLocalStorage) {
michael@0 10348 if (!DOMStorage::CanUseStorage()) {
michael@0 10349 aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
michael@0 10350 return nullptr;
michael@0 10351 }
michael@0 10352
michael@0 10353 nsIPrincipal *principal = GetPrincipal();
michael@0 10354 if (!principal) {
michael@0 10355 return nullptr;
michael@0 10356 }
michael@0 10357
michael@0 10358 nsresult rv;
michael@0 10359 nsCOMPtr<nsIDOMStorageManager> storageManager =
michael@0 10360 do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
michael@0 10361 if (NS_FAILED(rv)) {
michael@0 10362 aError.Throw(rv);
michael@0 10363 return nullptr;
michael@0 10364 }
michael@0 10365
michael@0 10366 // If the document has the sandboxed origin flag set
michael@0 10367 // don't allow access to localStorage.
michael@0 10368 if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
michael@0 10369 aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
michael@0 10370 return nullptr;
michael@0 10371 }
michael@0 10372
michael@0 10373 nsString documentURI;
michael@0 10374 if (mDoc) {
michael@0 10375 mDoc->GetDocumentURI(documentURI);
michael@0 10376 }
michael@0 10377
michael@0 10378 nsCOMPtr<nsIURI> firstPartyIsolationURI;
michael@0 10379 rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
michael@0 10380 if (NS_FAILED(rv)) {
michael@0 10381 aError.Throw(rv);
michael@0 10382 return nullptr;
michael@0 10383 }
michael@0 10384
michael@0 10385 nsIDocShell* docShell = GetDocShell();
michael@0 10386 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
michael@0 10387
michael@0 10388 aError = storageManager->CreateStorageForFirstParty(firstPartyIsolationURI, principal,
michael@0 10389 documentURI,
michael@0 10390 loadContext && loadContext->UsePrivateBrowsing(),
michael@0 10391 getter_AddRefs(mLocalStorage));
michael@0 10392 }
michael@0 10393
michael@0 10394 return mLocalStorage;
michael@0 10395 }
michael@0 10396
michael@0 10397 NS_IMETHODIMP
michael@0 10398 nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
michael@0 10399 {
michael@0 10400 NS_ENSURE_ARG(aLocalStorage);
michael@0 10401
michael@0 10402 ErrorResult rv;
michael@0 10403 nsCOMPtr<nsIDOMStorage> storage = GetLocalStorage(rv);
michael@0 10404 storage.forget(aLocalStorage);
michael@0 10405
michael@0 10406 return rv.ErrorCode();
michael@0 10407 }
michael@0 10408
michael@0 10409 indexedDB::IDBFactory*
michael@0 10410 nsGlobalWindow::GetIndexedDB(ErrorResult& aError)
michael@0 10411 {
michael@0 10412 if (!mIndexedDB) {
michael@0 10413 // If the document has the sandboxed origin flag set
michael@0 10414 // don't allow access to indexedDB.
michael@0 10415 if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
michael@0 10416 aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
michael@0 10417 return nullptr;
michael@0 10418 }
michael@0 10419
michael@0 10420 if (!IsChromeWindow()) {
michael@0 10421 // Whitelist about:home, since it doesn't have a base domain it would not
michael@0 10422 // pass the thirdPartyUtil check, though it should be able to use
michael@0 10423 // indexedDB.
michael@0 10424 bool skipThirdPartyCheck = false;
michael@0 10425 nsIPrincipal *principal = GetPrincipal();
michael@0 10426 if (principal) {
michael@0 10427 nsCOMPtr<nsIURI> uri;
michael@0 10428 principal->GetURI(getter_AddRefs(uri));
michael@0 10429 bool isAbout = false;
michael@0 10430 if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
michael@0 10431 nsAutoCString path;
michael@0 10432 skipThirdPartyCheck = NS_SUCCEEDED(uri->GetPath(path)) &&
michael@0 10433 path.EqualsLiteral("home");
michael@0 10434 }
michael@0 10435 }
michael@0 10436
michael@0 10437 if (!skipThirdPartyCheck) {
michael@0 10438 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
michael@0 10439 do_GetService(THIRDPARTYUTIL_CONTRACTID);
michael@0 10440 if (!thirdPartyUtil) {
michael@0 10441 aError.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
michael@0 10442 return nullptr;
michael@0 10443 }
michael@0 10444
michael@0 10445 bool isThirdParty;
michael@0 10446 aError = thirdPartyUtil->IsThirdPartyWindow(this, nullptr,
michael@0 10447 &isThirdParty);
michael@0 10448 if (aError.Failed() || isThirdParty) {
michael@0 10449 NS_WARN_IF_FALSE(aError.Failed(),
michael@0 10450 "IndexedDB is not permitted in a third-party window.");
michael@0 10451 return nullptr;
michael@0 10452 }
michael@0 10453 }
michael@0 10454 }
michael@0 10455
michael@0 10456 // This may be null if being created from a file.
michael@0 10457 aError = indexedDB::IDBFactory::Create(this, nullptr,
michael@0 10458 getter_AddRefs(mIndexedDB));
michael@0 10459 }
michael@0 10460
michael@0 10461 return mIndexedDB;
michael@0 10462 }
michael@0 10463
michael@0 10464 NS_IMETHODIMP
michael@0 10465 nsGlobalWindow::GetIndexedDB(nsISupports** _retval)
michael@0 10466 {
michael@0 10467 ErrorResult rv;
michael@0 10468 nsCOMPtr<nsISupports> request(GetIndexedDB(rv));
michael@0 10469 request.forget(_retval);
michael@0 10470
michael@0 10471 return rv.ErrorCode();
michael@0 10472 }
michael@0 10473
michael@0 10474 NS_IMETHODIMP
michael@0 10475 nsGlobalWindow::GetMozIndexedDB(nsISupports** _retval)
michael@0 10476 {
michael@0 10477 return GetIndexedDB(_retval);
michael@0 10478 }
michael@0 10479
michael@0 10480 //*****************************************************************************
michael@0 10481 // nsGlobalWindow::nsIInterfaceRequestor
michael@0 10482 //*****************************************************************************
michael@0 10483
michael@0 10484 NS_IMETHODIMP
michael@0 10485 nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
michael@0 10486 {
michael@0 10487 NS_ENSURE_ARG_POINTER(aSink);
michael@0 10488 *aSink = nullptr;
michael@0 10489
michael@0 10490 if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
michael@0 10491 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 10492 NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
michael@0 10493
michael@0 10494 NS_WARNING("Using deprecated nsIDocCharset: use nsIDocShell.GetCharset() instead ");
michael@0 10495 nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(outer->mDocShell));
michael@0 10496 docCharset.forget(aSink);
michael@0 10497 }
michael@0 10498 else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
michael@0 10499 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 10500 NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
michael@0 10501
michael@0 10502 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(outer->mDocShell));
michael@0 10503 webNav.forget(aSink);
michael@0 10504 }
michael@0 10505 else if (aIID.Equals(NS_GET_IID(nsIDocShell))) {
michael@0 10506 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 10507 NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
michael@0 10508
michael@0 10509 nsCOMPtr<nsIDocShell> docShell = outer->mDocShell;
michael@0 10510 docShell.forget(aSink);
michael@0 10511 }
michael@0 10512 #ifdef NS_PRINTING
michael@0 10513 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
michael@0 10514 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 10515 NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
michael@0 10516
michael@0 10517 if (outer->mDocShell) {
michael@0 10518 nsCOMPtr<nsIContentViewer> viewer;
michael@0 10519 outer->mDocShell->GetContentViewer(getter_AddRefs(viewer));
michael@0 10520 if (viewer) {
michael@0 10521 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
michael@0 10522 webBrowserPrint.forget(aSink);
michael@0 10523 }
michael@0 10524 }
michael@0 10525 }
michael@0 10526 #endif
michael@0 10527 else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
michael@0 10528 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 10529 NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
michael@0 10530
michael@0 10531 if (!mWindowUtils) {
michael@0 10532 mWindowUtils = new nsDOMWindowUtils(outer);
michael@0 10533 }
michael@0 10534
michael@0 10535 *aSink = mWindowUtils;
michael@0 10536 NS_ADDREF(((nsISupports *) *aSink));
michael@0 10537 }
michael@0 10538 else if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
michael@0 10539 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 10540 NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
michael@0 10541
michael@0 10542 nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(outer->mDocShell));
michael@0 10543 loadContext.forget(aSink);
michael@0 10544 }
michael@0 10545 else {
michael@0 10546 return QueryInterface(aIID, aSink);
michael@0 10547 }
michael@0 10548
michael@0 10549 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
michael@0 10550 }
michael@0 10551
michael@0 10552 void
michael@0 10553 nsGlobalWindow::GetInterface(JSContext* aCx, nsIJSID* aIID,
michael@0 10554 JS::MutableHandle<JS::Value> aRetval,
michael@0 10555 ErrorResult& aError)
michael@0 10556 {
michael@0 10557 dom::GetInterface(aCx, this, aIID, aRetval, aError);
michael@0 10558 }
michael@0 10559
michael@0 10560 void
michael@0 10561 nsGlobalWindow::FireOfflineStatusEvent()
michael@0 10562 {
michael@0 10563 if (!IsCurrentInnerWindow())
michael@0 10564 return;
michael@0 10565 nsAutoString name;
michael@0 10566 if (NS_IsOffline()) {
michael@0 10567 name.AssignLiteral("offline");
michael@0 10568 } else {
michael@0 10569 name.AssignLiteral("online");
michael@0 10570 }
michael@0 10571 // The event is fired at the body element, or if there is no body element,
michael@0 10572 // at the document.
michael@0 10573 nsCOMPtr<EventTarget> eventTarget = mDoc.get();
michael@0 10574 nsHTMLDocument* htmlDoc = mDoc->AsHTMLDocument();
michael@0 10575 if (htmlDoc) {
michael@0 10576 Element* body = htmlDoc->GetBody();
michael@0 10577 if (body) {
michael@0 10578 eventTarget = body;
michael@0 10579 }
michael@0 10580 } else {
michael@0 10581 Element* documentElement = mDoc->GetDocumentElement();
michael@0 10582 if (documentElement) {
michael@0 10583 eventTarget = documentElement;
michael@0 10584 }
michael@0 10585 }
michael@0 10586 nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, true, false);
michael@0 10587 }
michael@0 10588
michael@0 10589 class NotifyIdleObserverRunnable : public nsRunnable
michael@0 10590 {
michael@0 10591 public:
michael@0 10592 NotifyIdleObserverRunnable(nsIIdleObserver* aIdleObserver,
michael@0 10593 uint32_t aTimeInS,
michael@0 10594 bool aCallOnidle,
michael@0 10595 nsGlobalWindow* aIdleWindow)
michael@0 10596 : mIdleObserver(aIdleObserver), mTimeInS(aTimeInS), mIdleWindow(aIdleWindow),
michael@0 10597 mCallOnidle(aCallOnidle)
michael@0 10598 { }
michael@0 10599
michael@0 10600 NS_IMETHOD Run()
michael@0 10601 {
michael@0 10602 if (mIdleWindow->ContainsIdleObserver(mIdleObserver, mTimeInS)) {
michael@0 10603 return mCallOnidle ? mIdleObserver->Onidle() : mIdleObserver->Onactive();
michael@0 10604 }
michael@0 10605 return NS_OK;
michael@0 10606 }
michael@0 10607
michael@0 10608 private:
michael@0 10609 nsCOMPtr<nsIIdleObserver> mIdleObserver;
michael@0 10610 uint32_t mTimeInS;
michael@0 10611 nsRefPtr<nsGlobalWindow> mIdleWindow;
michael@0 10612
michael@0 10613 // If false then call on active
michael@0 10614 bool mCallOnidle;
michael@0 10615 };
michael@0 10616
michael@0 10617 void
michael@0 10618 nsGlobalWindow::NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
michael@0 10619 bool aCallOnidle)
michael@0 10620 {
michael@0 10621 MOZ_ASSERT(aIdleObserverHolder);
michael@0 10622 aIdleObserverHolder->mPrevNotificationIdle = aCallOnidle;
michael@0 10623
michael@0 10624 nsCOMPtr<nsIRunnable> caller =
michael@0 10625 new NotifyIdleObserverRunnable(aIdleObserverHolder->mIdleObserver,
michael@0 10626 aIdleObserverHolder->mTimeInS,
michael@0 10627 aCallOnidle, this);
michael@0 10628 if (NS_FAILED(NS_DispatchToCurrentThread(caller))) {
michael@0 10629 NS_WARNING("Failed to dispatch thread for idle observer notification.");
michael@0 10630 }
michael@0 10631 }
michael@0 10632
michael@0 10633 bool
michael@0 10634 nsGlobalWindow::ContainsIdleObserver(nsIIdleObserver* aIdleObserver, uint32_t aTimeInS)
michael@0 10635 {
michael@0 10636 MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
michael@0 10637 bool found = false;
michael@0 10638 nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
michael@0 10639 while (iter.HasMore()) {
michael@0 10640 IdleObserverHolder& idleObserver = iter.GetNext();
michael@0 10641 if (idleObserver.mIdleObserver == aIdleObserver &&
michael@0 10642 idleObserver.mTimeInS == aTimeInS) {
michael@0 10643 found = true;
michael@0 10644 break;
michael@0 10645 }
michael@0 10646 }
michael@0 10647 return found;
michael@0 10648 }
michael@0 10649
michael@0 10650 void
michael@0 10651 IdleActiveTimerCallback(nsITimer* aTimer, void* aClosure)
michael@0 10652 {
michael@0 10653 nsRefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
michael@0 10654 MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
michael@0 10655 idleWindow->HandleIdleActiveEvent();
michael@0 10656 }
michael@0 10657
michael@0 10658 void
michael@0 10659 IdleObserverTimerCallback(nsITimer* aTimer, void* aClosure)
michael@0 10660 {
michael@0 10661 nsRefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
michael@0 10662 MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
michael@0 10663 idleWindow->HandleIdleObserverCallback();
michael@0 10664 }
michael@0 10665
michael@0 10666 void
michael@0 10667 nsGlobalWindow::HandleIdleObserverCallback()
michael@0 10668 {
michael@0 10669 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
michael@0 10670 MOZ_ASSERT(static_cast<uint32_t>(mIdleCallbackIndex) < mIdleObservers.Length(),
michael@0 10671 "Idle callback index exceeds array bounds!");
michael@0 10672 IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(mIdleCallbackIndex);
michael@0 10673 NotifyIdleObserver(&idleObserver, true);
michael@0 10674 mIdleCallbackIndex++;
michael@0 10675 if (NS_FAILED(ScheduleNextIdleObserverCallback())) {
michael@0 10676 NS_WARNING("Failed to set next idle observer callback.");
michael@0 10677 }
michael@0 10678 }
michael@0 10679
michael@0 10680 nsresult
michael@0 10681 nsGlobalWindow::ScheduleNextIdleObserverCallback()
michael@0 10682 {
michael@0 10683 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
michael@0 10684 MOZ_ASSERT(mIdleService, "No idle service!");
michael@0 10685
michael@0 10686 if (mIdleCallbackIndex < 0 ||
michael@0 10687 static_cast<uint32_t>(mIdleCallbackIndex) >= mIdleObservers.Length()) {
michael@0 10688 return NS_OK;
michael@0 10689 }
michael@0 10690
michael@0 10691 IdleObserverHolder& idleObserver =
michael@0 10692 mIdleObservers.ElementAt(mIdleCallbackIndex);
michael@0 10693
michael@0 10694 uint32_t userIdleTimeMS = 0;
michael@0 10695 nsresult rv = mIdleService->GetIdleTime(&userIdleTimeMS);
michael@0 10696 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10697
michael@0 10698 uint32_t callbackTimeMS = 0;
michael@0 10699 if (idleObserver.mTimeInS * 1000 + mIdleFuzzFactor > userIdleTimeMS) {
michael@0 10700 callbackTimeMS = idleObserver.mTimeInS * 1000 - userIdleTimeMS + mIdleFuzzFactor;
michael@0 10701 }
michael@0 10702
michael@0 10703 mIdleTimer->Cancel();
michael@0 10704 rv = mIdleTimer->InitWithFuncCallback(IdleObserverTimerCallback,
michael@0 10705 this,
michael@0 10706 callbackTimeMS,
michael@0 10707 nsITimer::TYPE_ONE_SHOT);
michael@0 10708 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10709
michael@0 10710 return NS_OK;
michael@0 10711 }
michael@0 10712
michael@0 10713 uint32_t
michael@0 10714 nsGlobalWindow::GetFuzzTimeMS()
michael@0 10715 {
michael@0 10716 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
michael@0 10717
michael@0 10718 if (sIdleObserversAPIFuzzTimeDisabled) {
michael@0 10719 return 0;
michael@0 10720 }
michael@0 10721
michael@0 10722 uint32_t randNum = MAX_IDLE_FUZZ_TIME_MS;
michael@0 10723 size_t nbytes = PR_GetRandomNoise(&randNum, sizeof(randNum));
michael@0 10724 if (nbytes != sizeof(randNum)) {
michael@0 10725 NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!");
michael@0 10726 return MAX_IDLE_FUZZ_TIME_MS;
michael@0 10727 }
michael@0 10728
michael@0 10729 if (randNum > MAX_IDLE_FUZZ_TIME_MS) {
michael@0 10730 randNum %= MAX_IDLE_FUZZ_TIME_MS;
michael@0 10731 }
michael@0 10732
michael@0 10733 return randNum;
michael@0 10734 }
michael@0 10735
michael@0 10736 nsresult
michael@0 10737 nsGlobalWindow::ScheduleActiveTimerCallback()
michael@0 10738 {
michael@0 10739 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
michael@0 10740
michael@0 10741 if (!mAddActiveEventFuzzTime) {
michael@0 10742 return HandleIdleActiveEvent();
michael@0 10743 }
michael@0 10744
michael@0 10745 MOZ_ASSERT(mIdleTimer);
michael@0 10746 mIdleTimer->Cancel();
michael@0 10747
michael@0 10748 uint32_t fuzzFactorInMS = GetFuzzTimeMS();
michael@0 10749 nsresult rv = mIdleTimer->InitWithFuncCallback(IdleActiveTimerCallback,
michael@0 10750 this,
michael@0 10751 fuzzFactorInMS,
michael@0 10752 nsITimer::TYPE_ONE_SHOT);
michael@0 10753 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10754 return NS_OK;
michael@0 10755 }
michael@0 10756
michael@0 10757 nsresult
michael@0 10758 nsGlobalWindow::HandleIdleActiveEvent()
michael@0 10759 {
michael@0 10760 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
michael@0 10761
michael@0 10762 if (mCurrentlyIdle) {
michael@0 10763 mIdleCallbackIndex = 0;
michael@0 10764 mIdleFuzzFactor = GetFuzzTimeMS();
michael@0 10765 nsresult rv = ScheduleNextIdleObserverCallback();
michael@0 10766 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10767 return NS_OK;
michael@0 10768 }
michael@0 10769
michael@0 10770 mIdleCallbackIndex = -1;
michael@0 10771 MOZ_ASSERT(mIdleTimer);
michael@0 10772 mIdleTimer->Cancel();
michael@0 10773 nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
michael@0 10774 while (iter.HasMore()) {
michael@0 10775 IdleObserverHolder& idleObserver = iter.GetNext();
michael@0 10776 if (idleObserver.mPrevNotificationIdle) {
michael@0 10777 NotifyIdleObserver(&idleObserver, false);
michael@0 10778 }
michael@0 10779 }
michael@0 10780
michael@0 10781 return NS_OK;
michael@0 10782 }
michael@0 10783
michael@0 10784 nsGlobalWindow::SlowScriptResponse
michael@0 10785 nsGlobalWindow::ShowSlowScriptDialog()
michael@0 10786 {
michael@0 10787 MOZ_ASSERT(IsInnerWindow());
michael@0 10788
michael@0 10789 nsresult rv;
michael@0 10790 AutoJSContext cx;
michael@0 10791
michael@0 10792 // If it isn't safe to run script, then it isn't safe to bring up the prompt
michael@0 10793 // (since that spins the event loop). In that (rare) case, we just kill the
michael@0 10794 // script and report a warning.
michael@0 10795 if (!nsContentUtils::IsSafeToRunScript()) {
michael@0 10796 JS_ReportWarning(cx, "A long running script was terminated");
michael@0 10797 return KillSlowScript;
michael@0 10798 }
michael@0 10799
michael@0 10800 // If our document is not active, just kill the script: we've been unloaded
michael@0 10801 if (!HasActiveDocument()) {
michael@0 10802 return KillSlowScript;
michael@0 10803 }
michael@0 10804
michael@0 10805 // Get the nsIPrompt interface from the docshell
michael@0 10806 nsCOMPtr<nsIDocShell> ds = GetDocShell();
michael@0 10807 NS_ENSURE_TRUE(ds, KillSlowScript);
michael@0 10808 nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
michael@0 10809 NS_ENSURE_TRUE(prompt, KillSlowScript);
michael@0 10810
michael@0 10811 // Check if we should offer the option to debug
michael@0 10812 JS::AutoFilename filename;
michael@0 10813 unsigned lineno;
michael@0 10814 bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
michael@0 10815
michael@0 10816 bool debugPossible = hasFrame && js::CanCallContextDebugHandler(cx);
michael@0 10817 #ifdef MOZ_JSDEBUGGER
michael@0 10818 // Get the debugger service if necessary.
michael@0 10819 if (debugPossible) {
michael@0 10820 bool jsds_IsOn = false;
michael@0 10821 const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
michael@0 10822 nsCOMPtr<jsdIExecutionHook> jsdHook;
michael@0 10823 nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
michael@0 10824
michael@0 10825 // Check if there's a user for the debugger service that's 'on' for us
michael@0 10826 if (NS_SUCCEEDED(rv)) {
michael@0 10827 jsds->GetDebuggerHook(getter_AddRefs(jsdHook));
michael@0 10828 jsds->GetIsOn(&jsds_IsOn);
michael@0 10829 }
michael@0 10830
michael@0 10831 // If there is a debug handler registered for this runtime AND
michael@0 10832 // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
michael@0 10833 // then something useful will be done with our request to debug.
michael@0 10834 debugPossible = ((jsds_IsOn && (jsdHook != nullptr)) || !jsds_IsOn);
michael@0 10835 }
michael@0 10836 #endif
michael@0 10837
michael@0 10838 // Get localizable strings
michael@0 10839 nsXPIDLString title, msg, stopButton, waitButton, debugButton, neverShowDlg;
michael@0 10840
michael@0 10841 rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
michael@0 10842 "KillScriptTitle",
michael@0 10843 title);
michael@0 10844
michael@0 10845 nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
michael@0 10846 "StopScriptButton",
michael@0 10847 stopButton);
michael@0 10848 if (NS_FAILED(tmp)) {
michael@0 10849 rv = tmp;
michael@0 10850 }
michael@0 10851
michael@0 10852 tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
michael@0 10853 "WaitForScriptButton",
michael@0 10854 waitButton);
michael@0 10855 if (NS_FAILED(tmp)) {
michael@0 10856 rv = tmp;
michael@0 10857 }
michael@0 10858
michael@0 10859 tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
michael@0 10860 "DontAskAgain",
michael@0 10861 neverShowDlg);
michael@0 10862 if (NS_FAILED(tmp)) {
michael@0 10863 rv = tmp;
michael@0 10864 }
michael@0 10865
michael@0 10866
michael@0 10867 if (debugPossible) {
michael@0 10868 tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
michael@0 10869 "DebugScriptButton",
michael@0 10870 debugButton);
michael@0 10871 if (NS_FAILED(tmp)) {
michael@0 10872 rv = tmp;
michael@0 10873 }
michael@0 10874
michael@0 10875 tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
michael@0 10876 "KillScriptWithDebugMessage",
michael@0 10877 msg);
michael@0 10878 if (NS_FAILED(tmp)) {
michael@0 10879 rv = tmp;
michael@0 10880 }
michael@0 10881 }
michael@0 10882 else {
michael@0 10883 tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
michael@0 10884 "KillScriptMessage",
michael@0 10885 msg);
michael@0 10886 if (NS_FAILED(tmp)) {
michael@0 10887 rv = tmp;
michael@0 10888 }
michael@0 10889 }
michael@0 10890
michael@0 10891 // GetStringFromName can return NS_OK and still give nullptr string
michael@0 10892 if (NS_FAILED(rv) || !title || !msg || !stopButton || !waitButton ||
michael@0 10893 (!debugButton && debugPossible) || !neverShowDlg) {
michael@0 10894 NS_ERROR("Failed to get localized strings.");
michael@0 10895 return ContinueSlowScript;
michael@0 10896 }
michael@0 10897
michael@0 10898 // Append file and line number information, if available
michael@0 10899 if (filename.get()) {
michael@0 10900 nsXPIDLString scriptLocation;
michael@0 10901 NS_ConvertUTF8toUTF16 filenameUTF16(filename.get());
michael@0 10902 const char16_t *formatParams[] = { filenameUTF16.get() };
michael@0 10903 rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
michael@0 10904 "KillScriptLocation",
michael@0 10905 formatParams,
michael@0 10906 scriptLocation);
michael@0 10907
michael@0 10908 if (NS_SUCCEEDED(rv) && scriptLocation) {
michael@0 10909 msg.AppendLiteral("\n\n");
michael@0 10910 msg.Append(scriptLocation);
michael@0 10911 msg.Append(':');
michael@0 10912 msg.AppendInt(lineno);
michael@0 10913 }
michael@0 10914 }
michael@0 10915
michael@0 10916 int32_t buttonPressed = 0; // In case the user exits dialog by clicking X.
michael@0 10917 bool neverShowDlgChk = false;
michael@0 10918 uint32_t buttonFlags = nsIPrompt::BUTTON_POS_1_DEFAULT +
michael@0 10919 (nsIPrompt::BUTTON_TITLE_IS_STRING *
michael@0 10920 (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
michael@0 10921
michael@0 10922 // Add a third button if necessary.
michael@0 10923 if (debugPossible)
michael@0 10924 buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
michael@0 10925
michael@0 10926 // Null out the operation callback while we're re-entering JS here.
michael@0 10927 JSRuntime* rt = JS_GetRuntime(cx);
michael@0 10928 JSInterruptCallback old = JS_SetInterruptCallback(rt, nullptr);
michael@0 10929
michael@0 10930 // Open the dialog.
michael@0 10931 rv = prompt->ConfirmEx(title, msg, buttonFlags, waitButton, stopButton,
michael@0 10932 debugButton, neverShowDlg, &neverShowDlgChk,
michael@0 10933 &buttonPressed);
michael@0 10934
michael@0 10935 JS_SetInterruptCallback(rt, old);
michael@0 10936
michael@0 10937 if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) {
michael@0 10938 return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript;
michael@0 10939 }
michael@0 10940 if ((buttonPressed == 2) && debugPossible) {
michael@0 10941 return js_CallContextDebugHandler(cx) ? ContinueSlowScript : KillSlowScript;
michael@0 10942 }
michael@0 10943 JS_ClearPendingException(cx);
michael@0 10944 return KillSlowScript;
michael@0 10945 }
michael@0 10946
michael@0 10947 uint32_t
michael@0 10948 nsGlobalWindow::FindInsertionIndex(IdleObserverHolder* aIdleObserver)
michael@0 10949 {
michael@0 10950 MOZ_ASSERT(IsInnerWindow());
michael@0 10951 MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
michael@0 10952
michael@0 10953 uint32_t i = 0;
michael@0 10954 nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
michael@0 10955 while (iter.HasMore()) {
michael@0 10956 IdleObserverHolder& idleObserver = iter.GetNext();
michael@0 10957 if (idleObserver.mTimeInS > aIdleObserver->mTimeInS) {
michael@0 10958 break;
michael@0 10959 }
michael@0 10960 i++;
michael@0 10961 MOZ_ASSERT(i <= mIdleObservers.Length(), "Array index out of bounds error.");
michael@0 10962 }
michael@0 10963
michael@0 10964 return i;
michael@0 10965 }
michael@0 10966
michael@0 10967 nsresult
michael@0 10968 nsGlobalWindow::RegisterIdleObserver(nsIIdleObserver* aIdleObserver)
michael@0 10969 {
michael@0 10970 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
michael@0 10971
michael@0 10972 nsresult rv;
michael@0 10973 if (mIdleObservers.IsEmpty()) {
michael@0 10974 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1", &rv);
michael@0 10975 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10976
michael@0 10977 rv = mIdleService->AddIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
michael@0 10978 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10979
michael@0 10980 if (!mIdleTimer) {
michael@0 10981 mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
michael@0 10982 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10983 } else {
michael@0 10984 mIdleTimer->Cancel();
michael@0 10985 }
michael@0 10986 }
michael@0 10987
michael@0 10988 MOZ_ASSERT(mIdleService);
michael@0 10989 MOZ_ASSERT(mIdleTimer);
michael@0 10990
michael@0 10991 IdleObserverHolder tmpIdleObserver;
michael@0 10992 tmpIdleObserver.mIdleObserver = aIdleObserver;
michael@0 10993 rv = aIdleObserver->GetTime(&tmpIdleObserver.mTimeInS);
michael@0 10994 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10995 NS_ENSURE_ARG_MAX(tmpIdleObserver.mTimeInS, UINT32_MAX / 1000);
michael@0 10996 NS_ENSURE_ARG_MIN(tmpIdleObserver.mTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
michael@0 10997
michael@0 10998 uint32_t insertAtIndex = FindInsertionIndex(&tmpIdleObserver);
michael@0 10999 if (insertAtIndex == mIdleObservers.Length()) {
michael@0 11000 mIdleObservers.AppendElement(tmpIdleObserver);
michael@0 11001 }
michael@0 11002 else {
michael@0 11003 mIdleObservers.InsertElementAt(insertAtIndex, tmpIdleObserver);
michael@0 11004 }
michael@0 11005
michael@0 11006 bool userIsIdle = false;
michael@0 11007 rv = nsContentUtils::IsUserIdle(MIN_IDLE_NOTIFICATION_TIME_S, &userIsIdle);
michael@0 11008 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11009
michael@0 11010 // Special case. First idle observer added to empty list while the user is idle.
michael@0 11011 // Haven't received 'idle' topic notification from slow idle service yet.
michael@0 11012 // Need to wait for the idle notification and then notify idle observers in the list.
michael@0 11013 if (userIsIdle && mIdleCallbackIndex == -1) {
michael@0 11014 return NS_OK;
michael@0 11015 }
michael@0 11016
michael@0 11017 if (!mCurrentlyIdle) {
michael@0 11018 return NS_OK;
michael@0 11019 }
michael@0 11020
michael@0 11021 MOZ_ASSERT(mIdleCallbackIndex >= 0);
michael@0 11022
michael@0 11023 if (static_cast<int32_t>(insertAtIndex) < mIdleCallbackIndex) {
michael@0 11024 IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(insertAtIndex);
michael@0 11025 NotifyIdleObserver(&idleObserver, true);
michael@0 11026 mIdleCallbackIndex++;
michael@0 11027 return NS_OK;
michael@0 11028 }
michael@0 11029
michael@0 11030 if (static_cast<int32_t>(insertAtIndex) == mIdleCallbackIndex) {
michael@0 11031 mIdleTimer->Cancel();
michael@0 11032 rv = ScheduleNextIdleObserverCallback();
michael@0 11033 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11034 }
michael@0 11035 return NS_OK;
michael@0 11036 }
michael@0 11037
michael@0 11038 nsresult
michael@0 11039 nsGlobalWindow::FindIndexOfElementToRemove(nsIIdleObserver* aIdleObserver,
michael@0 11040 int32_t* aRemoveElementIndex)
michael@0 11041 {
michael@0 11042 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
michael@0 11043 MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
michael@0 11044
michael@0 11045 *aRemoveElementIndex = 0;
michael@0 11046 if (mIdleObservers.IsEmpty()) {
michael@0 11047 return NS_ERROR_FAILURE;
michael@0 11048 }
michael@0 11049
michael@0 11050 uint32_t aIdleObserverTimeInS;
michael@0 11051 nsresult rv = aIdleObserver->GetTime(&aIdleObserverTimeInS);
michael@0 11052 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11053 NS_ENSURE_ARG_MIN(aIdleObserverTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
michael@0 11054
michael@0 11055 nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
michael@0 11056 while (iter.HasMore()) {
michael@0 11057 IdleObserverHolder& idleObserver = iter.GetNext();
michael@0 11058 if (idleObserver.mTimeInS == aIdleObserverTimeInS &&
michael@0 11059 idleObserver.mIdleObserver == aIdleObserver ) {
michael@0 11060 break;
michael@0 11061 }
michael@0 11062 (*aRemoveElementIndex)++;
michael@0 11063 }
michael@0 11064 return static_cast<uint32_t>(*aRemoveElementIndex) >= mIdleObservers.Length() ?
michael@0 11065 NS_ERROR_FAILURE : NS_OK;
michael@0 11066 }
michael@0 11067
michael@0 11068 nsresult
michael@0 11069 nsGlobalWindow::UnregisterIdleObserver(nsIIdleObserver* aIdleObserver)
michael@0 11070 {
michael@0 11071 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
michael@0 11072
michael@0 11073 int32_t removeElementIndex;
michael@0 11074 nsresult rv = FindIndexOfElementToRemove(aIdleObserver, &removeElementIndex);
michael@0 11075 if (NS_FAILED(rv)) {
michael@0 11076 NS_WARNING("Idle observer not found in list of idle observers. No idle observer removed.");
michael@0 11077 return NS_OK;
michael@0 11078 }
michael@0 11079 mIdleObservers.RemoveElementAt(removeElementIndex);
michael@0 11080
michael@0 11081 MOZ_ASSERT(mIdleTimer);
michael@0 11082 if (mIdleObservers.IsEmpty() && mIdleService) {
michael@0 11083 rv = mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
michael@0 11084 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11085 mIdleService = nullptr;
michael@0 11086
michael@0 11087 mIdleTimer->Cancel();
michael@0 11088 mIdleCallbackIndex = -1;
michael@0 11089 return NS_OK;
michael@0 11090 }
michael@0 11091
michael@0 11092 if (!mCurrentlyIdle) {
michael@0 11093 return NS_OK;
michael@0 11094 }
michael@0 11095
michael@0 11096 if (removeElementIndex < mIdleCallbackIndex) {
michael@0 11097 mIdleCallbackIndex--;
michael@0 11098 return NS_OK;
michael@0 11099 }
michael@0 11100
michael@0 11101 if (removeElementIndex != mIdleCallbackIndex) {
michael@0 11102 return NS_OK;
michael@0 11103 }
michael@0 11104
michael@0 11105 mIdleTimer->Cancel();
michael@0 11106
michael@0 11107 // If the last element in the array had been notified then decrement
michael@0 11108 // mIdleCallbackIndex because an idle was removed from the list of
michael@0 11109 // idle observers.
michael@0 11110 // Example: add idle observer with time 1, 2, 3,
michael@0 11111 // Idle notifications for idle observers with time 1, 2, 3 are complete
michael@0 11112 // Remove idle observer with time 3 while the user is still idle.
michael@0 11113 // The user never transitioned to active state.
michael@0 11114 // Add an idle observer with idle time 4
michael@0 11115 if (static_cast<uint32_t>(mIdleCallbackIndex) == mIdleObservers.Length()) {
michael@0 11116 mIdleCallbackIndex--;
michael@0 11117 }
michael@0 11118 rv = ScheduleNextIdleObserverCallback();
michael@0 11119 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11120
michael@0 11121 return NS_OK;
michael@0 11122 }
michael@0 11123
michael@0 11124 nsresult
michael@0 11125 nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
michael@0 11126 const char16_t* aData)
michael@0 11127 {
michael@0 11128 if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
michael@0 11129 if (IsFrozen()) {
michael@0 11130 // if an even number of notifications arrive while we're frozen,
michael@0 11131 // we don't need to fire.
michael@0 11132 mFireOfflineStatusChangeEventOnThaw = !mFireOfflineStatusChangeEventOnThaw;
michael@0 11133 } else {
michael@0 11134 FireOfflineStatusEvent();
michael@0 11135 }
michael@0 11136 return NS_OK;
michael@0 11137 }
michael@0 11138
michael@0 11139 if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE)) {
michael@0 11140 mCurrentlyIdle = true;
michael@0 11141 if (IsFrozen()) {
michael@0 11142 // need to fire only one idle event while the window is frozen.
michael@0 11143 mNotifyIdleObserversIdleOnThaw = true;
michael@0 11144 mNotifyIdleObserversActiveOnThaw = false;
michael@0 11145 } else if (IsCurrentInnerWindow()) {
michael@0 11146 HandleIdleActiveEvent();
michael@0 11147 }
michael@0 11148 return NS_OK;
michael@0 11149 }
michael@0 11150
michael@0 11151 if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_ACTIVE)) {
michael@0 11152 mCurrentlyIdle = false;
michael@0 11153 if (IsFrozen()) {
michael@0 11154 mNotifyIdleObserversActiveOnThaw = true;
michael@0 11155 mNotifyIdleObserversIdleOnThaw = false;
michael@0 11156 } else if (IsCurrentInnerWindow()) {
michael@0 11157 MOZ_ASSERT(IsInnerWindow());
michael@0 11158 ScheduleActiveTimerCallback();
michael@0 11159 }
michael@0 11160 return NS_OK;
michael@0 11161 }
michael@0 11162
michael@0 11163 if (!nsCRT::strcmp(aTopic, "dom-storage2-changed")) {
michael@0 11164 if (!IsInnerWindow() || !IsCurrentInnerWindow()) {
michael@0 11165 return NS_OK;
michael@0 11166 }
michael@0 11167
michael@0 11168 nsIPrincipal *principal;
michael@0 11169 nsresult rv;
michael@0 11170
michael@0 11171 nsCOMPtr<nsIDOMStorageEvent> event = do_QueryInterface(aSubject, &rv);
michael@0 11172 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11173
michael@0 11174 nsCOMPtr<nsIDOMStorage> changingStorage;
michael@0 11175 rv = event->GetStorageArea(getter_AddRefs(changingStorage));
michael@0 11176 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11177
michael@0 11178 bool fireMozStorageChanged = false;
michael@0 11179 principal = GetPrincipal();
michael@0 11180 if (!principal) {
michael@0 11181 return NS_OK;
michael@0 11182 }
michael@0 11183
michael@0 11184 nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
michael@0 11185
michael@0 11186 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell());
michael@0 11187 bool isPrivate = loadContext && loadContext->UsePrivateBrowsing();
michael@0 11188 if (pistorage->IsPrivate() != isPrivate) {
michael@0 11189 return NS_OK;
michael@0 11190 }
michael@0 11191
michael@0 11192 switch (pistorage->GetType())
michael@0 11193 {
michael@0 11194 case nsPIDOMStorage::SessionStorage:
michael@0 11195 {
michael@0 11196 bool check = false;
michael@0 11197
michael@0 11198 nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(GetDocShell());
michael@0 11199 if (storageManager) {
michael@0 11200 nsresult rv;
michael@0 11201 nsCOMPtr<nsIURI> firstPartyIsolationURI;
michael@0 11202 rv = GetFirstPartyIsolationURI(getter_AddRefs(firstPartyIsolationURI));
michael@0 11203 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11204
michael@0 11205 rv = storageManager->CheckStorageForFirstParty(firstPartyIsolationURI,
michael@0 11206 principal, changingStorage, &check);
michael@0 11207 if (NS_FAILED(rv)) {
michael@0 11208 return rv;
michael@0 11209 }
michael@0 11210 }
michael@0 11211
michael@0 11212 if (!check) {
michael@0 11213 // This storage event is not coming from our storage or is coming
michael@0 11214 // from a different docshell, i.e. it is a clone, ignore this event.
michael@0 11215 return NS_OK;
michael@0 11216 }
michael@0 11217
michael@0 11218 #ifdef PR_LOGGING
michael@0 11219 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
michael@0 11220 PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
michael@0 11221 }
michael@0 11222 #endif
michael@0 11223
michael@0 11224 fireMozStorageChanged = SameCOMIdentity(mSessionStorage, changingStorage);
michael@0 11225 break;
michael@0 11226 }
michael@0 11227
michael@0 11228 case nsPIDOMStorage::LocalStorage:
michael@0 11229 {
michael@0 11230 // Allow event fire only for the same principal storages
michael@0 11231 // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
michael@0 11232 nsIPrincipal* storagePrincipal = pistorage->GetPrincipal();
michael@0 11233
michael@0 11234 bool equals = false;
michael@0 11235 rv = storagePrincipal->Equals(principal, &equals);
michael@0 11236 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11237
michael@0 11238 if (!equals)
michael@0 11239 return NS_OK;
michael@0 11240
michael@0 11241 fireMozStorageChanged = SameCOMIdentity(mLocalStorage, changingStorage);
michael@0 11242 break;
michael@0 11243 }
michael@0 11244 default:
michael@0 11245 return NS_OK;
michael@0 11246 }
michael@0 11247
michael@0 11248 // Clone the storage event included in the observer notification. We want
michael@0 11249 // to dispatch clones rather than the original event.
michael@0 11250 rv = CloneStorageEvent(fireMozStorageChanged ?
michael@0 11251 NS_LITERAL_STRING("MozStorageChanged") :
michael@0 11252 NS_LITERAL_STRING("storage"),
michael@0 11253 event);
michael@0 11254 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11255
michael@0 11256 event->SetTrusted(true);
michael@0 11257
michael@0 11258 if (fireMozStorageChanged) {
michael@0 11259 WidgetEvent* internalEvent = event->GetInternalNSEvent();
michael@0 11260 internalEvent->mFlags.mOnlyChromeDispatch = true;
michael@0 11261 }
michael@0 11262
michael@0 11263 if (IsFrozen()) {
michael@0 11264 // This window is frozen, rather than firing the events here,
michael@0 11265 // store the domain in which the change happened and fire the
michael@0 11266 // events if we're ever thawed.
michael@0 11267
michael@0 11268 mPendingStorageEvents.AppendObject(event);
michael@0 11269 return NS_OK;
michael@0 11270 }
michael@0 11271
michael@0 11272 bool defaultActionEnabled;
michael@0 11273 DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
michael@0 11274
michael@0 11275 return NS_OK;
michael@0 11276 }
michael@0 11277
michael@0 11278 if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) {
michael@0 11279 if (mApplicationCache)
michael@0 11280 return NS_OK;
michael@0 11281
michael@0 11282 // Instantiate the application object now. It observes update belonging to
michael@0 11283 // this window's document and correctly updates the applicationCache object
michael@0 11284 // state.
michael@0 11285 nsCOMPtr<nsIDOMOfflineResourceList> applicationCache;
michael@0 11286 GetApplicationCache(getter_AddRefs(applicationCache));
michael@0 11287 nsCOMPtr<nsIObserver> observer = do_QueryInterface(applicationCache);
michael@0 11288 if (observer)
michael@0 11289 observer->Observe(aSubject, aTopic, aData);
michael@0 11290
michael@0 11291 return NS_OK;
michael@0 11292 }
michael@0 11293
michael@0 11294 #ifdef MOZ_B2G
michael@0 11295 if (!nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC) ||
michael@0 11296 !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC)) {
michael@0 11297 MOZ_ASSERT(IsInnerWindow());
michael@0 11298 if (!IsCurrentInnerWindow()) {
michael@0 11299 return NS_OK;
michael@0 11300 }
michael@0 11301
michael@0 11302 nsCOMPtr<nsIDOMEvent> event;
michael@0 11303 NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
michael@0 11304 nsresult rv = event->InitEvent(
michael@0 11305 !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC)
michael@0 11306 ? NETWORK_UPLOAD_EVENT_NAME
michael@0 11307 : NETWORK_DOWNLOAD_EVENT_NAME,
michael@0 11308 false, false);
michael@0 11309 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11310
michael@0 11311 event->SetTrusted(true);
michael@0 11312
michael@0 11313 bool dummy;
michael@0 11314 return DispatchEvent(event, &dummy);
michael@0 11315 }
michael@0 11316 #endif // MOZ_B2G
michael@0 11317
michael@0 11318 NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
michael@0 11319 return NS_ERROR_FAILURE;
michael@0 11320 }
michael@0 11321
michael@0 11322 nsresult
michael@0 11323 nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
michael@0 11324 nsCOMPtr<nsIDOMStorageEvent>& aEvent)
michael@0 11325 {
michael@0 11326 nsresult rv;
michael@0 11327
michael@0 11328 bool canBubble;
michael@0 11329 bool cancelable;
michael@0 11330 nsAutoString key;
michael@0 11331 nsAutoString oldValue;
michael@0 11332 nsAutoString newValue;
michael@0 11333 nsAutoString url;
michael@0 11334 nsCOMPtr<nsIDOMStorage> storageArea;
michael@0 11335
michael@0 11336 nsCOMPtr<nsIDOMEvent> domEvent = do_QueryInterface(aEvent, &rv);
michael@0 11337 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11338
michael@0 11339 domEvent->GetBubbles(&canBubble);
michael@0 11340 domEvent->GetCancelable(&cancelable);
michael@0 11341
michael@0 11342 aEvent->GetKey(key);
michael@0 11343 aEvent->GetOldValue(oldValue);
michael@0 11344 aEvent->GetNewValue(newValue);
michael@0 11345 aEvent->GetUrl(url);
michael@0 11346 aEvent->GetStorageArea(getter_AddRefs(storageArea));
michael@0 11347
michael@0 11348 NS_NewDOMStorageEvent(getter_AddRefs(domEvent), this, nullptr, nullptr);
michael@0 11349 aEvent = do_QueryInterface(domEvent);
michael@0 11350 return aEvent->InitStorageEvent(aType, canBubble, cancelable,
michael@0 11351 key, oldValue, newValue,
michael@0 11352 url, storageArea);
michael@0 11353 }
michael@0 11354
michael@0 11355 nsresult
michael@0 11356 nsGlobalWindow::FireDelayedDOMEvents()
michael@0 11357 {
michael@0 11358 FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
michael@0 11359
michael@0 11360 for (int32_t i = 0; i < mPendingStorageEvents.Count(); ++i) {
michael@0 11361 Observe(mPendingStorageEvents[i], "dom-storage2-changed", nullptr);
michael@0 11362 }
michael@0 11363
michael@0 11364 if (mApplicationCache) {
michael@0 11365 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
michael@0 11366 }
michael@0 11367
michael@0 11368 if (mFireOfflineStatusChangeEventOnThaw) {
michael@0 11369 mFireOfflineStatusChangeEventOnThaw = false;
michael@0 11370 FireOfflineStatusEvent();
michael@0 11371 }
michael@0 11372
michael@0 11373 if (mNotifyIdleObserversIdleOnThaw) {
michael@0 11374 mNotifyIdleObserversIdleOnThaw = false;
michael@0 11375 HandleIdleActiveEvent();
michael@0 11376 }
michael@0 11377
michael@0 11378 if (mNotifyIdleObserversActiveOnThaw) {
michael@0 11379 mNotifyIdleObserversActiveOnThaw = false;
michael@0 11380 ScheduleActiveTimerCallback();
michael@0 11381 }
michael@0 11382
michael@0 11383 nsCOMPtr<nsIDocShell> docShell = GetDocShell();
michael@0 11384 if (docShell) {
michael@0 11385 int32_t childCount = 0;
michael@0 11386 docShell->GetChildCount(&childCount);
michael@0 11387
michael@0 11388 for (int32_t i = 0; i < childCount; ++i) {
michael@0 11389 nsCOMPtr<nsIDocShellTreeItem> childShell;
michael@0 11390 docShell->GetChildAt(i, getter_AddRefs(childShell));
michael@0 11391 NS_ASSERTION(childShell, "null child shell");
michael@0 11392
michael@0 11393 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
michael@0 11394 if (pWin) {
michael@0 11395 nsGlobalWindow *win =
michael@0 11396 static_cast<nsGlobalWindow*>
michael@0 11397 (static_cast<nsPIDOMWindow*>(pWin));
michael@0 11398 win->FireDelayedDOMEvents();
michael@0 11399 }
michael@0 11400 }
michael@0 11401 }
michael@0 11402
michael@0 11403 return NS_OK;
michael@0 11404 }
michael@0 11405
michael@0 11406 //*****************************************************************************
michael@0 11407 // nsGlobalWindow: Window Control Functions
michael@0 11408 //*****************************************************************************
michael@0 11409
michael@0 11410 nsIDOMWindow *
michael@0 11411 nsGlobalWindow::GetParentInternal()
michael@0 11412 {
michael@0 11413 if (IsInnerWindow()) {
michael@0 11414 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 11415 if (!outer) {
michael@0 11416 NS_WARNING("No outer window available!");
michael@0 11417 return nullptr;
michael@0 11418 }
michael@0 11419 return outer->GetParentInternal();
michael@0 11420 }
michael@0 11421
michael@0 11422 nsCOMPtr<nsIDOMWindow> parent;
michael@0 11423 GetParent(getter_AddRefs(parent));
michael@0 11424
michael@0 11425 if (parent && parent != static_cast<nsIDOMWindow *>(this)) {
michael@0 11426 return parent;
michael@0 11427 }
michael@0 11428
michael@0 11429 return nullptr;
michael@0 11430 }
michael@0 11431
michael@0 11432 void
michael@0 11433 nsGlobalWindow::UnblockScriptedClosing()
michael@0 11434 {
michael@0 11435 MOZ_ASSERT(IsOuterWindow());
michael@0 11436 mBlockScriptedClosingFlag = false;
michael@0 11437 }
michael@0 11438
michael@0 11439 class AutoUnblockScriptClosing
michael@0 11440 {
michael@0 11441 private:
michael@0 11442 nsRefPtr<nsGlobalWindow> mWin;
michael@0 11443 public:
michael@0 11444 AutoUnblockScriptClosing(nsGlobalWindow* aWin)
michael@0 11445 : mWin(aWin)
michael@0 11446 {
michael@0 11447 MOZ_ASSERT(mWin);
michael@0 11448 MOZ_ASSERT(mWin->IsOuterWindow());
michael@0 11449 }
michael@0 11450 ~AutoUnblockScriptClosing()
michael@0 11451 {
michael@0 11452 void (nsGlobalWindow::*run)() = &nsGlobalWindow::UnblockScriptedClosing;
michael@0 11453 NS_DispatchToCurrentThread(NS_NewRunnableMethod(mWin, run));
michael@0 11454 }
michael@0 11455 };
michael@0 11456
michael@0 11457 nsresult
michael@0 11458 nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
michael@0 11459 const nsAString& aOptions, bool aDialog,
michael@0 11460 bool aContentModal, bool aCalledNoScript,
michael@0 11461 bool aDoJSFixups, bool aNavigate,
michael@0 11462 nsIArray *argv,
michael@0 11463 nsISupports *aExtraArgument,
michael@0 11464 nsIPrincipal *aCalleePrincipal,
michael@0 11465 JSContext *aJSCallerContext,
michael@0 11466 nsIDOMWindow **aReturn)
michael@0 11467 {
michael@0 11468 FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
michael@0 11469 aContentModal, aCalledNoScript, aDoJSFixups,
michael@0 11470 aNavigate, argv, aExtraArgument,
michael@0 11471 aCalleePrincipal, aJSCallerContext, aReturn),
michael@0 11472 NS_ERROR_NOT_INITIALIZED);
michael@0 11473
michael@0 11474 #ifdef DEBUG
michael@0 11475 uint32_t argc = 0;
michael@0 11476 if (argv)
michael@0 11477 argv->GetLength(&argc);
michael@0 11478 #endif
michael@0 11479 NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
michael@0 11480 "Can't pass in arguments both ways");
michael@0 11481 NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
michael@0 11482 "Can't pass JS args when called via the noscript methods");
michael@0 11483 NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
michael@0 11484 "Shouldn't have caller context when called noscript");
michael@0 11485
michael@0 11486 mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
michael@0 11487
michael@0 11488 // Calls to window.open from script should navigate.
michael@0 11489 MOZ_ASSERT(aCalledNoScript || aNavigate);
michael@0 11490
michael@0 11491 *aReturn = nullptr;
michael@0 11492
michael@0 11493 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
michael@0 11494 if (!chrome) {
michael@0 11495 // No chrome means we don't want to go through with this open call
michael@0 11496 // -- see nsIWindowWatcher.idl
michael@0 11497 return NS_ERROR_NOT_AVAILABLE;
michael@0 11498 }
michael@0 11499
michael@0 11500 NS_ASSERTION(mDocShell, "Must have docshell here");
michael@0 11501
michael@0 11502 // Popups from apps are never blocked.
michael@0 11503 bool isApp = false;
michael@0 11504 if (mDoc) {
michael@0 11505 isApp = mDoc->NodePrincipal()->GetAppStatus() >=
michael@0 11506 nsIPrincipal::APP_STATUS_INSTALLED;
michael@0 11507 }
michael@0 11508
michael@0 11509 const bool checkForPopup = !nsContentUtils::IsCallerChrome() &&
michael@0 11510 !isApp && !aDialog && !WindowExists(aName, !aCalledNoScript);
michael@0 11511
michael@0 11512 // Note: it's very important that this be an nsXPIDLCString, since we want
michael@0 11513 // .get() on it to return nullptr until we write stuff to it. The window
michael@0 11514 // watcher expects a null URL string if there is no URL to load.
michael@0 11515 nsXPIDLCString url;
michael@0 11516 nsresult rv = NS_OK;
michael@0 11517
michael@0 11518 // It's important to do this security check before determining whether this
michael@0 11519 // window opening should be blocked, to ensure that we don't FireAbuseEvents
michael@0 11520 // for a window opening that wouldn't have succeeded in the first place.
michael@0 11521 if (!aUrl.IsEmpty()) {
michael@0 11522 AppendUTF16toUTF8(aUrl, url);
michael@0 11523
michael@0 11524 // It's safe to skip the security check below if we're not a dialog
michael@0 11525 // because window.openDialog is not callable from content script. See bug
michael@0 11526 // 56851.
michael@0 11527 //
michael@0 11528 // If we're not navigating, we assume that whoever *does* navigate the
michael@0 11529 // window will do a security check of their own.
michael@0 11530 if (url.get() && !aDialog && aNavigate)
michael@0 11531 rv = SecurityCheckURL(url.get());
michael@0 11532 }
michael@0 11533
michael@0 11534 if (NS_FAILED(rv))
michael@0 11535 return rv;
michael@0 11536
michael@0 11537 PopupControlState abuseLevel = gPopupControlState;
michael@0 11538 if (checkForPopup) {
michael@0 11539 abuseLevel = RevisePopupAbuseLevel(abuseLevel);
michael@0 11540 if (abuseLevel >= openAbused) {
michael@0 11541 if (aJSCallerContext) {
michael@0 11542 // If script in some other window is doing a window.open on us and
michael@0 11543 // it's being blocked, then it's OK to close us afterwards, probably.
michael@0 11544 // But if we're doing a window.open on ourselves and block the popup,
michael@0 11545 // prevent this window from closing until after this script terminates
michael@0 11546 // so that whatever popup blocker UI the app has will be visible.
michael@0 11547 if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
michael@0 11548 mBlockScriptedClosingFlag = true;
michael@0 11549 closeUnblocker.construct(this);
michael@0 11550 }
michael@0 11551 }
michael@0 11552
michael@0 11553 FireAbuseEvents(true, false, aUrl, aName, aOptions);
michael@0 11554 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
michael@0 11555 }
michael@0 11556 }
michael@0 11557
michael@0 11558 nsCOMPtr<nsIDOMWindow> domReturn;
michael@0 11559
michael@0 11560 nsCOMPtr<nsIWindowWatcher> wwatch =
michael@0 11561 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
michael@0 11562 NS_ENSURE_TRUE(wwatch, rv);
michael@0 11563
michael@0 11564 NS_ConvertUTF16toUTF8 options(aOptions);
michael@0 11565 NS_ConvertUTF16toUTF8 name(aName);
michael@0 11566
michael@0 11567 const char *options_ptr = aOptions.IsEmpty() ? nullptr : options.get();
michael@0 11568 const char *name_ptr = aName.IsEmpty() ? nullptr : name.get();
michael@0 11569
michael@0 11570 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
michael@0 11571 NS_ENSURE_STATE(pwwatch);
michael@0 11572
michael@0 11573 {
michael@0 11574 // Reset popup state while opening a window to prevent the
michael@0 11575 // current state from being active the whole time a modal
michael@0 11576 // dialog is open.
michael@0 11577 nsAutoPopupStatePusher popupStatePusher(openAbused, true);
michael@0 11578
michael@0 11579 if (!aCalledNoScript) {
michael@0 11580 // We asserted at the top of this function that aNavigate is true for
michael@0 11581 // !aCalledNoScript.
michael@0 11582 rv = pwwatch->OpenWindow2(this, url.get(), name_ptr, options_ptr,
michael@0 11583 /* aCalledFromScript = */ true,
michael@0 11584 aDialog, aNavigate, argv,
michael@0 11585 getter_AddRefs(domReturn));
michael@0 11586 } else {
michael@0 11587 // Force a system caller here so that the window watcher won't screw us
michael@0 11588 // up. We do NOT want this case looking at the JS context on the stack
michael@0 11589 // when searching. Compare comments on
michael@0 11590 // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
michael@0 11591
michael@0 11592 // Note: Because nsWindowWatcher is so broken, it's actually important
michael@0 11593 // that we don't force a system caller here, because that screws it up
michael@0 11594 // when it tries to compute the caller principal to associate with dialog
michael@0 11595 // arguments. That whole setup just really needs to be rewritten. :-(
michael@0 11596 Maybe<AutoNoJSAPI> nojsapi;
michael@0 11597 if (!aContentModal) {
michael@0 11598 nojsapi.construct();
michael@0 11599 }
michael@0 11600
michael@0 11601
michael@0 11602 rv = pwwatch->OpenWindow2(this, url.get(), name_ptr, options_ptr,
michael@0 11603 /* aCalledFromScript = */ false,
michael@0 11604 aDialog, aNavigate, aExtraArgument,
michael@0 11605 getter_AddRefs(domReturn));
michael@0 11606
michael@0 11607 }
michael@0 11608 }
michael@0 11609
michael@0 11610 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11611
michael@0 11612 // success!
michael@0 11613
michael@0 11614 NS_ENSURE_TRUE(domReturn, NS_OK);
michael@0 11615 domReturn.swap(*aReturn);
michael@0 11616
michael@0 11617 if (aDoJSFixups) {
michael@0 11618 nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
michael@0 11619 if (!chrome_win) {
michael@0 11620 // A new non-chrome window was created from a call to
michael@0 11621 // window.open() from JavaScript, make sure there's a document in
michael@0 11622 // the new window. We do this by simply asking the new window for
michael@0 11623 // its document, this will synchronously create an empty document
michael@0 11624 // if there is no document in the window.
michael@0 11625 // XXXbz should this just use EnsureInnerWindow()?
michael@0 11626 #ifdef DEBUG_jst
michael@0 11627 {
michael@0 11628 nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
michael@0 11629 NS_ASSERTION(pidomwin->GetExtantDoc(), "No document in new window!!!");
michael@0 11630 }
michael@0 11631 #endif
michael@0 11632
michael@0 11633 nsCOMPtr<nsIDOMDocument> doc;
michael@0 11634 (*aReturn)->GetDocument(getter_AddRefs(doc));
michael@0 11635 }
michael@0 11636 }
michael@0 11637
michael@0 11638 if (checkForPopup) {
michael@0 11639 if (abuseLevel >= openControlled) {
michael@0 11640 nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
michael@0 11641 if (!opened->IsPopupSpamWindow()) {
michael@0 11642 opened->SetPopupSpamWindow(true);
michael@0 11643 ++gOpenPopupSpamCount;
michael@0 11644 }
michael@0 11645 }
michael@0 11646 if (abuseLevel >= openAbused)
michael@0 11647 FireAbuseEvents(false, true, aUrl, aName, aOptions);
michael@0 11648 }
michael@0 11649
michael@0 11650 return rv;
michael@0 11651 }
michael@0 11652
michael@0 11653 //*****************************************************************************
michael@0 11654 // nsGlobalWindow: Timeout Functions
michael@0 11655 //*****************************************************************************
michael@0 11656
michael@0 11657 uint32_t sNestingLevel;
michael@0 11658
michael@0 11659 nsGlobalWindow*
michael@0 11660 nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult& aError)
michael@0 11661 {
michael@0 11662 nsGlobalWindow* currentInner;
michael@0 11663 nsGlobalWindow* forwardTo;
michael@0 11664 if (IsInnerWindow()) {
michael@0 11665 nsGlobalWindow* outer = GetOuterWindowInternal();
michael@0 11666 currentInner = outer ? outer->GetCurrentInnerWindowInternal() : this;
michael@0 11667
michael@0 11668 forwardTo = this;
michael@0 11669 } else {
michael@0 11670 currentInner = GetCurrentInnerWindowInternal();
michael@0 11671
michael@0 11672 // This needs to forward to the inner window, but since the current
michael@0 11673 // inner may not be the inner in the calling scope, we need to treat
michael@0 11674 // this specially here as we don't want timeouts registered in a
michael@0 11675 // dying inner window to get registered and run on the current inner
michael@0 11676 // window. To get this right, we need to forward this call to the
michael@0 11677 // inner window that's calling window.setTimeout().
michael@0 11678
michael@0 11679 forwardTo = CallerInnerWindow();
michael@0 11680 if (!forwardTo) {
michael@0 11681 aError.Throw(NS_ERROR_NOT_AVAILABLE);
michael@0 11682 return nullptr;
michael@0 11683 }
michael@0 11684
michael@0 11685 // If the caller and the callee share the same outer window, forward to the
michael@0 11686 // caller inner. Else, we forward to the current inner (e.g. someone is
michael@0 11687 // calling setTimeout() on a reference to some other window).
michael@0 11688 if (forwardTo->GetOuterWindow() != this || !forwardTo->IsInnerWindow()) {
michael@0 11689 if (!currentInner) {
michael@0 11690 NS_WARNING("No inner window available!");
michael@0 11691 aError.Throw(NS_ERROR_NOT_INITIALIZED);
michael@0 11692 return nullptr;
michael@0 11693 }
michael@0 11694
michael@0 11695 return currentInner;
michael@0 11696 }
michael@0 11697 }
michael@0 11698
michael@0 11699 // If forwardTo is not the window with an active document then we want the
michael@0 11700 // call to setTimeout/Interval to be a noop, so return null but don't set an
michael@0 11701 // error.
michael@0 11702 return forwardTo->HasActiveDocument() ? currentInner : nullptr;
michael@0 11703 }
michael@0 11704
michael@0 11705 int32_t
michael@0 11706 nsGlobalWindow::SetTimeout(JSContext* aCx, Function& aFunction,
michael@0 11707 int32_t aTimeout,
michael@0 11708 const Sequence<JS::Value>& aArguments,
michael@0 11709 ErrorResult& aError)
michael@0 11710 {
michael@0 11711 return SetTimeoutOrInterval(aFunction, aTimeout, aArguments, false, aError);
michael@0 11712 }
michael@0 11713
michael@0 11714 int32_t
michael@0 11715 nsGlobalWindow::SetTimeout(JSContext* aCx, const nsAString& aHandler,
michael@0 11716 int32_t aTimeout,
michael@0 11717 const Sequence<JS::Value>& /* unused */,
michael@0 11718 ErrorResult& aError)
michael@0 11719 {
michael@0 11720 return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError);
michael@0 11721 }
michael@0 11722
michael@0 11723 static bool
michael@0 11724 IsInterval(const Optional<int32_t>& aTimeout, int32_t& aResultTimeout)
michael@0 11725 {
michael@0 11726 if (aTimeout.WasPassed()) {
michael@0 11727 aResultTimeout = aTimeout.Value();
michael@0 11728 return true;
michael@0 11729 }
michael@0 11730
michael@0 11731 // If no interval was specified, treat this like a timeout, to avoid setting
michael@0 11732 // an interval of 0 milliseconds.
michael@0 11733 aResultTimeout = 0;
michael@0 11734 return false;
michael@0 11735 }
michael@0 11736
michael@0 11737 int32_t
michael@0 11738 nsGlobalWindow::SetInterval(JSContext* aCx, Function& aFunction,
michael@0 11739 const Optional<int32_t>& aTimeout,
michael@0 11740 const Sequence<JS::Value>& aArguments,
michael@0 11741 ErrorResult& aError)
michael@0 11742 {
michael@0 11743 int32_t timeout;
michael@0 11744 bool isInterval = IsInterval(aTimeout, timeout);
michael@0 11745 return SetTimeoutOrInterval(aFunction, timeout, aArguments, isInterval,
michael@0 11746 aError);
michael@0 11747 }
michael@0 11748
michael@0 11749 int32_t
michael@0 11750 nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler,
michael@0 11751 const Optional<int32_t>& aTimeout,
michael@0 11752 const Sequence<JS::Value>& /* unused */,
michael@0 11753 ErrorResult& aError)
michael@0 11754 {
michael@0 11755 int32_t timeout;
michael@0 11756 bool isInterval = IsInterval(aTimeout, timeout);
michael@0 11757 return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError);
michael@0 11758 }
michael@0 11759
michael@0 11760 nsresult
michael@0 11761 nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
michael@0 11762 int32_t interval,
michael@0 11763 bool aIsInterval, int32_t *aReturn)
michael@0 11764 {
michael@0 11765 MOZ_ASSERT(IsInnerWindow());
michael@0 11766
michael@0 11767 // If we don't have a document (we could have been unloaded since
michael@0 11768 // the call to setTimeout was made), do nothing.
michael@0 11769 if (!mDoc) {
michael@0 11770 return NS_OK;
michael@0 11771 }
michael@0 11772
michael@0 11773 // Disallow negative intervals. If aIsInterval also disallow 0,
michael@0 11774 // because we use that as a "don't repeat" flag.
michael@0 11775 interval = std::max(aIsInterval ? 1 : 0, interval);
michael@0 11776
michael@0 11777 // Make sure we don't proceed with an interval larger than our timer
michael@0 11778 // code can handle. (Note: we already forced |interval| to be non-negative,
michael@0 11779 // so the uint32_t cast (to avoid compiler warnings) is ok.)
michael@0 11780 uint32_t maxTimeoutMs = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
michael@0 11781 if (static_cast<uint32_t>(interval) > maxTimeoutMs) {
michael@0 11782 interval = maxTimeoutMs;
michael@0 11783 }
michael@0 11784
michael@0 11785 nsRefPtr<nsTimeout> timeout = new nsTimeout();
michael@0 11786 timeout->mIsInterval = aIsInterval;
michael@0 11787 timeout->mInterval = interval;
michael@0 11788 timeout->mScriptHandler = aHandler;
michael@0 11789
michael@0 11790 // Now clamp the actual interval we will use for the timer based on
michael@0 11791 uint32_t nestingLevel = sNestingLevel + 1;
michael@0 11792 uint32_t realInterval = interval;
michael@0 11793 if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
michael@0 11794 // Don't allow timeouts less than DOMMinTimeoutValue() from
michael@0 11795 // now...
michael@0 11796 realInterval = std::max(realInterval, uint32_t(DOMMinTimeoutValue()));
michael@0 11797 }
michael@0 11798
michael@0 11799 // Get principal of currently executing code, save for execution of timeout.
michael@0 11800 // If our principals subsume the subject principal then use the subject
michael@0 11801 // principal. Otherwise, use our principal to avoid running script in
michael@0 11802 // elevated principals.
michael@0 11803
michael@0 11804 nsCOMPtr<nsIPrincipal> subjectPrincipal;
michael@0 11805 nsresult rv;
michael@0 11806 rv = nsContentUtils::GetSecurityManager()->
michael@0 11807 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
michael@0 11808 if (NS_FAILED(rv)) {
michael@0 11809 return NS_ERROR_FAILURE;
michael@0 11810 }
michael@0 11811
michael@0 11812 bool subsumes = false;
michael@0 11813 nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
michael@0 11814
michael@0 11815 // Note the direction of this test: We don't allow setTimeouts running with
michael@0 11816 // chrome privileges on content windows, but we do allow setTimeouts running
michael@0 11817 // with content privileges on chrome windows (where they can't do very much,
michael@0 11818 // of course).
michael@0 11819 rv = ourPrincipal->Subsumes(subjectPrincipal, &subsumes);
michael@0 11820 if (NS_FAILED(rv)) {
michael@0 11821 return NS_ERROR_FAILURE;
michael@0 11822 }
michael@0 11823
michael@0 11824 if (subsumes) {
michael@0 11825 timeout->mPrincipal = subjectPrincipal;
michael@0 11826 } else {
michael@0 11827 timeout->mPrincipal = ourPrincipal;
michael@0 11828 }
michael@0 11829
michael@0 11830 ++gTimeoutsRecentlySet;
michael@0 11831 TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
michael@0 11832
michael@0 11833 if (!IsFrozen() && !mTimeoutsSuspendDepth) {
michael@0 11834 // If we're not currently frozen, then we set timeout->mWhen to be the
michael@0 11835 // actual firing time of the timer (i.e., now + delta). We also actually
michael@0 11836 // create a timer and fire it off.
michael@0 11837
michael@0 11838 timeout->mWhen = TimeStamp::Now() + delta;
michael@0 11839
michael@0 11840 timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
michael@0 11841 if (NS_FAILED(rv)) {
michael@0 11842 return rv;
michael@0 11843 }
michael@0 11844
michael@0 11845 nsRefPtr<nsTimeout> copy = timeout;
michael@0 11846
michael@0 11847 rv = timeout->InitTimer(TimerCallback, realInterval);
michael@0 11848 if (NS_FAILED(rv)) {
michael@0 11849 return rv;
michael@0 11850 }
michael@0 11851
michael@0 11852 // The timeout is now also held in the timer's closure.
michael@0 11853 unused << copy.forget();
michael@0 11854 } else {
michael@0 11855 // If we are frozen, however, then we instead simply set
michael@0 11856 // timeout->mTimeRemaining to be the "time remaining" in the timeout (i.e.,
michael@0 11857 // the interval itself). We don't create a timer for it, since that will
michael@0 11858 // happen when we are thawed and the timeout will then get a timer and run
michael@0 11859 // to completion.
michael@0 11860
michael@0 11861 timeout->mTimeRemaining = delta;
michael@0 11862 }
michael@0 11863
michael@0 11864 timeout->mWindow = this;
michael@0 11865
michael@0 11866 if (!aIsInterval) {
michael@0 11867 timeout->mNestingLevel = nestingLevel;
michael@0 11868 }
michael@0 11869
michael@0 11870 // No popups from timeouts by default
michael@0 11871 timeout->mPopupState = openAbused;
michael@0 11872
michael@0 11873 if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
michael@0 11874 // This timeout is *not* set from another timeout and it's set
michael@0 11875 // while popups are enabled. Propagate the state to the timeout if
michael@0 11876 // its delay (interval) is equal to or less than what
michael@0 11877 // "dom.disable_open_click_delay" is set to (in ms).
michael@0 11878
michael@0 11879 int32_t delay =
michael@0 11880 Preferences::GetInt("dom.disable_open_click_delay");
michael@0 11881
michael@0 11882 // This is checking |interval|, not realInterval, on purpose,
michael@0 11883 // because our lower bound for |realInterval| could be pretty high
michael@0 11884 // in some cases.
michael@0 11885 if (interval <= delay) {
michael@0 11886 timeout->mPopupState = gPopupControlState;
michael@0 11887 }
michael@0 11888 }
michael@0 11889
michael@0 11890 InsertTimeoutIntoList(timeout);
michael@0 11891
michael@0 11892 timeout->mPublicId = ++mTimeoutPublicIdCounter;
michael@0 11893 *aReturn = timeout->mPublicId;
michael@0 11894
michael@0 11895 return NS_OK;
michael@0 11896
michael@0 11897 }
michael@0 11898
michael@0 11899 nsresult
michael@0 11900 nsGlobalWindow::SetTimeoutOrInterval(bool aIsInterval, int32_t *aReturn)
michael@0 11901 {
michael@0 11902 // This needs to forward to the inner window, but since the current
michael@0 11903 // inner may not be the inner in the calling scope, we need to treat
michael@0 11904 // this specially here as we don't want timeouts registered in a
michael@0 11905 // dying inner window to get registered and run on the current inner
michael@0 11906 // window. To get this right, we need to forward this call to the
michael@0 11907 // inner window that's calling window.setTimeout().
michael@0 11908
michael@0 11909 if (IsOuterWindow()) {
michael@0 11910 nsGlobalWindow* callerInner = CallerInnerWindow();
michael@0 11911 NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
michael@0 11912
michael@0 11913 // If the caller and the callee share the same outer window,
michael@0 11914 // forward to the callee inner. Else, we forward to the current
michael@0 11915 // inner (e.g. someone is calling setTimeout() on a reference to
michael@0 11916 // some other window).
michael@0 11917
michael@0 11918 if (callerInner->GetOuterWindow() == this &&
michael@0 11919 callerInner->IsInnerWindow()) {
michael@0 11920 return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
michael@0 11921 }
michael@0 11922
michael@0 11923 FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
michael@0 11924 NS_ERROR_NOT_INITIALIZED);
michael@0 11925 }
michael@0 11926
michael@0 11927 int32_t interval = 0;
michael@0 11928 bool isInterval = aIsInterval;
michael@0 11929 nsCOMPtr<nsIScriptTimeoutHandler> handler;
michael@0 11930 nsresult rv = NS_CreateJSTimeoutHandler(this,
michael@0 11931 &isInterval,
michael@0 11932 &interval,
michael@0 11933 getter_AddRefs(handler));
michael@0 11934 if (!handler) {
michael@0 11935 *aReturn = 0;
michael@0 11936 return rv;
michael@0 11937 }
michael@0 11938
michael@0 11939 return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
michael@0 11940 }
michael@0 11941
michael@0 11942 int32_t
michael@0 11943 nsGlobalWindow::SetTimeoutOrInterval(Function& aFunction, int32_t aTimeout,
michael@0 11944 const Sequence<JS::Value>& aArguments,
michael@0 11945 bool aIsInterval, ErrorResult& aError)
michael@0 11946 {
michael@0 11947 nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
michael@0 11948 if (!inner) {
michael@0 11949 return -1;
michael@0 11950 }
michael@0 11951
michael@0 11952 if (inner != this) {
michael@0 11953 return inner->SetTimeoutOrInterval(aFunction, aTimeout, aArguments,
michael@0 11954 aIsInterval, aError);
michael@0 11955 }
michael@0 11956
michael@0 11957 nsCOMPtr<nsIScriptTimeoutHandler> handler =
michael@0 11958 NS_CreateJSTimeoutHandler(this, aFunction, aArguments, aError);
michael@0 11959 if (!handler) {
michael@0 11960 return 0;
michael@0 11961 }
michael@0 11962
michael@0 11963 int32_t result;
michael@0 11964 aError = SetTimeoutOrInterval(handler, aTimeout, aIsInterval, &result);
michael@0 11965 return result;
michael@0 11966 }
michael@0 11967
michael@0 11968 int32_t
michael@0 11969 nsGlobalWindow::SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
michael@0 11970 int32_t aTimeout, bool aIsInterval,
michael@0 11971 ErrorResult& aError)
michael@0 11972 {
michael@0 11973 nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
michael@0 11974 if (!inner) {
michael@0 11975 return -1;
michael@0 11976 }
michael@0 11977
michael@0 11978 if (inner != this) {
michael@0 11979 return inner->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
michael@0 11980 aError);
michael@0 11981 }
michael@0 11982
michael@0 11983 nsCOMPtr<nsIScriptTimeoutHandler> handler =
michael@0 11984 NS_CreateJSTimeoutHandler(aCx, this, aHandler, aError);
michael@0 11985 if (!handler) {
michael@0 11986 return 0;
michael@0 11987 }
michael@0 11988
michael@0 11989 int32_t result;
michael@0 11990 aError = SetTimeoutOrInterval(handler, aTimeout, aIsInterval, &result);
michael@0 11991 return result;
michael@0 11992 }
michael@0 11993
michael@0 11994 bool
michael@0 11995 nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
michael@0 11996 nsIScriptContext* aScx)
michael@0 11997 {
michael@0 11998 // Hold on to the timeout in case mExpr or mFunObj releases its
michael@0 11999 // doc.
michael@0 12000 nsRefPtr<nsTimeout> timeout = aTimeout;
michael@0 12001 nsTimeout* last_running_timeout = mRunningTimeout;
michael@0 12002 mRunningTimeout = timeout;
michael@0 12003 timeout->mRunning = true;
michael@0 12004
michael@0 12005 // Push this timeout's popup control state, which should only be
michael@0 12006 // eabled the first time a timeout fires that was created while
michael@0 12007 // popups were enabled and with a delay less than
michael@0 12008 // "dom.disable_open_click_delay".
michael@0 12009 nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
michael@0 12010
michael@0 12011 // Clear the timeout's popup state, if any, to prevent interval
michael@0 12012 // timeouts from repeatedly opening poups.
michael@0 12013 timeout->mPopupState = openAbused;
michael@0 12014
michael@0 12015 ++gRunningTimeoutDepth;
michael@0 12016 ++mTimeoutFiringDepth;
michael@0 12017
michael@0 12018 bool trackNestingLevel = !timeout->mIsInterval;
michael@0 12019 uint32_t nestingLevel;
michael@0 12020 if (trackNestingLevel) {
michael@0 12021 nestingLevel = sNestingLevel;
michael@0 12022 sNestingLevel = timeout->mNestingLevel;
michael@0 12023 }
michael@0 12024
michael@0 12025 nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
michael@0 12026 nsRefPtr<Function> callback = handler->GetCallback();
michael@0 12027 if (!callback) {
michael@0 12028 // Evaluate the timeout expression.
michael@0 12029 const char16_t* script = handler->GetHandlerText();
michael@0 12030 NS_ASSERTION(script, "timeout has no script nor handler text!");
michael@0 12031
michael@0 12032 const char* filename = nullptr;
michael@0 12033 uint32_t lineNo = 0;
michael@0 12034 handler->GetLocation(&filename, &lineNo);
michael@0 12035
michael@0 12036 // New script entry point required, due to the "Create a script" sub-step of
michael@0 12037 // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialization-steps
michael@0 12038 AutoEntryScript entryScript(this, true, aScx->GetNativeContext());
michael@0 12039 JS::CompileOptions options(entryScript.cx());
michael@0 12040 options.setFileAndLine(filename, lineNo)
michael@0 12041 .setVersion(JSVERSION_DEFAULT);
michael@0 12042 JS::Rooted<JSObject*> global(entryScript.cx(), FastGetGlobalJSObject());
michael@0 12043 nsJSUtils::EvaluateString(entryScript.cx(), nsDependentString(script),
michael@0 12044 global, options);
michael@0 12045 } else {
michael@0 12046 // Hold strong ref to ourselves while we call the callback.
michael@0 12047 nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
michael@0 12048 ErrorResult ignored;
michael@0 12049 JS::Rooted<JS::Value> ignoredVal(CycleCollectedJSRuntime::Get()->Runtime());
michael@0 12050 callback->Call(me, handler->GetArgs(), &ignoredVal, ignored);
michael@0 12051 }
michael@0 12052
michael@0 12053 // We ignore any failures from calling EvaluateString() on the context or
michael@0 12054 // Call() on a Function here since we're in a loop
michael@0 12055 // where we're likely to be running timeouts whose OS timers
michael@0 12056 // didn't fire in time and we don't want to not fire those timers
michael@0 12057 // now just because execution of one timer failed. We can't
michael@0 12058 // propagate the error to anyone who cares about it from this
michael@0 12059 // point anyway, and the script context should have already reported
michael@0 12060 // the script error in the usual way - so we just drop it.
michael@0 12061
michael@0 12062 if (trackNestingLevel) {
michael@0 12063 sNestingLevel = nestingLevel;
michael@0 12064 }
michael@0 12065
michael@0 12066 --mTimeoutFiringDepth;
michael@0 12067 --gRunningTimeoutDepth;
michael@0 12068
michael@0 12069 mRunningTimeout = last_running_timeout;
michael@0 12070 timeout->mRunning = false;
michael@0 12071 return timeout->mCleared;
michael@0 12072 }
michael@0 12073
michael@0 12074 bool
michael@0 12075 nsGlobalWindow::RescheduleTimeout(nsTimeout* aTimeout, const TimeStamp& now,
michael@0 12076 bool aRunningPendingTimeouts)
michael@0 12077 {
michael@0 12078 if (!aTimeout->mIsInterval) {
michael@0 12079 if (aTimeout->mTimer) {
michael@0 12080 // The timeout still has an OS timer, and it's not an interval,
michael@0 12081 // that means that the OS timer could still fire; cancel the OS
michael@0 12082 // timer and release its reference to the timeout.
michael@0 12083 aTimeout->mTimer->Cancel();
michael@0 12084 aTimeout->mTimer = nullptr;
michael@0 12085 aTimeout->Release();
michael@0 12086 }
michael@0 12087 return false;
michael@0 12088 }
michael@0 12089
michael@0 12090 // Compute time to next timeout for interval timer.
michael@0 12091 // Make sure nextInterval is at least DOMMinTimeoutValue().
michael@0 12092 TimeDuration nextInterval =
michael@0 12093 TimeDuration::FromMilliseconds(std::max(aTimeout->mInterval,
michael@0 12094 uint32_t(DOMMinTimeoutValue())));
michael@0 12095
michael@0 12096 // If we're running pending timeouts, set the next interval to be
michael@0 12097 // relative to "now", and not to when the timeout that was pending
michael@0 12098 // should have fired.
michael@0 12099 TimeStamp firingTime;
michael@0 12100 if (aRunningPendingTimeouts) {
michael@0 12101 firingTime = now + nextInterval;
michael@0 12102 } else {
michael@0 12103 firingTime = aTimeout->mWhen + nextInterval;
michael@0 12104 }
michael@0 12105
michael@0 12106 TimeStamp currentNow = TimeStamp::Now();
michael@0 12107 TimeDuration delay = firingTime - currentNow;
michael@0 12108
michael@0 12109 // And make sure delay is nonnegative; that might happen if the timer
michael@0 12110 // thread is firing our timers somewhat early or if they're taking a long
michael@0 12111 // time to run the callback.
michael@0 12112 if (delay < TimeDuration(0)) {
michael@0 12113 delay = TimeDuration(0);
michael@0 12114 }
michael@0 12115
michael@0 12116 if (!aTimeout->mTimer) {
michael@0 12117 NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
michael@0 12118 "How'd our timer end up null if we're not frozen or "
michael@0 12119 "suspended?");
michael@0 12120
michael@0 12121 aTimeout->mTimeRemaining = delay;
michael@0 12122 return true;
michael@0 12123 }
michael@0 12124
michael@0 12125 aTimeout->mWhen = currentNow + delay;
michael@0 12126
michael@0 12127 // Reschedule the OS timer. Don't bother returning any error codes if
michael@0 12128 // this fails since the callers of this method don't care about them.
michael@0 12129 nsresult rv = aTimeout->InitTimer(TimerCallback, delay.ToMilliseconds());
michael@0 12130
michael@0 12131 if (NS_FAILED(rv)) {
michael@0 12132 NS_ERROR("Error initializing timer for DOM timeout!");
michael@0 12133
michael@0 12134 // We failed to initialize the new OS timer, this timer does
michael@0 12135 // us no good here so we just cancel it (just in case) and
michael@0 12136 // null out the pointer to the OS timer, this will release the
michael@0 12137 // OS timer. As we continue executing the code below we'll end
michael@0 12138 // up deleting the timeout since it's not an interval timeout
michael@0 12139 // any more (since timeout->mTimer == nullptr).
michael@0 12140 aTimeout->mTimer->Cancel();
michael@0 12141 aTimeout->mTimer = nullptr;
michael@0 12142
michael@0 12143 // Now that the OS timer no longer has a reference to the
michael@0 12144 // timeout we need to drop that reference.
michael@0 12145 aTimeout->Release();
michael@0 12146
michael@0 12147 return false;
michael@0 12148 }
michael@0 12149
michael@0 12150 return true;
michael@0 12151 }
michael@0 12152
michael@0 12153 void
michael@0 12154 nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
michael@0 12155 {
michael@0 12156 // If a modal dialog is open for this window, return early. Pending
michael@0 12157 // timeouts will run when the modal dialog is dismissed.
michael@0 12158 if (IsInModalState() || mTimeoutsSuspendDepth) {
michael@0 12159 return;
michael@0 12160 }
michael@0 12161
michael@0 12162 NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
michael@0 12163 NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
michael@0 12164
michael@0 12165 nsTimeout *nextTimeout;
michael@0 12166 nsTimeout *last_expired_timeout, *last_insertion_point;
michael@0 12167 uint32_t firingDepth = mTimeoutFiringDepth + 1;
michael@0 12168
michael@0 12169 // Make sure that the window and the script context don't go away as
michael@0 12170 // a result of running timeouts
michael@0 12171 nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
michael@0 12172
michael@0 12173 // A native timer has gone off. See which of our timeouts need
michael@0 12174 // servicing
michael@0 12175 TimeStamp now = TimeStamp::Now();
michael@0 12176 TimeStamp deadline;
michael@0 12177
michael@0 12178 if (aTimeout && aTimeout->mWhen > now) {
michael@0 12179 // The OS timer fired early (which can happen due to the timers
michael@0 12180 // having lower precision than TimeStamp does). Set |deadline| to
michael@0 12181 // be the time when the OS timer *should* have fired so that any
michael@0 12182 // timers that *should* have fired before aTimeout *will* be fired
michael@0 12183 // now.
michael@0 12184
michael@0 12185 deadline = aTimeout->mWhen;
michael@0 12186 } else {
michael@0 12187 deadline = now;
michael@0 12188 }
michael@0 12189
michael@0 12190 // The timeout list is kept in deadline order. Discover the latest
michael@0 12191 // timeout whose deadline has expired. On some platforms, native
michael@0 12192 // timeout events fire "early", so we need to test the timer as well
michael@0 12193 // as the deadline.
michael@0 12194 last_expired_timeout = nullptr;
michael@0 12195 for (nsTimeout *timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
michael@0 12196 if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
michael@0 12197 (timeout->mFiringDepth == 0)) {
michael@0 12198 // Mark any timeouts that are on the list to be fired with the
michael@0 12199 // firing depth so that we can reentrantly run timeouts
michael@0 12200 timeout->mFiringDepth = firingDepth;
michael@0 12201 last_expired_timeout = timeout;
michael@0 12202 }
michael@0 12203 }
michael@0 12204
michael@0 12205 // Maybe the timeout that the event was fired for has been deleted
michael@0 12206 // and there are no others timeouts with deadlines that make them
michael@0 12207 // eligible for execution yet. Go away.
michael@0 12208 if (!last_expired_timeout) {
michael@0 12209 return;
michael@0 12210 }
michael@0 12211
michael@0 12212 // Record telemetry information about timers set recently.
michael@0 12213 TimeDuration recordingInterval = TimeDuration::FromMilliseconds(STATISTICS_INTERVAL);
michael@0 12214 if (gLastRecordedRecentTimeouts.IsNull() ||
michael@0 12215 now - gLastRecordedRecentTimeouts > recordingInterval) {
michael@0 12216 uint32_t count = gTimeoutsRecentlySet;
michael@0 12217 gTimeoutsRecentlySet = 0;
michael@0 12218 Telemetry::Accumulate(Telemetry::DOM_TIMERS_RECENTLY_SET, count);
michael@0 12219 gLastRecordedRecentTimeouts = now;
michael@0 12220 }
michael@0 12221
michael@0 12222 // Insert a dummy timeout into the list of timeouts between the
michael@0 12223 // portion of the list that we are about to process now and those
michael@0 12224 // timeouts that will be processed in a future call to
michael@0 12225 // win_run_timeout(). This dummy timeout serves as the head of the
michael@0 12226 // list for any timeouts inserted as a result of running a timeout.
michael@0 12227 nsRefPtr<nsTimeout> dummy_timeout = new nsTimeout();
michael@0 12228 dummy_timeout->mFiringDepth = firingDepth;
michael@0 12229 dummy_timeout->mWhen = now;
michael@0 12230 last_expired_timeout->setNext(dummy_timeout);
michael@0 12231 dummy_timeout->AddRef();
michael@0 12232
michael@0 12233 last_insertion_point = mTimeoutInsertionPoint;
michael@0 12234 // If we ever start setting mTimeoutInsertionPoint to a non-dummy timeout,
michael@0 12235 // the logic in ResetTimersForNonBackgroundWindow will need to change.
michael@0 12236 mTimeoutInsertionPoint = dummy_timeout;
michael@0 12237
michael@0 12238 Telemetry::AutoCounter<Telemetry::DOM_TIMERS_FIRED_PER_NATIVE_TIMEOUT> timeoutsRan;
michael@0 12239
michael@0 12240 for (nsTimeout *timeout = mTimeouts.getFirst();
michael@0 12241 timeout != dummy_timeout && !IsFrozen();
michael@0 12242 timeout = nextTimeout) {
michael@0 12243 nextTimeout = timeout->getNext();
michael@0 12244
michael@0 12245 if (timeout->mFiringDepth != firingDepth) {
michael@0 12246 // We skip the timeout since it's on the list to run at another
michael@0 12247 // depth.
michael@0 12248
michael@0 12249 continue;
michael@0 12250 }
michael@0 12251
michael@0 12252 if (mTimeoutsSuspendDepth) {
michael@0 12253 // Some timer did suspend us. Make sure the
michael@0 12254 // rest of the timers get executed later.
michael@0 12255 timeout->mFiringDepth = 0;
michael@0 12256 continue;
michael@0 12257 }
michael@0 12258
michael@0 12259 // The timeout is on the list to run at this depth, go ahead and
michael@0 12260 // process it.
michael@0 12261
michael@0 12262 // Get the script context (a strong ref to prevent it going away)
michael@0 12263 // for this timeout and ensure the script language is enabled.
michael@0 12264 nsCOMPtr<nsIScriptContext> scx = GetContextInternal();
michael@0 12265
michael@0 12266 if (!scx) {
michael@0 12267 // No context means this window was closed or never properly
michael@0 12268 // initialized for this language.
michael@0 12269 continue;
michael@0 12270 }
michael@0 12271
michael@0 12272 // This timeout is good to run
michael@0 12273 ++timeoutsRan;
michael@0 12274 bool timeout_was_cleared = RunTimeoutHandler(timeout, scx);
michael@0 12275
michael@0 12276 if (timeout_was_cleared) {
michael@0 12277 // The running timeout's window was cleared, this means that
michael@0 12278 // ClearAllTimeouts() was called from a *nested* call, possibly
michael@0 12279 // through a timeout that fired while a modal (to this window)
michael@0 12280 // dialog was open or through other non-obvious paths.
michael@0 12281 MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
michael@0 12282
michael@0 12283 mTimeoutInsertionPoint = last_insertion_point;
michael@0 12284
michael@0 12285 return;
michael@0 12286 }
michael@0 12287
michael@0 12288 // If we have a regular interval timer, we re-schedule the
michael@0 12289 // timeout, accounting for clock drift.
michael@0 12290 bool needsReinsertion = RescheduleTimeout(timeout, now, !aTimeout);
michael@0 12291
michael@0 12292 // Running a timeout can cause another timeout to be deleted, so
michael@0 12293 // we need to reset the pointer to the following timeout.
michael@0 12294 nextTimeout = timeout->getNext();
michael@0 12295
michael@0 12296 timeout->remove();
michael@0 12297
michael@0 12298 if (needsReinsertion) {
michael@0 12299 // Insert interval timeout onto list sorted in deadline order.
michael@0 12300 // AddRefs timeout.
michael@0 12301 InsertTimeoutIntoList(timeout);
michael@0 12302 }
michael@0 12303
michael@0 12304 // Release the timeout struct since it's possibly out of the list
michael@0 12305 timeout->Release();
michael@0 12306 }
michael@0 12307
michael@0 12308 // Take the dummy timeout off the head of the list
michael@0 12309 dummy_timeout->remove();
michael@0 12310 dummy_timeout->Release();
michael@0 12311 MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
michael@0 12312
michael@0 12313 mTimeoutInsertionPoint = last_insertion_point;
michael@0 12314 }
michael@0 12315
michael@0 12316 void
michael@0 12317 nsGlobalWindow::ClearTimeoutOrInterval(int32_t aTimerID, ErrorResult& aError)
michael@0 12318 {
michael@0 12319 FORWARD_TO_INNER_OR_THROW(ClearTimeoutOrInterval, (aTimerID, aError),
michael@0 12320 aError, );
michael@0 12321
michael@0 12322 uint32_t public_id = (uint32_t)aTimerID;
michael@0 12323 nsTimeout *timeout;
michael@0 12324
michael@0 12325 for (timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
michael@0 12326 if (timeout->mPublicId == public_id) {
michael@0 12327 if (timeout->mRunning) {
michael@0 12328 /* We're running from inside the timeout. Mark this
michael@0 12329 timeout for deferred deletion by the code in
michael@0 12330 RunTimeout() */
michael@0 12331 timeout->mIsInterval = false;
michael@0 12332 }
michael@0 12333 else {
michael@0 12334 /* Delete the timeout from the pending timeout list */
michael@0 12335 timeout->remove();
michael@0 12336
michael@0 12337 if (timeout->mTimer) {
michael@0 12338 timeout->mTimer->Cancel();
michael@0 12339 timeout->mTimer = nullptr;
michael@0 12340 timeout->Release();
michael@0 12341 }
michael@0 12342 timeout->Release();
michael@0 12343 }
michael@0 12344 break;
michael@0 12345 }
michael@0 12346 }
michael@0 12347 }
michael@0 12348
michael@0 12349 nsresult nsGlobalWindow::ResetTimersForNonBackgroundWindow()
michael@0 12350 {
michael@0 12351 FORWARD_TO_INNER(ResetTimersForNonBackgroundWindow, (),
michael@0 12352 NS_ERROR_NOT_INITIALIZED);
michael@0 12353
michael@0 12354 if (IsFrozen() || mTimeoutsSuspendDepth) {
michael@0 12355 return NS_OK;
michael@0 12356 }
michael@0 12357
michael@0 12358 TimeStamp now = TimeStamp::Now();
michael@0 12359
michael@0 12360 // If mTimeoutInsertionPoint is non-null, we're in the middle of firing
michael@0 12361 // timers and the timers we're planning to fire all come before
michael@0 12362 // mTimeoutInsertionPoint; mTimeoutInsertionPoint itself is a dummy timeout
michael@0 12363 // with an mWhen that may be semi-bogus. In that case, we don't need to do
michael@0 12364 // anything with mTimeoutInsertionPoint or anything before it, so should
michael@0 12365 // start at the timer after mTimeoutInsertionPoint, if there is one.
michael@0 12366 // Otherwise, start at the beginning of the list.
michael@0 12367 for (nsTimeout *timeout = mTimeoutInsertionPoint ?
michael@0 12368 mTimeoutInsertionPoint->getNext() : mTimeouts.getFirst();
michael@0 12369 timeout; ) {
michael@0 12370 // It's important that this check be <= so that we guarantee that
michael@0 12371 // taking std::max with |now| won't make a quantity equal to
michael@0 12372 // timeout->mWhen below.
michael@0 12373 if (timeout->mWhen <= now) {
michael@0 12374 timeout = timeout->getNext();
michael@0 12375 continue;
michael@0 12376 }
michael@0 12377
michael@0 12378 if (timeout->mWhen - now >
michael@0 12379 TimeDuration::FromMilliseconds(gMinBackgroundTimeoutValue)) {
michael@0 12380 // No need to loop further. Timeouts are sorted in mWhen order
michael@0 12381 // and the ones after this point were all set up for at least
michael@0 12382 // gMinBackgroundTimeoutValue ms and hence were not clamped.
michael@0 12383 break;
michael@0 12384 }
michael@0 12385
michael@0 12386 /* We switched from background. Re-init the timer appropriately */
michael@0 12387 // Compute the interval the timer should have had if it had not been set in a
michael@0 12388 // background window
michael@0 12389 TimeDuration interval =
michael@0 12390 TimeDuration::FromMilliseconds(std::max(timeout->mInterval,
michael@0 12391 uint32_t(DOMMinTimeoutValue())));
michael@0 12392 uint32_t oldIntervalMillisecs = 0;
michael@0 12393 timeout->mTimer->GetDelay(&oldIntervalMillisecs);
michael@0 12394 TimeDuration oldInterval = TimeDuration::FromMilliseconds(oldIntervalMillisecs);
michael@0 12395 if (oldInterval > interval) {
michael@0 12396 // unclamp
michael@0 12397 TimeStamp firingTime =
michael@0 12398 std::max(timeout->mWhen - oldInterval + interval, now);
michael@0 12399
michael@0 12400 NS_ASSERTION(firingTime < timeout->mWhen,
michael@0 12401 "Our firing time should strictly decrease!");
michael@0 12402
michael@0 12403 TimeDuration delay = firingTime - now;
michael@0 12404 timeout->mWhen = firingTime;
michael@0 12405
michael@0 12406 // Since we reset mWhen we need to move |timeout| to the right
michael@0 12407 // place in the list so that it remains sorted by mWhen.
michael@0 12408
michael@0 12409 // Get the pointer to the next timeout now, before we move the
michael@0 12410 // current timeout in the list.
michael@0 12411 nsTimeout* nextTimeout = timeout->getNext();
michael@0 12412
michael@0 12413 // It is safe to remove and re-insert because mWhen is now
michael@0 12414 // strictly smaller than it used to be, so we know we'll insert
michael@0 12415 // |timeout| before nextTimeout.
michael@0 12416 NS_ASSERTION(!nextTimeout ||
michael@0 12417 timeout->mWhen < nextTimeout->mWhen, "How did that happen?");
michael@0 12418 timeout->remove();
michael@0 12419 // InsertTimeoutIntoList will addref |timeout| and reset
michael@0 12420 // mFiringDepth. Make sure to undo that after calling it.
michael@0 12421 uint32_t firingDepth = timeout->mFiringDepth;
michael@0 12422 InsertTimeoutIntoList(timeout);
michael@0 12423 timeout->mFiringDepth = firingDepth;
michael@0 12424 timeout->Release();
michael@0 12425
michael@0 12426 nsresult rv = timeout->InitTimer(TimerCallback, delay.ToMilliseconds());
michael@0 12427
michael@0 12428 if (NS_FAILED(rv)) {
michael@0 12429 NS_WARNING("Error resetting non background timer for DOM timeout!");
michael@0 12430 return rv;
michael@0 12431 }
michael@0 12432
michael@0 12433 timeout = nextTimeout;
michael@0 12434 } else {
michael@0 12435 timeout = timeout->getNext();
michael@0 12436 }
michael@0 12437 }
michael@0 12438
michael@0 12439 return NS_OK;
michael@0 12440 }
michael@0 12441
michael@0 12442 void
michael@0 12443 nsGlobalWindow::ClearAllTimeouts()
michael@0 12444 {
michael@0 12445 nsTimeout *timeout, *nextTimeout;
michael@0 12446
michael@0 12447 for (timeout = mTimeouts.getFirst(); timeout; timeout = nextTimeout) {
michael@0 12448 /* If RunTimeout() is higher up on the stack for this
michael@0 12449 window, e.g. as a result of document.write from a timeout,
michael@0 12450 then we need to reset the list insertion point for
michael@0 12451 newly-created timeouts in case the user adds a timeout,
michael@0 12452 before we pop the stack back to RunTimeout. */
michael@0 12453 if (mRunningTimeout == timeout)
michael@0 12454 mTimeoutInsertionPoint = nullptr;
michael@0 12455
michael@0 12456 nextTimeout = timeout->getNext();
michael@0 12457
michael@0 12458 if (timeout->mTimer) {
michael@0 12459 timeout->mTimer->Cancel();
michael@0 12460 timeout->mTimer = nullptr;
michael@0 12461
michael@0 12462 // Drop the count since the timer isn't going to hold on
michael@0 12463 // anymore.
michael@0 12464 timeout->Release();
michael@0 12465 }
michael@0 12466
michael@0 12467 // Set timeout->mCleared to true to indicate that the timeout was
michael@0 12468 // cleared and taken out of the list of timeouts
michael@0 12469 timeout->mCleared = true;
michael@0 12470
michael@0 12471 // Drop the count since we're removing it from the list.
michael@0 12472 timeout->Release();
michael@0 12473 }
michael@0 12474
michael@0 12475 // Clear out our list
michael@0 12476 mTimeouts.clear();
michael@0 12477 }
michael@0 12478
michael@0 12479 void
michael@0 12480 nsGlobalWindow::InsertTimeoutIntoList(nsTimeout *aTimeout)
michael@0 12481 {
michael@0 12482 NS_ASSERTION(IsInnerWindow(),
michael@0 12483 "InsertTimeoutIntoList() called on outer window!");
michael@0 12484
michael@0 12485 // Start at mLastTimeout and go backwards. Don't go further than
michael@0 12486 // mTimeoutInsertionPoint, though. This optimizes for the common case of
michael@0 12487 // insertion at the end.
michael@0 12488 nsTimeout* prevSibling;
michael@0 12489 for (prevSibling = mTimeouts.getLast();
michael@0 12490 prevSibling && prevSibling != mTimeoutInsertionPoint &&
michael@0 12491 // This condition needs to match the one in SetTimeoutOrInterval that
michael@0 12492 // determines whether to set mWhen or mTimeRemaining.
michael@0 12493 ((IsFrozen() || mTimeoutsSuspendDepth) ?
michael@0 12494 prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
michael@0 12495 prevSibling->mWhen > aTimeout->mWhen);
michael@0 12496 prevSibling = prevSibling->getPrevious()) {
michael@0 12497 /* Do nothing; just searching */
michael@0 12498 }
michael@0 12499
michael@0 12500 // Now link in aTimeout after prevSibling.
michael@0 12501 if (prevSibling) {
michael@0 12502 prevSibling->setNext(aTimeout);
michael@0 12503 } else {
michael@0 12504 mTimeouts.insertFront(aTimeout);
michael@0 12505 }
michael@0 12506
michael@0 12507 aTimeout->mFiringDepth = 0;
michael@0 12508
michael@0 12509 // Increment the timeout's reference count since it's now held on to
michael@0 12510 // by the list
michael@0 12511 aTimeout->AddRef();
michael@0 12512 }
michael@0 12513
michael@0 12514 // static
michael@0 12515 void
michael@0 12516 nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
michael@0 12517 {
michael@0 12518 nsRefPtr<nsTimeout> timeout = (nsTimeout *)aClosure;
michael@0 12519
michael@0 12520 timeout->mWindow->RunTimeout(timeout);
michael@0 12521 }
michael@0 12522
michael@0 12523 //*****************************************************************************
michael@0 12524 // nsGlobalWindow: Helper Functions
michael@0 12525 //*****************************************************************************
michael@0 12526
michael@0 12527 already_AddRefed<nsIDocShellTreeOwner>
michael@0 12528 nsGlobalWindow::GetTreeOwner()
michael@0 12529 {
michael@0 12530 FORWARD_TO_OUTER(GetTreeOwner, (), nullptr);
michael@0 12531
michael@0 12532 // If there's no docShellAsItem, this window must have been closed,
michael@0 12533 // in that case there is no tree owner.
michael@0 12534
michael@0 12535 if (!mDocShell) {
michael@0 12536 return nullptr;
michael@0 12537 }
michael@0 12538
michael@0 12539 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
michael@0 12540 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
michael@0 12541 return treeOwner.forget();
michael@0 12542 }
michael@0 12543
michael@0 12544 already_AddRefed<nsIBaseWindow>
michael@0 12545 nsGlobalWindow::GetTreeOwnerWindow()
michael@0 12546 {
michael@0 12547 MOZ_ASSERT(IsOuterWindow());
michael@0 12548
michael@0 12549 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
michael@0 12550
michael@0 12551 // If there's no mDocShell, this window must have been closed,
michael@0 12552 // in that case there is no tree owner.
michael@0 12553
michael@0 12554 if (mDocShell) {
michael@0 12555 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
michael@0 12556 }
michael@0 12557
michael@0 12558 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
michael@0 12559 return baseWindow.forget();
michael@0 12560 }
michael@0 12561
michael@0 12562 already_AddRefed<nsIWebBrowserChrome>
michael@0 12563 nsGlobalWindow::GetWebBrowserChrome()
michael@0 12564 {
michael@0 12565 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
michael@0 12566
michael@0 12567 nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
michael@0 12568 return browserChrome.forget();
michael@0 12569 }
michael@0 12570
michael@0 12571 nsIScrollableFrame *
michael@0 12572 nsGlobalWindow::GetScrollFrame()
michael@0 12573 {
michael@0 12574 FORWARD_TO_OUTER(GetScrollFrame, (), nullptr);
michael@0 12575
michael@0 12576 if (!mDocShell) {
michael@0 12577 return nullptr;
michael@0 12578 }
michael@0 12579
michael@0 12580 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 12581 if (presShell) {
michael@0 12582 return presShell->GetRootScrollFrameAsScrollable();
michael@0 12583 }
michael@0 12584 return nullptr;
michael@0 12585 }
michael@0 12586
michael@0 12587 nsresult
michael@0 12588 nsGlobalWindow::SecurityCheckURL(const char *aURL)
michael@0 12589 {
michael@0 12590 nsCOMPtr<nsPIDOMWindow> sourceWindow;
michael@0 12591 JSContext* topCx = nsContentUtils::GetCurrentJSContext();
michael@0 12592 if (topCx) {
michael@0 12593 sourceWindow = do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(topCx));
michael@0 12594 }
michael@0 12595 if (!sourceWindow) {
michael@0 12596 sourceWindow = this;
michael@0 12597 }
michael@0 12598 AutoJSContext cx;
michael@0 12599 nsGlobalWindow* sourceWin = static_cast<nsGlobalWindow*>(sourceWindow.get());
michael@0 12600 JSAutoCompartment ac(cx, sourceWin->GetGlobalJSObject());
michael@0 12601
michael@0 12602 // Resolve the baseURI, which could be relative to the calling window.
michael@0 12603 //
michael@0 12604 // Note the algorithm to get the base URI should match the one
michael@0 12605 // used to actually kick off the load in nsWindowWatcher.cpp.
michael@0 12606 nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
michael@0 12607 nsIURI* baseURI = nullptr;
michael@0 12608 nsAutoCString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
michael@0 12609 if (doc) {
michael@0 12610 baseURI = doc->GetDocBaseURI();
michael@0 12611 charset = doc->GetDocumentCharacterSet();
michael@0 12612 }
michael@0 12613 nsCOMPtr<nsIURI> uri;
michael@0 12614 nsresult rv = NS_NewURI(getter_AddRefs(uri), nsDependentCString(aURL),
michael@0 12615 charset.get(), baseURI);
michael@0 12616 if (NS_WARN_IF(NS_FAILED(rv))) {
michael@0 12617 return rv;
michael@0 12618 }
michael@0 12619
michael@0 12620 if (NS_FAILED(nsContentUtils::GetSecurityManager()->
michael@0 12621 CheckLoadURIFromScript(cx, uri))) {
michael@0 12622 return NS_ERROR_FAILURE;
michael@0 12623 }
michael@0 12624
michael@0 12625 return NS_OK;
michael@0 12626 }
michael@0 12627
michael@0 12628 void
michael@0 12629 nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
michael@0 12630 {
michael@0 12631 if (mDoc) {
michael@0 12632 mDoc->FlushPendingNotifications(aType);
michael@0 12633 }
michael@0 12634 }
michael@0 12635
michael@0 12636 void
michael@0 12637 nsGlobalWindow::EnsureSizeUpToDate()
michael@0 12638 {
michael@0 12639 MOZ_ASSERT(IsOuterWindow());
michael@0 12640
michael@0 12641 // If we're a subframe, make sure our size is up to date. It's OK that this
michael@0 12642 // crosses the content/chrome boundary, since chrome can have pending reflows
michael@0 12643 // too.
michael@0 12644 nsGlobalWindow *parent =
michael@0 12645 static_cast<nsGlobalWindow *>(GetPrivateParent());
michael@0 12646 if (parent) {
michael@0 12647 parent->FlushPendingNotifications(Flush_Layout);
michael@0 12648 }
michael@0 12649 }
michael@0 12650
michael@0 12651 already_AddRefed<nsISupports>
michael@0 12652 nsGlobalWindow::SaveWindowState()
michael@0 12653 {
michael@0 12654 NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
michael@0 12655
michael@0 12656 if (!mContext || !GetWrapperPreserveColor()) {
michael@0 12657 // The window may be getting torn down; don't bother saving state.
michael@0 12658 return nullptr;
michael@0 12659 }
michael@0 12660
michael@0 12661 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
michael@0 12662 NS_ASSERTION(inner, "No inner window to save");
michael@0 12663
michael@0 12664 // Don't do anything else to this inner window! After this point, all
michael@0 12665 // calls to SetTimeoutOrInterval will create entries in the timeout
michael@0 12666 // list that will only run after this window has come out of the bfcache.
michael@0 12667 // Also, while we're frozen, we won't dispatch online/offline events
michael@0 12668 // to the page.
michael@0 12669 inner->Freeze();
michael@0 12670
michael@0 12671 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
michael@0 12672
michael@0 12673 #ifdef DEBUG_PAGE_CACHE
michael@0 12674 printf("saving window state, state = %p\n", (void*)state);
michael@0 12675 #endif
michael@0 12676
michael@0 12677 return state.forget();
michael@0 12678 }
michael@0 12679
michael@0 12680 nsresult
michael@0 12681 nsGlobalWindow::RestoreWindowState(nsISupports *aState)
michael@0 12682 {
michael@0 12683 NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
michael@0 12684
michael@0 12685 if (!mContext || !GetWrapperPreserveColor()) {
michael@0 12686 // The window may be getting torn down; don't bother restoring state.
michael@0 12687 return NS_OK;
michael@0 12688 }
michael@0 12689
michael@0 12690 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
michael@0 12691 NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
michael@0 12692
michael@0 12693 #ifdef DEBUG_PAGE_CACHE
michael@0 12694 printf("restoring window state, state = %p\n", (void*)holder);
michael@0 12695 #endif
michael@0 12696
michael@0 12697 // And we're ready to go!
michael@0 12698 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
michael@0 12699
michael@0 12700 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
michael@0 12701 // it easy to tell which link was last clicked when going back a page.
michael@0 12702 nsIContent* focusedNode = inner->GetFocusedNode();
michael@0 12703 if (IsLink(focusedNode)) {
michael@0 12704 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
michael@0 12705 if (fm) {
michael@0 12706 nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
michael@0 12707 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
michael@0 12708 nsIFocusManager::FLAG_SHOWRING);
michael@0 12709 }
michael@0 12710 }
michael@0 12711
michael@0 12712 inner->Thaw();
michael@0 12713
michael@0 12714 holder->DidRestoreWindow();
michael@0 12715
michael@0 12716 return NS_OK;
michael@0 12717 }
michael@0 12718
michael@0 12719 void
michael@0 12720 nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease,
michael@0 12721 bool aFreezeChildren)
michael@0 12722 {
michael@0 12723 FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren));
michael@0 12724
michael@0 12725 bool suspended = (mTimeoutsSuspendDepth != 0);
michael@0 12726 mTimeoutsSuspendDepth += aIncrease;
michael@0 12727
michael@0 12728 if (!suspended) {
michael@0 12729 nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
michael@0 12730 if (ac) {
michael@0 12731 for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
michael@0 12732 ac->RemoveWindowListener(mEnabledSensors[i], this);
michael@0 12733 }
michael@0 12734 DisableGamepadUpdates();
michael@0 12735
michael@0 12736 // Suspend all of the workers for this window.
michael@0 12737 mozilla::dom::workers::SuspendWorkersForWindow(this);
michael@0 12738
michael@0 12739 TimeStamp now = TimeStamp::Now();
michael@0 12740 for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
michael@0 12741 // Set mTimeRemaining to be the time remaining for this timer.
michael@0 12742 if (t->mWhen > now)
michael@0 12743 t->mTimeRemaining = t->mWhen - now;
michael@0 12744 else
michael@0 12745 t->mTimeRemaining = TimeDuration(0);
michael@0 12746
michael@0 12747 // Drop the XPCOM timer; we'll reschedule when restoring the state.
michael@0 12748 if (t->mTimer) {
michael@0 12749 t->mTimer->Cancel();
michael@0 12750 t->mTimer = nullptr;
michael@0 12751
michael@0 12752 // Drop the reference that the timer's closure had on this timeout, we'll
michael@0 12753 // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
michael@0 12754 // passing null for the context, since this shouldn't actually release this
michael@0 12755 // timeout.
michael@0 12756 t->Release();
michael@0 12757 }
michael@0 12758 }
michael@0 12759
michael@0 12760 // Suspend all of the AudioContexts for this window
michael@0 12761 for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
michael@0 12762 mAudioContexts[i]->Suspend();
michael@0 12763 }
michael@0 12764 }
michael@0 12765
michael@0 12766 // Suspend our children as well.
michael@0 12767 nsCOMPtr<nsIDocShell> docShell = GetDocShell();
michael@0 12768 if (docShell) {
michael@0 12769 int32_t childCount = 0;
michael@0 12770 docShell->GetChildCount(&childCount);
michael@0 12771
michael@0 12772 for (int32_t i = 0; i < childCount; ++i) {
michael@0 12773 nsCOMPtr<nsIDocShellTreeItem> childShell;
michael@0 12774 docShell->GetChildAt(i, getter_AddRefs(childShell));
michael@0 12775 NS_ASSERTION(childShell, "null child shell");
michael@0 12776
michael@0 12777 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
michael@0 12778 if (pWin) {
michael@0 12779 nsGlobalWindow *win =
michael@0 12780 static_cast<nsGlobalWindow*>
michael@0 12781 (static_cast<nsPIDOMWindow*>(pWin));
michael@0 12782 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
michael@0 12783 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
michael@0 12784
michael@0 12785 // This is a bit hackish. Only freeze/suspend windows which are truly our
michael@0 12786 // subwindows.
michael@0 12787 nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
michael@0 12788 if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
michael@0 12789 continue;
michael@0 12790 }
michael@0 12791
michael@0 12792 win->SuspendTimeouts(aIncrease, aFreezeChildren);
michael@0 12793
michael@0 12794 if (inner && aFreezeChildren) {
michael@0 12795 inner->Freeze();
michael@0 12796 }
michael@0 12797 }
michael@0 12798 }
michael@0 12799 }
michael@0 12800 }
michael@0 12801
michael@0 12802 nsresult
michael@0 12803 nsGlobalWindow::ResumeTimeouts(bool aThawChildren)
michael@0 12804 {
michael@0 12805 FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
michael@0 12806
michael@0 12807 NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
michael@0 12808 --mTimeoutsSuspendDepth;
michael@0 12809 bool shouldResume = (mTimeoutsSuspendDepth == 0) && !mInnerObjectsFreed;
michael@0 12810 nsresult rv;
michael@0 12811
michael@0 12812 if (shouldResume) {
michael@0 12813 nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
michael@0 12814 if (ac) {
michael@0 12815 for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
michael@0 12816 ac->AddWindowListener(mEnabledSensors[i], this);
michael@0 12817 }
michael@0 12818 EnableGamepadUpdates();
michael@0 12819
michael@0 12820 // Resume all of the AudioContexts for this window
michael@0 12821 for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
michael@0 12822 mAudioContexts[i]->Resume();
michael@0 12823 }
michael@0 12824
michael@0 12825 // Resume all of the workers for this window.
michael@0 12826 mozilla::dom::workers::ResumeWorkersForWindow(this);
michael@0 12827
michael@0 12828 // Restore all of the timeouts, using the stored time remaining
michael@0 12829 // (stored in timeout->mTimeRemaining).
michael@0 12830
michael@0 12831 TimeStamp now = TimeStamp::Now();
michael@0 12832
michael@0 12833 #ifdef DEBUG
michael@0 12834 bool _seenDummyTimeout = false;
michael@0 12835 #endif
michael@0 12836
michael@0 12837 for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
michael@0 12838 // There's a chance we're being called with RunTimeout on the stack in which
michael@0 12839 // case we have a dummy timeout in the list that *must not* be resumed. It
michael@0 12840 // can be identified by a null mWindow.
michael@0 12841 if (!t->mWindow) {
michael@0 12842 #ifdef DEBUG
michael@0 12843 NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
michael@0 12844 _seenDummyTimeout = true;
michael@0 12845 #endif
michael@0 12846 continue;
michael@0 12847 }
michael@0 12848
michael@0 12849 // XXXbz the combination of the way |delay| and |t->mWhen| are set here
michael@0 12850 // makes no sense. Are we trying to impose that min timeout value or
michael@0 12851 // not???
michael@0 12852 uint32_t delay =
michael@0 12853 std::max(int32_t(t->mTimeRemaining.ToMilliseconds()),
michael@0 12854 DOMMinTimeoutValue());
michael@0 12855
michael@0 12856 // Set mWhen back to the time when the timer is supposed to
michael@0 12857 // fire.
michael@0 12858 t->mWhen = now + t->mTimeRemaining;
michael@0 12859
michael@0 12860 t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
michael@0 12861 NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
michael@0 12862
michael@0 12863 rv = t->InitTimer(TimerCallback, delay);
michael@0 12864 if (NS_FAILED(rv)) {
michael@0 12865 t->mTimer = nullptr;
michael@0 12866 return rv;
michael@0 12867 }
michael@0 12868
michael@0 12869 // Add a reference for the new timer's closure.
michael@0 12870 t->AddRef();
michael@0 12871 }
michael@0 12872 }
michael@0 12873
michael@0 12874 // Resume our children as well.
michael@0 12875 nsCOMPtr<nsIDocShell> docShell = GetDocShell();
michael@0 12876 if (docShell) {
michael@0 12877 int32_t childCount = 0;
michael@0 12878 docShell->GetChildCount(&childCount);
michael@0 12879
michael@0 12880 for (int32_t i = 0; i < childCount; ++i) {
michael@0 12881 nsCOMPtr<nsIDocShellTreeItem> childShell;
michael@0 12882 docShell->GetChildAt(i, getter_AddRefs(childShell));
michael@0 12883 NS_ASSERTION(childShell, "null child shell");
michael@0 12884
michael@0 12885 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
michael@0 12886 if (pWin) {
michael@0 12887 nsGlobalWindow *win =
michael@0 12888 static_cast<nsGlobalWindow*>
michael@0 12889 (static_cast<nsPIDOMWindow*>(pWin));
michael@0 12890
michael@0 12891 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
michael@0 12892 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
michael@0 12893
michael@0 12894 // This is a bit hackish. Only thaw/resume windows which are truly our
michael@0 12895 // subwindows.
michael@0 12896 nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
michael@0 12897 if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
michael@0 12898 continue;
michael@0 12899 }
michael@0 12900
michael@0 12901 if (inner && aThawChildren) {
michael@0 12902 inner->Thaw();
michael@0 12903 }
michael@0 12904
michael@0 12905 rv = win->ResumeTimeouts(aThawChildren);
michael@0 12906 NS_ENSURE_SUCCESS(rv, rv);
michael@0 12907 }
michael@0 12908 }
michael@0 12909 }
michael@0 12910
michael@0 12911 return NS_OK;
michael@0 12912 }
michael@0 12913
michael@0 12914 uint32_t
michael@0 12915 nsGlobalWindow::TimeoutSuspendCount()
michael@0 12916 {
michael@0 12917 FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
michael@0 12918 return mTimeoutsSuspendDepth;
michael@0 12919 }
michael@0 12920
michael@0 12921 void
michael@0 12922 nsGlobalWindow::EnableDeviceSensor(uint32_t aType)
michael@0 12923 {
michael@0 12924 MOZ_ASSERT(IsInnerWindow());
michael@0 12925
michael@0 12926 bool alreadyEnabled = false;
michael@0 12927 for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
michael@0 12928 if (mEnabledSensors[i] == aType) {
michael@0 12929 alreadyEnabled = true;
michael@0 12930 break;
michael@0 12931 }
michael@0 12932 }
michael@0 12933
michael@0 12934 mEnabledSensors.AppendElement(aType);
michael@0 12935
michael@0 12936 if (alreadyEnabled) {
michael@0 12937 return;
michael@0 12938 }
michael@0 12939
michael@0 12940 nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
michael@0 12941 if (ac) {
michael@0 12942 ac->AddWindowListener(aType, this);
michael@0 12943 }
michael@0 12944 }
michael@0 12945
michael@0 12946 void
michael@0 12947 nsGlobalWindow::DisableDeviceSensor(uint32_t aType)
michael@0 12948 {
michael@0 12949 MOZ_ASSERT(IsInnerWindow());
michael@0 12950
michael@0 12951 int32_t doomedElement = -1;
michael@0 12952 int32_t listenerCount = 0;
michael@0 12953 for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
michael@0 12954 if (mEnabledSensors[i] == aType) {
michael@0 12955 doomedElement = i;
michael@0 12956 listenerCount++;
michael@0 12957 }
michael@0 12958 }
michael@0 12959
michael@0 12960 if (doomedElement == -1) {
michael@0 12961 return;
michael@0 12962 }
michael@0 12963
michael@0 12964 mEnabledSensors.RemoveElementAt(doomedElement);
michael@0 12965
michael@0 12966 if (listenerCount > 1) {
michael@0 12967 return;
michael@0 12968 }
michael@0 12969
michael@0 12970 nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
michael@0 12971 if (ac) {
michael@0 12972 ac->RemoveWindowListener(aType, this);
michael@0 12973 }
michael@0 12974 }
michael@0 12975
michael@0 12976 void
michael@0 12977 nsGlobalWindow::SetHasGamepadEventListener(bool aHasGamepad/* = true*/)
michael@0 12978 {
michael@0 12979 FORWARD_TO_INNER_VOID(SetHasGamepadEventListener, (aHasGamepad));
michael@0 12980 mHasGamepad = aHasGamepad;
michael@0 12981 if (aHasGamepad) {
michael@0 12982 EnableGamepadUpdates();
michael@0 12983 }
michael@0 12984 }
michael@0 12985
michael@0 12986 void
michael@0 12987 nsGlobalWindow::EnableTimeChangeNotifications()
michael@0 12988 {
michael@0 12989 mozilla::time::AddWindowListener(this);
michael@0 12990 }
michael@0 12991
michael@0 12992 void
michael@0 12993 nsGlobalWindow::DisableTimeChangeNotifications()
michael@0 12994 {
michael@0 12995 mozilla::time::RemoveWindowListener(this);
michael@0 12996 }
michael@0 12997
michael@0 12998 static PLDHashOperator
michael@0 12999 CollectSizeAndListenerCount(
michael@0 13000 nsPtrHashKey<DOMEventTargetHelper>* aEntry,
michael@0 13001 void *arg)
michael@0 13002 {
michael@0 13003 nsWindowSizes* windowSizes = static_cast<nsWindowSizes*>(arg);
michael@0 13004
michael@0 13005 DOMEventTargetHelper* et = aEntry->GetKey();
michael@0 13006
michael@0 13007 if (nsCOMPtr<nsISizeOfEventTarget> iSizeOf = do_QueryObject(et)) {
michael@0 13008 windowSizes->mDOMEventTargetsSize +=
michael@0 13009 iSizeOf->SizeOfEventTargetIncludingThis(windowSizes->mMallocSizeOf);
michael@0 13010 }
michael@0 13011
michael@0 13012 if (EventListenerManager* elm = et->GetExistingListenerManager()) {
michael@0 13013 windowSizes->mDOMEventListenersCount += elm->ListenerCount();
michael@0 13014 }
michael@0 13015
michael@0 13016 return PL_DHASH_NEXT;
michael@0 13017 }
michael@0 13018
michael@0 13019 void
michael@0 13020 nsGlobalWindow::AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
michael@0 13021 {
michael@0 13022 aWindowSizes->mDOMOtherSize += aWindowSizes->mMallocSizeOf(this);
michael@0 13023
michael@0 13024 if (IsInnerWindow()) {
michael@0 13025 EventListenerManager* elm = GetExistingListenerManager();
michael@0 13026 if (elm) {
michael@0 13027 aWindowSizes->mDOMOtherSize +=
michael@0 13028 elm->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
michael@0 13029 aWindowSizes->mDOMEventListenersCount +=
michael@0 13030 elm->ListenerCount();
michael@0 13031 }
michael@0 13032 if (mDoc) {
michael@0 13033 mDoc->DocAddSizeOfIncludingThis(aWindowSizes);
michael@0 13034 }
michael@0 13035 }
michael@0 13036
michael@0 13037 if (mNavigator) {
michael@0 13038 aWindowSizes->mDOMOtherSize +=
michael@0 13039 mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
michael@0 13040 }
michael@0 13041
michael@0 13042 // The things pointed to by the entries will be measured below, so we
michael@0 13043 // use nullptr for the callback here.
michael@0 13044 aWindowSizes->mDOMEventTargetsSize +=
michael@0 13045 mEventTargetObjects.SizeOfExcludingThis(nullptr,
michael@0 13046 aWindowSizes->mMallocSizeOf);
michael@0 13047 aWindowSizes->mDOMEventTargetsCount +=
michael@0 13048 const_cast<nsTHashtable<nsPtrHashKey<DOMEventTargetHelper> >*>
michael@0 13049 (&mEventTargetObjects)->EnumerateEntries(CollectSizeAndListenerCount,
michael@0 13050 aWindowSizes);
michael@0 13051 }
michael@0 13052
michael@0 13053
michael@0 13054 #ifdef MOZ_GAMEPAD
michael@0 13055 void
michael@0 13056 nsGlobalWindow::AddGamepad(uint32_t aIndex, Gamepad* aGamepad)
michael@0 13057 {
michael@0 13058 FORWARD_TO_INNER_VOID(AddGamepad, (aIndex, aGamepad));
michael@0 13059 mGamepads.Put(aIndex, aGamepad);
michael@0 13060 }
michael@0 13061
michael@0 13062 void
michael@0 13063 nsGlobalWindow::RemoveGamepad(uint32_t aIndex)
michael@0 13064 {
michael@0 13065 FORWARD_TO_INNER_VOID(RemoveGamepad, (aIndex));
michael@0 13066 mGamepads.Remove(aIndex);
michael@0 13067 }
michael@0 13068
michael@0 13069 // static
michael@0 13070 PLDHashOperator
michael@0 13071 nsGlobalWindow::EnumGamepadsForGet(const uint32_t& aKey, Gamepad* aData,
michael@0 13072 void* aUserArg)
michael@0 13073 {
michael@0 13074 nsTArray<nsRefPtr<Gamepad> >* array =
michael@0 13075 static_cast<nsTArray<nsRefPtr<Gamepad> >*>(aUserArg);
michael@0 13076 array->EnsureLengthAtLeast(aKey + 1);
michael@0 13077 (*array)[aKey] = aData;
michael@0 13078 return PL_DHASH_NEXT;
michael@0 13079 }
michael@0 13080
michael@0 13081 void
michael@0 13082 nsGlobalWindow::GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads)
michael@0 13083 {
michael@0 13084 FORWARD_TO_INNER_VOID(GetGamepads, (aGamepads));
michael@0 13085 aGamepads.Clear();
michael@0 13086 // mGamepads.Count() may not be sufficient, but it's not harmful.
michael@0 13087 aGamepads.SetCapacity(mGamepads.Count());
michael@0 13088 mGamepads.EnumerateRead(EnumGamepadsForGet, &aGamepads);
michael@0 13089 }
michael@0 13090
michael@0 13091 already_AddRefed<Gamepad>
michael@0 13092 nsGlobalWindow::GetGamepad(uint32_t aIndex)
michael@0 13093 {
michael@0 13094 FORWARD_TO_INNER(GetGamepad, (aIndex), nullptr);
michael@0 13095 nsRefPtr<Gamepad> gamepad;
michael@0 13096 if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
michael@0 13097 return gamepad.forget();
michael@0 13098 }
michael@0 13099
michael@0 13100 return nullptr;
michael@0 13101 }
michael@0 13102
michael@0 13103 void
michael@0 13104 nsGlobalWindow::SetHasSeenGamepadInput(bool aHasSeen)
michael@0 13105 {
michael@0 13106 FORWARD_TO_INNER_VOID(SetHasSeenGamepadInput, (aHasSeen));
michael@0 13107 mHasSeenGamepadInput = aHasSeen;
michael@0 13108 }
michael@0 13109
michael@0 13110 bool
michael@0 13111 nsGlobalWindow::HasSeenGamepadInput()
michael@0 13112 {
michael@0 13113 FORWARD_TO_INNER(HasSeenGamepadInput, (), false);
michael@0 13114 return mHasSeenGamepadInput;
michael@0 13115 }
michael@0 13116
michael@0 13117 // static
michael@0 13118 PLDHashOperator
michael@0 13119 nsGlobalWindow::EnumGamepadsForSync(const uint32_t& aKey, Gamepad* aData,
michael@0 13120 void* aUserArg)
michael@0 13121 {
michael@0 13122 nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
michael@0 13123 gamepadsvc->SyncGamepadState(aKey, aData);
michael@0 13124 return PL_DHASH_NEXT;
michael@0 13125 }
michael@0 13126
michael@0 13127 void
michael@0 13128 nsGlobalWindow::SyncGamepadState()
michael@0 13129 {
michael@0 13130 FORWARD_TO_INNER_VOID(SyncGamepadState, ());
michael@0 13131 if (mHasSeenGamepadInput) {
michael@0 13132 mGamepads.EnumerateRead(EnumGamepadsForSync, nullptr);
michael@0 13133 }
michael@0 13134 }
michael@0 13135 #endif
michael@0 13136 // nsGlobalChromeWindow implementation
michael@0 13137
michael@0 13138 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
michael@0 13139
michael@0 13140 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
michael@0 13141 nsGlobalWindow)
michael@0 13142 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserDOMWindow)
michael@0 13143 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
michael@0 13144 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 13145
michael@0 13146
michael@0 13147 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow,
michael@0 13148 nsGlobalWindow)
michael@0 13149 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserDOMWindow)
michael@0 13150 if (tmp->mMessageManager) {
michael@0 13151 static_cast<nsFrameMessageManager*>(
michael@0 13152 tmp->mMessageManager.get())->Disconnect();
michael@0 13153 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
michael@0 13154 }
michael@0 13155 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
michael@0 13156
michael@0 13157 DOMCI_DATA(ChromeWindow, nsGlobalChromeWindow)
michael@0 13158
michael@0 13159 // QueryInterface implementation for nsGlobalChromeWindow
michael@0 13160 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
michael@0 13161 NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
michael@0 13162 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
michael@0 13163 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
michael@0 13164
michael@0 13165 NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
michael@0 13166 NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
michael@0 13167
michael@0 13168 NS_IMETHODIMP
michael@0 13169 nsGlobalChromeWindow::GetWindowState(uint16_t* aWindowState)
michael@0 13170 {
michael@0 13171 *aWindowState = WindowState();
michael@0 13172 return NS_OK;
michael@0 13173 }
michael@0 13174
michael@0 13175 uint16_t
michael@0 13176 nsGlobalWindow::WindowState()
michael@0 13177 {
michael@0 13178 nsCOMPtr<nsIWidget> widget = GetMainWidget();
michael@0 13179
michael@0 13180 int32_t mode = widget ? widget->SizeMode() : 0;
michael@0 13181
michael@0 13182 switch (mode) {
michael@0 13183 case nsSizeMode_Minimized:
michael@0 13184 return nsIDOMChromeWindow::STATE_MINIMIZED;
michael@0 13185 case nsSizeMode_Maximized:
michael@0 13186 return nsIDOMChromeWindow::STATE_MAXIMIZED;
michael@0 13187 case nsSizeMode_Fullscreen:
michael@0 13188 return nsIDOMChromeWindow::STATE_FULLSCREEN;
michael@0 13189 case nsSizeMode_Normal:
michael@0 13190 return nsIDOMChromeWindow::STATE_NORMAL;
michael@0 13191 default:
michael@0 13192 NS_WARNING("Illegal window state for this chrome window");
michael@0 13193 break;
michael@0 13194 }
michael@0 13195
michael@0 13196 return nsIDOMChromeWindow::STATE_NORMAL;
michael@0 13197 }
michael@0 13198
michael@0 13199 NS_IMETHODIMP
michael@0 13200 nsGlobalChromeWindow::Maximize()
michael@0 13201 {
michael@0 13202 ErrorResult rv;
michael@0 13203 Maximize(rv);
michael@0 13204 return rv.ErrorCode();
michael@0 13205 }
michael@0 13206
michael@0 13207 void
michael@0 13208 nsGlobalWindow::Maximize(ErrorResult& aError)
michael@0 13209 {
michael@0 13210 nsCOMPtr<nsIWidget> widget = GetMainWidget();
michael@0 13211
michael@0 13212 if (widget) {
michael@0 13213 aError = widget->SetSizeMode(nsSizeMode_Maximized);
michael@0 13214 }
michael@0 13215 }
michael@0 13216
michael@0 13217 NS_IMETHODIMP
michael@0 13218 nsGlobalChromeWindow::Minimize()
michael@0 13219 {
michael@0 13220 ErrorResult rv;
michael@0 13221 Minimize(rv);
michael@0 13222 return rv.ErrorCode();
michael@0 13223 }
michael@0 13224
michael@0 13225 void
michael@0 13226 nsGlobalWindow::Minimize(ErrorResult& aError)
michael@0 13227 {
michael@0 13228 nsCOMPtr<nsIWidget> widget = GetMainWidget();
michael@0 13229
michael@0 13230 if (widget) {
michael@0 13231 aError = widget->SetSizeMode(nsSizeMode_Minimized);
michael@0 13232 }
michael@0 13233 }
michael@0 13234
michael@0 13235 NS_IMETHODIMP
michael@0 13236 nsGlobalChromeWindow::Restore()
michael@0 13237 {
michael@0 13238 ErrorResult rv;
michael@0 13239 Restore(rv);
michael@0 13240 return rv.ErrorCode();
michael@0 13241 }
michael@0 13242
michael@0 13243 void
michael@0 13244 nsGlobalWindow::Restore(ErrorResult& aError)
michael@0 13245 {
michael@0 13246 nsCOMPtr<nsIWidget> widget = GetMainWidget();
michael@0 13247
michael@0 13248 if (widget) {
michael@0 13249 aError = widget->SetSizeMode(nsSizeMode_Normal);
michael@0 13250 }
michael@0 13251 }
michael@0 13252
michael@0 13253 NS_IMETHODIMP
michael@0 13254 nsGlobalChromeWindow::GetAttention()
michael@0 13255 {
michael@0 13256 ErrorResult rv;
michael@0 13257 GetAttention(rv);
michael@0 13258 return rv.ErrorCode();
michael@0 13259 }
michael@0 13260
michael@0 13261 void
michael@0 13262 nsGlobalWindow::GetAttention(ErrorResult& aResult)
michael@0 13263 {
michael@0 13264 return GetAttentionWithCycleCount(-1, aResult);
michael@0 13265 }
michael@0 13266
michael@0 13267 NS_IMETHODIMP
michael@0 13268 nsGlobalChromeWindow::GetAttentionWithCycleCount(int32_t aCycleCount)
michael@0 13269 {
michael@0 13270 ErrorResult rv;
michael@0 13271 GetAttentionWithCycleCount(aCycleCount, rv);
michael@0 13272 return rv.ErrorCode();
michael@0 13273 }
michael@0 13274
michael@0 13275 void
michael@0 13276 nsGlobalWindow::GetAttentionWithCycleCount(int32_t aCycleCount,
michael@0 13277 ErrorResult& aError)
michael@0 13278 {
michael@0 13279 nsCOMPtr<nsIWidget> widget = GetMainWidget();
michael@0 13280
michael@0 13281 if (widget) {
michael@0 13282 aError = widget->GetAttention(aCycleCount);
michael@0 13283 }
michael@0 13284 }
michael@0 13285
michael@0 13286 NS_IMETHODIMP
michael@0 13287 nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent, nsIDOMElement* aPanel)
michael@0 13288 {
michael@0 13289 NS_ENSURE_TRUE(aMouseDownEvent, NS_ERROR_FAILURE);
michael@0 13290 Event* mouseDownEvent = aMouseDownEvent->InternalDOMEvent();
michael@0 13291 NS_ENSURE_TRUE(mouseDownEvent, NS_ERROR_FAILURE);
michael@0 13292
michael@0 13293 nsCOMPtr<Element> panel = do_QueryInterface(aPanel);
michael@0 13294 NS_ENSURE_TRUE(panel || !aPanel, NS_ERROR_FAILURE);
michael@0 13295
michael@0 13296 ErrorResult rv;
michael@0 13297 BeginWindowMove(*mouseDownEvent, panel, rv);
michael@0 13298 return rv.ErrorCode();
michael@0 13299 }
michael@0 13300
michael@0 13301 void
michael@0 13302 nsGlobalWindow::BeginWindowMove(Event& aMouseDownEvent, Element* aPanel,
michael@0 13303 ErrorResult& aError)
michael@0 13304 {
michael@0 13305 nsCOMPtr<nsIWidget> widget;
michael@0 13306
michael@0 13307 // if a panel was supplied, use its widget instead.
michael@0 13308 #ifdef MOZ_XUL
michael@0 13309 if (aPanel) {
michael@0 13310 nsIFrame* frame = aPanel->GetPrimaryFrame();
michael@0 13311 if (!frame || frame->GetType() != nsGkAtoms::menuPopupFrame) {
michael@0 13312 return;
michael@0 13313 }
michael@0 13314
michael@0 13315 widget = (static_cast<nsMenuPopupFrame*>(frame))->GetWidget();
michael@0 13316 }
michael@0 13317 else {
michael@0 13318 #endif
michael@0 13319 widget = GetMainWidget();
michael@0 13320 #ifdef MOZ_XUL
michael@0 13321 }
michael@0 13322 #endif
michael@0 13323
michael@0 13324 if (!widget) {
michael@0 13325 return;
michael@0 13326 }
michael@0 13327
michael@0 13328 WidgetMouseEvent* mouseEvent =
michael@0 13329 aMouseDownEvent.GetInternalNSEvent()->AsMouseEvent();
michael@0 13330 if (!mouseEvent || mouseEvent->eventStructType != NS_MOUSE_EVENT) {
michael@0 13331 aError.Throw(NS_ERROR_FAILURE);
michael@0 13332 return;
michael@0 13333 }
michael@0 13334
michael@0 13335 aError = widget->BeginMoveDrag(mouseEvent);
michael@0 13336 }
michael@0 13337
michael@0 13338 //Note: This call will lock the cursor, it will not change as it moves.
michael@0 13339 //To unlock, the cursor must be set back to CURSOR_AUTO.
michael@0 13340 NS_IMETHODIMP
michael@0 13341 nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
michael@0 13342 {
michael@0 13343 ErrorResult rv;
michael@0 13344 SetCursor(aCursor, rv);
michael@0 13345 return rv.ErrorCode();
michael@0 13346 }
michael@0 13347
michael@0 13348 void
michael@0 13349 nsGlobalWindow::SetCursor(const nsAString& aCursor, ErrorResult& aError)
michael@0 13350 {
michael@0 13351 FORWARD_TO_OUTER_OR_THROW(SetCursor, (aCursor, aError), aError, );
michael@0 13352
michael@0 13353 int32_t cursor;
michael@0 13354
michael@0 13355 if (aCursor.EqualsLiteral("auto"))
michael@0 13356 cursor = NS_STYLE_CURSOR_AUTO;
michael@0 13357 else {
michael@0 13358 nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
michael@0 13359 if (eCSSKeyword_UNKNOWN == keyword ||
michael@0 13360 !nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
michael@0 13361 return;
michael@0 13362 }
michael@0 13363 }
michael@0 13364
michael@0 13365 nsRefPtr<nsPresContext> presContext;
michael@0 13366 if (mDocShell) {
michael@0 13367 mDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 13368 }
michael@0 13369
michael@0 13370 if (presContext) {
michael@0 13371 // Need root widget.
michael@0 13372 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 13373 if (!presShell) {
michael@0 13374 aError.Throw(NS_ERROR_FAILURE);
michael@0 13375 return;
michael@0 13376 }
michael@0 13377
michael@0 13378 nsViewManager* vm = presShell->GetViewManager();
michael@0 13379 if (!vm) {
michael@0 13380 aError.Throw(NS_ERROR_FAILURE);
michael@0 13381 return;
michael@0 13382 }
michael@0 13383
michael@0 13384 nsView* rootView = vm->GetRootView();
michael@0 13385 if (!rootView) {
michael@0 13386 aError.Throw(NS_ERROR_FAILURE);
michael@0 13387 return;
michael@0 13388 }
michael@0 13389
michael@0 13390 nsIWidget* widget = rootView->GetNearestWidget(nullptr);
michael@0 13391 if (!widget) {
michael@0 13392 aError.Throw(NS_ERROR_FAILURE);
michael@0 13393 return;
michael@0 13394 }
michael@0 13395
michael@0 13396 // Call esm and set cursor.
michael@0 13397 aError = presContext->EventStateManager()->SetCursor(cursor, nullptr,
michael@0 13398 false, 0.0f, 0.0f,
michael@0 13399 widget, true);
michael@0 13400 }
michael@0 13401 }
michael@0 13402
michael@0 13403 NS_IMETHODIMP
michael@0 13404 nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
michael@0 13405 {
michael@0 13406 ErrorResult rv;
michael@0 13407 NS_IF_ADDREF(*aBrowserWindow = GetBrowserDOMWindow(rv));
michael@0 13408 return rv.ErrorCode();
michael@0 13409 }
michael@0 13410
michael@0 13411 nsIBrowserDOMWindow*
michael@0 13412 nsGlobalWindow::GetBrowserDOMWindow(ErrorResult& aError)
michael@0 13413 {
michael@0 13414 FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindow, (aError), aError, nullptr);
michael@0 13415
michael@0 13416 MOZ_ASSERT(IsChromeWindow());
michael@0 13417 return static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow;
michael@0 13418 }
michael@0 13419
michael@0 13420 NS_IMETHODIMP
michael@0 13421 nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
michael@0 13422 {
michael@0 13423 ErrorResult rv;
michael@0 13424 SetBrowserDOMWindow(aBrowserWindow, rv);
michael@0 13425 return rv.ErrorCode();
michael@0 13426 }
michael@0 13427
michael@0 13428 void
michael@0 13429 nsGlobalWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow,
michael@0 13430 ErrorResult& aError)
michael@0 13431 {
michael@0 13432 FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindow, (aBrowserWindow, aError),
michael@0 13433 aError, );
michael@0 13434 MOZ_ASSERT(IsChromeWindow());
michael@0 13435 static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow = aBrowserWindow;
michael@0 13436 }
michael@0 13437
michael@0 13438 NS_IMETHODIMP
michael@0 13439 nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement* aDefaultButton)
michael@0 13440 {
michael@0 13441 nsCOMPtr<Element> defaultButton = do_QueryInterface(aDefaultButton);
michael@0 13442 NS_ENSURE_ARG(defaultButton);
michael@0 13443
michael@0 13444 ErrorResult rv;
michael@0 13445 NotifyDefaultButtonLoaded(*defaultButton, rv);
michael@0 13446 return rv.ErrorCode();
michael@0 13447 }
michael@0 13448
michael@0 13449 void
michael@0 13450 nsGlobalWindow::NotifyDefaultButtonLoaded(Element& aDefaultButton,
michael@0 13451 ErrorResult& aError)
michael@0 13452 {
michael@0 13453 #ifdef MOZ_XUL
michael@0 13454 // Don't snap to a disabled button.
michael@0 13455 nsCOMPtr<nsIDOMXULControlElement> xulControl =
michael@0 13456 do_QueryInterface(&aDefaultButton);
michael@0 13457 if (!xulControl) {
michael@0 13458 aError.Throw(NS_ERROR_FAILURE);
michael@0 13459 return;
michael@0 13460 }
michael@0 13461 bool disabled;
michael@0 13462 aError = xulControl->GetDisabled(&disabled);
michael@0 13463 if (aError.Failed() || disabled) {
michael@0 13464 return;
michael@0 13465 }
michael@0 13466
michael@0 13467 // Get the button rect in screen coordinates.
michael@0 13468 nsIFrame *frame = aDefaultButton.GetPrimaryFrame();
michael@0 13469 if (!frame) {
michael@0 13470 aError.Throw(NS_ERROR_FAILURE);
michael@0 13471 return;
michael@0 13472 }
michael@0 13473 nsIntRect buttonRect = frame->GetScreenRect();
michael@0 13474
michael@0 13475 // Get the widget rect in screen coordinates.
michael@0 13476 nsIWidget *widget = GetNearestWidget();
michael@0 13477 if (!widget) {
michael@0 13478 aError.Throw(NS_ERROR_FAILURE);
michael@0 13479 return;
michael@0 13480 }
michael@0 13481 nsIntRect widgetRect;
michael@0 13482 aError = widget->GetScreenBounds(widgetRect);
michael@0 13483 if (aError.Failed()) {
michael@0 13484 return;
michael@0 13485 }
michael@0 13486
michael@0 13487 // Convert the buttonRect coordinates from screen to the widget.
michael@0 13488 buttonRect -= widgetRect.TopLeft();
michael@0 13489 nsresult rv = widget->OnDefaultButtonLoaded(buttonRect);
michael@0 13490 if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
michael@0 13491 aError.Throw(rv);
michael@0 13492 }
michael@0 13493 #else
michael@0 13494 aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
michael@0 13495 #endif
michael@0 13496 }
michael@0 13497
michael@0 13498 NS_IMETHODIMP
michael@0 13499 nsGlobalChromeWindow::GetMessageManager(nsIMessageBroadcaster** aManager)
michael@0 13500 {
michael@0 13501 ErrorResult rv;
michael@0 13502 NS_IF_ADDREF(*aManager = GetMessageManager(rv));
michael@0 13503 return rv.ErrorCode();
michael@0 13504 }
michael@0 13505
michael@0 13506 nsIMessageBroadcaster*
michael@0 13507 nsGlobalWindow::GetMessageManager(ErrorResult& aError)
michael@0 13508 {
michael@0 13509 FORWARD_TO_INNER_OR_THROW(GetMessageManager, (aError), aError, nullptr);
michael@0 13510 MOZ_ASSERT(IsChromeWindow());
michael@0 13511 nsGlobalChromeWindow* myself = static_cast<nsGlobalChromeWindow*>(this);
michael@0 13512 if (!myself->mMessageManager) {
michael@0 13513 nsIScriptContext* scx = GetContextInternal();
michael@0 13514 if (NS_WARN_IF(!scx || !(scx->GetNativeContext()))) {
michael@0 13515 aError.Throw(NS_ERROR_UNEXPECTED);
michael@0 13516 return nullptr;
michael@0 13517 }
michael@0 13518
michael@0 13519 nsCOMPtr<nsIMessageBroadcaster> globalMM =
michael@0 13520 do_GetService("@mozilla.org/globalmessagemanager;1");
michael@0 13521 myself->mMessageManager =
michael@0 13522 new nsFrameMessageManager(nullptr,
michael@0 13523 static_cast<nsFrameMessageManager*>(globalMM.get()),
michael@0 13524 MM_CHROME | MM_BROADCASTER);
michael@0 13525 }
michael@0 13526 return myself->mMessageManager;
michael@0 13527 }
michael@0 13528
michael@0 13529 // nsGlobalModalWindow implementation
michael@0 13530
michael@0 13531 // QueryInterface implementation for nsGlobalModalWindow
michael@0 13532 DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
michael@0 13533
michael@0 13534 NS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow)
michael@0 13535 NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
michael@0 13536 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
michael@0 13537 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
michael@0 13538
michael@0 13539 NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
michael@0 13540 NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
michael@0 13541
michael@0 13542
michael@0 13543 void
michael@0 13544 nsGlobalWindow::GetDialogArguments(JSContext* aCx,
michael@0 13545 JS::MutableHandle<JS::Value> aRetval,
michael@0 13546 ErrorResult& aError)
michael@0 13547 {
michael@0 13548 FORWARD_TO_OUTER_OR_THROW(GetDialogArguments, (aCx, aRetval, aError),
michael@0 13549 aError, );
michael@0 13550
michael@0 13551 MOZ_ASSERT(IsModalContentWindow(),
michael@0 13552 "This should only be called on modal windows!");
michael@0 13553
michael@0 13554 // This does an internal origin check, and returns undefined if the subject
michael@0 13555 // does not subsumes the origin of the arguments.
michael@0 13556 JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
michael@0 13557 JSAutoCompartment ac(aCx, wrapper);
michael@0 13558 mDialogArguments->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
michael@0 13559 aRetval, aError);
michael@0 13560 }
michael@0 13561
michael@0 13562 NS_IMETHODIMP
michael@0 13563 nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments)
michael@0 13564 {
michael@0 13565 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
michael@0 13566 NS_ERROR_NOT_INITIALIZED);
michael@0 13567
michael@0 13568 // This does an internal origin check, and returns undefined if the subject
michael@0 13569 // does not subsumes the origin of the arguments.
michael@0 13570 return mDialogArguments->Get(nsContentUtils::GetSubjectPrincipal(), aArguments);
michael@0 13571 }
michael@0 13572
michael@0 13573 void
michael@0 13574 nsGlobalWindow::GetReturnValue(JSContext* aCx,
michael@0 13575 JS::MutableHandle<JS::Value> aReturnValue,
michael@0 13576 ErrorResult& aError)
michael@0 13577 {
michael@0 13578 FORWARD_TO_OUTER_OR_THROW(GetReturnValue, (aCx, aReturnValue, aError),
michael@0 13579 aError, );
michael@0 13580
michael@0 13581 MOZ_ASSERT(IsModalContentWindow(),
michael@0 13582 "This should only be called on modal windows!");
michael@0 13583
michael@0 13584 if (mReturnValue) {
michael@0 13585 JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
michael@0 13586 JSAutoCompartment ac(aCx, wrapper);
michael@0 13587 mReturnValue->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
michael@0 13588 aReturnValue, aError);
michael@0 13589 } else {
michael@0 13590 aReturnValue.setUndefined();
michael@0 13591 }
michael@0 13592 }
michael@0 13593
michael@0 13594 NS_IMETHODIMP
michael@0 13595 nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
michael@0 13596 {
michael@0 13597 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
michael@0 13598
michael@0 13599 nsCOMPtr<nsIVariant> result;
michael@0 13600 if (!mReturnValue) {
michael@0 13601 nsCOMPtr<nsIVariant> variant = CreateVoidVariant();
michael@0 13602 variant.forget(aRetVal);
michael@0 13603 return NS_OK;
michael@0 13604 }
michael@0 13605 return mReturnValue->Get(nsContentUtils::GetSubjectPrincipal(), aRetVal);
michael@0 13606 }
michael@0 13607
michael@0 13608 void
michael@0 13609 nsGlobalWindow::SetReturnValue(JSContext* aCx,
michael@0 13610 JS::Handle<JS::Value> aReturnValue,
michael@0 13611 ErrorResult& aError)
michael@0 13612 {
michael@0 13613 FORWARD_TO_OUTER_OR_THROW(SetReturnValue, (aCx, aReturnValue, aError),
michael@0 13614 aError, );
michael@0 13615
michael@0 13616 MOZ_ASSERT(IsModalContentWindow(),
michael@0 13617 "This should only be called on modal windows!");
michael@0 13618
michael@0 13619 nsCOMPtr<nsIVariant> returnValue;
michael@0 13620 aError =
michael@0 13621 nsContentUtils::XPConnect()->JSToVariant(aCx, aReturnValue,
michael@0 13622 getter_AddRefs(returnValue));
michael@0 13623 if (!aError.Failed()) {
michael@0 13624 mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
michael@0 13625 returnValue);
michael@0 13626 }
michael@0 13627 }
michael@0 13628
michael@0 13629 NS_IMETHODIMP
michael@0 13630 nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
michael@0 13631 {
michael@0 13632 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
michael@0 13633
michael@0 13634 mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
michael@0 13635 aRetVal);
michael@0 13636 return NS_OK;
michael@0 13637 }
michael@0 13638
michael@0 13639 /* static */
michael@0 13640 bool
michael@0 13641 nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
michael@0 13642 {
michael@0 13643 // For now, have to deal with XPConnect objects here.
michael@0 13644 return xpc::WindowOrNull(aGlobal)->IsModalContentWindow();
michael@0 13645 }
michael@0 13646
michael@0 13647 NS_IMETHODIMP
michael@0 13648 nsGlobalWindow::GetConsole(JSContext* aCx,
michael@0 13649 JS::MutableHandle<JS::Value> aConsole)
michael@0 13650 {
michael@0 13651 ErrorResult rv;
michael@0 13652 nsRefPtr<Console> console = GetConsole(rv);
michael@0 13653 if (rv.Failed()) {
michael@0 13654 return rv.ErrorCode();
michael@0 13655 }
michael@0 13656
michael@0 13657 if (!WrapNewBindingObject(aCx, console, aConsole)) {
michael@0 13658 return NS_ERROR_FAILURE;
michael@0 13659 }
michael@0 13660
michael@0 13661 return NS_OK;
michael@0 13662 }
michael@0 13663
michael@0 13664 NS_IMETHODIMP
michael@0 13665 nsGlobalWindow::SetConsole(JSContext* aCx, JS::Handle<JS::Value> aValue)
michael@0 13666 {
michael@0 13667 JS::Rooted<JSObject*> thisObj(aCx, GetWrapper());
michael@0 13668 if (!thisObj) {
michael@0 13669 return NS_ERROR_UNEXPECTED;
michael@0 13670 }
michael@0 13671
michael@0 13672 if (!JS_WrapObject(aCx, &thisObj) ||
michael@0 13673 !JS_DefineProperty(aCx, thisObj, "console", aValue,
michael@0 13674 JSPROP_ENUMERATE, JS_PropertyStub,
michael@0 13675 JS_StrictPropertyStub)) {
michael@0 13676 return NS_ERROR_FAILURE;
michael@0 13677 }
michael@0 13678
michael@0 13679 return NS_OK;
michael@0 13680 }
michael@0 13681
michael@0 13682 Console*
michael@0 13683 nsGlobalWindow::GetConsole(ErrorResult& aRv)
michael@0 13684 {
michael@0 13685 FORWARD_TO_INNER_OR_THROW(GetConsole, (aRv), aRv, nullptr);
michael@0 13686
michael@0 13687 if (!mConsole) {
michael@0 13688 mConsole = new Console(this);
michael@0 13689 }
michael@0 13690
michael@0 13691 return mConsole;
michael@0 13692 }
michael@0 13693
michael@0 13694 already_AddRefed<External>
michael@0 13695 nsGlobalWindow::GetExternal(ErrorResult& aRv)
michael@0 13696 {
michael@0 13697 FORWARD_TO_INNER_OR_THROW(GetExternal, (aRv), aRv, nullptr);
michael@0 13698
michael@0 13699 #ifdef HAVE_SIDEBAR
michael@0 13700 if (!mExternal) {
michael@0 13701 AutoJSContext cx;
michael@0 13702 JS::Rooted<JSObject*> jsImplObj(cx);
michael@0 13703 ConstructJSImplementation(cx, "@mozilla.org/sidebar;1",
michael@0 13704 this, &jsImplObj, aRv);
michael@0 13705 if (aRv.Failed()) {
michael@0 13706 return nullptr;
michael@0 13707 }
michael@0 13708 mExternal = new External(jsImplObj, this);
michael@0 13709 }
michael@0 13710
michael@0 13711 nsRefPtr<External> external = static_cast<External*>(mExternal.get());
michael@0 13712 return external.forget();
michael@0 13713 #else
michael@0 13714 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
michael@0 13715 return nullptr;
michael@0 13716 #endif
michael@0 13717 }
michael@0 13718
michael@0 13719 void
michael@0 13720 nsGlobalWindow::GetSidebar(OwningExternalOrWindowProxy& aResult,
michael@0 13721 ErrorResult& aRv)
michael@0 13722 {
michael@0 13723 FORWARD_TO_INNER_OR_THROW(GetSidebar, (aResult, aRv), aRv, );
michael@0 13724
michael@0 13725 #ifdef HAVE_SIDEBAR
michael@0 13726 // First check for a named frame named "sidebar"
michael@0 13727 nsCOMPtr<nsIDOMWindow> domWindow = GetChildWindow(NS_LITERAL_STRING("sidebar"));
michael@0 13728 if (domWindow) {
michael@0 13729 aResult.SetAsWindowProxy() = domWindow.forget();
michael@0 13730 return;
michael@0 13731 }
michael@0 13732
michael@0 13733 nsRefPtr<External> external = GetExternal(aRv);
michael@0 13734 if (external) {
michael@0 13735 aResult.SetAsExternal() = external;
michael@0 13736 }
michael@0 13737 #else
michael@0 13738 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
michael@0 13739 #endif
michael@0 13740 }
michael@0 13741
michael@0 13742 /* static */
michael@0 13743 bool
michael@0 13744 nsGlobalWindow::WindowOnWebIDL(JSContext* aCx, JSObject* aObj)
michael@0 13745 {
michael@0 13746 DebugOnly<nsGlobalWindow*> win;
michael@0 13747 MOZ_ASSERT_IF(IsDOMObject(aObj),
michael@0 13748 NS_SUCCEEDED(UNWRAP_OBJECT(Window, aObj, win)));
michael@0 13749
michael@0 13750 return IsDOMObject(aObj);
michael@0 13751 }
michael@0 13752
michael@0 13753 #ifdef MOZ_B2G
michael@0 13754 void
michael@0 13755 nsGlobalWindow::EnableNetworkEvent(uint32_t aType)
michael@0 13756 {
michael@0 13757 MOZ_ASSERT(IsInnerWindow());
michael@0 13758
michael@0 13759 nsCOMPtr<nsIPermissionManager> permMgr =
michael@0 13760 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
michael@0 13761 if (!permMgr) {
michael@0 13762 NS_ERROR("No PermissionManager available!");
michael@0 13763 return;
michael@0 13764 }
michael@0 13765
michael@0 13766 uint32_t permission = nsIPermissionManager::DENY_ACTION;
michael@0 13767 permMgr->TestExactPermissionFromPrincipal(GetPrincipal(), "network-events",
michael@0 13768 &permission);
michael@0 13769
michael@0 13770 if (permission != nsIPermissionManager::ALLOW_ACTION) {
michael@0 13771 return;
michael@0 13772 }
michael@0 13773
michael@0 13774 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
michael@0 13775 if (!os) {
michael@0 13776 NS_ERROR("ObserverService should be available!");
michael@0 13777 return;
michael@0 13778 }
michael@0 13779
michael@0 13780 switch (aType) {
michael@0 13781 case NS_NETWORK_UPLOAD_EVENT:
michael@0 13782 if (!mNetworkUploadObserverEnabled) {
michael@0 13783 mNetworkUploadObserverEnabled = true;
michael@0 13784 os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC, false);
michael@0 13785 }
michael@0 13786 break;
michael@0 13787 case NS_NETWORK_DOWNLOAD_EVENT:
michael@0 13788 if (!mNetworkDownloadObserverEnabled) {
michael@0 13789 mNetworkDownloadObserverEnabled = true;
michael@0 13790 os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC, false);
michael@0 13791 }
michael@0 13792 break;
michael@0 13793 }
michael@0 13794 }
michael@0 13795
michael@0 13796 void
michael@0 13797 nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
michael@0 13798 {
michael@0 13799 MOZ_ASSERT(IsInnerWindow());
michael@0 13800
michael@0 13801 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
michael@0 13802 if (!os) {
michael@0 13803 return;
michael@0 13804 }
michael@0 13805
michael@0 13806 switch (aType) {
michael@0 13807 case NS_NETWORK_UPLOAD_EVENT:
michael@0 13808 if (mNetworkUploadObserverEnabled) {
michael@0 13809 mNetworkUploadObserverEnabled = false;
michael@0 13810 os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC);
michael@0 13811 }
michael@0 13812 break;
michael@0 13813 case NS_NETWORK_DOWNLOAD_EVENT:
michael@0 13814 if (mNetworkDownloadObserverEnabled) {
michael@0 13815 mNetworkDownloadObserverEnabled = false;
michael@0 13816 os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC);
michael@0 13817 }
michael@0 13818 break;
michael@0 13819 }
michael@0 13820 }
michael@0 13821 #endif // MOZ_B2G
michael@0 13822
michael@0 13823 #define EVENT(name_, id_, type_, struct_) \
michael@0 13824 NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
michael@0 13825 JS::MutableHandle<JS::Value> vp) { \
michael@0 13826 EventHandlerNonNull* h = GetOn##name_(); \
michael@0 13827 vp.setObjectOrNull(h ? h->Callable().get() : nullptr); \
michael@0 13828 return NS_OK; \
michael@0 13829 } \
michael@0 13830 NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
michael@0 13831 JS::Handle<JS::Value> v) { \
michael@0 13832 nsRefPtr<EventHandlerNonNull> handler; \
michael@0 13833 JS::Rooted<JSObject*> callable(cx); \
michael@0 13834 if (v.isObject() && \
michael@0 13835 JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
michael@0 13836 handler = new EventHandlerNonNull(callable, GetIncumbentGlobal()); \
michael@0 13837 } \
michael@0 13838 SetOn##name_(handler); \
michael@0 13839 return NS_OK; \
michael@0 13840 }
michael@0 13841 #define ERROR_EVENT(name_, id_, type_, struct_) \
michael@0 13842 NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
michael@0 13843 JS::MutableHandle<JS::Value> vp) { \
michael@0 13844 EventListenerManager *elm = GetExistingListenerManager(); \
michael@0 13845 if (elm) { \
michael@0 13846 OnErrorEventHandlerNonNull* h = elm->GetOnErrorEventHandler(); \
michael@0 13847 if (h) { \
michael@0 13848 vp.setObject(*h->Callable()); \
michael@0 13849 return NS_OK; \
michael@0 13850 } \
michael@0 13851 } \
michael@0 13852 vp.setNull(); \
michael@0 13853 return NS_OK; \
michael@0 13854 } \
michael@0 13855 NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
michael@0 13856 JS::Handle<JS::Value> v) { \
michael@0 13857 EventListenerManager *elm = GetOrCreateListenerManager(); \
michael@0 13858 if (!elm) { \
michael@0 13859 return NS_ERROR_OUT_OF_MEMORY; \
michael@0 13860 } \
michael@0 13861 \
michael@0 13862 nsRefPtr<OnErrorEventHandlerNonNull> handler; \
michael@0 13863 JS::Rooted<JSObject*> callable(cx); \
michael@0 13864 if (v.isObject() && \
michael@0 13865 JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
michael@0 13866 handler = new OnErrorEventHandlerNonNull(callable, GetIncumbentGlobal()); \
michael@0 13867 } \
michael@0 13868 elm->SetEventHandler(handler); \
michael@0 13869 return NS_OK; \
michael@0 13870 }
michael@0 13871 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
michael@0 13872 NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
michael@0 13873 JS::MutableHandle<JS::Value> vp) { \
michael@0 13874 EventListenerManager *elm = GetExistingListenerManager(); \
michael@0 13875 if (elm) { \
michael@0 13876 OnBeforeUnloadEventHandlerNonNull* h = \
michael@0 13877 elm->GetOnBeforeUnloadEventHandler(); \
michael@0 13878 if (h) { \
michael@0 13879 vp.setObject(*h->Callable()); \
michael@0 13880 return NS_OK; \
michael@0 13881 } \
michael@0 13882 } \
michael@0 13883 vp.setNull(); \
michael@0 13884 return NS_OK; \
michael@0 13885 } \
michael@0 13886 NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
michael@0 13887 JS::Handle<JS::Value> v) { \
michael@0 13888 EventListenerManager *elm = GetOrCreateListenerManager(); \
michael@0 13889 if (!elm) { \
michael@0 13890 return NS_ERROR_OUT_OF_MEMORY; \
michael@0 13891 } \
michael@0 13892 \
michael@0 13893 nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handler; \
michael@0 13894 JS::Rooted<JSObject*> callable(cx); \
michael@0 13895 if (v.isObject() && \
michael@0 13896 JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
michael@0 13897 handler = new OnBeforeUnloadEventHandlerNonNull(callable, GetIncumbentGlobal()); \
michael@0 13898 } \
michael@0 13899 elm->SetEventHandler(handler); \
michael@0 13900 return NS_OK; \
michael@0 13901 }
michael@0 13902 #define WINDOW_ONLY_EVENT EVENT
michael@0 13903 #define TOUCH_EVENT EVENT
michael@0 13904 #include "mozilla/EventNameList.h"
michael@0 13905 #undef TOUCH_EVENT
michael@0 13906 #undef WINDOW_ONLY_EVENT
michael@0 13907 #undef BEFOREUNLOAD_EVENT
michael@0 13908 #undef ERROR_EVENT
michael@0 13909 #undef EVENT
michael@0 13910
michael@0 13911 #ifdef _WINDOWS_
michael@0 13912 #error "Never include windows.h in this file!"
michael@0 13913 #endif

mercurial