Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsGlobalWindow.h"
8 :
9 : #include <algorithm>
10 :
11 : #include "mozilla/MemoryReporting.h"
12 :
13 : // Local Includes
14 : #include "Navigator.h"
15 : #include "nsContentSecurityManager.h"
16 : #include "nsScreen.h"
17 : #include "nsHistory.h"
18 : #include "nsDOMNavigationTiming.h"
19 : #include "nsIDOMStorageManager.h"
20 : #include "mozilla/dom/LocalStorage.h"
21 : #include "mozilla/dom/Storage.h"
22 : #include "mozilla/dom/IdleRequest.h"
23 : #include "mozilla/dom/Performance.h"
24 : #include "mozilla/dom/StorageEvent.h"
25 : #include "mozilla/dom/StorageEventBinding.h"
26 : #include "mozilla/dom/StorageNotifierService.h"
27 : #include "mozilla/dom/Timeout.h"
28 : #include "mozilla/dom/TimeoutHandler.h"
29 : #include "mozilla/dom/TimeoutManager.h"
30 : #include "mozilla/IntegerPrintfMacros.h"
31 : #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
32 : #include "mozilla/dom/WindowOrientationObserver.h"
33 : #endif
34 : #include "nsDOMOfflineResourceList.h"
35 : #include "nsError.h"
36 : #include "nsIIdleService.h"
37 : #include "nsISizeOfEventTarget.h"
38 : #include "nsDOMJSUtils.h"
39 : #include "nsArrayUtils.h"
40 : #include "nsIDOMWindowCollection.h"
41 : #include "nsDOMWindowList.h"
42 : #include "mozilla/dom/WakeLock.h"
43 : #include "mozilla/dom/power/PowerManagerService.h"
44 : #include "nsIDocShellTreeOwner.h"
45 : #include "nsIInterfaceRequestorUtils.h"
46 : #include "nsIPermissionManager.h"
47 : #include "nsIScriptContext.h"
48 : #include "nsIScriptTimeoutHandler.h"
49 : #include "nsITimeoutHandler.h"
50 : #include "nsIController.h"
51 : #include "nsScriptNameSpaceManager.h"
52 : #include "nsISlowScriptDebug.h"
53 : #include "nsWindowMemoryReporter.h"
54 : #include "WindowNamedPropertiesHandler.h"
55 : #include "nsFrameSelection.h"
56 : #include "nsNetUtil.h"
57 : #include "nsVariant.h"
58 : #include "nsPrintfCString.h"
59 : #include "mozilla/intl/LocaleService.h"
60 :
61 : // Helper Classes
62 : #include "nsJSUtils.h"
63 : #include "jsapi.h" // for JSAutoRequest
64 : #include "jswrapper.h"
65 : #include "nsCharSeparatedTokenizer.h"
66 : #include "nsReadableUtils.h"
67 : #include "nsDOMClassInfo.h"
68 : #include "nsJSEnvironment.h"
69 : #include "mozilla/dom/ScriptSettings.h"
70 : #include "mozilla/Preferences.h"
71 : #include "mozilla/Likely.h"
72 : #include "mozilla/Sprintf.h"
73 : #include "mozilla/Unused.h"
74 :
75 : // Other Classes
76 : #include "mozilla/dom/BarProps.h"
77 : #include "nsContentCID.h"
78 : #include "nsLayoutStatics.h"
79 : #include "nsCCUncollectableMarker.h"
80 : #include "mozilla/dom/workers/Workers.h"
81 : #include "mozilla/dom/ToJSValue.h"
82 : #include "nsJSPrincipals.h"
83 : #include "mozilla/Attributes.h"
84 : #include "mozilla/Debug.h"
85 : #include "mozilla/EventListenerManager.h"
86 : #include "mozilla/EventStates.h"
87 : #include "mozilla/MouseEvents.h"
88 : #include "mozilla/ProcessHangMonitor.h"
89 : #include "mozilla/ThrottledEventQueue.h"
90 : #include "AudioChannelService.h"
91 : #include "nsAboutProtocolUtils.h"
92 : #include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
93 : #include "PostMessageEvent.h"
94 : #include "mozilla/dom/DocGroup.h"
95 : #include "mozilla/dom/TabGroup.h"
96 :
97 : // Interfaces Needed
98 : #include "nsIFrame.h"
99 : #include "nsCanvasFrame.h"
100 : #include "nsIWidget.h"
101 : #include "nsIWidgetListener.h"
102 : #include "nsIBaseWindow.h"
103 : #include "nsIDeviceSensors.h"
104 : #include "nsIContent.h"
105 : #include "nsIDocShell.h"
106 : #include "nsIDocCharset.h"
107 : #include "nsIDocument.h"
108 : #include "Crypto.h"
109 : #include "nsIDOMDocument.h"
110 : #include "nsIDOMElement.h"
111 : #include "nsIDOMEvent.h"
112 : #include "nsIDOMOfflineResourceList.h"
113 : #include "nsDOMString.h"
114 : #include "nsIEmbeddingSiteWindow.h"
115 : #include "nsThreadUtils.h"
116 : #include "nsILoadContext.h"
117 : #include "nsIPresShell.h"
118 : #include "nsIScrollableFrame.h"
119 : #include "nsView.h"
120 : #include "nsViewManager.h"
121 : #include "nsISelectionController.h"
122 : #include "nsISelection.h"
123 : #include "nsIPrompt.h"
124 : #include "nsIPromptService.h"
125 : #include "nsIPromptFactory.h"
126 : #include "nsIWritablePropertyBag2.h"
127 : #include "nsIWebNavigation.h"
128 : #include "nsIWebBrowserChrome.h"
129 : #include "nsIWebBrowserFind.h" // For window.find()
130 : #include "nsIWindowMediator.h" // For window.find()
131 : #include "nsComputedDOMStyle.h"
132 : #include "nsDOMCID.h"
133 : #include "nsDOMWindowUtils.h"
134 : #include "nsIWindowWatcher.h"
135 : #include "nsPIWindowWatcher.h"
136 : #include "nsIContentViewer.h"
137 : #include "nsIScriptError.h"
138 : #include "nsIControllers.h"
139 : #include "nsIControllerContext.h"
140 : #include "nsGlobalWindowCommands.h"
141 : #include "nsQueryObject.h"
142 : #include "nsContentUtils.h"
143 : #include "nsCSSProps.h"
144 : #include "nsIDOMFileList.h"
145 : #include "nsIURIFixup.h"
146 : #ifndef DEBUG
147 : #include "nsIAppStartup.h"
148 : #include "nsToolkitCompsCID.h"
149 : #endif
150 : #include "nsCDefaultURIFixup.h"
151 : #include "mozilla/EventDispatcher.h"
152 : #include "mozilla/EventStateManager.h"
153 : #include "nsIObserverService.h"
154 : #include "nsFocusManager.h"
155 : #include "nsIXULWindow.h"
156 : #include "nsITimedChannel.h"
157 : #include "nsServiceManagerUtils.h"
158 : #ifdef MOZ_XUL
159 : #include "nsIDOMXULControlElement.h"
160 : #include "nsMenuPopupFrame.h"
161 : #endif
162 : #include "mozilla/dom/CustomEvent.h"
163 : #include "nsIJARChannel.h"
164 : #include "nsIScreenManager.h"
165 : #include "nsIEffectiveTLDService.h"
166 :
167 : #include "xpcprivate.h"
168 :
169 : #ifdef NS_PRINTING
170 : #include "nsIPrintSettings.h"
171 : #include "nsIPrintSettingsService.h"
172 : #include "nsIWebBrowserPrint.h"
173 : #endif
174 :
175 : #include "nsWindowRoot.h"
176 : #include "nsNetCID.h"
177 : #include "nsIArray.h"
178 :
179 : // XXX An unfortunate dependency exists here (two XUL files).
180 : #include "nsIDOMXULDocument.h"
181 : #include "nsIDOMXULCommandDispatcher.h"
182 :
183 : #include "nsBindingManager.h"
184 : #include "nsXBLService.h"
185 :
186 : // used for popup blocking, needs to be converted to something
187 : // belonging to the back-end like nsIContentPolicy
188 : #include "nsIPopupWindowManager.h"
189 :
190 : #include "nsIDragService.h"
191 : #include "mozilla/dom/Element.h"
192 : #include "mozilla/dom/Selection.h"
193 : #include "nsFrameLoader.h"
194 : #include "nsISupportsPrimitives.h"
195 : #include "nsXPCOMCID.h"
196 : #include "mozilla/Logging.h"
197 : #include "prenv.h"
198 :
199 : #include "mozilla/dom/IDBFactory.h"
200 : #include "mozilla/dom/MessageChannel.h"
201 : #include "mozilla/dom/Promise.h"
202 :
203 : #include "mozilla/dom/Gamepad.h"
204 : #include "mozilla/dom/GamepadManager.h"
205 :
206 : #include "gfxVR.h"
207 : #include "mozilla/dom/VRDisplay.h"
208 : #include "mozilla/dom/VRDisplayEvent.h"
209 : #include "mozilla/dom/VRDisplayEventBinding.h"
210 : #include "mozilla/dom/VREventObserver.h"
211 :
212 : #include "nsRefreshDriver.h"
213 : #include "Layers.h"
214 :
215 : #include "mozilla/AddonPathService.h"
216 : #include "mozilla/BasePrincipal.h"
217 : #include "mozilla/Services.h"
218 : #include "mozilla/Telemetry.h"
219 : #include "mozilla/dom/Location.h"
220 : #include "nsHTMLDocument.h"
221 : #include "nsWrapperCacheInlines.h"
222 : #include "mozilla/DOMEventTargetHelper.h"
223 : #include "prrng.h"
224 : #include "nsSandboxFlags.h"
225 : #include "TimeChangeObserver.h"
226 : #include "mozilla/dom/AudioContext.h"
227 : #include "mozilla/dom/BrowserElementDictionariesBinding.h"
228 : #include "mozilla/dom/cache/CacheStorage.h"
229 : #include "mozilla/dom/Console.h"
230 : #include "mozilla/dom/Fetch.h"
231 : #include "mozilla/dom/FunctionBinding.h"
232 : #include "mozilla/dom/HashChangeEvent.h"
233 : #ifdef ENABLE_INTL_API
234 : #include "mozilla/dom/IntlUtils.h"
235 : #endif
236 : #include "mozilla/dom/MozSelfSupportBinding.h"
237 : #include "mozilla/dom/PopStateEvent.h"
238 : #include "mozilla/dom/PopupBlockedEvent.h"
239 : #include "mozilla/dom/PrimitiveConversions.h"
240 : #include "mozilla/dom/WindowBinding.h"
241 : #include "nsITabChild.h"
242 : #include "mozilla/dom/MediaQueryList.h"
243 : #include "mozilla/dom/ScriptSettings.h"
244 : #include "mozilla/dom/NavigatorBinding.h"
245 : #include "mozilla/dom/ImageBitmap.h"
246 : #include "mozilla/dom/ImageBitmapBinding.h"
247 : #include "mozilla/dom/ServiceWorkerRegistration.h"
248 : #include "mozilla/dom/U2F.h"
249 : #include "mozilla/dom/WebIDLGlobalNameHash.h"
250 : #include "mozilla/dom/Worklet.h"
251 : #ifdef HAVE_SIDEBAR
252 : #include "mozilla/dom/ExternalBinding.h"
253 : #endif
254 :
255 : #ifdef MOZ_WEBSPEECH
256 : #include "mozilla/dom/SpeechSynthesis.h"
257 : #endif
258 :
259 : #ifdef MOZ_B2G
260 : #include "nsPISocketTransportService.h"
261 : #endif
262 :
263 : // Apple system headers seem to have a check() macro. <sigh>
264 : #ifdef check
265 : class nsIScriptTimeoutHandler;
266 : #undef check
267 : #endif // check
268 : #include "AccessCheck.h"
269 :
270 : #ifdef ANDROID
271 : #include <android/log.h>
272 : #endif
273 :
274 : #ifdef XP_WIN
275 : #include <process.h>
276 : #define getpid _getpid
277 : #else
278 : #include <unistd.h> // for getpid()
279 : #endif
280 :
281 : static const char kStorageEnabled[] = "dom.storage.enabled";
282 :
283 : using namespace mozilla;
284 : using namespace mozilla::dom;
285 : using namespace mozilla::dom::ipc;
286 : using mozilla::BasePrincipal;
287 : using mozilla::OriginAttributes;
288 : using mozilla::TimeStamp;
289 : using mozilla::TimeDuration;
290 : using mozilla::dom::cache::CacheStorage;
291 :
292 : static LazyLogModule gDOMLeakPRLog("DOMLeak");
293 :
294 : nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sWindowsById = nullptr;
295 : bool nsGlobalWindow::sWarnedAboutWindowInternal = false;
296 : bool nsGlobalWindow::sIdleObserversAPIFuzzTimeDisabled = false;
297 :
298 : static int32_t gRefCnt = 0;
299 : static int32_t gOpenPopupSpamCount = 0;
300 : static PopupControlState gPopupControlState = openAbused;
301 : static bool gMouseDown = false;
302 : static bool gDragServiceDisabled = false;
303 : static FILE *gDumpFile = nullptr;
304 : static uint32_t gSerialCounter = 0;
305 :
306 : #ifdef DEBUG_jst
307 : int32_t gTimeoutCnt = 0;
308 : #endif
309 :
310 : #if defined(DEBUG_bryner) || defined(DEBUG_chb)
311 : #define DEBUG_PAGE_CACHE
312 : #endif
313 :
314 : #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
315 :
316 : // The interval at which we execute idle callbacks
317 : static uint32_t gThrottledIdlePeriodLength;
318 :
319 : #define DEFAULT_THROTTLED_IDLE_PERIOD_LENGTH 10000
320 :
321 : #define FORWARD_TO_OUTER(method, args, err_rval) \
322 : PR_BEGIN_MACRO \
323 : if (IsInnerWindow()) { \
324 : nsGlobalWindow *outer = GetOuterWindowInternal(); \
325 : if (!AsInner()->HasActiveDocument()) { \
326 : NS_WARNING(outer ? \
327 : "Inner window does not have active document." : \
328 : "No outer window available!"); \
329 : return err_rval; \
330 : } \
331 : return outer->method args; \
332 : } \
333 : PR_END_MACRO
334 :
335 : #define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval) \
336 : PR_BEGIN_MACRO \
337 : MOZ_RELEASE_ASSERT(IsInnerWindow()); \
338 : nsGlobalWindow *outer = GetOuterWindowInternal(); \
339 : if (MOZ_LIKELY(AsInner()->HasActiveDocument())) { \
340 : return outer->method args; \
341 : } \
342 : if (!outer) { \
343 : NS_WARNING("No outer window available!"); \
344 : errorresult.Throw(NS_ERROR_NOT_INITIALIZED); \
345 : } else { \
346 : errorresult.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \
347 : } \
348 : return err_rval; \
349 : PR_END_MACRO
350 :
351 : #define FORWARD_TO_OUTER_VOID(method, args) \
352 : PR_BEGIN_MACRO \
353 : if (IsInnerWindow()) { \
354 : nsGlobalWindow *outer = GetOuterWindowInternal(); \
355 : if (!AsInner()->HasActiveDocument()) { \
356 : NS_WARNING(outer ? \
357 : "Inner window does not have active document." : \
358 : "No outer window available!"); \
359 : return; \
360 : } \
361 : outer->method args; \
362 : return; \
363 : } \
364 : PR_END_MACRO
365 :
366 : #define FORWARD_TO_OUTER_CHROME(method, args, err_rval) \
367 : PR_BEGIN_MACRO \
368 : if (IsInnerWindow()) { \
369 : nsGlobalWindow *outer = GetOuterWindowInternal(); \
370 : if (!AsInner()->HasActiveDocument()) { \
371 : NS_WARNING(outer ? \
372 : "Inner window does not have active document." : \
373 : "No outer window available!"); \
374 : return err_rval; \
375 : } \
376 : return ((nsGlobalChromeWindow *)outer)->method args; \
377 : } \
378 : PR_END_MACRO
379 :
380 : #define FORWARD_TO_INNER_CHROME(method, args, err_rval) \
381 : PR_BEGIN_MACRO \
382 : if (IsOuterWindow()) { \
383 : if (!mInnerWindow) { \
384 : NS_WARNING("No inner window available!"); \
385 : return err_rval; \
386 : } \
387 : return ((nsGlobalChromeWindow *)nsGlobalWindow::Cast(mInnerWindow))->method args; \
388 : } \
389 : PR_END_MACRO
390 :
391 : #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
392 : PR_BEGIN_MACRO \
393 : if (IsInnerWindow()) { \
394 : nsGlobalWindow *outer = GetOuterWindowInternal(); \
395 : if (!AsInner()->HasActiveDocument()) { \
396 : NS_WARNING(outer ? \
397 : "Inner window does not have active document." : \
398 : "No outer window available!"); \
399 : return err_rval; \
400 : } \
401 : return ((nsGlobalModalWindow *)outer)->method args; \
402 : } \
403 : PR_END_MACRO
404 :
405 : #define FORWARD_TO_INNER(method, args, err_rval) \
406 : PR_BEGIN_MACRO \
407 : if (IsOuterWindow()) { \
408 : if (!mInnerWindow) { \
409 : NS_WARNING("No inner window available!"); \
410 : return err_rval; \
411 : } \
412 : return GetCurrentInnerWindowInternal()->method args; \
413 : } \
414 : PR_END_MACRO
415 :
416 : #define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
417 : PR_BEGIN_MACRO \
418 : if (IsOuterWindow()) { \
419 : if (!mInnerWindow) { \
420 : NS_WARNING("No inner window available!"); \
421 : return err_rval; \
422 : } \
423 : return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
424 : } \
425 : PR_END_MACRO
426 :
427 : #define FORWARD_TO_INNER_VOID(method, args) \
428 : PR_BEGIN_MACRO \
429 : if (IsOuterWindow()) { \
430 : if (!mInnerWindow) { \
431 : NS_WARNING("No inner window available!"); \
432 : return; \
433 : } \
434 : GetCurrentInnerWindowInternal()->method args; \
435 : return; \
436 : } \
437 : PR_END_MACRO
438 :
439 : // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
440 : // inner doesn't already exists.
441 : #define FORWARD_TO_INNER_CREATE(method, args, err_rval) \
442 : PR_BEGIN_MACRO \
443 : if (IsOuterWindow()) { \
444 : if (!mInnerWindow) { \
445 : if (mIsClosed) { \
446 : return err_rval; \
447 : } \
448 : nsCOMPtr<nsIDocument> kungFuDeathGrip = GetDoc(); \
449 : ::mozilla::Unused << kungFuDeathGrip; \
450 : if (!mInnerWindow) { \
451 : return err_rval; \
452 : } \
453 : } \
454 : return GetCurrentInnerWindowInternal()->method args; \
455 : } \
456 : PR_END_MACRO
457 :
458 : // CIDs
459 : static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
460 :
461 : #define NETWORK_UPLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkupload")
462 : #define NETWORK_DOWNLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkdownload")
463 :
464 : /**
465 : * An indirect observer object that means we don't have to implement nsIObserver
466 : * on nsGlobalWindow, where any script could see it.
467 : */
468 : class nsGlobalWindowObserver final : public nsIObserver
469 : , public nsIInterfaceRequestor
470 : , public StorageNotificationObserver
471 : {
472 : public:
473 7 : explicit nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
474 : NS_DECL_ISUPPORTS
475 0 : NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) override
476 : {
477 0 : if (!mWindow)
478 0 : return NS_OK;
479 0 : return mWindow->Observe(aSubject, aTopic, aData);
480 : }
481 1 : void Forget() { mWindow = nullptr; }
482 0 : NS_IMETHOD GetInterface(const nsIID& aIID, void** aResult) override
483 : {
484 0 : if (mWindow && aIID.Equals(NS_GET_IID(nsIDOMWindow)) && mWindow) {
485 0 : return mWindow->QueryInterface(aIID, aResult);
486 : }
487 0 : return NS_NOINTERFACE;
488 : }
489 :
490 : void
491 0 : ObserveStorageNotification(StorageEvent* aEvent,
492 : const char16_t* aStorageType,
493 : bool aPrivateBrowsing) override
494 : {
495 0 : if (mWindow) {
496 0 : mWindow->ObserveStorageNotification(aEvent, aStorageType,
497 0 : aPrivateBrowsing);
498 : }
499 0 : }
500 :
501 : virtual nsIEventTarget*
502 0 : GetEventTarget() const override
503 : {
504 0 : return mWindow ? mWindow->EventTargetFor(TaskCategory::Other) : nullptr;
505 : }
506 :
507 : private:
508 : ~nsGlobalWindowObserver() = default;
509 :
510 : // This reference is non-owning and safe because it's cleared by
511 : // nsGlobalWindow::CleanUp().
512 : nsGlobalWindow* MOZ_NON_OWNING_REF mWindow;
513 : };
514 :
515 94 : NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)
516 :
517 : static already_AddRefed<nsIVariant>
518 0 : CreateVoidVariant()
519 : {
520 0 : RefPtr<nsVariantCC> writable = new nsVariantCC();
521 0 : writable->SetAsVoid();
522 0 : return writable.forget();
523 : }
524 :
525 : nsresult
526 0 : DialogValueHolder::Get(nsIPrincipal* aSubject, nsIVariant** aResult)
527 : {
528 0 : nsCOMPtr<nsIVariant> result;
529 0 : if (aSubject->SubsumesConsideringDomain(mOrigin)) {
530 0 : result = mValue;
531 : } else {
532 0 : result = CreateVoidVariant();
533 : }
534 0 : result.forget(aResult);
535 0 : return NS_OK;
536 : }
537 :
538 : void
539 0 : DialogValueHolder::Get(JSContext* aCx, JS::Handle<JSObject*> aScope,
540 : nsIPrincipal* aSubject,
541 : JS::MutableHandle<JS::Value> aResult,
542 : mozilla::ErrorResult& aError)
543 : {
544 0 : if (aSubject->Subsumes(mOrigin)) {
545 0 : aError = nsContentUtils::XPConnect()->VariantToJS(aCx, aScope,
546 0 : mValue, aResult);
547 : } else {
548 0 : aResult.setUndefined();
549 : }
550 0 : }
551 :
552 : class IdleRequestExecutor;
553 :
554 : class IdleRequestExecutorTimeoutHandler final : public TimeoutHandler
555 : {
556 : public:
557 1 : explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor* aExecutor)
558 1 : : mExecutor(aExecutor)
559 : {
560 1 : }
561 :
562 : NS_DECL_ISUPPORTS_INHERITED
563 1 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestExecutorTimeoutHandler,
564 : TimeoutHandler)
565 :
566 : nsresult Call() override;
567 :
568 : private:
569 0 : ~IdleRequestExecutorTimeoutHandler() override {}
570 : RefPtr<IdleRequestExecutor> mExecutor;
571 : };
572 :
573 0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler, mExecutor)
574 :
575 2 : NS_IMPL_ADDREF_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler)
576 1 : NS_IMPL_RELEASE_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler)
577 :
578 2 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler)
579 1 : NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler)
580 :
581 :
582 : class IdleRequestExecutor final : public nsIRunnable
583 : , public nsICancelableRunnable
584 : , public nsINamed
585 : , public nsIIdleRunnable
586 : {
587 : public:
588 1 : explicit IdleRequestExecutor(nsGlobalWindow* aWindow)
589 1 : : mDispatched(false)
590 : , mDeadline(TimeStamp::Now())
591 1 : , mWindow(aWindow)
592 : {
593 1 : MOZ_DIAGNOSTIC_ASSERT(mWindow);
594 1 : MOZ_DIAGNOSTIC_ASSERT(mWindow->IsInnerWindow());
595 :
596 1 : mIdlePeriodLimit = { mDeadline, mWindow->LastIdleRequestHandle() };
597 1 : mDelayedExecutorDispatcher = new IdleRequestExecutorTimeoutHandler(this);
598 1 : }
599 :
600 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
601 7 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor, nsIRunnable)
602 :
603 : NS_DECL_NSIRUNNABLE
604 : NS_DECL_NSINAMED
605 : nsresult Cancel() override;
606 : void SetDeadline(TimeStamp aDeadline) override;
607 :
608 1 : bool IsCancelled() const { return !mWindow || mWindow->AsInner()->InnerObjectsFreed(); }
609 : // Checks if aRequest shouldn't execute in the current idle period
610 : // since it has been queued from a chained call to
611 : // requestIdleCallback from within a running idle callback.
612 0 : bool IneligibleForCurrentIdlePeriod(IdleRequest* aRequest) const
613 : {
614 0 : return aRequest->Handle() >= mIdlePeriodLimit.mLastRequestIdInIdlePeriod &&
615 0 : TimeStamp::Now() <= mIdlePeriodLimit.mEndOfIdlePeriod;
616 : }
617 :
618 : void MaybeUpdateIdlePeriodLimit();
619 :
620 : // Maybe dispatch the IdleRequestExecutor. MabyeDispatch will
621 : // schedule a delayed dispatch if the associated window is in the
622 : // background or if given a time to wait until dispatching.
623 : void MaybeDispatch(TimeStamp aDelayUntil = TimeStamp());
624 : void ScheduleDispatch();
625 : private:
626 1 : struct IdlePeriodLimit
627 : {
628 : TimeStamp mEndOfIdlePeriod;
629 : uint32_t mLastRequestIdInIdlePeriod;
630 : };
631 :
632 : void DelayedDispatch(uint32_t aDelay);
633 :
634 0 : ~IdleRequestExecutor() override {}
635 :
636 : bool mDispatched;
637 : TimeStamp mDeadline;
638 : IdlePeriodLimit mIdlePeriodLimit;
639 : RefPtr<nsGlobalWindow> mWindow;
640 : // The timeout handler responsible for dispatching this executor in
641 : // the case of immediate dispatch to the idle queue isn't
642 : // desirable. This is used if we've dispatched all idle callbacks
643 : // that are allowed to run in the current idle period, or if the
644 : // associated window is currently in the background.
645 : nsCOMPtr<nsITimeoutHandler> mDelayedExecutorDispatcher;
646 : // If not Nothing() then this value is the handle to the currently
647 : // scheduled delayed executor dispatcher. This is needed to be able
648 : // to cancel the timeout handler in case of the executor being
649 : // cancelled.
650 : Maybe<int32_t> mDelayedExecutorHandle;
651 : };
652 :
653 : NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequestExecutor)
654 :
655 4 : NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor)
656 1 : NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor)
657 :
658 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequestExecutor)
659 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
660 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mDelayedExecutorDispatcher)
661 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
662 :
663 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequestExecutor)
664 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
665 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDelayedExecutorDispatcher)
666 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
667 :
668 2 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor)
669 1 : NS_INTERFACE_MAP_ENTRY(nsIRunnable)
670 0 : NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable)
671 0 : NS_INTERFACE_MAP_ENTRY(nsINamed)
672 0 : NS_INTERFACE_MAP_ENTRY(nsIIdleRunnable)
673 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable)
674 0 : NS_INTERFACE_MAP_END
675 :
676 : NS_IMETHODIMP
677 0 : IdleRequestExecutor::GetName(nsACString& aName)
678 : {
679 0 : aName.AssignASCII("IdleRequestExecutor");
680 0 : return NS_OK;
681 : }
682 :
683 : NS_IMETHODIMP
684 0 : IdleRequestExecutor::SetName(const char* aName)
685 : {
686 0 : return NS_ERROR_NOT_IMPLEMENTED;
687 : }
688 :
689 : NS_IMETHODIMP
690 0 : IdleRequestExecutor::Run()
691 : {
692 0 : MOZ_ASSERT(NS_IsMainThread());
693 :
694 0 : mDispatched = false;
695 0 : if (mWindow) {
696 0 : return mWindow->ExecuteIdleRequest(mDeadline);
697 : }
698 :
699 0 : return NS_OK;
700 : }
701 :
702 : nsresult
703 0 : IdleRequestExecutor::Cancel()
704 : {
705 0 : MOZ_ASSERT(NS_IsMainThread());
706 :
707 0 : if (mDelayedExecutorHandle && mWindow) {
708 0 : mWindow->AsInner()->TimeoutManager().ClearTimeout(
709 : mDelayedExecutorHandle.value(),
710 0 : Timeout::Reason::eIdleCallbackTimeout);
711 : }
712 :
713 0 : mWindow = nullptr;
714 0 : return NS_OK;
715 : }
716 :
717 : void
718 0 : IdleRequestExecutor::SetDeadline(TimeStamp aDeadline)
719 : {
720 0 : MOZ_ASSERT(NS_IsMainThread());
721 :
722 0 : if (!mWindow) {
723 0 : return;
724 : }
725 :
726 0 : mDeadline = aDeadline;
727 : }
728 :
729 : void
730 0 : IdleRequestExecutor::MaybeUpdateIdlePeriodLimit()
731 : {
732 0 : if (TimeStamp::Now() > mIdlePeriodLimit.mEndOfIdlePeriod) {
733 0 : mIdlePeriodLimit = { mDeadline, mWindow->LastIdleRequestHandle() };
734 : }
735 0 : }
736 :
737 : void
738 3 : IdleRequestExecutor::MaybeDispatch(TimeStamp aDelayUntil)
739 : {
740 : // If we've already dispatched the executor we don't want to do it
741 : // again. Also, if we've called IdleRequestExecutor::Cancel mWindow
742 : // will be null, which indicates that we shouldn't dispatch this
743 : // executor either.
744 3 : if (mDispatched || IsCancelled()) {
745 5 : return;
746 : }
747 :
748 1 : mDispatched = true;
749 :
750 1 : nsPIDOMWindowOuter* outer = mWindow->GetOuterWindow();
751 1 : if (outer && outer->AsOuter()->IsBackground()) {
752 : // Set a timeout handler with a timeout of 0 ms to throttle idle
753 : // callback requests coming from a backround window using
754 : // background timeout throttling.
755 0 : DelayedDispatch(0);
756 0 : return;
757 : }
758 :
759 1 : TimeStamp now = TimeStamp::Now();
760 1 : if (!aDelayUntil || aDelayUntil < now) {
761 1 : ScheduleDispatch();
762 1 : return;
763 : }
764 :
765 0 : TimeDuration delay = aDelayUntil - now;
766 0 : DelayedDispatch(static_cast<uint32_t>(delay.ToMilliseconds()));
767 : }
768 :
769 : void
770 1 : IdleRequestExecutor::ScheduleDispatch()
771 : {
772 1 : MOZ_ASSERT(mWindow);
773 1 : mDelayedExecutorHandle = Nothing();
774 2 : RefPtr<IdleRequestExecutor> request = this;
775 1 : NS_IdleDispatchToCurrentThread(request.forget());
776 1 : }
777 :
778 : void
779 0 : IdleRequestExecutor::DelayedDispatch(uint32_t aDelay)
780 : {
781 0 : MOZ_ASSERT(mWindow);
782 0 : MOZ_ASSERT(mDelayedExecutorHandle.isNothing());
783 : int32_t handle;
784 0 : mWindow->AsInner()->TimeoutManager().SetTimeout(
785 0 : mDelayedExecutorDispatcher, aDelay, false, Timeout::Reason::eIdleCallbackTimeout, &handle);
786 0 : mDelayedExecutorHandle = Some(handle);
787 0 : }
788 :
789 : nsresult
790 0 : IdleRequestExecutorTimeoutHandler::Call()
791 : {
792 0 : if (!mExecutor->IsCancelled()) {
793 0 : mExecutor->ScheduleDispatch();
794 : }
795 0 : return NS_OK;
796 : }
797 :
798 : void
799 3 : nsGlobalWindow::ScheduleIdleRequestDispatch()
800 : {
801 3 : AssertIsOnMainThread();
802 :
803 3 : if (!mIdleRequestExecutor) {
804 1 : mIdleRequestExecutor = new IdleRequestExecutor(this);
805 : }
806 :
807 3 : mIdleRequestExecutor->MaybeDispatch();
808 3 : }
809 :
810 : void
811 0 : nsGlobalWindow::SuspendIdleRequests()
812 : {
813 0 : if (mIdleRequestExecutor) {
814 0 : mIdleRequestExecutor->Cancel();
815 0 : mIdleRequestExecutor = nullptr;
816 : }
817 0 : }
818 :
819 : void
820 0 : nsGlobalWindow::ResumeIdleRequests()
821 : {
822 0 : MOZ_ASSERT(!mIdleRequestExecutor);
823 :
824 0 : ScheduleIdleRequestDispatch();
825 0 : }
826 :
827 : void
828 3 : nsGlobalWindow::InsertIdleCallback(IdleRequest* aRequest)
829 : {
830 3 : AssertIsOnMainThread();
831 3 : mIdleRequestCallbacks.insertBack(aRequest);
832 3 : aRequest->AddRef();
833 3 : }
834 :
835 : void
836 1 : nsGlobalWindow::RemoveIdleCallback(mozilla::dom::IdleRequest* aRequest)
837 : {
838 1 : AssertIsOnMainThread();
839 :
840 1 : if (aRequest->HasTimeout()) {
841 1 : mTimeoutManager->ClearTimeout(aRequest->GetTimeoutHandle(),
842 1 : Timeout::Reason::eIdleCallbackTimeout);
843 : }
844 :
845 1 : aRequest->removeFrom(mIdleRequestCallbacks);
846 1 : aRequest->Release();
847 1 : }
848 :
849 : nsresult
850 1 : nsGlobalWindow::RunIdleRequest(IdleRequest* aRequest,
851 : DOMHighResTimeStamp aDeadline,
852 : bool aDidTimeout)
853 : {
854 1 : AssertIsOnMainThread();
855 2 : RefPtr<IdleRequest> request(aRequest);
856 1 : RemoveIdleCallback(request);
857 2 : return request->IdleRun(AsInner(), aDeadline, aDidTimeout);
858 : }
859 :
860 : nsresult
861 0 : nsGlobalWindow::ExecuteIdleRequest(TimeStamp aDeadline)
862 : {
863 0 : AssertIsOnMainThread();
864 0 : RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
865 :
866 0 : if (!request) {
867 : // There are no more idle requests, so stop scheduling idle
868 : // request callbacks.
869 0 : return NS_OK;
870 : }
871 :
872 : // If the request that we're trying to execute has been queued
873 : // during the current idle period, then dispatch it again at the end
874 : // of the idle period.
875 0 : if (mIdleRequestExecutor->IneligibleForCurrentIdlePeriod(request)) {
876 0 : mIdleRequestExecutor->MaybeDispatch(aDeadline);
877 0 : return NS_OK;
878 : }
879 :
880 0 : DOMHighResTimeStamp deadline = 0.0;
881 :
882 0 : if (Performance* perf = GetPerformance()) {
883 0 : deadline = perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline);
884 : }
885 :
886 0 : mIdleRequestExecutor->MaybeUpdateIdlePeriodLimit();
887 0 : nsresult result = RunIdleRequest(request, deadline, false);
888 :
889 : // Running the idle callback could've suspended the window, in which
890 : // case mIdleRequestExecutor will be null.
891 0 : if (mIdleRequestExecutor) {
892 0 : mIdleRequestExecutor->MaybeDispatch();
893 : }
894 0 : return result;
895 : }
896 :
897 : class IdleRequestTimeoutHandler final : public TimeoutHandler
898 : {
899 : public:
900 2 : IdleRequestTimeoutHandler(JSContext* aCx,
901 : IdleRequest* aIdleRequest,
902 : nsPIDOMWindowInner* aWindow)
903 2 : : TimeoutHandler(aCx)
904 : , mIdleRequest(aIdleRequest)
905 2 : , mWindow(aWindow)
906 : {
907 2 : }
908 :
909 : NS_DECL_ISUPPORTS_INHERITED
910 2 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestTimeoutHandler,
911 : TimeoutHandler)
912 :
913 1 : nsresult Call() override
914 : {
915 1 : return nsGlobalWindow::Cast(mWindow)->RunIdleRequest(mIdleRequest, 0.0, true);
916 : }
917 :
918 : private:
919 0 : ~IdleRequestTimeoutHandler() override {}
920 :
921 : RefPtr<IdleRequest> mIdleRequest;
922 : nsCOMPtr<nsPIDOMWindowInner> mWindow;
923 : };
924 :
925 0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestTimeoutHandler,
926 : TimeoutHandler,
927 : mIdleRequest,
928 : mWindow)
929 :
930 9 : NS_IMPL_ADDREF_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler)
931 7 : NS_IMPL_RELEASE_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler)
932 :
933 7 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler)
934 5 : NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler)
935 :
936 : uint32_t
937 3 : nsGlobalWindow::RequestIdleCallback(JSContext* aCx,
938 : IdleRequestCallback& aCallback,
939 : const IdleRequestOptions& aOptions,
940 : ErrorResult& aError)
941 : {
942 3 : MOZ_RELEASE_ASSERT(IsInnerWindow());
943 3 : AssertIsOnMainThread();
944 :
945 3 : uint32_t handle = mIdleRequestCallbackCounter++;
946 :
947 : RefPtr<IdleRequest> request =
948 6 : new IdleRequest(&aCallback, handle);
949 :
950 3 : if (aOptions.mTimeout.WasPassed()) {
951 : int32_t timeoutHandle;
952 6 : nsCOMPtr<nsITimeoutHandler> handler(new IdleRequestTimeoutHandler(aCx, request, AsInner()));
953 :
954 2 : nsresult rv = mTimeoutManager->SetTimeout(
955 2 : handler, aOptions.mTimeout.Value(), false,
956 2 : Timeout::Reason::eIdleCallbackTimeout, &timeoutHandle);
957 :
958 2 : if (NS_WARN_IF(NS_FAILED(rv))) {
959 0 : return 0;
960 : }
961 :
962 2 : request->SetTimeoutHandle(timeoutHandle);
963 : }
964 :
965 : // mIdleRequestCallbacks now owns request
966 3 : InsertIdleCallback(request);
967 :
968 3 : if (!IsSuspended()) {
969 3 : ScheduleIdleRequestDispatch();
970 : }
971 :
972 3 : return handle;
973 : }
974 :
975 : void
976 0 : nsGlobalWindow::CancelIdleCallback(uint32_t aHandle)
977 : {
978 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
979 :
980 0 : for (IdleRequest* r : mIdleRequestCallbacks) {
981 0 : if (r->Handle() == aHandle) {
982 0 : RemoveIdleCallback(r);
983 0 : break;
984 : }
985 : }
986 0 : }
987 :
988 : void
989 4 : nsGlobalWindow::DisableIdleCallbackRequests()
990 : {
991 4 : if (mIdleRequestExecutor) {
992 0 : mIdleRequestExecutor->Cancel();
993 0 : mIdleRequestExecutor = nullptr;
994 : }
995 :
996 4 : while (!mIdleRequestCallbacks.isEmpty()) {
997 0 : RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
998 0 : RemoveIdleCallback(request);
999 : }
1000 4 : }
1001 :
1002 : bool
1003 12 : nsGlobalWindow::IsBackgroundInternal() const
1004 : {
1005 12 : return !mOuterWindow || mOuterWindow->IsBackground();
1006 : }
1007 : namespace mozilla {
1008 : namespace dom {
1009 : extern uint64_t
1010 : NextWindowID();
1011 : } // namespace dom
1012 : } // namespace mozilla
1013 :
1014 : template<class T>
1015 12 : nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMWindowOuter *aOuterWindow)
1016 : : mFrameElement(nullptr), mDocShell(nullptr), mModalStateDepth(0),
1017 : mMutationBits(0), mIsDocumentLoaded(false),
1018 12 : mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nullptr),
1019 : mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
1020 : mMayHaveSelectionChangeEventListener(false),
1021 : mMayHaveMouseEnterLeaveEventListener(false),
1022 : mMayHavePointerEnterLeaveEventListener(false),
1023 : mInnerObjectsFreed(false),
1024 : mIsModalContentWindow(false),
1025 : mIsActive(false), mIsBackground(false),
1026 12 : mMediaSuspend(Preferences::GetBool("media.block-autoplay-until-in-foreground", true) ?
1027 : nsISuspendedTypes::SUSPENDED_BLOCK : nsISuspendedTypes::NONE_SUSPENDED),
1028 : mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false),
1029 : mDesktopModeViewport(false), mIsRootOuterWindow(false), mInnerWindow(nullptr),
1030 : mOuterWindow(aOuterWindow),
1031 : // Make sure no actual window ends up with mWindowID == 0
1032 12 : mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false),
1033 : mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false),
1034 : mLargeAllocStatus(LargeAllocStatus::NONE),
1035 : mHasTriedToCacheTopInnerWindow(false),
1036 48 : mNumOfIndexedDBDatabases(0)
1037 : {
1038 12 : if (aOuterWindow) {
1039 7 : mTimeoutManager =
1040 7 : MakeUnique<mozilla::dom::TimeoutManager>(*nsGlobalWindow::Cast(AsInner()));
1041 : }
1042 12 : }
1043 :
1044 : template<class T>
1045 0 : nsPIDOMWindow<T>::~nsPIDOMWindow() {}
1046 :
1047 : /* static */
1048 : nsPIDOMWindowOuter*
1049 35 : nsPIDOMWindowOuter::GetFromCurrentInner(nsPIDOMWindowInner* aInner)
1050 : {
1051 35 : if (!aInner) {
1052 0 : return nullptr;
1053 : }
1054 :
1055 35 : nsPIDOMWindowOuter* outer = aInner->GetOuterWindow();
1056 35 : if (!outer || outer->GetCurrentInnerWindow() != aInner) {
1057 0 : return nullptr;
1058 : }
1059 :
1060 35 : return outer;
1061 : }
1062 :
1063 : // DialogValueHolder CC goop.
1064 0 : NS_IMPL_CYCLE_COLLECTION(DialogValueHolder, mValue)
1065 :
1066 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DialogValueHolder)
1067 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
1068 0 : NS_INTERFACE_MAP_END
1069 :
1070 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(DialogValueHolder)
1071 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(DialogValueHolder)
1072 :
1073 : //*****************************************************************************
1074 : // nsOuterWindowProxy: Outer Window Proxy
1075 : //*****************************************************************************
1076 :
1077 : class nsOuterWindowProxy : public js::Wrapper
1078 : {
1079 : public:
1080 : constexpr nsOuterWindowProxy() : js::Wrapper(0) { }
1081 :
1082 7 : bool finalizeInBackground(const JS::Value& priv) const override {
1083 7 : return false;
1084 : }
1085 :
1086 : // Standard internal methods
1087 : bool getOwnPropertyDescriptor(JSContext* cx,
1088 : JS::Handle<JSObject*> proxy,
1089 : JS::Handle<jsid> id,
1090 : JS::MutableHandle<JS::PropertyDescriptor> desc)
1091 : const override;
1092 : bool defineProperty(JSContext* cx,
1093 : JS::Handle<JSObject*> proxy,
1094 : JS::Handle<jsid> id,
1095 : JS::Handle<JS::PropertyDescriptor> desc,
1096 : JS::ObjectOpResult &result) const override;
1097 : bool ownPropertyKeys(JSContext *cx,
1098 : JS::Handle<JSObject*> proxy,
1099 : JS::AutoIdVector &props) const override;
1100 : bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
1101 : JS::Handle<jsid> id,
1102 : JS::ObjectOpResult &result) const override;
1103 :
1104 : bool getPrototypeIfOrdinary(JSContext* cx,
1105 : JS::Handle<JSObject*> proxy,
1106 : bool* isOrdinary,
1107 : JS::MutableHandle<JSObject*> protop) const override;
1108 :
1109 : JSObject* enumerate(JSContext *cx, JS::Handle<JSObject*> proxy) const override;
1110 : bool preventExtensions(JSContext* cx,
1111 : JS::Handle<JSObject*> proxy,
1112 : JS::ObjectOpResult& result) const override;
1113 : bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
1114 : const override;
1115 : bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
1116 : JS::Handle<jsid> id, bool *bp) const override;
1117 : bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
1118 : JS::Handle<JS::Value> receiver,
1119 : JS::Handle<jsid> id,
1120 : JS::MutableHandle<JS::Value> vp) const override;
1121 : bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
1122 : JS::Handle<jsid> id, JS::Handle<JS::Value> v,
1123 : JS::Handle<JS::Value> receiver,
1124 : JS::ObjectOpResult &result) const override;
1125 :
1126 : // SpiderMonkey extensions
1127 : bool getPropertyDescriptor(JSContext* cx,
1128 : JS::Handle<JSObject*> proxy,
1129 : JS::Handle<jsid> id,
1130 : JS::MutableHandle<JS::PropertyDescriptor> desc)
1131 : const override;
1132 : bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
1133 : JS::Handle<jsid> id, bool *bp) const override;
1134 : bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
1135 : JS::AutoIdVector &props) const override;
1136 : const char *className(JSContext *cx,
1137 : JS::Handle<JSObject*> wrapper) const override;
1138 :
1139 : void finalize(JSFreeOp *fop, JSObject *proxy) const override;
1140 :
1141 70 : bool isCallable(JSObject *obj) const override {
1142 70 : return false;
1143 : }
1144 17 : bool isConstructor(JSObject *obj) const override {
1145 17 : return false;
1146 : }
1147 :
1148 : bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
1149 : JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const override;
1150 : bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
1151 : JS::Handle<jsid> id) const override;
1152 :
1153 : static void ObjectMoved(JSObject *obj, const JSObject *old);
1154 :
1155 : static const nsOuterWindowProxy singleton;
1156 :
1157 : protected:
1158 0 : static nsGlobalWindow* GetOuterWindow(JSObject *proxy)
1159 : {
1160 : nsGlobalWindow* outerWindow = nsGlobalWindow::FromSupports(
1161 0 : static_cast<nsISupports*>(js::GetProxyReservedSlot(proxy, 0).toPrivate()));
1162 0 : MOZ_ASSERT_IF(outerWindow, outerWindow->IsOuterWindow());
1163 0 : return outerWindow;
1164 : }
1165 :
1166 : // False return value means we threw an exception. True return value
1167 : // but false "found" means we didn't have a subframe at that index.
1168 : bool GetSubframeWindow(JSContext *cx, JS::Handle<JSObject*> proxy,
1169 : JS::Handle<jsid> id,
1170 : JS::MutableHandle<JS::Value> vp,
1171 : bool &found) const;
1172 :
1173 : // Returns a non-null window only if id is an index and we have a
1174 : // window at that index.
1175 : already_AddRefed<nsPIDOMWindowOuter>
1176 : GetSubframeWindow(JSContext *cx,
1177 : JS::Handle<JSObject*> proxy,
1178 : JS::Handle<jsid> id) const;
1179 :
1180 : bool AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
1181 : JS::AutoIdVector &props) const;
1182 : };
1183 :
1184 : static const js::ClassExtension OuterWindowProxyClassExtension = PROXY_MAKE_EXT(
1185 : nsOuterWindowProxy::ObjectMoved
1186 : );
1187 :
1188 : // Give OuterWindowProxyClass 2 reserved slots, like the other wrappers, so
1189 : // JSObject::swap can swap it with CrossCompartmentWrappers without requiring
1190 : // malloc.
1191 : const js::Class OuterWindowProxyClass = PROXY_CLASS_WITH_EXT(
1192 : "Proxy",
1193 : JSCLASS_HAS_RESERVED_SLOTS(2), /* additional class flags */
1194 : &OuterWindowProxyClassExtension);
1195 :
1196 : const char *
1197 0 : nsOuterWindowProxy::className(JSContext *cx, JS::Handle<JSObject*> proxy) const
1198 : {
1199 0 : MOZ_ASSERT(js::IsProxy(proxy));
1200 :
1201 0 : return "Window";
1202 : }
1203 :
1204 : void
1205 0 : nsOuterWindowProxy::finalize(JSFreeOp *fop, JSObject *proxy) const
1206 : {
1207 0 : nsGlobalWindow* outerWindow = GetOuterWindow(proxy);
1208 0 : if (outerWindow) {
1209 0 : outerWindow->ClearWrapper(proxy);
1210 :
1211 : // Ideally we would use OnFinalize here, but it's possible that
1212 : // EnsureScriptEnvironment will later be called on the window, and we don't
1213 : // want to create a new script object in that case. Therefore, we need to
1214 : // write a non-null value that will reliably crash when dereferenced.
1215 0 : outerWindow->PoisonOuterWindowProxy(proxy);
1216 : }
1217 0 : }
1218 :
1219 : bool
1220 0 : nsOuterWindowProxy::getPropertyDescriptor(JSContext* cx,
1221 : JS::Handle<JSObject*> proxy,
1222 : JS::Handle<jsid> id,
1223 : JS::MutableHandle<JS::PropertyDescriptor> desc) const
1224 : {
1225 : // The only thing we can do differently from js::Wrapper is shadow stuff with
1226 : // our indexed properties, so we can just try getOwnPropertyDescriptor and if
1227 : // that gives us nothing call on through to js::Wrapper.
1228 0 : desc.object().set(nullptr);
1229 0 : if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) {
1230 0 : return false;
1231 : }
1232 :
1233 0 : if (desc.object()) {
1234 0 : return true;
1235 : }
1236 :
1237 0 : return js::Wrapper::getPropertyDescriptor(cx, proxy, id, desc);
1238 : }
1239 :
1240 : bool
1241 30 : nsOuterWindowProxy::getOwnPropertyDescriptor(JSContext* cx,
1242 : JS::Handle<JSObject*> proxy,
1243 : JS::Handle<jsid> id,
1244 : JS::MutableHandle<JS::PropertyDescriptor> desc)
1245 : const
1246 : {
1247 : bool found;
1248 30 : if (!GetSubframeWindow(cx, proxy, id, desc.value(), found)) {
1249 0 : return false;
1250 : }
1251 30 : if (found) {
1252 0 : FillPropertyDescriptor(desc, proxy, true);
1253 0 : return true;
1254 : }
1255 : // else fall through to js::Wrapper
1256 :
1257 30 : return js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
1258 : }
1259 :
1260 : bool
1261 216 : nsOuterWindowProxy::defineProperty(JSContext* cx,
1262 : JS::Handle<JSObject*> proxy,
1263 : JS::Handle<jsid> id,
1264 : JS::Handle<JS::PropertyDescriptor> desc,
1265 : JS::ObjectOpResult &result) const
1266 : {
1267 216 : if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
1268 : // Spec says to Reject whether this is a supported index or not,
1269 : // since we have no indexed setter or indexed creator. It is up
1270 : // to the caller to decide whether to throw a TypeError.
1271 0 : return result.failCantDefineWindowElement();
1272 : }
1273 :
1274 216 : return js::Wrapper::defineProperty(cx, proxy, id, desc, result);
1275 : }
1276 :
1277 : bool
1278 0 : nsOuterWindowProxy::ownPropertyKeys(JSContext *cx,
1279 : JS::Handle<JSObject*> proxy,
1280 : JS::AutoIdVector &props) const
1281 : {
1282 : // Just our indexed stuff followed by our "normal" own property names.
1283 0 : if (!AppendIndexedPropertyNames(cx, proxy, props)) {
1284 0 : return false;
1285 : }
1286 :
1287 0 : JS::AutoIdVector innerProps(cx);
1288 0 : if (!js::Wrapper::ownPropertyKeys(cx, proxy, innerProps)) {
1289 0 : return false;
1290 : }
1291 0 : return js::AppendUnique(cx, props, innerProps);
1292 : }
1293 :
1294 : bool
1295 40 : nsOuterWindowProxy::delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
1296 : JS::Handle<jsid> id, JS::ObjectOpResult &result) const
1297 : {
1298 80 : if (nsCOMPtr<nsPIDOMWindowOuter> frame = GetSubframeWindow(cx, proxy, id)) {
1299 : // Fail (which means throw if strict, else return false).
1300 0 : return result.failCantDeleteWindowElement();
1301 : }
1302 :
1303 40 : if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
1304 : // Indexed, but not supported. Spec says return true.
1305 0 : return result.succeed();
1306 : }
1307 :
1308 40 : return js::Wrapper::delete_(cx, proxy, id, result);
1309 : }
1310 :
1311 : bool
1312 0 : nsOuterWindowProxy::getPrototypeIfOrdinary(JSContext* cx,
1313 : JS::Handle<JSObject*> proxy,
1314 : bool* isOrdinary,
1315 : JS::MutableHandle<JSObject*> protop) const
1316 : {
1317 : // Window's [[GetPrototypeOf]] trap isn't the ordinary definition:
1318 : //
1319 : // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof
1320 : //
1321 : // We nonetheless can implement it with a static [[Prototype]], because
1322 : // wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) supply
1323 : // all non-ordinary behavior.
1324 : //
1325 : // But from a spec point of view, it's the exact same object in both cases --
1326 : // only the observer's changed. So this getPrototypeIfOrdinary trap on the
1327 : // non-wrapper object *must* report non-ordinary, even if static [[Prototype]]
1328 : // usually means ordinary.
1329 0 : *isOrdinary = false;
1330 0 : return true;
1331 : }
1332 :
1333 : bool
1334 0 : nsOuterWindowProxy::preventExtensions(JSContext* cx,
1335 : JS::Handle<JSObject*> proxy,
1336 : JS::ObjectOpResult& result) const
1337 : {
1338 : // If [[Extensible]] could be false, then navigating a window could navigate
1339 : // to a window that's [[Extensible]] after being at one that wasn't: an
1340 : // invariant violation. So never change a window's extensibility.
1341 0 : return result.failCantPreventExtensions();
1342 : }
1343 :
1344 : bool
1345 0 : nsOuterWindowProxy::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy,
1346 : bool *extensible) const
1347 : {
1348 : // See above.
1349 0 : *extensible = true;
1350 0 : return true;
1351 : }
1352 :
1353 : bool
1354 0 : nsOuterWindowProxy::has(JSContext *cx, JS::Handle<JSObject*> proxy,
1355 : JS::Handle<jsid> id, bool *bp) const
1356 : {
1357 0 : if (nsCOMPtr<nsPIDOMWindowOuter> frame = GetSubframeWindow(cx, proxy, id)) {
1358 0 : *bp = true;
1359 0 : return true;
1360 : }
1361 :
1362 0 : return js::Wrapper::has(cx, proxy, id, bp);
1363 : }
1364 :
1365 : bool
1366 1 : nsOuterWindowProxy::hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
1367 : JS::Handle<jsid> id, bool *bp) const
1368 : {
1369 2 : if (nsCOMPtr<nsPIDOMWindowOuter> frame = GetSubframeWindow(cx, proxy, id)) {
1370 0 : *bp = true;
1371 0 : return true;
1372 : }
1373 :
1374 1 : return js::Wrapper::hasOwn(cx, proxy, id, bp);
1375 : }
1376 :
1377 : bool
1378 268 : nsOuterWindowProxy::get(JSContext *cx, JS::Handle<JSObject*> proxy,
1379 : JS::Handle<JS::Value> receiver,
1380 : JS::Handle<jsid> id,
1381 : JS::MutableHandle<JS::Value> vp) const
1382 : {
1383 268 : if (id == nsDOMClassInfo::sWrappedJSObject_id &&
1384 0 : xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
1385 0 : vp.set(JS::ObjectValue(*proxy));
1386 0 : return true;
1387 : }
1388 :
1389 : bool found;
1390 268 : if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
1391 0 : return false;
1392 : }
1393 268 : if (found) {
1394 0 : return true;
1395 : }
1396 : // Else fall through to js::Wrapper
1397 :
1398 268 : return js::Wrapper::get(cx, proxy, receiver, id, vp);
1399 : }
1400 :
1401 : bool
1402 6 : nsOuterWindowProxy::set(JSContext *cx, JS::Handle<JSObject*> proxy,
1403 : JS::Handle<jsid> id,
1404 : JS::Handle<JS::Value> v,
1405 : JS::Handle<JS::Value> receiver,
1406 : JS::ObjectOpResult &result) const
1407 : {
1408 6 : if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
1409 : // Reject the set. It's up to the caller to decide whether to throw a
1410 : // TypeError. If the caller is strict mode JS code, it'll throw.
1411 0 : return result.failReadOnly();
1412 : }
1413 :
1414 6 : return js::Wrapper::set(cx, proxy, id, v, receiver, result);
1415 : }
1416 :
1417 : bool
1418 0 : nsOuterWindowProxy::getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
1419 : JS::AutoIdVector &props) const
1420 : {
1421 : // Like ownPropertyKeys, our indexed stuff followed by our "normal" enumerable
1422 : // own property names.
1423 : //
1424 : // Note that this does not match current spec per
1425 : // https://github.com/whatwg/html/issues/2753 but as that issue says I believe
1426 : // the spec is wrong.
1427 0 : if (!AppendIndexedPropertyNames(cx, proxy, props)) {
1428 0 : return false;
1429 : }
1430 :
1431 0 : JS::AutoIdVector innerProps(cx);
1432 0 : if (!js::Wrapper::getOwnEnumerablePropertyKeys(cx, proxy, innerProps)) {
1433 0 : return false;
1434 : }
1435 0 : return js::AppendUnique(cx, props, innerProps);
1436 : }
1437 :
1438 : JSObject*
1439 0 : nsOuterWindowProxy::enumerate(JSContext *cx, JS::Handle<JSObject*> proxy) const
1440 : {
1441 : // BaseProxyHandler::enumerate seems to do what we want here: fall
1442 : // back on the property names returned from js::GetPropertyKeys()
1443 0 : return js::BaseProxyHandler::enumerate(cx, proxy);
1444 : }
1445 :
1446 : bool
1447 298 : nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
1448 : JS::Handle<JSObject*> proxy,
1449 : JS::Handle<jsid> id,
1450 : JS::MutableHandle<JS::Value> vp,
1451 : bool& found) const
1452 : {
1453 596 : nsCOMPtr<nsPIDOMWindowOuter> frame = GetSubframeWindow(cx, proxy, id);
1454 298 : if (!frame) {
1455 298 : found = false;
1456 298 : return true;
1457 : }
1458 :
1459 0 : found = true;
1460 : // Just return the window's global
1461 0 : nsGlobalWindow* global = nsGlobalWindow::Cast(frame);
1462 0 : frame->EnsureInnerWindow();
1463 0 : JSObject* obj = global->FastGetGlobalJSObject();
1464 : // This null check fixes a hard-to-reproduce crash that occurs when we
1465 : // get here when we're mid-call to nsDocShell::Destroy. See bug 640904
1466 : // comment 105.
1467 0 : if (MOZ_UNLIKELY(!obj)) {
1468 0 : return xpc::Throw(cx, NS_ERROR_FAILURE);
1469 : }
1470 0 : JS::ExposeObjectToActiveJS(obj);
1471 0 : vp.setObject(*obj);
1472 0 : return JS_WrapValue(cx, vp);
1473 : }
1474 :
1475 : already_AddRefed<nsPIDOMWindowOuter>
1476 339 : nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
1477 : JS::Handle<JSObject*> proxy,
1478 : JS::Handle<jsid> id) const
1479 : {
1480 339 : uint32_t index = GetArrayIndexFromId(cx, id);
1481 339 : if (!IsArrayIndex(index)) {
1482 339 : return nullptr;
1483 : }
1484 :
1485 0 : nsGlobalWindow* win = GetOuterWindow(proxy);
1486 0 : MOZ_ASSERT(win->IsOuterWindow());
1487 0 : return win->IndexedGetterOuter(index);
1488 : }
1489 :
1490 : bool
1491 0 : nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
1492 : JS::AutoIdVector &props) const
1493 : {
1494 0 : uint32_t length = GetOuterWindow(proxy)->Length();
1495 0 : MOZ_ASSERT(int32_t(length) >= 0);
1496 0 : if (!props.reserve(props.length() + length)) {
1497 0 : return false;
1498 : }
1499 0 : for (int32_t i = 0; i < int32_t(length); ++i) {
1500 0 : if (!props.append(INT_TO_JSID(i))) {
1501 0 : return false;
1502 : }
1503 : }
1504 :
1505 0 : return true;
1506 : }
1507 :
1508 : bool
1509 0 : nsOuterWindowProxy::watch(JSContext *cx, JS::Handle<JSObject*> proxy,
1510 : JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const
1511 : {
1512 0 : return js::WatchGuts(cx, proxy, id, callable);
1513 : }
1514 :
1515 : bool
1516 0 : nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
1517 : JS::Handle<jsid> id) const
1518 : {
1519 0 : return js::UnwatchGuts(cx, proxy, id);
1520 : }
1521 :
1522 : void
1523 0 : nsOuterWindowProxy::ObjectMoved(JSObject *obj, const JSObject *old)
1524 : {
1525 0 : nsGlobalWindow* outerWindow = GetOuterWindow(obj);
1526 0 : if (outerWindow) {
1527 0 : outerWindow->UpdateWrapper(obj, old);
1528 : }
1529 0 : }
1530 :
1531 : const nsOuterWindowProxy
1532 : nsOuterWindowProxy::singleton;
1533 :
1534 : class nsChromeOuterWindowProxy : public nsOuterWindowProxy
1535 : {
1536 : public:
1537 : constexpr nsChromeOuterWindowProxy() : nsOuterWindowProxy() { }
1538 :
1539 : const char *className(JSContext *cx, JS::Handle<JSObject*> wrapper) const override;
1540 :
1541 : static const nsChromeOuterWindowProxy singleton;
1542 : };
1543 :
1544 : const char *
1545 0 : nsChromeOuterWindowProxy::className(JSContext *cx,
1546 : JS::Handle<JSObject*> proxy) const
1547 : {
1548 0 : MOZ_ASSERT(js::IsProxy(proxy));
1549 :
1550 0 : return "ChromeWindow";
1551 : }
1552 :
1553 : const nsChromeOuterWindowProxy
1554 : nsChromeOuterWindowProxy::singleton;
1555 :
1556 : static JSObject*
1557 7 : NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> global, bool isChrome)
1558 : {
1559 14 : JSAutoCompartment ac(cx, global);
1560 7 : MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(global) == global);
1561 :
1562 14 : js::WrapperOptions options;
1563 7 : options.setClass(&OuterWindowProxyClass);
1564 7 : options.setSingleton(true);
1565 14 : JSObject *obj = js::Wrapper::New(cx, global,
1566 : isChrome ? &nsChromeOuterWindowProxy::singleton
1567 : : &nsOuterWindowProxy::singleton,
1568 14 : options);
1569 7 : MOZ_ASSERT_IF(obj, js::IsWindowProxy(obj));
1570 14 : return obj;
1571 : }
1572 :
1573 : //*****************************************************************************
1574 : //*** nsGlobalWindow: Object Management
1575 : //*****************************************************************************
1576 :
1577 12 : nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
1578 7 : : nsPIDOMWindow<nsISupports>(aOuterWindow ? aOuterWindow->AsOuter() : nullptr),
1579 : mIdleFuzzFactor(0),
1580 : mIdleCallbackIndex(-1),
1581 : mCurrentlyIdle(false),
1582 : mAddActiveEventFuzzTime(true),
1583 : mFullScreen(false),
1584 : mFullscreenMode(false),
1585 : mIsClosed(false),
1586 : mInClose(false),
1587 : mHavePendingClose(false),
1588 : mHadOriginalOpener(false),
1589 : mOriginalOpenerWasSecureContext(false),
1590 : mIsPopupSpam(false),
1591 : mBlockScriptedClosingFlag(false),
1592 : mWasOffline(false),
1593 : mHasHadSlowScript(false),
1594 : mNotifyIdleObserversIdleOnThaw(false),
1595 : mNotifyIdleObserversActiveOnThaw(false),
1596 : mCreatingInnerWindow(false),
1597 : mIsChrome(false),
1598 : mCleanMessageManager(false),
1599 : mNeedsFocus(true),
1600 : mHasFocus(false),
1601 : mShowFocusRingForContent(false),
1602 : mFocusByKeyOccurred(false),
1603 : mHasGamepad(false),
1604 : mHasVREvents(false),
1605 : mHasVRDisplayActivateEvents(false),
1606 : mHasSeenGamepadInput(false),
1607 : mNotifiedIDDestroyed(false),
1608 : mAllowScriptsToClose(false),
1609 : mTopLevelOuterContentWindow(false),
1610 : mSuspendDepth(0),
1611 : mFreezeDepth(0),
1612 : mFocusMethod(0),
1613 : mSerial(0),
1614 : mIdleRequestCallbackCounter(1),
1615 : mIdleRequestExecutor(nullptr),
1616 : #ifdef DEBUG
1617 : mSetOpenerWindowCalled(false),
1618 : #endif
1619 : #ifdef MOZ_B2G
1620 : mNetworkUploadObserverEnabled(false),
1621 : mNetworkDownloadObserverEnabled(false),
1622 : #endif
1623 : mCleanedUp(false),
1624 : mDialogAbuseCount(0),
1625 : mAreDialogsEnabled(true),
1626 : #ifdef DEBUG
1627 : mIsValidatingTabGroup(false),
1628 : #endif
1629 : mCanSkipCCGeneration(0),
1630 : mAutoActivateVRDisplayID(0),
1631 19 : mBeforeUnloadListenerCount(0)
1632 : {
1633 12 : AssertIsOnMainThread();
1634 :
1635 12 : nsLayoutStatics::AddRef();
1636 :
1637 : // Initialize the PRCList (this).
1638 12 : PR_INIT_CLIST(this);
1639 :
1640 12 : if (aOuterWindow) {
1641 : // |this| is an inner window, add this inner window to the outer
1642 : // window list of inners.
1643 7 : PR_INSERT_AFTER(this, aOuterWindow);
1644 :
1645 7 : mObserver = new nsGlobalWindowObserver(this);
1646 7 : if (mObserver) {
1647 14 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1648 7 : if (os) {
1649 : // Watch for online/offline status changes so we can fire events. Use
1650 : // a strong reference.
1651 7 : os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1652 7 : false);
1653 : }
1654 :
1655 7 : Preferences::AddStrongObserver(mObserver, "intl.accept_languages");
1656 :
1657 : // Watch for storage notifications so we can fire storage events.
1658 : RefPtr<StorageNotifierService> sns =
1659 14 : StorageNotifierService::GetOrCreate();
1660 7 : if (sns) {
1661 7 : sns->Register(mObserver);
1662 : }
1663 : }
1664 : } else {
1665 : // |this| is an outer window. Outer windows start out frozen and
1666 : // remain frozen until they get an inner window.
1667 5 : MOZ_ASSERT(IsFrozen());
1668 : }
1669 :
1670 12 : if (XRE_IsContentProcess()) {
1671 6 : nsCOMPtr<nsIDocShell> docShell = GetDocShell();
1672 3 : if (docShell) {
1673 2 : mTabChild = docShell->GetTabChild();
1674 : }
1675 : }
1676 :
1677 : // We could have failed the first time through trying
1678 : // to create the entropy collector, so we should
1679 : // try to get one until we succeed.
1680 :
1681 12 : gRefCnt++;
1682 :
1683 : static bool sFirstTime = true;
1684 12 : if (sFirstTime) {
1685 2 : TimeoutManager::Initialize();
1686 : Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled,
1687 : "dom.idle-observers-api.fuzz_time.disabled",
1688 2 : false);
1689 :
1690 : Preferences::AddUintVarCache(&gThrottledIdlePeriodLength,
1691 : "dom.idle_period.throttled_length",
1692 2 : DEFAULT_THROTTLED_IDLE_PERIOD_LENGTH);
1693 2 : sFirstTime = false;
1694 : }
1695 :
1696 12 : if (gDumpFile == nullptr) {
1697 : const nsAdoptingCString& fname =
1698 4 : Preferences::GetCString("browser.dom.window.dump.file");
1699 2 : if (!fname.IsEmpty()) {
1700 : // if this fails to open, Dump() knows to just go to stdout
1701 : // on null.
1702 0 : gDumpFile = fopen(fname, "wb+");
1703 : } else {
1704 2 : gDumpFile = stdout;
1705 : }
1706 : }
1707 :
1708 12 : mSerial = ++gSerialCounter;
1709 :
1710 : #ifdef DEBUG
1711 12 : if (!PR_GetEnv("MOZ_QUIET")) {
1712 12 : printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
1713 : gRefCnt,
1714 12 : static_cast<void*>(ToCanonicalSupports(this)),
1715 : getpid(),
1716 : gSerialCounter,
1717 24 : static_cast<void*>(ToCanonicalSupports(aOuterWindow)));
1718 : }
1719 : #endif
1720 :
1721 12 : MOZ_LOG(gDOMLeakPRLog, LogLevel::Debug,
1722 : ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
1723 :
1724 12 : NS_ASSERTION(sWindowsById, "Windows hash table must be created!");
1725 12 : NS_ASSERTION(!sWindowsById->Get(mWindowID),
1726 : "This window shouldn't be in the hash table yet!");
1727 : // We seem to see crashes in release builds because of null |sWindowsById|.
1728 12 : if (sWindowsById) {
1729 12 : sWindowsById->Put(mWindowID, this);
1730 : }
1731 12 : }
1732 :
1733 : #ifdef DEBUG
1734 :
1735 : /* static */
1736 : void
1737 1174 : nsGlobalWindow::AssertIsOnMainThread()
1738 : {
1739 1174 : MOZ_ASSERT(NS_IsMainThread());
1740 1174 : }
1741 :
1742 : #endif // DEBUG
1743 :
1744 : /* static */
1745 : void
1746 3 : nsGlobalWindow::Init()
1747 : {
1748 3 : AssertIsOnMainThread();
1749 :
1750 3 : NS_ASSERTION(gDOMLeakPRLog, "gDOMLeakPRLog should have been initialized!");
1751 :
1752 3 : sWindowsById = new WindowByIdTable();
1753 3 : }
1754 :
1755 0 : nsGlobalWindow::~nsGlobalWindow()
1756 : {
1757 0 : AssertIsOnMainThread();
1758 :
1759 0 : DisconnectEventTargetObjects();
1760 :
1761 : // We have to check if sWindowsById isn't null because ::Shutdown might have
1762 : // been called.
1763 0 : if (sWindowsById) {
1764 0 : NS_ASSERTION(sWindowsById->Get(mWindowID),
1765 : "This window should be in the hash table");
1766 0 : sWindowsById->Remove(mWindowID);
1767 : }
1768 :
1769 0 : --gRefCnt;
1770 :
1771 : #ifdef DEBUG
1772 0 : if (!PR_GetEnv("MOZ_QUIET")) {
1773 0 : nsAutoCString url;
1774 0 : if (mLastOpenedURI) {
1775 0 : url = mLastOpenedURI->GetSpecOrDefault();
1776 :
1777 : // Data URLs can be very long, so truncate to avoid flooding the log.
1778 0 : const uint32_t maxURLLength = 1000;
1779 0 : if (url.Length() > maxURLLength) {
1780 0 : url.Truncate(maxURLLength);
1781 : }
1782 : }
1783 :
1784 0 : nsGlobalWindow* outer = nsGlobalWindow::Cast(mOuterWindow);
1785 0 : printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n",
1786 : gRefCnt,
1787 0 : static_cast<void*>(ToCanonicalSupports(this)),
1788 : getpid(),
1789 : mSerial,
1790 0 : static_cast<void*>(ToCanonicalSupports(outer)),
1791 0 : url.get());
1792 : }
1793 : #endif
1794 :
1795 0 : MOZ_LOG(gDOMLeakPRLog, LogLevel::Debug, ("DOMWINDOW %p destroyed", this));
1796 :
1797 0 : if (IsOuterWindow()) {
1798 0 : JSObject *proxy = GetWrapperMaybeDead();
1799 0 : if (proxy) {
1800 0 : js::SetProxyReservedSlot(proxy, 0, js::PrivateValue(nullptr));
1801 : }
1802 :
1803 : // An outer window is destroyed with inner windows still possibly
1804 : // alive, iterate through the inner windows and null out their
1805 : // back pointer to this outer, and pull them out of the list of
1806 : // inner windows.
1807 :
1808 : nsGlobalWindow *w;
1809 0 : while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
1810 0 : PR_REMOVE_AND_INIT_LINK(w);
1811 : }
1812 :
1813 0 : DropOuterWindowDocs();
1814 : } else {
1815 0 : Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
1816 0 : mMutationBits ? 1 : 0);
1817 :
1818 0 : if (mListenerManager) {
1819 0 : mListenerManager->Disconnect();
1820 0 : mListenerManager = nullptr;
1821 : }
1822 :
1823 : // An inner window is destroyed, pull it out of the outer window's
1824 : // list if inner windows.
1825 :
1826 0 : PR_REMOVE_LINK(this);
1827 :
1828 : // If our outer window's inner window is this window, null out the
1829 : // outer window's reference to this window that's being deleted.
1830 0 : nsGlobalWindow *outer = GetOuterWindowInternal();
1831 0 : if (outer) {
1832 0 : outer->MaybeClearInnerWindow(this);
1833 : }
1834 : }
1835 :
1836 : // We don't have to leave the tab group if we are an inner window.
1837 0 : if (mTabGroup && IsOuterWindow()) {
1838 0 : mTabGroup->Leave(AsOuter());
1839 : }
1840 :
1841 : // Outer windows are always supposed to call CleanUp before letting themselves
1842 : // be destroyed. And while CleanUp generally seems to be intended to clean up
1843 : // outers, we've historically called it for both. Changing this would probably
1844 : // involve auditing all of the references that inners and outers can have, and
1845 : // separating the handling into CleanUp() and FreeInnerObjects.
1846 0 : if (IsInnerWindow()) {
1847 0 : CleanUp();
1848 : } else {
1849 0 : MOZ_ASSERT(mCleanedUp);
1850 : }
1851 :
1852 0 : nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
1853 0 : if (ac)
1854 0 : ac->RemoveWindowAsListener(this);
1855 :
1856 0 : nsLayoutStatics::Release();
1857 0 : }
1858 :
1859 : void
1860 11 : nsGlobalWindow::AddEventTargetObject(DOMEventTargetHelper* aObject)
1861 : {
1862 11 : MOZ_ASSERT(IsInnerWindow());
1863 11 : mEventTargetObjects.PutEntry(aObject);
1864 11 : }
1865 :
1866 : void
1867 0 : nsGlobalWindow::RemoveEventTargetObject(DOMEventTargetHelper* aObject)
1868 : {
1869 0 : MOZ_ASSERT(IsInnerWindow());
1870 0 : mEventTargetObjects.RemoveEntry(aObject);
1871 0 : }
1872 :
1873 : void
1874 2 : nsGlobalWindow::DisconnectEventTargetObjects()
1875 : {
1876 3 : for (auto iter = mEventTargetObjects.ConstIter(); !iter.Done();
1877 1 : iter.Next()) {
1878 2 : RefPtr<DOMEventTargetHelper> target = iter.Get()->GetKey();
1879 1 : target->DisconnectFromOwner();
1880 : }
1881 2 : mEventTargetObjects.Clear();
1882 2 : }
1883 :
1884 : // static
1885 : void
1886 0 : nsGlobalWindow::ShutDown()
1887 : {
1888 0 : AssertIsOnMainThread();
1889 :
1890 0 : if (gDumpFile && gDumpFile != stdout) {
1891 0 : fclose(gDumpFile);
1892 : }
1893 0 : gDumpFile = nullptr;
1894 :
1895 0 : delete sWindowsById;
1896 0 : sWindowsById = nullptr;
1897 0 : }
1898 :
1899 : // static
1900 : void
1901 5 : nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
1902 : {
1903 5 : if (aWindow->mCachedXBLPrototypeHandlers &&
1904 5 : aWindow->mCachedXBLPrototypeHandlers->Count() > 0) {
1905 0 : aWindow->mCachedXBLPrototypeHandlers->Clear();
1906 : }
1907 5 : }
1908 :
1909 : void
1910 1 : nsGlobalWindow::MaybeForgiveSpamCount()
1911 : {
1912 2 : if (IsOuterWindow() &&
1913 1 : IsPopupSpamWindow()) {
1914 0 : SetIsPopupSpamWindow(false);
1915 : }
1916 1 : }
1917 :
1918 : void
1919 0 : nsGlobalWindow::SetIsPopupSpamWindow(bool aIsPopupSpam)
1920 : {
1921 0 : MOZ_ASSERT(IsOuterWindow());
1922 :
1923 0 : mIsPopupSpam = aIsPopupSpam;
1924 0 : if (aIsPopupSpam) {
1925 0 : ++gOpenPopupSpamCount;
1926 : } else {
1927 0 : --gOpenPopupSpamCount;
1928 0 : NS_ASSERTION(gOpenPopupSpamCount >= 0,
1929 : "Unbalanced decrement of gOpenPopupSpamCount");
1930 : }
1931 0 : }
1932 :
1933 : void
1934 1 : nsGlobalWindow::DropOuterWindowDocs()
1935 : {
1936 1 : MOZ_ASSERT(IsOuterWindow());
1937 1 : MOZ_ASSERT_IF(mDoc, !mDoc->EventHandlingSuppressed());
1938 1 : mDoc = nullptr;
1939 1 : mSuspendedDoc = nullptr;
1940 1 : }
1941 :
1942 : void
1943 2 : nsGlobalWindow::CleanUp()
1944 : {
1945 : // Guarantee idempotence.
1946 2 : if (mCleanedUp)
1947 0 : return;
1948 2 : mCleanedUp = true;
1949 :
1950 2 : StartDying();
1951 :
1952 2 : DisconnectEventTargetObjects();
1953 :
1954 2 : if (mObserver) {
1955 2 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1956 1 : if (os) {
1957 1 : os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
1958 : }
1959 :
1960 2 : RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
1961 1 : if (sns) {
1962 1 : sns->Unregister(mObserver);
1963 : }
1964 :
1965 : #ifdef MOZ_B2G
1966 : DisableNetworkEvent(eNetworkUpload);
1967 : DisableNetworkEvent(eNetworkDownload);
1968 : #endif // MOZ_B2G
1969 :
1970 1 : if (mIdleService) {
1971 0 : mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
1972 : }
1973 :
1974 1 : Preferences::RemoveObserver(mObserver, "intl.accept_languages");
1975 :
1976 : // Drop its reference to this dying window, in case for some bogus reason
1977 : // the object stays around.
1978 1 : mObserver->Forget();
1979 : }
1980 :
1981 2 : if (mNavigator) {
1982 0 : mNavigator->Invalidate();
1983 0 : mNavigator = nullptr;
1984 : }
1985 :
1986 2 : mScreen = nullptr;
1987 2 : mMenubar = nullptr;
1988 2 : mToolbar = nullptr;
1989 2 : mLocationbar = nullptr;
1990 2 : mPersonalbar = nullptr;
1991 2 : mStatusbar = nullptr;
1992 2 : mScrollbars = nullptr;
1993 2 : mHistory = nullptr;
1994 2 : mCustomElements = nullptr;
1995 2 : mFrames = nullptr;
1996 2 : mWindowUtils = nullptr;
1997 2 : mApplicationCache = nullptr;
1998 2 : mIndexedDB = nullptr;
1999 :
2000 2 : mConsole = nullptr;
2001 :
2002 2 : mAudioWorklet = nullptr;
2003 2 : mPaintWorklet = nullptr;
2004 :
2005 2 : mExternal = nullptr;
2006 :
2007 2 : mMozSelfSupport = nullptr;
2008 :
2009 2 : mPerformance = nullptr;
2010 :
2011 : #ifdef MOZ_WEBSPEECH
2012 2 : mSpeechSynthesis = nullptr;
2013 : #endif
2014 :
2015 : #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
2016 : mOrientationChangeObserver = nullptr;
2017 : #endif
2018 :
2019 2 : ClearControllers();
2020 :
2021 2 : mOpener = nullptr; // Forces Release
2022 2 : if (mContext) {
2023 0 : mContext = nullptr; // Forces Release
2024 : }
2025 2 : mChromeEventHandler = nullptr; // Forces Release
2026 2 : mParentTarget = nullptr;
2027 :
2028 2 : if (IsOuterWindow()) {
2029 1 : nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
2030 1 : if (inner) {
2031 1 : inner->CleanUp();
2032 : }
2033 : }
2034 :
2035 2 : if (IsInnerWindow()) {
2036 1 : DisableGamepadUpdates();
2037 1 : mHasGamepad = false;
2038 1 : DisableVRUpdates();
2039 1 : mHasVREvents = false;
2040 1 : mHasVRDisplayActivateEvents = false;
2041 : #ifdef MOZ_B2G
2042 : DisableTimeChangeNotifications();
2043 : #endif
2044 1 : DisableIdleCallbackRequests();
2045 : } else {
2046 1 : MOZ_ASSERT(!mHasGamepad);
2047 1 : MOZ_ASSERT(!mHasVREvents);
2048 1 : MOZ_ASSERT(!mHasVRDisplayActivateEvents);
2049 : }
2050 :
2051 2 : if (mCleanMessageManager) {
2052 0 : MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned");
2053 0 : nsGlobalChromeWindow *asChrome = static_cast<nsGlobalChromeWindow*>(this);
2054 0 : if (asChrome->mMessageManager) {
2055 : static_cast<nsFrameMessageManager*>(
2056 0 : asChrome->mMessageManager.get())->Disconnect();
2057 : }
2058 : }
2059 :
2060 2 : mArguments = nullptr;
2061 2 : mDialogArguments = nullptr;
2062 :
2063 2 : CleanupCachedXBLHandlers(this);
2064 :
2065 2 : for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
2066 0 : mAudioContexts[i]->Shutdown();
2067 : }
2068 2 : mAudioContexts.Clear();
2069 :
2070 2 : if (mIdleTimer) {
2071 0 : mIdleTimer->Cancel();
2072 0 : mIdleTimer = nullptr;
2073 : }
2074 :
2075 2 : mServiceWorkerRegistrationTable.Clear();
2076 :
2077 : #ifdef ENABLE_INTL_API
2078 2 : mIntlUtils = nullptr;
2079 : #endif
2080 : }
2081 :
2082 : void
2083 3 : nsGlobalWindow::ClearControllers()
2084 : {
2085 3 : if (mControllers) {
2086 : uint32_t count;
2087 0 : mControllers->GetControllerCount(&count);
2088 :
2089 0 : while (count--) {
2090 0 : nsCOMPtr<nsIController> controller;
2091 0 : mControllers->GetControllerAt(count, getter_AddRefs(controller));
2092 :
2093 0 : nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
2094 0 : if (context)
2095 0 : context->SetCommandContext(nullptr);
2096 : }
2097 :
2098 0 : mControllers = nullptr;
2099 : }
2100 3 : }
2101 :
2102 : void
2103 3 : nsGlobalWindow::FreeInnerObjects()
2104 : {
2105 3 : NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
2106 :
2107 : // Make sure that this is called before we null out the document and
2108 : // other members that the window destroyed observers could
2109 : // re-create.
2110 3 : NotifyDOMWindowDestroyed(this);
2111 3 : if (auto* reporter = nsWindowMemoryReporter::Get()) {
2112 3 : reporter->ObserveDOMWindowDetached(this);
2113 : }
2114 :
2115 3 : mInnerObjectsFreed = true;
2116 :
2117 : // Kill all of the workers for this window.
2118 3 : mozilla::dom::workers::CancelWorkersForWindow(AsInner());
2119 :
2120 3 : if (mTimeoutManager) {
2121 3 : mTimeoutManager->ClearAllTimeouts();
2122 : }
2123 :
2124 3 : if (mIdleTimer) {
2125 0 : mIdleTimer->Cancel();
2126 0 : mIdleTimer = nullptr;
2127 : }
2128 :
2129 3 : mIdleObservers.Clear();
2130 :
2131 3 : DisableIdleCallbackRequests();
2132 :
2133 3 : mChromeEventHandler = nullptr;
2134 :
2135 3 : if (mListenerManager) {
2136 0 : mListenerManager->Disconnect();
2137 0 : mListenerManager = nullptr;
2138 : }
2139 :
2140 3 : mHistory = nullptr;
2141 3 : mCustomElements = nullptr;
2142 :
2143 3 : if (mNavigator) {
2144 0 : mNavigator->OnNavigation();
2145 0 : mNavigator->Invalidate();
2146 0 : mNavigator = nullptr;
2147 : }
2148 :
2149 3 : if (mScreen) {
2150 0 : mScreen = nullptr;
2151 : }
2152 :
2153 : #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
2154 : mOrientationChangeObserver = nullptr;
2155 : #endif
2156 :
2157 3 : if (mDoc) {
2158 : // Remember the document's principal and URI.
2159 3 : mDocumentPrincipal = mDoc->NodePrincipal();
2160 3 : mDocumentURI = mDoc->GetDocumentURI();
2161 3 : mDocBaseURI = mDoc->GetDocBaseURI();
2162 :
2163 3 : while (mDoc->EventHandlingSuppressed()) {
2164 0 : mDoc->UnsuppressEventHandlingAndFireEvents(false);
2165 : }
2166 : }
2167 :
2168 : // Remove our reference to the document and the document principal.
2169 3 : mFocusedNode = nullptr;
2170 :
2171 3 : if (mApplicationCache) {
2172 0 : static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
2173 0 : mApplicationCache = nullptr;
2174 : }
2175 :
2176 3 : mIndexedDB = nullptr;
2177 :
2178 3 : UnlinkHostObjectURIs();
2179 :
2180 3 : NotifyWindowIDDestroyed("inner-window-destroyed");
2181 :
2182 3 : CleanupCachedXBLHandlers(this);
2183 :
2184 3 : for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
2185 0 : mAudioContexts[i]->Shutdown();
2186 : }
2187 3 : mAudioContexts.Clear();
2188 :
2189 3 : DisableGamepadUpdates();
2190 3 : mHasGamepad = false;
2191 3 : mGamepads.Clear();
2192 3 : DisableVRUpdates();
2193 3 : mHasVREvents = false;
2194 3 : mHasVRDisplayActivateEvents = false;
2195 3 : mVRDisplays.Clear();
2196 :
2197 3 : if (mTabChild) {
2198 1 : while (mBeforeUnloadListenerCount-- > 0) {
2199 0 : mTabChild->BeforeUnloadRemoved();
2200 : }
2201 : }
2202 3 : }
2203 :
2204 : //*****************************************************************************
2205 : // nsGlobalWindow::nsISupports
2206 : //*****************************************************************************
2207 :
2208 : // QueryInterface implementation for nsGlobalWindow
2209 14404 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
2210 14393 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
2211 : // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
2212 14181 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
2213 13905 : NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
2214 13901 : if (aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) {
2215 0 : foundInterface = static_cast<nsIDOMWindowInternal*>(this);
2216 0 : if (!sWarnedAboutWindowInternal) {
2217 0 : sWarnedAboutWindowInternal = true;
2218 0 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
2219 0 : NS_LITERAL_CSTRING("Extensions"), mDoc,
2220 : nsContentUtils::eDOM_PROPERTIES,
2221 0 : "nsIDOMWindowInternalWarning");
2222 : }
2223 : } else
2224 13901 : NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
2225 5270 : NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
2226 4086 : NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
2227 4017 : NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
2228 4017 : NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
2229 3522 : if (aIID.Equals(NS_GET_IID(nsPIDOMWindowInner))) {
2230 759 : foundInterface = AsInner();
2231 : } else
2232 2763 : if (aIID.Equals(NS_GET_IID(mozIDOMWindow)) && IsInnerWindow()) {
2233 2 : foundInterface = AsInner();
2234 : } else
2235 2761 : if (aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter))) {
2236 2236 : foundInterface = AsOuter();
2237 : } else
2238 525 : if (aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) && IsOuterWindow()) {
2239 260 : foundInterface = AsOuter();
2240 : } else
2241 265 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
2242 228 : NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
2243 176 : NS_INTERFACE_MAP_END
2244 :
2245 :
2246 19922 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
2247 19623 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
2248 :
2249 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
2250 0 : if (tmp->IsBlackForCC(false)) {
2251 0 : if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
2252 0 : return true;
2253 : }
2254 0 : tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
2255 0 : if (tmp->mCachedXBLPrototypeHandlers) {
2256 0 : for (auto iter = tmp->mCachedXBLPrototypeHandlers->Iter();
2257 0 : !iter.Done();
2258 0 : iter.Next()) {
2259 0 : iter.Data().exposeToActiveJS();
2260 : }
2261 : }
2262 0 : if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
2263 0 : elm->MarkForCC();
2264 : }
2265 0 : if (tmp->mTimeoutManager) {
2266 0 : tmp->mTimeoutManager->UnmarkGrayTimers();
2267 : }
2268 0 : return true;
2269 : }
2270 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
2271 :
2272 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)
2273 0 : return tmp->IsBlackForCC(true);
2274 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
2275 :
2276 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)
2277 0 : return tmp->IsBlackForCC(false);
2278 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
2279 :
2280 : inline void
2281 0 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
2282 : IdleObserverHolder& aField,
2283 : const char* aName,
2284 : unsigned aFlags)
2285 : {
2286 0 : CycleCollectionNoteChild(aCallback, aField.mIdleObserver.get(), aName, aFlags);
2287 0 : }
2288 :
2289 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
2290 :
2291 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
2292 1 : if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
2293 : char name[512];
2294 0 : nsAutoCString uri;
2295 0 : if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
2296 0 : uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
2297 : }
2298 0 : SprintfLiteral(name, "nsGlobalWindow # %" PRIu64 " %s %s", tmp->mWindowID,
2299 0 : tmp->IsInnerWindow() ? "inner" : "outer", uri.get());
2300 0 : cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
2301 : } else {
2302 1 : NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow, tmp->mRefCnt.get())
2303 : }
2304 :
2305 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
2306 :
2307 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
2308 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
2309 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments)
2310 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue)
2311 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
2312 :
2313 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
2314 :
2315 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerRegistrationTable)
2316 :
2317 : #ifdef MOZ_WEBSPEECH
2318 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
2319 : #endif
2320 :
2321 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)
2322 :
2323 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopInnerWindow)
2324 :
2325 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
2326 :
2327 1 : if (tmp->mTimeoutManager) {
2328 13 : tmp->mTimeoutManager->ForEachUnorderedTimeout([&cb](Timeout* timeout) {
2329 12 : cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout));
2330 8 : });
2331 : }
2332 :
2333 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
2334 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
2335 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
2336 :
2337 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
2338 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
2339 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
2340 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
2341 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
2342 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
2343 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
2344 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
2345 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
2346 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
2347 :
2348 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
2349 3 : for (IdleRequest* request : tmp->mIdleRequestCallbacks) {
2350 2 : cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));
2351 : }
2352 :
2353 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
2354 :
2355 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
2356 :
2357 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
2358 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays)
2359 :
2360 : // Traverse stuff from nsPIDOMWindow
2361 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
2362 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
2363 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
2364 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode)
2365 :
2366 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
2367 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
2368 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
2369 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
2370 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
2371 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
2372 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
2373 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mU2F)
2374 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
2375 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioWorklet)
2376 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet)
2377 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
2378 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMozSelfSupport)
2379 : #ifdef ENABLE_INTL_API
2380 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
2381 : #endif
2382 :
2383 1 : tmp->TraverseHostObjectURIs(cb);
2384 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2385 :
2386 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
2387 0 : nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
2388 :
2389 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
2390 :
2391 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
2392 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
2393 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments)
2394 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue)
2395 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
2396 :
2397 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
2398 :
2399 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorkerRegistrationTable)
2400 :
2401 : #ifdef MOZ_WEBSPEECH
2402 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
2403 : #endif
2404 :
2405 0 : if (tmp->mOuterWindow) {
2406 0 : nsGlobalWindow::Cast(tmp->mOuterWindow)->MaybeClearInnerWindow(tmp);
2407 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
2408 : }
2409 :
2410 0 : if (tmp->mListenerManager) {
2411 0 : tmp->mListenerManager->Disconnect();
2412 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
2413 : }
2414 :
2415 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow)
2416 :
2417 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
2418 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
2419 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)
2420 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
2421 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
2422 0 : if (tmp->mApplicationCache) {
2423 0 : static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();
2424 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
2425 : }
2426 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
2427 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
2428 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
2429 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild)
2430 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
2431 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
2432 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mWakeLock)
2433 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
2434 :
2435 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
2436 :
2437 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
2438 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays)
2439 :
2440 : // Unlink stuff from nsPIDOMWindow
2441 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
2442 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
2443 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
2444 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode)
2445 :
2446 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
2447 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
2448 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
2449 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
2450 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
2451 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
2452 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
2453 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mU2F)
2454 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
2455 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioWorklet)
2456 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet)
2457 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
2458 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mMozSelfSupport)
2459 : #ifdef ENABLE_INTL_API
2460 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
2461 : #endif
2462 :
2463 0 : tmp->UnlinkHostObjectURIs();
2464 :
2465 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)
2466 0 : tmp->DisableIdleCallbackRequests();
2467 :
2468 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
2469 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2470 :
2471 : #ifdef DEBUG
2472 : void
2473 0 : nsGlobalWindow::RiskyUnlink()
2474 : {
2475 0 : NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);
2476 0 : }
2477 : #endif
2478 :
2479 3 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
2480 3 : if (tmp->mCachedXBLPrototypeHandlers) {
2481 10 : for (auto iter = tmp->mCachedXBLPrototypeHandlers->Iter();
2482 5 : !iter.Done();
2483 2 : iter.Next()) {
2484 2 : aCallbacks.Trace(&iter.Data(), "Cached XBL prototype handler", aClosure);
2485 : }
2486 : }
2487 3 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
2488 3 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
2489 :
2490 : bool
2491 0 : nsGlobalWindow::IsBlackForCC(bool aTracingNeeded)
2492 : {
2493 0 : if (!nsCCUncollectableMarker::sGeneration) {
2494 0 : return false;
2495 : }
2496 :
2497 0 : return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
2498 0 : HasKnownLiveWrapper()) &&
2499 0 : (!aTracingNeeded ||
2500 0 : HasNothingToTrace(static_cast<nsIDOMEventTarget*>(this)));
2501 : }
2502 :
2503 : //*****************************************************************************
2504 : // nsGlobalWindow::nsIScriptGlobalObject
2505 : //*****************************************************************************
2506 :
2507 : nsresult
2508 606 : nsGlobalWindow::EnsureScriptEnvironment()
2509 : {
2510 606 : nsGlobalWindow* outer = GetOuterWindowInternal();
2511 606 : if (!outer) {
2512 0 : NS_WARNING("No outer window available!");
2513 0 : return NS_ERROR_FAILURE;
2514 : }
2515 :
2516 606 : if (outer->GetWrapperPreserveColor()) {
2517 601 : return NS_OK;
2518 : }
2519 :
2520 5 : NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(),
2521 : "No cached wrapper, but we have an inner window?");
2522 :
2523 : // If this window is a [i]frame, don't bother GC'ing when the frame's context
2524 : // is destroyed since a GC will happen when the frameset or host document is
2525 : // destroyed anyway.
2526 15 : nsCOMPtr<nsIScriptContext> context = new nsJSContext(!IsFrame(), outer);
2527 :
2528 5 : NS_ASSERTION(!outer->mContext, "Will overwrite mContext!");
2529 :
2530 : // should probably assert the context is clean???
2531 5 : context->WillInitializeContext();
2532 :
2533 5 : nsresult rv = context->InitContext();
2534 5 : NS_ENSURE_SUCCESS(rv, rv);
2535 :
2536 5 : outer->mContext = context;
2537 5 : return NS_OK;
2538 : }
2539 :
2540 : nsIScriptContext *
2541 559 : nsGlobalWindow::GetScriptContext()
2542 : {
2543 559 : nsGlobalWindow* outer = GetOuterWindowInternal();
2544 559 : if (!outer) {
2545 0 : return nullptr;
2546 : }
2547 559 : return outer->mContext;
2548 : }
2549 :
2550 : JSObject *
2551 9585 : nsGlobalWindow::GetGlobalJSObject()
2552 : {
2553 9585 : return FastGetGlobalJSObject();
2554 : }
2555 :
2556 : void
2557 3 : nsGlobalWindow::TraceGlobalJSObject(JSTracer* aTrc)
2558 : {
2559 3 : TraceWrapper(aTrc, "active window global");
2560 3 : }
2561 :
2562 : bool
2563 8 : nsGlobalWindow::WouldReuseInnerWindow(nsIDocument* aNewDocument)
2564 : {
2565 8 : MOZ_ASSERT(IsOuterWindow());
2566 :
2567 : // We reuse the inner window when:
2568 : // a. We are currently at our original document.
2569 : // b. At least one of the following conditions are true:
2570 : // -- The new document is the same as the old document. This means that we're
2571 : // getting called from document.open().
2572 : // -- The new document has the same origin as what we have loaded right now.
2573 :
2574 8 : if (!mDoc || !aNewDocument) {
2575 5 : return false;
2576 : }
2577 :
2578 3 : if (!mDoc->IsInitialDocument()) {
2579 0 : return false;
2580 : }
2581 :
2582 : #ifdef DEBUG
2583 : {
2584 6 : nsCOMPtr<nsIURI> uri;
2585 3 : mDoc->GetDocumentURI()->CloneIgnoringRef(getter_AddRefs(uri));
2586 3 : NS_ASSERTION(NS_IsAboutBlank(uri), "How'd this happen?");
2587 : }
2588 : #endif
2589 :
2590 : // Great, we're the original document, check for one of the other
2591 : // conditions.
2592 :
2593 3 : if (mDoc == aNewDocument) {
2594 0 : return true;
2595 : }
2596 :
2597 : bool equal;
2598 6 : if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
2599 3 : &equal)) &&
2600 : equal) {
2601 : // The origin is the same.
2602 1 : return true;
2603 : }
2604 :
2605 2 : return false;
2606 : }
2607 :
2608 : void
2609 2 : nsGlobalWindow::SetInitialPrincipalToSubject()
2610 : {
2611 2 : MOZ_ASSERT(IsOuterWindow());
2612 :
2613 : // First, grab the subject principal.
2614 2 : nsCOMPtr<nsIPrincipal> newWindowPrincipal = nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
2615 :
2616 : // We should never create windows with an expanded principal.
2617 : // If we have a system principal, make sure we're not using it for a content
2618 : // docshell.
2619 : // NOTE: Please keep this logic in sync with nsWebShellWindow::Initialize().
2620 4 : if (nsContentUtils::IsExpandedPrincipal(newWindowPrincipal) ||
2621 4 : (nsContentUtils::IsSystemPrincipal(newWindowPrincipal) &&
2622 2 : GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome)) {
2623 0 : newWindowPrincipal = nullptr;
2624 : }
2625 :
2626 : // If there's an existing document, bail if it either:
2627 2 : if (mDoc) {
2628 : // (a) is not an initial about:blank document, or
2629 2 : if (!mDoc->IsInitialDocument())
2630 2 : return;
2631 : // (b) already has the correct principal.
2632 2 : if (mDoc->NodePrincipal() == newWindowPrincipal)
2633 2 : return;
2634 :
2635 : #ifdef DEBUG
2636 : // If we have a document loaded at this point, it had better be about:blank.
2637 : // Otherwise, something is really weird. An about:blank page has a
2638 : // NullPrincipal.
2639 : bool isNullPrincipal;
2640 0 : MOZ_ASSERT(NS_SUCCEEDED(mDoc->NodePrincipal()->GetIsNullPrincipal(&isNullPrincipal)) &&
2641 : isNullPrincipal);
2642 : #endif
2643 : }
2644 :
2645 0 : GetDocShell()->CreateAboutBlankContentViewer(newWindowPrincipal);
2646 0 : mDoc->SetIsInitialDocument(true);
2647 :
2648 0 : nsCOMPtr<nsIPresShell> shell = GetDocShell()->GetPresShell();
2649 :
2650 0 : if (shell && !shell->DidInitialize()) {
2651 : // Ensure that if someone plays with this document they will get
2652 : // layout happening.
2653 0 : nsRect r = shell->GetPresContext()->GetVisibleArea();
2654 0 : shell->Initialize(r.width, r.height);
2655 : }
2656 : }
2657 :
2658 : PopupControlState
2659 830 : PushPopupControlState(PopupControlState aState, bool aForce)
2660 : {
2661 830 : MOZ_ASSERT(NS_IsMainThread());
2662 :
2663 830 : PopupControlState oldState = gPopupControlState;
2664 :
2665 830 : if (aState < gPopupControlState || aForce) {
2666 9 : gPopupControlState = aState;
2667 : }
2668 :
2669 830 : return oldState;
2670 : }
2671 :
2672 : void
2673 830 : PopPopupControlState(PopupControlState aState)
2674 : {
2675 830 : MOZ_ASSERT(NS_IsMainThread());
2676 :
2677 830 : gPopupControlState = aState;
2678 830 : }
2679 :
2680 : PopupControlState
2681 0 : nsGlobalWindow::PushPopupControlState(PopupControlState aState,
2682 : bool aForce) const
2683 : {
2684 0 : return ::PushPopupControlState(aState, aForce);
2685 : }
2686 :
2687 : void
2688 0 : nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
2689 : {
2690 0 : ::PopPopupControlState(aState);
2691 0 : }
2692 :
2693 : PopupControlState
2694 13 : nsGlobalWindow::GetPopupControlState() const
2695 : {
2696 13 : MOZ_ASSERT(NS_IsMainThread());
2697 13 : return gPopupControlState;
2698 : }
2699 :
2700 : #define WINDOWSTATEHOLDER_IID \
2701 : {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
2702 :
2703 : class WindowStateHolder final : public nsISupports
2704 : {
2705 : public:
2706 : NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
2707 : NS_DECL_ISUPPORTS
2708 :
2709 : explicit WindowStateHolder(nsGlobalWindow *aWindow);
2710 :
2711 0 : nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
2712 :
2713 0 : void DidRestoreWindow()
2714 : {
2715 0 : mInnerWindow = nullptr;
2716 0 : mInnerWindowReflector = nullptr;
2717 0 : }
2718 :
2719 : protected:
2720 : ~WindowStateHolder();
2721 :
2722 : nsGlobalWindow *mInnerWindow;
2723 : // We hold onto this to make sure the inner window doesn't go away. The outer
2724 : // window ends up recalculating it anyway.
2725 : JS::PersistentRooted<JSObject*> mInnerWindowReflector;
2726 : };
2727 :
2728 : NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
2729 :
2730 0 : WindowStateHolder::WindowStateHolder(nsGlobalWindow* aWindow)
2731 : : mInnerWindow(aWindow),
2732 0 : mInnerWindowReflector(RootingCx(), aWindow->GetWrapper())
2733 : {
2734 0 : NS_PRECONDITION(aWindow, "null window");
2735 0 : NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
2736 :
2737 0 : aWindow->Suspend();
2738 :
2739 : // When a global goes into the bfcache, we disable script.
2740 0 : xpc::Scriptability::Get(mInnerWindowReflector).SetDocShellAllowsScript(false);
2741 0 : }
2742 :
2743 0 : WindowStateHolder::~WindowStateHolder()
2744 : {
2745 0 : if (mInnerWindow) {
2746 : // This window was left in the bfcache and is now going away. We need to
2747 : // free it up.
2748 : // Note that FreeInnerObjects may already have been called on the
2749 : // inner window if its outer has already had SetDocShell(null)
2750 : // called.
2751 0 : mInnerWindow->FreeInnerObjects();
2752 : }
2753 0 : }
2754 :
2755 0 : NS_IMPL_ISUPPORTS(WindowStateHolder, WindowStateHolder)
2756 :
2757 : // We need certain special behavior for remote XUL whitelisted domains, but we
2758 : // don't want that behavior to take effect in automation, because we whitelist
2759 : // all the mochitest domains. So we need to check a pref here.
2760 : static bool
2761 4 : TreatAsRemoteXUL(nsIPrincipal* aPrincipal)
2762 : {
2763 4 : MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(aPrincipal));
2764 4 : return nsContentUtils::AllowXULXBLForPrincipal(aPrincipal) &&
2765 4 : !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
2766 : }
2767 :
2768 : static bool
2769 3 : EnablePrivilege(JSContext* cx, unsigned argc, JS::Value* vp)
2770 : {
2771 3 : Telemetry::Accumulate(Telemetry::ENABLE_PRIVILEGE_EVER_CALLED, true);
2772 3 : return xpc::EnableUniversalXPConnect(cx);
2773 : }
2774 :
2775 : static const JSFunctionSpec EnablePrivilegeSpec[] = {
2776 : JS_FS("enablePrivilege", EnablePrivilege, 1, 0),
2777 : JS_FS_END
2778 : };
2779 :
2780 : static bool
2781 7 : InitializeLegacyNetscapeObject(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
2782 : {
2783 14 : JSAutoCompartment ac(aCx, aGlobal);
2784 :
2785 : // Note: MathJax depends on window.netscape being exposed. See bug 791526.
2786 14 : JS::Rooted<JSObject*> obj(aCx);
2787 7 : obj = JS_DefineObject(aCx, aGlobal, "netscape", nullptr);
2788 7 : NS_ENSURE_TRUE(obj, false);
2789 :
2790 7 : obj = JS_DefineObject(aCx, obj, "security", nullptr);
2791 7 : NS_ENSURE_TRUE(obj, false);
2792 :
2793 : // We hide enablePrivilege behind a pref because it has been altered in a
2794 : // way that makes it fundamentally insecure to use in production. Mozilla
2795 : // uses this pref during automated testing to support legacy test code that
2796 : // uses enablePrivilege. If you're not doing test automation, you _must_ not
2797 : // flip this pref, or you will be exposing all your users to security
2798 : // vulnerabilities.
2799 7 : if (!xpc::IsInAutomation()) {
2800 0 : return true;
2801 : }
2802 :
2803 : /* Define PrivilegeManager object with the necessary "static" methods. */
2804 7 : obj = JS_DefineObject(aCx, obj, "PrivilegeManager", nullptr);
2805 7 : NS_ENSURE_TRUE(obj, false);
2806 :
2807 7 : return JS_DefineFunctions(aCx, obj, EnablePrivilegeSpec);
2808 : }
2809 :
2810 : bool
2811 14 : nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument, SecureContextFlags aFlags)
2812 : {
2813 14 : MOZ_ASSERT(IsOuterWindow());
2814 :
2815 28 : nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
2816 14 : if (nsContentUtils::IsSystemPrincipal(principal)) {
2817 6 : return true;
2818 : }
2819 :
2820 : // Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
2821 : // With some modifications to allow for aFlags.
2822 :
2823 8 : bool hadNonSecureContextCreator = false;
2824 :
2825 8 : nsPIDOMWindowOuter* parentOuterWin = GetScriptableParent();
2826 8 : MOZ_ASSERT(parentOuterWin, "How can we get here? No docShell somehow?");
2827 8 : if (nsGlobalWindow::Cast(parentOuterWin) != this) {
2828 : // There may be a small chance that parentOuterWin has navigated in
2829 : // the time that it took us to start loading this sub-document. If that
2830 : // were the case then parentOuterWin->GetCurrentInnerWindow() wouldn't
2831 : // return the window for the document that is embedding us. For this
2832 : // reason we only use the GetScriptableParent call above to check that we
2833 : // have a same-type parent, but actually get the inner window via the
2834 : // document that we know is embedding us.
2835 0 : nsIDocument* creatorDoc = aDocument->GetParentDocument();
2836 0 : if (!creatorDoc) {
2837 0 : return false; // we must be tearing down
2838 : }
2839 : nsGlobalWindow* parentWin =
2840 0 : nsGlobalWindow::Cast(creatorDoc->GetInnerWindow());
2841 0 : if (!parentWin) {
2842 0 : return false; // we must be tearing down
2843 : }
2844 0 : MOZ_ASSERT(parentWin ==
2845 : nsGlobalWindow::Cast(parentOuterWin->GetCurrentInnerWindow()),
2846 : "Creator window mismatch while setting Secure Context state");
2847 0 : if (aFlags != SecureContextFlags::eIgnoreOpener) {
2848 0 : hadNonSecureContextCreator = !parentWin->IsSecureContext();
2849 : } else {
2850 0 : hadNonSecureContextCreator = !parentWin->IsSecureContextIfOpenerIgnored();
2851 : }
2852 8 : } else if (mHadOriginalOpener) {
2853 0 : if (aFlags != SecureContextFlags::eIgnoreOpener) {
2854 0 : hadNonSecureContextCreator = !mOriginalOpenerWasSecureContext;
2855 : }
2856 : }
2857 :
2858 8 : if (hadNonSecureContextCreator) {
2859 0 : return false;
2860 : }
2861 :
2862 8 : if (nsContentUtils::HttpsStateIsModern(aDocument)) {
2863 4 : return true;
2864 : }
2865 :
2866 4 : if (principal->GetIsNullPrincipal()) {
2867 8 : nsCOMPtr<nsIURI> uri = aDocument->GetOriginalURI();
2868 : // IsOriginPotentiallyTrustworthy doesn't care about origin attributes so
2869 : // it doesn't actually matter what we use here, but reusing the document
2870 : // principal's attributes is convenient.
2871 4 : const OriginAttributes& attrs = principal->OriginAttributesRef();
2872 : // CreateCodebasePrincipal correctly gets a useful principal for blob: and
2873 : // other URI_INHERITS_SECURITY_CONTEXT URIs.
2874 4 : principal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
2875 4 : if (NS_WARN_IF(!principal)) {
2876 0 : return false;
2877 : }
2878 : }
2879 :
2880 : nsCOMPtr<nsIContentSecurityManager> csm =
2881 8 : do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
2882 4 : NS_WARNING_ASSERTION(csm, "csm is null");
2883 4 : if (csm) {
2884 4 : bool isTrustworthyOrigin = false;
2885 4 : csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin);
2886 4 : if (isTrustworthyOrigin) {
2887 0 : return true;
2888 : }
2889 : }
2890 :
2891 4 : return false;
2892 : }
2893 :
2894 : static JS::CompartmentCreationOptions&
2895 7 : SelectZoneGroup(nsGlobalWindow* aNewInner,
2896 : JS::CompartmentCreationOptions& aOptions)
2897 : {
2898 7 : JS::CompartmentCreationOptions options;
2899 :
2900 7 : if (aNewInner->GetOuterWindow()) {
2901 7 : nsGlobalWindow *top = aNewInner->GetTopInternal();
2902 :
2903 : // If we have a top-level window, use its zone (and zone group).
2904 7 : if (top && top->GetGlobalJSObject()) {
2905 3 : return aOptions.setExistingZone(top->GetGlobalJSObject());
2906 : }
2907 : }
2908 :
2909 : // If we're in the parent process, don't bother with zone groups.
2910 4 : if (XRE_IsParentProcess()) {
2911 3 : return aOptions.setNewZoneInSystemZoneGroup();
2912 : }
2913 :
2914 : // Otherwise, find a zone group from the TabGroup. Typically we only have to
2915 : // go through one iteration of this loop.
2916 2 : RefPtr<TabGroup> tabGroup = aNewInner->TabGroup();
2917 2 : for (nsPIDOMWindowOuter* outer : tabGroup->GetWindows()) {
2918 1 : nsGlobalWindow* window = nsGlobalWindow::Cast(outer);
2919 1 : if (JSObject* global = window->GetGlobalJSObject()) {
2920 0 : return aOptions.setNewZoneInExistingZoneGroup(global);
2921 : }
2922 : }
2923 :
2924 1 : return aOptions.setNewZoneInNewZoneGroup();
2925 : }
2926 :
2927 : /**
2928 : * Create a new global object that will be used for an inner window.
2929 : * Return the native global and an nsISupports 'holder' that can be used
2930 : * to manage the lifetime of it.
2931 : */
2932 : static nsresult
2933 7 : CreateNativeGlobalForInner(JSContext* aCx,
2934 : nsGlobalWindow* aNewInner,
2935 : nsIURI* aURI,
2936 : nsIPrincipal* aPrincipal,
2937 : JS::MutableHandle<JSObject*> aGlobal,
2938 : bool aIsSecureContext)
2939 : {
2940 7 : MOZ_ASSERT(aCx);
2941 7 : MOZ_ASSERT(aNewInner);
2942 7 : MOZ_ASSERT(aNewInner->IsInnerWindow());
2943 7 : MOZ_ASSERT(aPrincipal);
2944 :
2945 : // DOMWindow with nsEP is not supported, we have to make sure
2946 : // no one creates one accidentally.
2947 14 : nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(aPrincipal);
2948 7 : MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported");
2949 :
2950 7 : JS::CompartmentOptions options;
2951 :
2952 7 : SelectZoneGroup(aNewInner, options.creationOptions());
2953 :
2954 : // Sometimes add-ons load their own XUL windows, either as separate top-level
2955 : // windows or inside a browser element. In such cases we want to tag the
2956 : // window's compartment with the add-on ID. See bug 1092156.
2957 7 : if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
2958 3 : options.creationOptions().setAddonId(MapURIToAddonID(aURI));
2959 : }
2960 :
2961 7 : options.creationOptions().setSecureContext(aIsSecureContext);
2962 :
2963 7 : xpc::InitGlobalObjectOptions(options, aPrincipal);
2964 :
2965 : // Determine if we need the Components object.
2966 11 : bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
2967 11 : TreatAsRemoteXUL(aPrincipal);
2968 7 : uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
2969 7 : flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
2970 :
2971 21 : if (!WindowBinding::Wrap(aCx, aNewInner, aNewInner, options,
2972 28 : nsJSPrincipals::get(aPrincipal), false, aGlobal) ||
2973 28 : !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
2974 0 : return NS_ERROR_FAILURE;
2975 : }
2976 :
2977 7 : MOZ_ASSERT(aNewInner->GetWrapperPreserveColor() == aGlobal);
2978 :
2979 : // Set the location information for the new global, so that tools like
2980 : // about:memory may use that information
2981 7 : xpc::SetLocationForGlobal(aGlobal, aURI);
2982 :
2983 7 : if (!InitializeLegacyNetscapeObject(aCx, aGlobal)) {
2984 0 : return NS_ERROR_FAILURE;
2985 : }
2986 :
2987 7 : return NS_OK;
2988 : }
2989 :
2990 : nsresult
2991 8 : nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
2992 : nsISupports* aState,
2993 : bool aForceReuseInnerWindow)
2994 : {
2995 8 : NS_PRECONDITION(mDocumentPrincipal == nullptr,
2996 : "mDocumentPrincipal prematurely set!");
2997 8 : MOZ_ASSERT(aDocument);
2998 :
2999 8 : if (IsInnerWindow()) {
3000 0 : if (!mOuterWindow) {
3001 0 : return NS_ERROR_NOT_INITIALIZED;
3002 : }
3003 :
3004 : // Refuse to set a new document if the call came from an inner
3005 : // window that's not the current inner window.
3006 0 : if (mOuterWindow->GetCurrentInnerWindow() != AsInner()) {
3007 0 : return NS_ERROR_NOT_AVAILABLE;
3008 : }
3009 :
3010 0 : return GetOuterWindowInternal()->SetNewDocument(aDocument, aState,
3011 0 : aForceReuseInnerWindow);
3012 : }
3013 :
3014 8 : NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
3015 :
3016 : // Bail out early if we're in process of closing down the window.
3017 8 : NS_ENSURE_STATE(!mCleanedUp);
3018 :
3019 8 : NS_ASSERTION(!AsOuter()->GetCurrentInnerWindow() ||
3020 : AsOuter()->GetCurrentInnerWindow()->GetExtantDoc() == mDoc,
3021 : "Uh, mDoc doesn't match the current inner window "
3022 : "document!");
3023 :
3024 8 : bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
3025 8 : if (aForceReuseInnerWindow &&
3026 0 : !wouldReuseInnerWindow &&
3027 8 : mDoc &&
3028 0 : mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
3029 0 : NS_ERROR("Attempted forced inner window reuse while changing principal");
3030 0 : return NS_ERROR_UNEXPECTED;
3031 : }
3032 :
3033 16 : nsCOMPtr<nsIDocument> oldDoc = mDoc;
3034 :
3035 16 : AutoJSAPI jsapi;
3036 8 : jsapi.Init();
3037 8 : JSContext *cx = jsapi.cx();
3038 :
3039 : // Check if we're anywhere near the stack limit before we reach the
3040 : // transplanting code, since it has no good way to handle errors. This uses
3041 : // the untrusted script limit, which is not strictly necessary since no
3042 : // actual script should run.
3043 8 : if (!js::CheckRecursionLimitConservativeDontReport(cx)) {
3044 0 : NS_WARNING("Overrecursion in SetNewDocument");
3045 0 : return NS_ERROR_FAILURE;
3046 : }
3047 :
3048 8 : if (!mDoc) {
3049 : // First document load.
3050 :
3051 : // Get our private root. If it is equal to us, then we need to
3052 : // attach our global key bindings that handles browser scrolling
3053 : // and other browser commands.
3054 5 : nsPIDOMWindowOuter* privateRoot = nsGlobalWindow::GetPrivateRoot();
3055 :
3056 5 : if (privateRoot == AsOuter()) {
3057 3 : nsXBLService::AttachGlobalKeyHandler(mChromeEventHandler);
3058 : }
3059 : }
3060 :
3061 : /* No mDocShell means we're already been partially closed down. When that
3062 : happens, setting status isn't a big requirement, so don't. (Doesn't happen
3063 : under normal circumstances, but bug 49615 describes a case.) */
3064 :
3065 16 : nsContentUtils::AddScriptRunner(NewRunnableMethod(
3066 8 : "nsGlobalWindow::ClearStatus", this, &nsGlobalWindow::ClearStatus));
3067 :
3068 : // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
3069 : // window (see bug 776497). Be safe.
3070 9 : bool reUseInnerWindow = (aForceReuseInnerWindow || wouldReuseInnerWindow) &&
3071 9 : GetCurrentInnerWindowInternal();
3072 :
3073 8 : nsresult rv = NS_OK;
3074 :
3075 : // We set mDoc even though this is an outer window to avoid
3076 : // having to *always* reach into the inner window to find the
3077 : // document.
3078 8 : mDoc = aDocument;
3079 :
3080 : // Take this opportunity to clear mSuspendedDoc. Our old inner window is now
3081 : // responsible for unsuspending it.
3082 8 : mSuspendedDoc = nullptr;
3083 :
3084 : #ifdef DEBUG
3085 8 : mLastOpenedURI = aDocument->GetDocumentURI();
3086 : #endif
3087 :
3088 8 : mContext->WillInitializeContext();
3089 :
3090 8 : nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
3091 :
3092 8 : if (currentInner && currentInner->mNavigator) {
3093 0 : currentInner->mNavigator->OnNavigation();
3094 : }
3095 :
3096 16 : RefPtr<nsGlobalWindow> newInnerWindow;
3097 8 : bool createdInnerWindow = false;
3098 :
3099 8 : bool thisChrome = IsChromeWindow();
3100 :
3101 16 : nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
3102 8 : NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
3103 :
3104 16 : JS::Rooted<JSObject*> newInnerGlobal(cx);
3105 8 : if (reUseInnerWindow) {
3106 : // We're reusing the current inner window.
3107 1 : NS_ASSERTION(!currentInner->IsFrozen(),
3108 : "We should never be reusing a shared inner window");
3109 1 : newInnerWindow = currentInner;
3110 1 : newInnerGlobal = currentInner->GetWrapperPreserveColor();
3111 :
3112 1 : if (aDocument != oldDoc) {
3113 1 : JS::ExposeObjectToActiveJS(newInnerGlobal);
3114 : }
3115 :
3116 : // We're reusing the inner window, but this still counts as a navigation,
3117 : // so all expandos and such defined on the outer window should go away. Force
3118 : // all Xray wrappers to be recomputed.
3119 2 : JS::Rooted<JSObject*> rootedObject(cx, GetWrapper());
3120 1 : if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
3121 0 : return NS_ERROR_FAILURE;
3122 : }
3123 :
3124 : // Inner windows are only reused for same-origin principals, but the principals
3125 : // don't necessarily match exactly. Update the principal on the compartment to
3126 : // match the new document.
3127 : // NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
3128 : // because we haven't yet set its mDoc to aDocument.
3129 1 : JSCompartment *compartment = js::GetObjectCompartment(newInnerGlobal);
3130 : #ifdef DEBUG
3131 1 : bool sameOrigin = false;
3132 : nsIPrincipal *existing =
3133 1 : nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment));
3134 1 : aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
3135 1 : MOZ_ASSERT(sameOrigin);
3136 : #endif
3137 1 : MOZ_ASSERT_IF(aDocument == oldDoc,
3138 : xpc::GetCompartmentPrincipal(compartment) ==
3139 : aDocument->NodePrincipal());
3140 1 : if (aDocument != oldDoc) {
3141 1 : JS_SetCompartmentPrincipals(compartment,
3142 2 : nsJSPrincipals::get(aDocument->NodePrincipal()));
3143 : // Make sure we clear out the old content XBL scope, so the new one will
3144 : // get created with a principal that subsumes our new principal.
3145 1 : xpc::ClearContentXBLScope(newInnerGlobal);
3146 : }
3147 : } else {
3148 7 : if (aState) {
3149 0 : newInnerWindow = wsh->GetInnerWindow();
3150 0 : newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
3151 : } else {
3152 7 : if (thisChrome) {
3153 4 : newInnerWindow = nsGlobalChromeWindow::Create(this);
3154 3 : } else if (mIsModalContentWindow) {
3155 0 : newInnerWindow = nsGlobalModalWindow::Create(this);
3156 : } else {
3157 3 : newInnerWindow = nsGlobalWindow::Create(this);
3158 : }
3159 :
3160 : // The outer window is automatically treated as frozen when we
3161 : // null out the inner window. As a result, initializing classes
3162 : // on the new inner won't end up reaching into the old inner
3163 : // window for classes etc.
3164 : //
3165 : // [This happens with Object.prototype when XPConnect creates
3166 : // a temporary global while initializing classes; the reason
3167 : // being that xpconnect creates the temp global w/o a parent
3168 : // and proto, which makes the JS engine look up classes in
3169 : // cx->globalObject, i.e. this outer window].
3170 :
3171 7 : mInnerWindow = nullptr;
3172 :
3173 7 : mCreatingInnerWindow = true;
3174 : // Every script context we are initialized with must create a
3175 : // new global.
3176 14 : rv = CreateNativeGlobalForInner(cx, newInnerWindow,
3177 : aDocument->GetDocumentURI(),
3178 : aDocument->NodePrincipal(),
3179 : &newInnerGlobal,
3180 14 : ComputeIsSecureContext(aDocument));
3181 7 : NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
3182 : newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
3183 : "Failed to get script global");
3184 14 : newInnerWindow->mIsSecureContextIfOpenerIgnored =
3185 7 : ComputeIsSecureContext(aDocument, SecureContextFlags::eIgnoreOpener);
3186 :
3187 7 : mCreatingInnerWindow = false;
3188 7 : createdInnerWindow = true;
3189 :
3190 7 : NS_ENSURE_SUCCESS(rv, rv);
3191 : }
3192 :
3193 7 : if (currentInner && currentInner->GetWrapperPreserveColor()) {
3194 2 : if (oldDoc == aDocument) {
3195 : // Make a copy of the old window's performance object on document.open.
3196 : // Note that we have to force eager creation of it here, because we need
3197 : // to grab the current document channel and whatnot before that changes.
3198 0 : currentInner->AsInner()->CreatePerformanceObjectIfNeeded();
3199 0 : if (currentInner->mPerformance) {
3200 0 : newInnerWindow->mPerformance =
3201 0 : Performance::CreateForMainThread(newInnerWindow->AsInner(),
3202 0 : currentInner->mPerformance->GetDOMTiming(),
3203 0 : currentInner->mPerformance->GetChannel());
3204 : }
3205 : }
3206 :
3207 : // Don't free objects on our current inner window if it's going to be
3208 : // held in the bfcache.
3209 2 : if (!currentInner->IsFrozen()) {
3210 2 : currentInner->FreeInnerObjects();
3211 : }
3212 : }
3213 :
3214 7 : mInnerWindow = newInnerWindow->AsInner();
3215 7 : MOZ_ASSERT(mInnerWindow);
3216 7 : mInnerWindow->TryToCacheTopInnerWindow();
3217 :
3218 7 : if (!GetWrapperPreserveColor()) {
3219 : JS::Rooted<JSObject*> outer(cx,
3220 10 : NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
3221 5 : NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
3222 :
3223 5 : js::SetProxyReservedSlot(outer, 0, js::PrivateValue(ToSupports(this)));
3224 :
3225 : // Inform the nsJSContext, which is the canonical holder of the outer.
3226 5 : mContext->SetWindowProxy(outer);
3227 5 : mContext->DidInitializeContext();
3228 :
3229 5 : SetWrapper(mContext->GetWindowProxy());
3230 : } else {
3231 2 : JS::ExposeObjectToActiveJS(newInnerGlobal);
3232 : JS::Rooted<JSObject*> outerObject(cx,
3233 4 : NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
3234 2 : if (!outerObject) {
3235 0 : NS_ERROR("out of memory");
3236 0 : return NS_ERROR_FAILURE;
3237 : }
3238 :
3239 4 : JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
3240 :
3241 2 : js::SetProxyReservedSlot(obj, 0, js::PrivateValue(nullptr));
3242 2 : js::SetProxyReservedSlot(outerObject, 0, js::PrivateValue(nullptr));
3243 :
3244 2 : outerObject = xpc::TransplantObject(cx, obj, outerObject);
3245 2 : if (!outerObject) {
3246 0 : NS_ERROR("unable to transplant wrappers, probably OOM");
3247 0 : return NS_ERROR_FAILURE;
3248 : }
3249 :
3250 2 : js::SetProxyReservedSlot(outerObject, 0, js::PrivateValue(ToSupports(this)));
3251 :
3252 2 : SetWrapper(outerObject);
3253 :
3254 2 : MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(outerObject) == newInnerGlobal);
3255 :
3256 : // Inform the nsJSContext, which is the canonical holder of the outer.
3257 2 : mContext->SetWindowProxy(outerObject);
3258 : }
3259 :
3260 : // Enter the new global's compartment.
3261 14 : JSAutoCompartment ac(cx, GetWrapperPreserveColor());
3262 :
3263 : {
3264 14 : JS::Rooted<JSObject*> outer(cx, GetWrapperPreserveColor());
3265 7 : js::SetWindowProxy(cx, newInnerGlobal, outer);
3266 : }
3267 :
3268 : // Set scriptability based on the state of the docshell.
3269 7 : bool allow = GetDocShell()->GetCanExecuteScripts();
3270 7 : xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);
3271 :
3272 7 : if (!aState) {
3273 : // Get the "window" property once so it will be cached on our inner. We
3274 : // have to do this here, not in binding code, because this has to happen
3275 : // after we've created the outer window proxy and stashed it in the outer
3276 : // nsGlobalWindow, so GetWrapperPreserveColor() on that outer
3277 : // nsGlobalWindow doesn't return null and nsGlobalWindow::OuterObject
3278 : // works correctly.
3279 14 : JS::Rooted<JS::Value> unused(cx);
3280 7 : if (!JS_GetProperty(cx, newInnerGlobal, "window", &unused)) {
3281 0 : NS_ERROR("can't create the 'window' property");
3282 0 : return NS_ERROR_FAILURE;
3283 : }
3284 :
3285 : // And same thing for the "self" property.
3286 7 : if (!JS_GetProperty(cx, newInnerGlobal, "self", &unused)) {
3287 0 : NS_ERROR("can't create the 'self' property");
3288 0 : return NS_ERROR_FAILURE;
3289 : }
3290 : }
3291 : }
3292 :
3293 16 : JSAutoCompartment ac(cx, GetWrapperPreserveColor());
3294 :
3295 8 : if (!aState && !reUseInnerWindow) {
3296 : // Loading a new page and creating a new inner window, *not*
3297 : // restoring from session history.
3298 :
3299 : // Now that both the the inner and outer windows are initialized
3300 : // let the script context do its magic to hook them together.
3301 7 : MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor());
3302 : #ifdef DEBUG
3303 14 : JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
3304 14 : JS::Rooted<JSObject*> proto1(cx), proto2(cx);
3305 7 : JS_GetPrototype(cx, rootedJSObject, &proto1);
3306 7 : JS_GetPrototype(cx, newInnerGlobal, &proto2);
3307 7 : NS_ASSERTION(proto1 == proto2,
3308 : "outer and inner globals should have the same prototype");
3309 : #endif
3310 :
3311 7 : mInnerWindow->SyncStateFromParentWindow();
3312 : }
3313 :
3314 : // Add an extra ref in case we release mContext during GC.
3315 16 : nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
3316 :
3317 8 : aDocument->SetScriptGlobalObject(newInnerWindow);
3318 8 : MOZ_ASSERT(newInnerWindow->mTabGroup,
3319 : "We must have a TabGroup cached at this point");
3320 :
3321 8 : if (!aState) {
3322 8 : if (reUseInnerWindow) {
3323 :
3324 1 : if (newInnerWindow->mDoc != aDocument) {
3325 1 : newInnerWindow->mDoc = aDocument;
3326 :
3327 : // The storage objects contain the URL of the window. We have to
3328 : // recreate them when the innerWindow is reused.
3329 1 : newInnerWindow->mLocalStorage = nullptr;
3330 1 : newInnerWindow->mSessionStorage = nullptr;
3331 :
3332 1 : newInnerWindow->ClearDocumentDependentSlots(cx);
3333 : }
3334 : } else {
3335 7 : newInnerWindow->InnerSetNewDocument(cx, aDocument);
3336 :
3337 : // Initialize DOM classes etc on the inner window.
3338 14 : JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
3339 7 : rv = kungFuDeathGrip->InitClasses(obj);
3340 7 : NS_ENSURE_SUCCESS(rv, rv);
3341 : }
3342 :
3343 : // If the document comes from a JAR, check if the channel was determined
3344 : // to be unsafe. If so, permanently disable script on the compartment by
3345 : // calling Block() and throwing away the key.
3346 16 : nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aDocument->GetChannel());
3347 8 : if (jarChannel && jarChannel->GetIsUnsafe()) {
3348 0 : xpc::Scriptability::Get(newInnerGlobal).Block();
3349 : }
3350 :
3351 8 : if (mArguments) {
3352 1 : newInnerWindow->DefineArgumentsProperty(mArguments);
3353 1 : mArguments = nullptr;
3354 : }
3355 :
3356 : // Give the new inner window our chrome event handler (since it
3357 : // doesn't have one).
3358 8 : newInnerWindow->mChromeEventHandler = mChromeEventHandler;
3359 : }
3360 :
3361 : // Ask the JS engine to assert that it's valid to access our DocGroup whenever
3362 : // it runs JS code for this compartment. We skip the check if this window is
3363 : // for chrome JS or an add-on.
3364 16 : nsCOMPtr<nsIPrincipal> principal = mDoc->NodePrincipal();
3365 16 : nsString addonId;
3366 8 : principal->GetAddonId(addonId);
3367 8 : if (GetDocGroup() && !nsContentUtils::IsSystemPrincipal(principal) && addonId.IsEmpty()) {
3368 8 : js::SetCompartmentValidAccessPtr(cx, newInnerGlobal,
3369 8 : newInnerWindow->GetDocGroup()->GetValidAccessPtr());
3370 : }
3371 :
3372 8 : kungFuDeathGrip->DidInitializeContext();
3373 :
3374 : // We wait to fire the debugger hook until the window is all set up and hooked
3375 : // up with the outer. See bug 969156.
3376 8 : if (createdInnerWindow) {
3377 14 : nsContentUtils::AddScriptRunner(
3378 14 : NewRunnableMethod("nsGlobalWindow::FireOnNewGlobalObject",
3379 : newInnerWindow,
3380 7 : &nsGlobalWindow::FireOnNewGlobalObject));
3381 : }
3382 :
3383 8 : if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
3384 : // We should probably notify. However if this is the, arguably bad,
3385 : // situation when we're creating a temporary non-chrome-about-blank
3386 : // document in a chrome docshell, don't notify just yet. Instead wait
3387 : // until we have a real chrome doc.
3388 21 : if (!mDocShell ||
3389 11 : mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome ||
3390 4 : nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
3391 6 : newInnerWindow->mHasNotifiedGlobalCreated = true;
3392 12 : nsContentUtils::AddScriptRunner(
3393 12 : NewRunnableMethod("nsGlobalWindow::DispatchDOMWindowCreated",
3394 : this,
3395 6 : &nsGlobalWindow::DispatchDOMWindowCreated));
3396 : }
3397 : }
3398 :
3399 8 : PreloadLocalStorage();
3400 :
3401 : // If we have a recorded interesting Large-Allocation header status, report it
3402 : // to the newly attached document.
3403 8 : ReportLargeAllocStatus();
3404 8 : mLargeAllocStatus = LargeAllocStatus::NONE;
3405 :
3406 8 : return NS_OK;
3407 : }
3408 :
3409 : void
3410 8 : nsGlobalWindow::PreloadLocalStorage()
3411 : {
3412 8 : MOZ_ASSERT(IsOuterWindow());
3413 :
3414 8 : if (!Preferences::GetBool(kStorageEnabled)) {
3415 5 : return;
3416 : }
3417 :
3418 8 : if (IsChromeWindow()) {
3419 5 : return;
3420 : }
3421 :
3422 3 : nsIPrincipal* principal = GetPrincipal();
3423 3 : if (!principal) {
3424 0 : return;
3425 : }
3426 :
3427 : nsresult rv;
3428 :
3429 : nsCOMPtr<nsIDOMStorageManager> storageManager =
3430 6 : do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
3431 3 : if (NS_FAILED(rv)) {
3432 0 : return;
3433 : }
3434 :
3435 : // private browsing windows do not persist local storage to disk so we should
3436 : // only try to precache storage when we're not a private browsing window.
3437 3 : if (principal->GetPrivateBrowsingId() == 0) {
3438 6 : nsCOMPtr<nsIDOMStorage> storage;
3439 3 : rv = storageManager->PrecacheStorage(principal, getter_AddRefs(storage));
3440 3 : if (NS_SUCCEEDED(rv)) {
3441 1 : mLocalStorage = static_cast<Storage*>(storage.get());
3442 : }
3443 : }
3444 : }
3445 :
3446 : void
3447 6 : nsGlobalWindow::DispatchDOMWindowCreated()
3448 : {
3449 6 : MOZ_ASSERT(IsOuterWindow());
3450 :
3451 6 : if (!mDoc) {
3452 0 : return;
3453 : }
3454 :
3455 : // Fire DOMWindowCreated at chrome event listeners
3456 24 : nsContentUtils::DispatchChromeEvent(mDoc, mDoc, NS_LITERAL_STRING("DOMWindowCreated"),
3457 : true /* bubbles */,
3458 18 : false /* not cancellable */);
3459 :
3460 : nsCOMPtr<nsIObserverService> observerService =
3461 12 : mozilla::services::GetObserverService();
3462 :
3463 : // The event dispatching could possibly cause docshell destory, and
3464 : // consequently cause mDoc to be set to nullptr by DropOuterWindowDocs(),
3465 : // so check it again here.
3466 6 : if (observerService && mDoc) {
3467 12 : nsAutoString origin;
3468 6 : nsIPrincipal* principal = mDoc->NodePrincipal();
3469 6 : nsContentUtils::GetUTFOrigin(principal, origin);
3470 6 : observerService->
3471 12 : NotifyObservers(static_cast<nsIDOMWindow*>(this),
3472 6 : nsContentUtils::IsSystemPrincipal(principal) ?
3473 : "chrome-document-global-created" :
3474 : "content-document-global-created",
3475 12 : origin.get());
3476 : }
3477 : }
3478 :
3479 : void
3480 8 : nsGlobalWindow::ClearStatus()
3481 : {
3482 8 : SetStatusOuter(EmptyString());
3483 8 : }
3484 :
3485 : void
3486 7 : nsGlobalWindow::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument)
3487 : {
3488 7 : NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
3489 7 : MOZ_ASSERT(aDocument);
3490 :
3491 7 : if (MOZ_LOG_TEST(gDOMLeakPRLog, LogLevel::Debug)) {
3492 0 : nsIURI *uri = aDocument->GetDocumentURI();
3493 0 : MOZ_LOG(gDOMLeakPRLog, LogLevel::Debug,
3494 : ("DOMWINDOW %p SetNewDocument %s",
3495 : this, uri ? uri->GetSpecOrDefault().get() : ""));
3496 : }
3497 :
3498 7 : mDoc = aDocument;
3499 7 : ClearDocumentDependentSlots(aCx);
3500 7 : mFocusedNode = nullptr;
3501 7 : mLocalStorage = nullptr;
3502 7 : mSessionStorage = nullptr;
3503 :
3504 : #ifdef DEBUG
3505 7 : mLastOpenedURI = aDocument->GetDocumentURI();
3506 : #endif
3507 :
3508 7 : Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
3509 14 : mMutationBits ? 1 : 0);
3510 :
3511 : // Clear our mutation bitfield.
3512 7 : mMutationBits = 0;
3513 7 : }
3514 :
3515 : void
3516 5 : nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
3517 : {
3518 5 : NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
3519 5 : MOZ_ASSERT(aDocShell);
3520 :
3521 5 : if (aDocShell == mDocShell) {
3522 0 : return;
3523 : }
3524 :
3525 5 : mDocShell = aDocShell; // Weak Reference
3526 :
3527 10 : nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetScriptableParentOrNull();
3528 5 : MOZ_RELEASE_ASSERT(!parentWindow || !mTabGroup || mTabGroup == Cast(parentWindow)->mTabGroup);
3529 :
3530 5 : mTopLevelOuterContentWindow =
3531 5 : !mIsChrome && GetScriptableTopInternal() == this;
3532 :
3533 5 : NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
3534 :
3535 5 : if (mFrames) {
3536 0 : mFrames->SetDocShell(aDocShell);
3537 : }
3538 :
3539 : // Get our enclosing chrome shell and retrieve its global window impl, so
3540 : // that we can do some forwarding to the chrome document.
3541 10 : nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
3542 5 : mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
3543 5 : mChromeEventHandler = do_QueryInterface(chromeEventHandler);
3544 5 : if (!mChromeEventHandler) {
3545 : // We have no chrome event handler. If we have a parent,
3546 : // get our chrome event handler from the parent. If
3547 : // we don't have a parent, then we need to make a new
3548 : // window root object that will function as a chrome event
3549 : // handler and receive all events that occur anywhere inside
3550 : // our window.
3551 6 : nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetParent();
3552 3 : if (parentWindow.get() != AsOuter()) {
3553 0 : mChromeEventHandler = parentWindow->GetChromeEventHandler();
3554 : }
3555 : else {
3556 3 : mChromeEventHandler = NS_NewWindowRoot(AsOuter());
3557 3 : mIsRootOuterWindow = true;
3558 : }
3559 : }
3560 :
3561 : bool docShellActive;
3562 5 : mDocShell->GetIsActive(&docShellActive);
3563 5 : SetIsBackgroundInternal(!docShellActive);
3564 : }
3565 :
3566 : void
3567 1 : nsGlobalWindow::DetachFromDocShell()
3568 : {
3569 1 : NS_ASSERTION(IsOuterWindow(), "Uh, DetachFromDocShell() called on inner window!");
3570 :
3571 : // DetachFromDocShell means the window is being torn down. Drop our
3572 : // reference to the script context, allowing it to be deleted
3573 : // later. Meanwhile, keep our weak reference to the script object
3574 : // so that it can be retrieved later (until it is finalized by the JS GC).
3575 :
3576 : // Call FreeInnerObjects on all inner windows, not just the current
3577 : // one, since some could be held by WindowStateHolder objects that
3578 : // are GC-owned.
3579 2 : for (RefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
3580 : inner != this;
3581 1 : inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
3582 1 : MOZ_ASSERT(!inner->mOuterWindow || inner->mOuterWindow == AsOuter());
3583 1 : inner->FreeInnerObjects();
3584 : }
3585 :
3586 1 : if (auto* reporter = nsWindowMemoryReporter::Get()) {
3587 1 : reporter->ObserveDOMWindowDetached(this);
3588 : }
3589 :
3590 1 : NotifyWindowIDDestroyed("outer-window-destroyed");
3591 :
3592 1 : nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
3593 :
3594 1 : if (currentInner) {
3595 1 : NS_ASSERTION(mDoc, "Must have doc!");
3596 :
3597 : // Remember the document's principal and URI.
3598 1 : mDocumentPrincipal = mDoc->NodePrincipal();
3599 1 : mDocumentURI = mDoc->GetDocumentURI();
3600 1 : mDocBaseURI = mDoc->GetDocBaseURI();
3601 :
3602 : // Release our document reference
3603 1 : DropOuterWindowDocs();
3604 1 : mFocusedNode = nullptr;
3605 : }
3606 :
3607 1 : ClearControllers();
3608 :
3609 1 : mChromeEventHandler = nullptr; // force release now
3610 :
3611 1 : if (mContext) {
3612 : // When we're about to destroy a top level content window
3613 : // (for example a tab), we trigger a full GC by passing null as the last
3614 : // param. We also trigger a full GC for chrome windows.
3615 1 : nsJSContext::PokeGC(JS::gcreason::SET_DOC_SHELL,
3616 1 : (mTopLevelOuterContentWindow || mIsChrome) ?
3617 1 : nullptr : GetWrapperPreserveColor());
3618 1 : mContext = nullptr;
3619 : }
3620 :
3621 1 : mDocShell = nullptr; // Weak Reference
3622 :
3623 1 : NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
3624 :
3625 1 : if (mFrames) {
3626 0 : mFrames->SetDocShell(nullptr);
3627 : }
3628 :
3629 1 : MaybeForgiveSpamCount();
3630 1 : CleanUp();
3631 1 : }
3632 :
3633 : void
3634 1 : nsGlobalWindow::SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
3635 : bool aOriginalOpener)
3636 : {
3637 2 : FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
3638 :
3639 1 : nsWeakPtr opener = do_GetWeakReference(aOpener);
3640 1 : if (opener == mOpener) {
3641 1 : return;
3642 : }
3643 :
3644 0 : NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
3645 : "aOriginalOpener is true, but not first call to "
3646 : "SetOpenerWindow!");
3647 0 : NS_ASSERTION(aOpener || !aOriginalOpener,
3648 : "Shouldn't set mHadOriginalOpener if aOpener is null");
3649 :
3650 0 : mOpener = opener.forget();
3651 0 : NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
3652 :
3653 : // Check that the js visible opener matches! We currently don't depend on this
3654 : // being true outside of nightly, so we disable the assertion in optimized
3655 : // release / beta builds.
3656 0 : nsPIDOMWindowOuter* contentOpener = GetSanitizedOpener(aOpener);
3657 :
3658 : // contentOpener is not used when the DIAGNOSTIC_ASSERT is compiled out.
3659 : mozilla::Unused << contentOpener;
3660 0 : MOZ_DIAGNOSTIC_ASSERT(!contentOpener || !mTabGroup ||
3661 : mTabGroup == Cast(contentOpener)->mTabGroup);
3662 :
3663 0 : if (aOriginalOpener) {
3664 0 : MOZ_ASSERT(!mHadOriginalOpener,
3665 : "Probably too late to call ComputeIsSecureContext again");
3666 0 : mHadOriginalOpener = true;
3667 0 : mOriginalOpenerWasSecureContext =
3668 0 : aOpener->GetCurrentInnerWindow()->IsSecureContext();
3669 : }
3670 :
3671 : #ifdef DEBUG
3672 0 : mSetOpenerWindowCalled = true;
3673 : #endif
3674 : }
3675 :
3676 : static
3677 : already_AddRefed<EventTarget>
3678 32 : TryGetTabChildGlobalAsEventTarget(nsISupports *aFrom)
3679 : {
3680 64 : nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(aFrom);
3681 32 : if (!frameLoaderOwner) {
3682 26 : return nullptr;
3683 : }
3684 :
3685 12 : RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
3686 6 : if (!frameLoader) {
3687 0 : return nullptr;
3688 : }
3689 :
3690 12 : nsCOMPtr<EventTarget> target = frameLoader->GetTabChildGlobalAsEventTarget();
3691 6 : return target.forget();
3692 : }
3693 :
3694 : void
3695 12 : nsGlobalWindow::UpdateParentTarget()
3696 : {
3697 : // Try to get our frame element's tab child global (its in-process message
3698 : // manager). If that fails, fall back to the chrome event handler's tab
3699 : // child global, and if it doesn't have one, just use the chrome event
3700 : // handler itself.
3701 :
3702 24 : nsCOMPtr<Element> frameElement = GetOuterWindow()->GetFrameElementInternal();
3703 : nsCOMPtr<EventTarget> eventTarget =
3704 24 : TryGetTabChildGlobalAsEventTarget(frameElement);
3705 :
3706 12 : if (!eventTarget) {
3707 10 : nsGlobalWindow* topWin = GetScriptableTopInternal();
3708 10 : if (topWin) {
3709 10 : frameElement = topWin->AsOuter()->GetFrameElementInternal();
3710 10 : eventTarget = TryGetTabChildGlobalAsEventTarget(frameElement);
3711 : }
3712 : }
3713 :
3714 12 : if (!eventTarget) {
3715 10 : eventTarget = TryGetTabChildGlobalAsEventTarget(mChromeEventHandler);
3716 : }
3717 :
3718 12 : if (!eventTarget) {
3719 10 : eventTarget = mChromeEventHandler;
3720 : }
3721 :
3722 12 : mParentTarget = eventTarget;
3723 12 : }
3724 :
3725 : EventTarget*
3726 68 : nsGlobalWindow::GetTargetForDOMEvent()
3727 : {
3728 68 : return GetOuterWindowInternal();
3729 : }
3730 :
3731 : EventTarget*
3732 460 : nsGlobalWindow::GetTargetForEventTargetChain()
3733 : {
3734 460 : return IsInnerWindow() ? this : GetCurrentInnerWindowInternal();
3735 : }
3736 :
3737 : nsresult
3738 0 : nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor)
3739 : {
3740 0 : return NS_OK;
3741 : }
3742 :
3743 : nsresult
3744 215 : nsGlobalWindow::GetEventTargetParent(EventChainPreVisitor& aVisitor)
3745 : {
3746 215 : NS_PRECONDITION(IsInnerWindow(),
3747 : "GetEventTargetParent is used on outer window!?");
3748 215 : EventMessage msg = aVisitor.mEvent->mMessage;
3749 :
3750 215 : aVisitor.mCanHandle = true;
3751 215 : aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
3752 215 : if (msg == eResize && aVisitor.mEvent->IsTrusted()) {
3753 : // QIing to window so that we can keep the old behavior also in case
3754 : // a child window is handling resize.
3755 : nsCOMPtr<nsPIDOMWindowInner> window =
3756 4 : do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
3757 2 : if (window) {
3758 2 : mIsHandlingResizeEvent = true;
3759 : }
3760 213 : } else if (msg == eMouseDown && aVisitor.mEvent->IsTrusted()) {
3761 0 : gMouseDown = true;
3762 213 : } else if ((msg == eMouseUp || msg == eDragEnd) &&
3763 0 : aVisitor.mEvent->IsTrusted()) {
3764 0 : gMouseDown = false;
3765 0 : if (gDragServiceDisabled) {
3766 : nsCOMPtr<nsIDragService> ds =
3767 0 : do_GetService("@mozilla.org/widget/dragservice;1");
3768 0 : if (ds) {
3769 0 : gDragServiceDisabled = false;
3770 0 : ds->Unsuppress();
3771 : }
3772 : }
3773 : }
3774 :
3775 215 : aVisitor.mParentTarget = GetParentTarget();
3776 :
3777 : // Handle 'active' event.
3778 430 : if (!mIdleObservers.IsEmpty() &&
3779 215 : aVisitor.mEvent->IsTrusted() &&
3780 0 : (aVisitor.mEvent->HasMouseEventMessage() ||
3781 0 : aVisitor.mEvent->HasDragEventMessage())) {
3782 0 : mAddActiveEventFuzzTime = false;
3783 : }
3784 :
3785 215 : return NS_OK;
3786 : }
3787 :
3788 : bool
3789 0 : nsGlobalWindow::ShouldPromptToBlockDialogs()
3790 : {
3791 0 : MOZ_ASSERT(IsOuterWindow());
3792 :
3793 0 : nsGlobalWindow *topWindow = GetScriptableTopInternal();
3794 0 : if (!topWindow) {
3795 0 : NS_ASSERTION(!mDocShell, "ShouldPromptToBlockDialogs() called without a top window?");
3796 0 : return true;
3797 : }
3798 :
3799 0 : topWindow = topWindow->GetCurrentInnerWindowInternal();
3800 0 : if (!topWindow) {
3801 0 : return true;
3802 : }
3803 :
3804 0 : return topWindow->DialogsAreBeingAbused();
3805 : }
3806 :
3807 : bool
3808 5 : nsGlobalWindow::AreDialogsEnabled()
3809 : {
3810 5 : MOZ_ASSERT(IsOuterWindow());
3811 :
3812 5 : nsGlobalWindow *topWindow = GetScriptableTopInternal();
3813 5 : if (!topWindow) {
3814 0 : NS_ERROR("AreDialogsEnabled() called without a top window?");
3815 0 : return false;
3816 : }
3817 :
3818 : // TODO: Warn if no top window?
3819 5 : topWindow = topWindow->GetCurrentInnerWindowInternal();
3820 5 : if (!topWindow) {
3821 0 : return false;
3822 : }
3823 :
3824 : // Dialogs are blocked if the content viewer is hidden
3825 5 : if (mDocShell) {
3826 10 : nsCOMPtr<nsIContentViewer> cv;
3827 5 : mDocShell->GetContentViewer(getter_AddRefs(cv));
3828 :
3829 : bool isHidden;
3830 5 : cv->GetIsHidden(&isHidden);
3831 5 : if (isHidden) {
3832 0 : return false;
3833 : }
3834 : }
3835 :
3836 : // Dialogs are also blocked if the document is sandboxed with SANDBOXED_MODALS
3837 : // (or if we have no document, of course). Which document? Who knows; the
3838 : // spec is daft. See <https://github.com/whatwg/html/issues/1206>. For now
3839 : // just go ahead and check mDoc, since in everything except edge cases in
3840 : // which a frame is allow-same-origin but not allow-scripts and is being poked
3841 : // at by some other window this should be the right thing anyway.
3842 5 : if (!mDoc || (mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
3843 0 : return false;
3844 : }
3845 :
3846 5 : return topWindow->mAreDialogsEnabled;
3847 : }
3848 :
3849 : bool
3850 0 : nsGlobalWindow::DialogsAreBeingAbused()
3851 : {
3852 0 : MOZ_ASSERT(IsInnerWindow());
3853 0 : NS_ASSERTION(GetScriptableTopInternal() &&
3854 : GetScriptableTopInternal()->GetCurrentInnerWindowInternal() == this,
3855 : "DialogsAreBeingAbused called with invalid window");
3856 :
3857 0 : if (mLastDialogQuitTime.IsNull() ||
3858 0 : nsContentUtils::IsCallerChrome()) {
3859 0 : return false;
3860 : }
3861 :
3862 0 : TimeDuration dialogInterval(TimeStamp::Now() - mLastDialogQuitTime);
3863 0 : if (dialogInterval.ToSeconds() <
3864 0 : Preferences::GetInt("dom.successive_dialog_time_limit",
3865 : DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT)) {
3866 0 : mDialogAbuseCount++;
3867 :
3868 0 : return GetPopupControlState() > openAllowed ||
3869 0 : mDialogAbuseCount > MAX_SUCCESSIVE_DIALOG_COUNT;
3870 : }
3871 :
3872 : // Reset the abuse counter
3873 0 : mDialogAbuseCount = 0;
3874 :
3875 0 : return false;
3876 : }
3877 :
3878 : bool
3879 0 : nsGlobalWindow::ConfirmDialogIfNeeded()
3880 : {
3881 0 : MOZ_ASSERT(IsOuterWindow());
3882 :
3883 0 : NS_ENSURE_TRUE(mDocShell, false);
3884 : nsCOMPtr<nsIPromptService> promptSvc =
3885 0 : do_GetService("@mozilla.org/embedcomp/prompt-service;1");
3886 :
3887 0 : if (!promptSvc) {
3888 0 : return true;
3889 : }
3890 :
3891 : // Reset popup state while opening a modal dialog, and firing events
3892 : // about the dialog, to prevent the current state from being active
3893 : // the whole time a modal dialog is open.
3894 0 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
3895 :
3896 0 : bool disableDialog = false;
3897 0 : nsXPIDLString label, title;
3898 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
3899 0 : "ScriptDialogLabel", label);
3900 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
3901 0 : "ScriptDialogPreventTitle", title);
3902 0 : promptSvc->Confirm(AsOuter(), title.get(), label.get(), &disableDialog);
3903 0 : if (disableDialog) {
3904 0 : DisableDialogs();
3905 0 : return false;
3906 : }
3907 :
3908 0 : return true;
3909 : }
3910 :
3911 : void
3912 0 : nsGlobalWindow::DisableDialogs()
3913 : {
3914 0 : nsGlobalWindow *topWindow = GetScriptableTopInternal();
3915 0 : if (!topWindow) {
3916 0 : NS_ERROR("DisableDialogs() called without a top window?");
3917 0 : return;
3918 : }
3919 :
3920 0 : topWindow = topWindow->GetCurrentInnerWindowInternal();
3921 : // TODO: Warn if no top window?
3922 0 : if (topWindow) {
3923 0 : topWindow->mAreDialogsEnabled = false;
3924 : }
3925 : }
3926 :
3927 : void
3928 0 : nsGlobalWindow::EnableDialogs()
3929 : {
3930 0 : nsGlobalWindow *topWindow = GetScriptableTopInternal();
3931 0 : if (!topWindow) {
3932 0 : NS_ERROR("EnableDialogs() called without a top window?");
3933 0 : return;
3934 : }
3935 :
3936 : // TODO: Warn if no top window?
3937 0 : topWindow = topWindow->GetCurrentInnerWindowInternal();
3938 0 : if (topWindow) {
3939 0 : topWindow->mAreDialogsEnabled = true;
3940 : }
3941 : }
3942 :
3943 : nsresult
3944 134 : nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
3945 : {
3946 134 : NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
3947 :
3948 : // Return early if there is nothing to do.
3949 134 : switch (aVisitor.mEvent->mMessage) {
3950 : case eResize:
3951 : case eUnload:
3952 : case eLoad:
3953 10 : break;
3954 : default:
3955 124 : return NS_OK;
3956 : }
3957 :
3958 : /* mChromeEventHandler and mContext go dangling in the middle of this
3959 : function under some circumstances (events that destroy the window)
3960 : without this addref. */
3961 20 : nsCOMPtr<nsIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
3962 : mozilla::Unused << kungFuDeathGrip1; // These aren't referred to through the function
3963 20 : nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
3964 : mozilla::Unused << kungFuDeathGrip2; // These aren't referred to through the function
3965 :
3966 :
3967 10 : if (aVisitor.mEvent->mMessage == eResize) {
3968 2 : mIsHandlingResizeEvent = false;
3969 12 : } else if (aVisitor.mEvent->mMessage == eUnload &&
3970 4 : aVisitor.mEvent->IsTrusted()) {
3971 :
3972 : // If any VR display presentation is active at unload, the next page
3973 : // will receive a vrdisplayactive event to indicate that it should
3974 : // immediately begin vr presentation. This should occur when navigating
3975 : // forwards, navigating backwards, and on page reload.
3976 4 : for (const auto& display : mVRDisplays) {
3977 0 : if (display->IsPresenting()) {
3978 : // Save this VR display ID to trigger vrdisplayactivate event
3979 : // after the next load event.
3980 0 : nsGlobalWindow* outer = GetOuterWindowInternal();
3981 0 : if (outer) {
3982 0 : outer->SetAutoActivateVRDisplayID(display->DisplayId());
3983 : }
3984 :
3985 : // XXX The WebVR 1.1 spec does not define which of multiple VR
3986 : // presenting VR displays will be chosen during navigation.
3987 : // As the underlying platform VR API's currently only allow a single
3988 : // VR display, it is safe to choose the first VR display for now.
3989 0 : break;
3990 : }
3991 : }
3992 : // Execute bindingdetached handlers before we tear ourselves
3993 : // down.
3994 4 : if (mDoc) {
3995 4 : mDoc->BindingManager()->ExecuteDetachedHandlers();
3996 : }
3997 4 : mIsDocumentLoaded = false;
3998 8 : } else if (aVisitor.mEvent->mMessage == eLoad &&
3999 4 : aVisitor.mEvent->IsTrusted()) {
4000 : // This is page load event since load events don't propagate to |window|.
4001 : // @see nsDocument::GetEventTargetParent.
4002 4 : mIsDocumentLoaded = true;
4003 :
4004 4 : mTimeoutManager->OnDocumentLoaded();
4005 :
4006 8 : nsCOMPtr<Element> element = GetOuterWindow()->GetFrameElementInternal();
4007 4 : nsIDocShell* docShell = GetDocShell();
4008 9 : if (element && GetParentInternal() &&
4009 5 : docShell && docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
4010 : // If we're not in chrome, or at a chrome boundary, fire the
4011 : // onload event for the frame element.
4012 :
4013 0 : nsEventStatus status = nsEventStatus_eIgnore;
4014 0 : WidgetEvent event(aVisitor.mEvent->IsTrusted(), eLoad);
4015 0 : event.mFlags.mBubbles = false;
4016 0 : event.mFlags.mCancelable = false;
4017 :
4018 : // Most of the time we could get a pres context to pass in here,
4019 : // but not always (i.e. if this window is not shown there won't
4020 : // be a pres context available). Since we're not firing a GUI
4021 : // event we don't need a pres context anyway so we just pass
4022 : // null as the pres context all the time here.
4023 0 : EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status);
4024 : }
4025 :
4026 4 : uint32_t autoActivateVRDisplayID = 0;
4027 4 : nsGlobalWindow* outer = GetOuterWindowInternal();
4028 4 : if (outer) {
4029 4 : autoActivateVRDisplayID = outer->GetAutoActivateVRDisplayID();
4030 : }
4031 4 : if (autoActivateVRDisplayID) {
4032 : DispatchVRDisplayActivate(autoActivateVRDisplayID,
4033 0 : VRDisplayEventReason::Navigation);
4034 : }
4035 : }
4036 :
4037 10 : return NS_OK;
4038 : }
4039 :
4040 : nsresult
4041 0 : nsGlobalWindow::DispatchDOMEvent(WidgetEvent* aEvent,
4042 : nsIDOMEvent* aDOMEvent,
4043 : nsPresContext* aPresContext,
4044 : nsEventStatus* aEventStatus)
4045 : {
4046 0 : return EventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),
4047 : aEvent, aDOMEvent, aPresContext,
4048 0 : aEventStatus);
4049 : }
4050 :
4051 : void
4052 0 : nsGlobalWindow::PoisonOuterWindowProxy(JSObject *aObject)
4053 : {
4054 0 : MOZ_ASSERT(IsOuterWindow());
4055 0 : if (aObject == GetWrapperMaybeDead()) {
4056 0 : PoisonWrapper();
4057 : }
4058 0 : }
4059 :
4060 : nsresult
4061 1 : nsGlobalWindow::SetArguments(nsIArray *aArguments)
4062 : {
4063 1 : MOZ_ASSERT(IsOuterWindow());
4064 : nsresult rv;
4065 :
4066 : // Historically, we've used the same machinery to handle openDialog arguments
4067 : // (exposed via window.arguments) and showModalDialog arguments (exposed via
4068 : // window.dialogArguments), even though the former is XUL-only and uses an XPCOM
4069 : // array while the latter is web-exposed and uses an arbitrary JS value.
4070 : // Moreover, per-spec |dialogArguments| is a property of the browsing context
4071 : // (outer), whereas |arguments| lives on the inner.
4072 : //
4073 : // We've now mostly separated them, but the difference is still opaque to
4074 : // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
4075 : // embedding waltz we do here).
4076 : //
4077 : // So we need to demultiplex the two cases here.
4078 1 : nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
4079 1 : if (mIsModalContentWindow) {
4080 : // nsWindowWatcher blindly converts the original nsISupports into an array
4081 : // of length 1. We need to recover it, and then cast it back to the concrete
4082 : // object we know it to be.
4083 0 : nsCOMPtr<nsISupports> supports = do_QueryElementAt(aArguments, 0, &rv);
4084 0 : NS_ENSURE_SUCCESS(rv, rv);
4085 0 : mDialogArguments = static_cast<DialogValueHolder*>(supports.get());
4086 : } else {
4087 1 : mArguments = aArguments;
4088 1 : rv = currentInner->DefineArgumentsProperty(aArguments);
4089 1 : NS_ENSURE_SUCCESS(rv, rv);
4090 : }
4091 :
4092 1 : return NS_OK;
4093 : }
4094 :
4095 : nsresult
4096 2 : nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
4097 : {
4098 2 : MOZ_ASSERT(IsInnerWindow());
4099 2 : MOZ_ASSERT(!mIsModalContentWindow); // Handled separately.
4100 :
4101 2 : nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
4102 2 : NS_ENSURE_TRUE(aArguments && ctx, NS_ERROR_NOT_INITIALIZED);
4103 :
4104 4 : JS::Rooted<JSObject*> obj(RootingCx(), GetWrapperPreserveColor());
4105 2 : return ctx->SetProperty(obj, "arguments", aArguments);
4106 : }
4107 :
4108 : //*****************************************************************************
4109 : // nsGlobalWindow::nsIScriptObjectPrincipal
4110 : //*****************************************************************************
4111 :
4112 : nsIPrincipal*
4113 72 : nsGlobalWindow::GetPrincipal()
4114 : {
4115 72 : if (mDoc) {
4116 : // If we have a document, get the principal from the document
4117 72 : return mDoc->NodePrincipal();
4118 : }
4119 :
4120 0 : if (mDocumentPrincipal) {
4121 0 : return mDocumentPrincipal;
4122 : }
4123 :
4124 : // If we don't have a principal and we don't have a document we
4125 : // ask the parent window for the principal. This can happen when
4126 : // loading a frameset that has a <frame src="javascript:xxx">, in
4127 : // that case the global window is used in JS before we've loaded
4128 : // a document into the window.
4129 :
4130 : nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
4131 0 : do_QueryInterface(GetParentInternal());
4132 :
4133 0 : if (objPrincipal) {
4134 0 : return objPrincipal->GetPrincipal();
4135 : }
4136 :
4137 0 : return nullptr;
4138 : }
4139 :
4140 : //*****************************************************************************
4141 : // nsGlobalWindow::nsIDOMWindow
4142 : //*****************************************************************************
4143 :
4144 : template <class T>
4145 : nsIURI*
4146 0 : nsPIDOMWindow<T>::GetDocumentURI() const
4147 : {
4148 0 : return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
4149 : }
4150 :
4151 : template <class T>
4152 : nsIURI*
4153 0 : nsPIDOMWindow<T>::GetDocBaseURI() const
4154 : {
4155 0 : return mDoc ? mDoc->GetDocBaseURI() : mDocBaseURI.get();
4156 : }
4157 :
4158 : template <class T>
4159 : void
4160 9 : nsPIDOMWindow<T>::MaybeCreateDoc()
4161 : {
4162 9 : MOZ_ASSERT(!mDoc);
4163 9 : if (nsIDocShell* docShell = GetDocShell()) {
4164 : // Note that |document| here is the same thing as our mDoc, but we
4165 : // don't have to explicitly set the member variable because the docshell
4166 : // has already called SetNewDocument().
4167 9 : nsCOMPtr<nsIDocument> document = docShell->GetDocument();
4168 : Unused << document;
4169 : }
4170 9 : }
4171 :
4172 : void
4173 1 : nsPIDOMWindowOuter::SetInitialKeyboardIndicators(
4174 : UIStateChangeType aShowAccelerators, UIStateChangeType aShowFocusRings)
4175 : {
4176 1 : MOZ_ASSERT(IsOuterWindow());
4177 1 : MOZ_ASSERT(!GetCurrentInnerWindow());
4178 :
4179 1 : nsPIDOMWindowOuter* piWin = GetPrivateRoot();
4180 1 : if (!piWin) {
4181 0 : return;
4182 : }
4183 :
4184 1 : MOZ_ASSERT(piWin == AsOuter());
4185 :
4186 : // only change the flags that have been modified
4187 2 : nsCOMPtr<nsPIWindowRoot> windowRoot = do_QueryInterface(mChromeEventHandler);
4188 1 : if (!windowRoot) {
4189 0 : return;
4190 : }
4191 :
4192 1 : if (aShowAccelerators != UIStateChangeType_NoChange) {
4193 1 : windowRoot->SetShowAccelerators(aShowAccelerators == UIStateChangeType_Set);
4194 : }
4195 1 : if (aShowFocusRings != UIStateChangeType_NoChange) {
4196 1 : windowRoot->SetShowFocusRings(aShowFocusRings == UIStateChangeType_Set);
4197 : }
4198 :
4199 1 : nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(GetOuterWindow(),
4200 : aShowAccelerators,
4201 1 : aShowFocusRings);
4202 : }
4203 :
4204 : Element*
4205 101 : nsPIDOMWindowOuter::GetFrameElementInternal() const
4206 : {
4207 101 : MOZ_ASSERT(IsOuterWindow());
4208 101 : return mFrameElement;
4209 : }
4210 :
4211 : void
4212 3 : nsPIDOMWindowOuter::SetFrameElementInternal(Element* aFrameElement)
4213 : {
4214 3 : MOZ_ASSERT(IsOuterWindow());
4215 3 : mFrameElement = aFrameElement;
4216 3 : }
4217 :
4218 : bool
4219 0 : nsPIDOMWindowInner::AddAudioContext(AudioContext* aAudioContext)
4220 : {
4221 0 : MOZ_ASSERT(IsInnerWindow());
4222 :
4223 0 : mAudioContexts.AppendElement(aAudioContext);
4224 :
4225 : // Return true if the context should be muted and false if not.
4226 0 : nsIDocShell* docShell = GetDocShell();
4227 0 : return docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline();
4228 : }
4229 :
4230 : void
4231 0 : nsPIDOMWindowInner::RemoveAudioContext(AudioContext* aAudioContext)
4232 : {
4233 0 : MOZ_ASSERT(IsInnerWindow());
4234 :
4235 0 : mAudioContexts.RemoveElement(aAudioContext);
4236 0 : }
4237 :
4238 : void
4239 0 : nsPIDOMWindowInner::MuteAudioContexts()
4240 : {
4241 0 : MOZ_ASSERT(IsInnerWindow());
4242 :
4243 0 : for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
4244 0 : if (!mAudioContexts[i]->IsOffline()) {
4245 0 : mAudioContexts[i]->Mute();
4246 : }
4247 : }
4248 0 : }
4249 :
4250 : void
4251 0 : nsPIDOMWindowInner::UnmuteAudioContexts()
4252 : {
4253 0 : MOZ_ASSERT(IsInnerWindow());
4254 :
4255 0 : for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
4256 0 : if (!mAudioContexts[i]->IsOffline()) {
4257 0 : mAudioContexts[i]->Unmute();
4258 : }
4259 : }
4260 0 : }
4261 :
4262 : nsGlobalWindow*
4263 7 : nsGlobalWindow::Window()
4264 : {
4265 7 : return this;
4266 : }
4267 :
4268 : nsGlobalWindow*
4269 7 : nsGlobalWindow::Self()
4270 : {
4271 7 : return this;
4272 : }
4273 :
4274 : Navigator*
4275 0 : nsGlobalWindow::Navigator()
4276 : {
4277 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
4278 :
4279 0 : if (!mNavigator) {
4280 0 : mNavigator = new mozilla::dom::Navigator(AsInner());
4281 : }
4282 :
4283 0 : return mNavigator;
4284 : }
4285 :
4286 : nsIDOMNavigator*
4287 0 : nsGlobalWindow::GetNavigator()
4288 : {
4289 0 : FORWARD_TO_INNER(GetNavigator, (), nullptr);
4290 :
4291 0 : return Navigator();
4292 : }
4293 :
4294 : nsScreen*
4295 6 : nsGlobalWindow::GetScreen(ErrorResult& aError)
4296 : {
4297 6 : MOZ_RELEASE_ASSERT(IsInnerWindow());
4298 :
4299 6 : if (!mScreen) {
4300 1 : mScreen = nsScreen::Create(AsInner());
4301 1 : if (!mScreen) {
4302 0 : aError.Throw(NS_ERROR_UNEXPECTED);
4303 0 : return nullptr;
4304 : }
4305 : }
4306 :
4307 6 : return mScreen;
4308 : }
4309 :
4310 : nsIDOMScreen*
4311 2 : nsGlobalWindow::GetScreen()
4312 : {
4313 2 : FORWARD_TO_INNER(GetScreen, (), nullptr);
4314 :
4315 2 : ErrorResult dummy;
4316 1 : nsIDOMScreen* screen = GetScreen(dummy);
4317 1 : dummy.SuppressException();
4318 1 : return screen;
4319 : }
4320 :
4321 : nsHistory*
4322 0 : nsGlobalWindow::GetHistory(ErrorResult& aError)
4323 : {
4324 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
4325 :
4326 0 : if (!mHistory) {
4327 0 : mHistory = new nsHistory(AsInner());
4328 : }
4329 :
4330 0 : return mHistory;
4331 : }
4332 :
4333 : CustomElementRegistry*
4334 0 : nsGlobalWindow::CustomElements()
4335 : {
4336 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
4337 :
4338 0 : if (!mCustomElements) {
4339 0 : mCustomElements = new CustomElementRegistry(AsInner());
4340 : }
4341 :
4342 0 : return mCustomElements;
4343 : }
4344 :
4345 : Performance*
4346 112 : nsPIDOMWindowInner::GetPerformance()
4347 : {
4348 112 : MOZ_ASSERT(IsInnerWindow());
4349 112 : CreatePerformanceObjectIfNeeded();
4350 112 : return mPerformance;
4351 : }
4352 :
4353 : Performance*
4354 15 : nsGlobalWindow::GetPerformance()
4355 : {
4356 15 : return AsInner()->GetPerformance();
4357 : }
4358 :
4359 : void
4360 112 : nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded()
4361 : {
4362 112 : MOZ_ASSERT(IsInnerWindow());
4363 :
4364 112 : if (mPerformance || !mDoc) {
4365 105 : return;
4366 : }
4367 14 : RefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
4368 14 : nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
4369 7 : bool timingEnabled = false;
4370 15 : if (!timedChannel ||
4371 8 : !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
4372 1 : !timingEnabled) {
4373 6 : timedChannel = nullptr;
4374 : }
4375 7 : if (timing) {
4376 7 : mPerformance = Performance::CreateForMainThread(this, timing, timedChannel);
4377 : }
4378 : }
4379 :
4380 : bool
4381 0 : nsPIDOMWindowInner::IsSecureContext() const
4382 : {
4383 0 : return nsGlobalWindow::Cast(this)->IsSecureContext();
4384 : }
4385 :
4386 : bool
4387 0 : nsPIDOMWindowInner::IsSecureContextIfOpenerIgnored() const
4388 : {
4389 0 : return nsGlobalWindow::Cast(this)->IsSecureContextIfOpenerIgnored();
4390 : }
4391 :
4392 : void
4393 0 : nsPIDOMWindowInner::Suspend()
4394 : {
4395 0 : nsGlobalWindow::Cast(this)->Suspend();
4396 0 : }
4397 :
4398 : void
4399 0 : nsPIDOMWindowInner::Resume()
4400 : {
4401 0 : nsGlobalWindow::Cast(this)->Resume();
4402 0 : }
4403 :
4404 : void
4405 0 : nsPIDOMWindowInner::Freeze()
4406 : {
4407 0 : nsGlobalWindow::Cast(this)->Freeze();
4408 0 : }
4409 :
4410 : void
4411 0 : nsPIDOMWindowInner::Thaw()
4412 : {
4413 0 : nsGlobalWindow::Cast(this)->Thaw();
4414 0 : }
4415 :
4416 : void
4417 7 : nsPIDOMWindowInner::SyncStateFromParentWindow()
4418 : {
4419 7 : nsGlobalWindow::Cast(this)->SyncStateFromParentWindow();
4420 7 : }
4421 :
4422 : bool
4423 4 : nsPIDOMWindowInner::IsPlayingAudio()
4424 : {
4425 8 : RefPtr<AudioChannelService> acs = AudioChannelService::Get();
4426 4 : if (!acs) {
4427 0 : return false;
4428 : }
4429 4 : auto outer = GetOuterWindow();
4430 4 : if (!outer) {
4431 : // We've been unlinked and are about to die. Not a good time to pretend to
4432 : // be playing audio.
4433 0 : return false;
4434 : }
4435 4 : return acs->IsWindowActive(outer);
4436 : }
4437 :
4438 : bool
4439 0 : nsPIDOMWindowInner::IsDocumentLoaded() const
4440 : {
4441 0 : return mIsDocumentLoaded;
4442 : }
4443 :
4444 : mozilla::dom::TimeoutManager&
4445 0 : nsPIDOMWindowInner::TimeoutManager()
4446 : {
4447 0 : return *mTimeoutManager;
4448 : }
4449 :
4450 : bool
4451 0 : nsPIDOMWindowInner::IsRunningTimeout()
4452 : {
4453 0 : return TimeoutManager().IsRunningTimeout();
4454 : }
4455 :
4456 : void
4457 7 : nsPIDOMWindowInner::TryToCacheTopInnerWindow()
4458 : {
4459 7 : if (mHasTriedToCacheTopInnerWindow) {
4460 0 : return;
4461 : }
4462 :
4463 7 : MOZ_ASSERT(!mInnerObjectsFreed);
4464 :
4465 7 : mHasTriedToCacheTopInnerWindow = true;
4466 :
4467 7 : nsGlobalWindow* window = nsGlobalWindow::Cast(AsInner());
4468 :
4469 7 : MOZ_ASSERT(window);
4470 :
4471 14 : if (nsCOMPtr<nsPIDOMWindowOuter> topOutter = window->GetScriptableTop()) {
4472 7 : mTopInnerWindow = topOutter->GetCurrentInnerWindow();
4473 : }
4474 : }
4475 :
4476 : void
4477 0 : nsPIDOMWindowInner::UpdateActiveIndexedDBTransactionCount(int32_t aDelta)
4478 : {
4479 0 : MOZ_ASSERT(NS_IsMainThread());
4480 :
4481 0 : if (aDelta == 0) {
4482 0 : return;
4483 : }
4484 :
4485 0 : TabGroup()->IndexedDBTransactionCounter() += aDelta;
4486 : }
4487 :
4488 : void
4489 0 : nsPIDOMWindowInner::UpdateActiveIndexedDBDatabaseCount(int32_t aDelta)
4490 : {
4491 0 : MOZ_ASSERT(NS_IsMainThread());
4492 :
4493 0 : if (aDelta == 0) {
4494 0 : return;
4495 : }
4496 :
4497 : // We count databases but not transactions because only active databases
4498 : // could block throttling.
4499 : uint32_t& counter = mTopInnerWindow ?
4500 0 : mTopInnerWindow->mNumOfIndexedDBDatabases : mNumOfIndexedDBDatabases;
4501 :
4502 0 : counter+= aDelta;
4503 :
4504 0 : TabGroup()->IndexedDBDatabaseCounter() += aDelta;
4505 : }
4506 :
4507 : bool
4508 4 : nsPIDOMWindowInner::HasActiveIndexedDBDatabases()
4509 : {
4510 4 : MOZ_ASSERT(NS_IsMainThread());
4511 :
4512 8 : return mTopInnerWindow ?
4513 4 : mTopInnerWindow->mNumOfIndexedDBDatabases > 0 :
4514 8 : mNumOfIndexedDBDatabases > 0;
4515 : }
4516 :
4517 : void
4518 5 : nsPIDOMWindowOuter::MaybeActiveMediaComponents()
4519 : {
4520 5 : if (IsInnerWindow()) {
4521 0 : return mOuterWindow->MaybeActiveMediaComponents();
4522 : }
4523 :
4524 5 : if (mMediaSuspend != nsISuspendedTypes::SUSPENDED_BLOCK) {
4525 1 : return;
4526 : }
4527 :
4528 4 : MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
4529 : ("nsPIDOMWindowOuter, MaybeActiveMediaComponents, "
4530 : "resume the window from blocked, this = %p\n", this));
4531 :
4532 4 : SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);
4533 : }
4534 :
4535 : SuspendTypes
4536 0 : nsPIDOMWindowOuter::GetMediaSuspend() const
4537 : {
4538 0 : if (IsInnerWindow()) {
4539 0 : return mOuterWindow->GetMediaSuspend();
4540 : }
4541 :
4542 0 : return mMediaSuspend;
4543 : }
4544 :
4545 : void
4546 4 : nsPIDOMWindowOuter::SetMediaSuspend(SuspendTypes aSuspend)
4547 : {
4548 4 : if (IsInnerWindow()) {
4549 0 : mOuterWindow->SetMediaSuspend(aSuspend);
4550 0 : return;
4551 : }
4552 :
4553 4 : if (!IsDisposableSuspend(aSuspend)) {
4554 4 : MaybeNotifyMediaResumedFromBlock(aSuspend);
4555 4 : mMediaSuspend = aSuspend;
4556 : }
4557 :
4558 4 : RefreshMediaElementsSuspend(aSuspend);
4559 : }
4560 :
4561 : void
4562 4 : nsPIDOMWindowOuter::MaybeNotifyMediaResumedFromBlock(SuspendTypes aSuspend)
4563 : {
4564 4 : if (mMediaSuspend == nsISuspendedTypes::SUSPENDED_BLOCK &&
4565 : aSuspend == nsISuspendedTypes::NONE_SUSPENDED) {
4566 8 : RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
4567 4 : if (service) {
4568 4 : service->NotifyMediaResumedFromBlock(GetOuterWindow());
4569 : }
4570 : }
4571 4 : }
4572 :
4573 : bool
4574 0 : nsPIDOMWindowOuter::GetAudioMuted() const
4575 : {
4576 0 : if (IsInnerWindow()) {
4577 0 : return mOuterWindow->GetAudioMuted();
4578 : }
4579 :
4580 0 : return mAudioMuted;
4581 : }
4582 :
4583 : void
4584 0 : nsPIDOMWindowOuter::SetAudioMuted(bool aMuted)
4585 : {
4586 0 : if (IsInnerWindow()) {
4587 0 : mOuterWindow->SetAudioMuted(aMuted);
4588 0 : return;
4589 : }
4590 :
4591 0 : if (mAudioMuted == aMuted) {
4592 0 : return;
4593 : }
4594 :
4595 0 : mAudioMuted = aMuted;
4596 0 : RefreshMediaElementsVolume();
4597 : }
4598 :
4599 : float
4600 0 : nsPIDOMWindowOuter::GetAudioVolume() const
4601 : {
4602 0 : if (IsInnerWindow()) {
4603 0 : return mOuterWindow->GetAudioVolume();
4604 : }
4605 :
4606 0 : return mAudioVolume;
4607 : }
4608 :
4609 : nsresult
4610 0 : nsPIDOMWindowOuter::SetAudioVolume(float aVolume)
4611 : {
4612 0 : if (IsInnerWindow()) {
4613 0 : return mOuterWindow->SetAudioVolume(aVolume);
4614 : }
4615 :
4616 0 : if (aVolume < 0.0) {
4617 0 : return NS_ERROR_DOM_INDEX_SIZE_ERR;
4618 : }
4619 :
4620 0 : if (mAudioVolume == aVolume) {
4621 0 : return NS_OK;
4622 : }
4623 :
4624 0 : mAudioVolume = aVolume;
4625 0 : RefreshMediaElementsVolume();
4626 0 : return NS_OK;
4627 : }
4628 :
4629 : void
4630 0 : nsPIDOMWindowOuter::RefreshMediaElementsVolume()
4631 : {
4632 0 : RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
4633 0 : if (service) {
4634 0 : service->RefreshAgentsVolume(GetOuterWindow());
4635 : }
4636 0 : }
4637 :
4638 : void
4639 4 : nsPIDOMWindowOuter::RefreshMediaElementsSuspend(SuspendTypes aSuspend)
4640 : {
4641 8 : RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
4642 4 : if (service) {
4643 4 : service->RefreshAgentsSuspend(GetOuterWindow(), aSuspend);
4644 : }
4645 4 : }
4646 :
4647 : bool
4648 4 : nsPIDOMWindowOuter::IsDisposableSuspend(SuspendTypes aSuspend) const
4649 : {
4650 4 : return (aSuspend == nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE ||
4651 4 : aSuspend == nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE);
4652 : }
4653 :
4654 : void
4655 0 : nsPIDOMWindowOuter::SetServiceWorkersTestingEnabled(bool aEnabled)
4656 : {
4657 : // Devtools should only be setting this on the top level window. Its
4658 : // ok if devtools clears the flag on clean up of nested windows, though.
4659 : // It will have no affect.
4660 : #ifdef DEBUG
4661 0 : nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetScriptableTop();
4662 0 : MOZ_ASSERT_IF(aEnabled, this == topWindow);
4663 : #endif
4664 0 : mServiceWorkersTestingEnabled = aEnabled;
4665 0 : }
4666 :
4667 : bool
4668 0 : nsPIDOMWindowOuter::GetServiceWorkersTestingEnabled()
4669 : {
4670 : // Automatically get this setting from the top level window so that nested
4671 : // iframes get the correct devtools setting.
4672 0 : nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetScriptableTop();
4673 0 : if (!topWindow) {
4674 0 : return false;
4675 : }
4676 0 : return topWindow->mServiceWorkersTestingEnabled;
4677 : }
4678 :
4679 : bool
4680 0 : nsPIDOMWindowInner::GetAudioCaptured() const
4681 : {
4682 0 : MOZ_ASSERT(IsInnerWindow());
4683 0 : return mAudioCaptured;
4684 : }
4685 :
4686 : nsresult
4687 0 : nsPIDOMWindowInner::SetAudioCapture(bool aCapture)
4688 : {
4689 0 : MOZ_ASSERT(IsInnerWindow());
4690 :
4691 0 : mAudioCaptured = aCapture;
4692 :
4693 0 : RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
4694 0 : if (service) {
4695 0 : service->SetWindowAudioCaptured(GetOuterWindow(), mWindowID, aCapture);
4696 : }
4697 :
4698 0 : return NS_OK;
4699 : }
4700 :
4701 : // nsISpeechSynthesisGetter
4702 :
4703 : #ifdef MOZ_WEBSPEECH
4704 : SpeechSynthesis*
4705 0 : nsGlobalWindow::GetSpeechSynthesis(ErrorResult& aError)
4706 : {
4707 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
4708 :
4709 0 : if (!mSpeechSynthesis) {
4710 0 : mSpeechSynthesis = new SpeechSynthesis(AsInner());
4711 : }
4712 :
4713 0 : return mSpeechSynthesis;
4714 : }
4715 :
4716 : bool
4717 0 : nsGlobalWindow::HasActiveSpeechSynthesis()
4718 : {
4719 0 : MOZ_ASSERT(IsInnerWindow());
4720 :
4721 0 : if (mSpeechSynthesis) {
4722 0 : return !mSpeechSynthesis->HasEmptyQueue();
4723 : }
4724 :
4725 0 : return false;
4726 : }
4727 :
4728 : #endif
4729 :
4730 : already_AddRefed<nsPIDOMWindowOuter>
4731 184 : nsGlobalWindow::GetParentOuter()
4732 : {
4733 184 : MOZ_RELEASE_ASSERT(IsOuterWindow());
4734 :
4735 184 : if (!mDocShell) {
4736 0 : return nullptr;
4737 : }
4738 :
4739 368 : nsCOMPtr<nsPIDOMWindowOuter> parent;
4740 184 : if (mDocShell->GetIsMozBrowser()) {
4741 0 : parent = AsOuter();
4742 : } else {
4743 184 : parent = GetParent();
4744 : }
4745 :
4746 184 : return parent.forget();
4747 : }
4748 :
4749 : already_AddRefed<nsPIDOMWindowOuter>
4750 0 : nsGlobalWindow::GetParent(ErrorResult& aError)
4751 : {
4752 0 : FORWARD_TO_OUTER_OR_THROW(GetParentOuter, (), aError, nullptr);
4753 : }
4754 :
4755 : /**
4756 : * GetScriptableParent is called when script reads window.parent.
4757 : *
4758 : * In contrast to GetRealParent, GetScriptableParent respects <iframe
4759 : * mozbrowser> boundaries, so if |this| is contained by an <iframe
4760 : * mozbrowser>, we will return |this| as its own parent.
4761 : */
4762 : nsPIDOMWindowOuter*
4763 184 : nsGlobalWindow::GetScriptableParent()
4764 : {
4765 184 : FORWARD_TO_OUTER(GetScriptableParent, (), nullptr);
4766 :
4767 368 : nsCOMPtr<nsPIDOMWindowOuter> parent = GetParentOuter();
4768 184 : return parent.get();
4769 : }
4770 :
4771 : /**
4772 : * Behavies identically to GetScriptableParent extept that it returns null
4773 : * if GetScriptableParent would return this window.
4774 : */
4775 : nsPIDOMWindowOuter*
4776 24 : nsGlobalWindow::GetScriptableParentOrNull()
4777 : {
4778 24 : FORWARD_TO_OUTER(GetScriptableParentOrNull, (), nullptr);
4779 :
4780 24 : nsPIDOMWindowOuter* parent = GetScriptableParent();
4781 24 : return (Cast(parent) == this) ? nullptr : parent;
4782 : }
4783 :
4784 : /**
4785 : * nsPIDOMWindow::GetParent (when called from C++) is just a wrapper around
4786 : * GetRealParent.
4787 : */
4788 : already_AddRefed<nsPIDOMWindowOuter>
4789 315 : nsGlobalWindow::GetParent()
4790 : {
4791 315 : MOZ_ASSERT(IsOuterWindow());
4792 :
4793 315 : if (!mDocShell) {
4794 0 : return nullptr;
4795 : }
4796 :
4797 630 : nsCOMPtr<nsIDocShell> parent;
4798 315 : mDocShell->GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent));
4799 :
4800 315 : if (parent) {
4801 26 : nsCOMPtr<nsPIDOMWindowOuter> win = parent->GetWindow();
4802 13 : return win.forget();
4803 : }
4804 :
4805 604 : nsCOMPtr<nsPIDOMWindowOuter> win(AsOuter());
4806 302 : return win.forget();
4807 : }
4808 :
4809 : static nsresult
4810 172 : GetTopImpl(nsGlobalWindow* aWin, nsPIDOMWindowOuter** aTop, bool aScriptable)
4811 : {
4812 172 : *aTop = nullptr;
4813 :
4814 : // Walk up the parent chain.
4815 :
4816 344 : nsCOMPtr<nsPIDOMWindowOuter> prevParent = aWin->AsOuter();
4817 344 : nsCOMPtr<nsPIDOMWindowOuter> parent = aWin->AsOuter();
4818 181 : do {
4819 181 : if (!parent) {
4820 0 : break;
4821 : }
4822 :
4823 181 : prevParent = parent;
4824 :
4825 362 : nsCOMPtr<nsPIDOMWindowOuter> newParent;
4826 181 : if (aScriptable) {
4827 87 : newParent = parent->GetScriptableParent();
4828 : }
4829 : else {
4830 94 : newParent = parent->GetParent();
4831 : }
4832 :
4833 181 : parent = newParent;
4834 :
4835 : } while (parent != prevParent);
4836 :
4837 172 : if (parent) {
4838 172 : parent.swap(*aTop);
4839 : }
4840 :
4841 344 : return NS_OK;
4842 : }
4843 :
4844 : /**
4845 : * GetScriptableTop is called when script reads window.top.
4846 : *
4847 : * In contrast to GetRealTop, GetScriptableTop respects <iframe mozbrowser>
4848 : * boundaries. If we encounter a window owned by an <iframe mozbrowser> while
4849 : * walking up the window hierarchy, we'll stop and return that window.
4850 : */
4851 : nsPIDOMWindowOuter*
4852 103 : nsGlobalWindow::GetScriptableTop()
4853 : {
4854 103 : FORWARD_TO_OUTER(GetScriptableTop, (), nullptr);
4855 160 : nsCOMPtr<nsPIDOMWindowOuter> window;
4856 80 : GetTopImpl(this, getter_AddRefs(window), /* aScriptable = */ true);
4857 80 : return window.get();
4858 : }
4859 :
4860 : already_AddRefed<nsPIDOMWindowOuter>
4861 92 : nsGlobalWindow::GetTop()
4862 : {
4863 92 : MOZ_ASSERT(IsOuterWindow());
4864 184 : nsCOMPtr<nsPIDOMWindowOuter> window;
4865 92 : GetTopImpl(this, getter_AddRefs(window), /* aScriptable = */ false);
4866 184 : return window.forget();
4867 : }
4868 :
4869 : void
4870 0 : nsGlobalWindow::GetContentOuter(JSContext* aCx,
4871 : JS::MutableHandle<JSObject*> aRetval,
4872 : CallerType aCallerType,
4873 : ErrorResult& aError)
4874 : {
4875 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
4876 :
4877 : nsCOMPtr<nsPIDOMWindowOuter> content =
4878 0 : GetContentInternal(aError, aCallerType);
4879 0 : if (aError.Failed()) {
4880 0 : return;
4881 : }
4882 :
4883 0 : if (content) {
4884 0 : JS::Rooted<JS::Value> val(aCx);
4885 0 : aError = nsContentUtils::WrapNative(aCx, content, &val);
4886 0 : if (aError.Failed()) {
4887 0 : return;
4888 : }
4889 :
4890 0 : aRetval.set(&val.toObject());
4891 0 : return;
4892 : }
4893 :
4894 0 : aRetval.set(nullptr);
4895 0 : return;
4896 : }
4897 :
4898 : void
4899 0 : nsGlobalWindow::GetContent(JSContext* aCx,
4900 : JS::MutableHandle<JSObject*> aRetval,
4901 : CallerType aCallerType,
4902 : ErrorResult& aError)
4903 : {
4904 0 : FORWARD_TO_OUTER_OR_THROW(GetContentOuter,
4905 : (aCx, aRetval, aCallerType, aError), aError, );
4906 : }
4907 :
4908 : already_AddRefed<nsPIDOMWindowOuter>
4909 0 : nsGlobalWindow::GetContentInternal(ErrorResult& aError, CallerType aCallerType)
4910 : {
4911 0 : MOZ_ASSERT(IsOuterWindow());
4912 :
4913 : // First check for a named frame named "content"
4914 : nsCOMPtr<nsPIDOMWindowOuter> domWindow =
4915 0 : GetChildWindow(NS_LITERAL_STRING("content"));
4916 0 : if (domWindow) {
4917 0 : return domWindow.forget();
4918 : }
4919 :
4920 : // If we're contained in <iframe mozbrowser>, then GetContent is the same as
4921 : // window.top.
4922 0 : if (mDocShell && mDocShell->GetIsInMozBrowser()) {
4923 0 : return GetTopOuter();
4924 : }
4925 :
4926 0 : nsCOMPtr<nsIDocShellTreeItem> primaryContent;
4927 0 : if (aCallerType != CallerType::System) {
4928 : // If we're called by non-chrome code, make sure we don't return
4929 : // the primary content window if the calling tab is hidden. In
4930 : // such a case we return the same-type root in the hidden tab,
4931 : // which is "good enough", for now.
4932 0 : nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
4933 :
4934 0 : if (baseWin) {
4935 0 : bool visible = false;
4936 0 : baseWin->GetVisibility(&visible);
4937 :
4938 0 : if (!visible) {
4939 0 : mDocShell->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
4940 : }
4941 : }
4942 : }
4943 :
4944 0 : if (!primaryContent) {
4945 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
4946 0 : if (!treeOwner) {
4947 0 : aError.Throw(NS_ERROR_FAILURE);
4948 0 : return nullptr;
4949 : }
4950 :
4951 0 : treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
4952 : }
4953 :
4954 0 : if (!primaryContent) {
4955 0 : return nullptr;
4956 : }
4957 :
4958 0 : domWindow = primaryContent->GetWindow();
4959 0 : return domWindow.forget();
4960 : }
4961 :
4962 : MozSelfSupport*
4963 0 : nsGlobalWindow::GetMozSelfSupport(ErrorResult& aError)
4964 : {
4965 0 : MOZ_ASSERT(IsInnerWindow());
4966 :
4967 0 : if (mMozSelfSupport) {
4968 0 : return mMozSelfSupport;
4969 : }
4970 :
4971 : // We're called from JS and want to use out existing JSContext (and,
4972 : // importantly, its compartment!) here.
4973 0 : AutoJSContext cx;
4974 0 : GlobalObject global(cx, FastGetGlobalJSObject());
4975 0 : mMozSelfSupport = MozSelfSupport::Constructor(global, cx, aError);
4976 0 : return mMozSelfSupport;
4977 : }
4978 :
4979 : nsresult
4980 0 : nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
4981 : {
4982 0 : if (IsInnerWindow()) {
4983 0 : nsGlobalWindow* outer = GetOuterWindowInternal();
4984 0 : if (!outer) {
4985 0 : NS_WARNING("No outer window available!");
4986 0 : return NS_ERROR_NOT_INITIALIZED;
4987 : }
4988 0 : return outer->GetPrompter(aPrompt);
4989 : }
4990 :
4991 0 : if (!mDocShell)
4992 0 : return NS_ERROR_FAILURE;
4993 :
4994 0 : nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
4995 0 : NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
4996 :
4997 0 : prompter.forget(aPrompt);
4998 0 : return NS_OK;
4999 : }
5000 :
5001 : BarProp*
5002 0 : nsGlobalWindow::GetMenubar(ErrorResult& aError)
5003 : {
5004 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
5005 :
5006 0 : if (!mMenubar) {
5007 0 : mMenubar = new MenubarProp(this);
5008 : }
5009 :
5010 0 : return mMenubar;
5011 : }
5012 :
5013 : BarProp*
5014 5 : nsGlobalWindow::GetToolbar(ErrorResult& aError)
5015 : {
5016 5 : MOZ_RELEASE_ASSERT(IsInnerWindow());
5017 :
5018 5 : if (!mToolbar) {
5019 1 : mToolbar = new ToolbarProp(this);
5020 : }
5021 :
5022 5 : return mToolbar;
5023 : }
5024 :
5025 : BarProp*
5026 0 : nsGlobalWindow::GetLocationbar(ErrorResult& aError)
5027 : {
5028 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
5029 :
5030 0 : if (!mLocationbar) {
5031 0 : mLocationbar = new LocationbarProp(this);
5032 : }
5033 0 : return mLocationbar;
5034 : }
5035 :
5036 : BarProp*
5037 0 : nsGlobalWindow::GetPersonalbar(ErrorResult& aError)
5038 : {
5039 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
5040 :
5041 0 : if (!mPersonalbar) {
5042 0 : mPersonalbar = new PersonalbarProp(this);
5043 : }
5044 0 : return mPersonalbar;
5045 : }
5046 :
5047 : BarProp*
5048 0 : nsGlobalWindow::GetStatusbar(ErrorResult& aError)
5049 : {
5050 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
5051 :
5052 0 : if (!mStatusbar) {
5053 0 : mStatusbar = new StatusbarProp(this);
5054 : }
5055 0 : return mStatusbar;
5056 : }
5057 :
5058 : BarProp*
5059 0 : nsGlobalWindow::GetScrollbars(ErrorResult& aError)
5060 : {
5061 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
5062 :
5063 0 : if (!mScrollbars) {
5064 0 : mScrollbars = new ScrollbarsProp(this);
5065 : }
5066 :
5067 0 : return mScrollbars;
5068 : }
5069 :
5070 : bool
5071 6 : nsGlobalWindow::GetClosedOuter()
5072 : {
5073 6 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5074 :
5075 : // If someone called close(), or if we don't have a docshell, we're closed.
5076 6 : return mIsClosed || !mDocShell;
5077 : }
5078 :
5079 : bool
5080 6 : nsGlobalWindow::GetClosed(ErrorResult& aError)
5081 : {
5082 6 : FORWARD_TO_OUTER_OR_THROW(GetClosedOuter, (), aError, false);
5083 : }
5084 :
5085 : bool
5086 0 : nsGlobalWindow::Closed()
5087 : {
5088 0 : MOZ_ASSERT(IsOuterWindow());
5089 :
5090 0 : return GetClosedOuter();
5091 : }
5092 :
5093 : nsDOMWindowList*
5094 384 : nsGlobalWindow::GetWindowList()
5095 : {
5096 384 : MOZ_ASSERT(IsOuterWindow());
5097 :
5098 384 : if (!mFrames && mDocShell) {
5099 2 : mFrames = new nsDOMWindowList(mDocShell);
5100 : }
5101 :
5102 384 : return mFrames;
5103 : }
5104 :
5105 : already_AddRefed<nsIDOMWindowCollection>
5106 0 : nsGlobalWindow::GetFrames()
5107 : {
5108 0 : FORWARD_TO_OUTER(GetFrames, (), nullptr);
5109 :
5110 0 : nsCOMPtr<nsIDOMWindowCollection> frames = GetWindowList();
5111 0 : return frames.forget();
5112 : }
5113 :
5114 : already_AddRefed<nsPIDOMWindowOuter>
5115 0 : nsGlobalWindow::IndexedGetterOuter(uint32_t aIndex)
5116 : {
5117 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5118 :
5119 0 : nsDOMWindowList* windows = GetWindowList();
5120 0 : NS_ENSURE_TRUE(windows, nullptr);
5121 :
5122 0 : return windows->IndexedGetter(aIndex);
5123 : }
5124 :
5125 : already_AddRefed<nsPIDOMWindowOuter>
5126 0 : nsGlobalWindow::IndexedGetter(uint32_t aIndex)
5127 : {
5128 0 : FORWARD_TO_OUTER(IndexedGetterOuter, (aIndex), nullptr);
5129 0 : MOZ_CRASH();
5130 : }
5131 :
5132 : bool
5133 3150 : nsGlobalWindow::DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
5134 : JS::Handle<jsid> aId,
5135 : JS::MutableHandle<JS::PropertyDescriptor> aDesc)
5136 : {
5137 3150 : MOZ_ASSERT(IsInnerWindow());
5138 :
5139 : // Note: Keep this in sync with MayResolve.
5140 :
5141 : // Note: The infallibleInit call in GlobalResolve depends on this check.
5142 3150 : if (!JSID_IS_STRING(aId)) {
5143 0 : return true;
5144 : }
5145 :
5146 : bool found;
5147 3150 : if (!WebIDLGlobalNameHash::DefineIfEnabled(aCx, aObj, aId, aDesc, &found)) {
5148 0 : return false;
5149 : }
5150 :
5151 3150 : if (found) {
5152 20 : return true;
5153 : }
5154 :
5155 3130 : nsresult rv = nsWindowSH::GlobalResolve(this, aCx, aObj, aId, aDesc);
5156 3130 : if (NS_FAILED(rv)) {
5157 0 : return Throw(aCx, rv);
5158 : }
5159 :
5160 3130 : return true;
5161 : }
5162 :
5163 : /* static */
5164 : bool
5165 8 : nsGlobalWindow::MayResolve(jsid aId)
5166 : {
5167 : // Note: This function does not fail and may not have any side-effects.
5168 : // Note: Keep this in sync with DoResolve.
5169 8 : if (!JSID_IS_STRING(aId)) {
5170 0 : return false;
5171 : }
5172 :
5173 8 : if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) {
5174 0 : return true;
5175 : }
5176 :
5177 32 : if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS) ||
5178 24 : aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS_CLASS)) {
5179 : // We only resolve .controllers/.Controllers in release builds and on non-chrome
5180 : // windows, but let's not worry about any of that stuff.
5181 0 : return true;
5182 : }
5183 :
5184 8 : if (WebIDLGlobalNameHash::MayResolve(aId)) {
5185 8 : return true;
5186 : }
5187 :
5188 0 : nsScriptNameSpaceManager *nameSpaceManager = PeekNameSpaceManager();
5189 0 : if (!nameSpaceManager) {
5190 : // Really shouldn't happen. Fail safe.
5191 0 : return true;
5192 : }
5193 :
5194 0 : nsAutoString name;
5195 0 : AssignJSFlatString(name, JSID_TO_FLAT_STRING(aId));
5196 :
5197 0 : return nameSpaceManager->LookupName(name);
5198 : }
5199 :
5200 : void
5201 0 : nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, JS::AutoIdVector& aNames,
5202 : bool aEnumerableOnly, ErrorResult& aRv)
5203 : {
5204 0 : if (aEnumerableOnly) {
5205 : // The names we would return from here get defined on the window via one of
5206 : // two codepaths. The ones coming from the WebIDLGlobalNameHash will end up
5207 : // in the DefineConstructor function in BindingUtils, which always defines
5208 : // things as non-enumerable. The ones coming from the script namespace
5209 : // manager get defined by nsDOMClassInfo::PostCreatePrototype calling
5210 : // ResolvePrototype and using the resulting descriptot to define the
5211 : // property. ResolvePrototype always passes 0 to the FillPropertyDescriptor
5212 : // for the property attributes, so all those are non-enumerable as well.
5213 : //
5214 : // So in the aEnumerableOnly case we have nothing to do.
5215 0 : return;
5216 : }
5217 :
5218 0 : MOZ_ASSERT(IsInnerWindow());
5219 : // "Components" is marked as enumerable but only resolved on demand :-/.
5220 : //aNames.AppendElement(NS_LITERAL_STRING("Components"));
5221 :
5222 0 : nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
5223 0 : if (nameSpaceManager) {
5224 0 : JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
5225 :
5226 : // There are actually two ways we can get called here: For normal
5227 : // enumeration or for Xray enumeration. In the latter case, we want to
5228 : // return all possible WebIDL names, because we don't really support
5229 : // deleting these names off our Xray; trying to resolve them will just make
5230 : // them come back. In the former case, we want to avoid returning deleted
5231 : // names. But the JS engine already knows about the non-deleted
5232 : // already-resolved names, so we can just return the so-far-unresolved ones.
5233 : //
5234 : // We can tell which case we're in by whether aCx is in our wrapper's
5235 : // compartment. If not, we're in the Xray case.
5236 : WebIDLGlobalNameHash::NameType nameType =
5237 0 : js::IsObjectInContextCompartment(wrapper, aCx) ?
5238 : WebIDLGlobalNameHash::UnresolvedNamesOnly :
5239 0 : WebIDLGlobalNameHash::AllNames;
5240 0 : if (!WebIDLGlobalNameHash::GetNames(aCx, wrapper, nameType, aNames)) {
5241 0 : aRv.NoteJSContextException(aCx);
5242 : }
5243 :
5244 0 : for (auto i = nameSpaceManager->GlobalNameIter(); !i.Done(); i.Next()) {
5245 0 : const GlobalNameMapEntry* entry = i.Get();
5246 0 : if (nsWindowSH::NameStructEnabled(aCx, this, entry->mKey,
5247 : entry->mGlobalName)) {
5248 : // Just append all of these; even if they get deleted our resolve hook
5249 : // just goes ahead and recreates them.
5250 0 : JSString* str = JS_AtomizeUCStringN(aCx,
5251 : entry->mKey.BeginReading(),
5252 0 : entry->mKey.Length());
5253 0 : if (!str || !aNames.append(NON_INTEGER_ATOM_TO_JSID(str))) {
5254 0 : aRv.NoteJSContextException(aCx);
5255 0 : return;
5256 : }
5257 : }
5258 : }
5259 : }
5260 : }
5261 :
5262 : /* static */ bool
5263 28 : nsGlobalWindow::IsPrivilegedChromeWindow(JSContext* aCx, JSObject* aObj)
5264 : {
5265 : // For now, have to deal with XPConnect objects here.
5266 44 : return xpc::WindowOrNull(aObj)->IsChromeWindow() &&
5267 44 : nsContentUtils::ObjectPrincipal(aObj) == nsContentUtils::GetSystemPrincipal();
5268 : }
5269 :
5270 : /* static */ bool
5271 7 : nsGlobalWindow::IsShowModalDialogEnabled(JSContext*, JSObject*)
5272 : {
5273 : static bool sAddedPrefCache = false;
5274 : static bool sIsDisabled;
5275 : static const char sShowModalDialogPref[] = "dom.disable_window_showModalDialog";
5276 :
5277 7 : if (!sAddedPrefCache) {
5278 2 : Preferences::AddBoolVarCache(&sIsDisabled, sShowModalDialogPref, false);
5279 2 : sAddedPrefCache = true;
5280 : }
5281 :
5282 7 : return !sIsDisabled && !XRE_IsContentProcess();
5283 : }
5284 :
5285 : /* static */ bool
5286 7 : nsGlobalWindow::IsRequestIdleCallbackEnabled(JSContext* aCx, JSObject* aObj)
5287 : {
5288 : // The requestIdleCallback should always be enabled for system code.
5289 7 : return nsContentUtils::RequestIdleCallbackEnabled() ||
5290 7 : nsContentUtils::IsSystemCaller(aCx);
5291 : }
5292 :
5293 : nsIDOMOfflineResourceList*
5294 0 : nsGlobalWindow::GetApplicationCache(ErrorResult& aError)
5295 : {
5296 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
5297 :
5298 0 : if (!mApplicationCache) {
5299 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
5300 0 : if (!webNav || !mDoc) {
5301 0 : aError.Throw(NS_ERROR_FAILURE);
5302 0 : return nullptr;
5303 : }
5304 :
5305 0 : nsCOMPtr<nsIURI> uri;
5306 0 : aError = webNav->GetCurrentURI(getter_AddRefs(uri));
5307 0 : if (aError.Failed()) {
5308 0 : return nullptr;
5309 : }
5310 :
5311 0 : nsCOMPtr<nsIURI> manifestURI;
5312 0 : nsContentUtils::GetOfflineAppManifest(mDoc, getter_AddRefs(manifestURI));
5313 :
5314 : RefPtr<nsDOMOfflineResourceList> applicationCache =
5315 0 : new nsDOMOfflineResourceList(manifestURI, uri, mDoc->NodePrincipal(),
5316 0 : AsInner());
5317 :
5318 0 : applicationCache->Init();
5319 :
5320 0 : mApplicationCache = applicationCache;
5321 : }
5322 :
5323 0 : return mApplicationCache;
5324 : }
5325 :
5326 : already_AddRefed<nsIDOMOfflineResourceList>
5327 0 : nsGlobalWindow::GetApplicationCache()
5328 : {
5329 0 : FORWARD_TO_INNER(GetApplicationCache, (), nullptr);
5330 :
5331 0 : ErrorResult dummy;
5332 : nsCOMPtr<nsIDOMOfflineResourceList> applicationCache =
5333 0 : GetApplicationCache(dummy);
5334 0 : dummy.SuppressException();
5335 0 : return applicationCache.forget();
5336 : }
5337 :
5338 : Crypto*
5339 0 : nsGlobalWindow::GetCrypto(ErrorResult& aError)
5340 : {
5341 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
5342 :
5343 0 : if (!mCrypto) {
5344 0 : mCrypto = new Crypto();
5345 0 : mCrypto->Init(this);
5346 : }
5347 0 : return mCrypto;
5348 : }
5349 :
5350 : mozilla::dom::U2F*
5351 0 : nsGlobalWindow::GetU2f(ErrorResult& aError)
5352 : {
5353 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
5354 :
5355 0 : if (!mU2F) {
5356 0 : RefPtr<U2F> u2f = new U2F();
5357 0 : u2f->Init(AsInner(), aError);
5358 0 : if (NS_WARN_IF(aError.Failed())) {
5359 0 : return nullptr;
5360 : }
5361 :
5362 0 : mU2F = u2f;
5363 : }
5364 0 : return mU2F;
5365 : }
5366 :
5367 : nsIControllers*
5368 15 : nsGlobalWindow::GetControllersOuter(ErrorResult& aError)
5369 : {
5370 15 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5371 :
5372 15 : if (!mControllers) {
5373 : nsresult rv;
5374 2 : mControllers = do_CreateInstance(kXULControllersCID, &rv);
5375 2 : if (NS_FAILED(rv)) {
5376 0 : aError.Throw(rv);
5377 0 : return nullptr;
5378 : }
5379 :
5380 : // Add in the default controller
5381 4 : nsCOMPtr<nsIController> controller = do_CreateInstance(
5382 4 : NS_WINDOWCONTROLLER_CONTRACTID, &rv);
5383 2 : if (NS_FAILED(rv)) {
5384 0 : aError.Throw(rv);
5385 0 : return nullptr;
5386 : }
5387 :
5388 2 : mControllers->InsertControllerAt(0, controller);
5389 4 : nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
5390 2 : if (!controllerContext) {
5391 0 : aError.Throw(NS_ERROR_FAILURE);
5392 0 : return nullptr;
5393 : }
5394 :
5395 2 : controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
5396 : }
5397 :
5398 15 : return mControllers;
5399 : }
5400 :
5401 : nsIControllers*
5402 15 : nsGlobalWindow::GetControllers(ErrorResult& aError)
5403 : {
5404 15 : FORWARD_TO_OUTER_OR_THROW(GetControllersOuter, (aError), aError, nullptr);
5405 : }
5406 :
5407 : nsresult
5408 30 : nsGlobalWindow::GetControllers(nsIControllers** aResult)
5409 : {
5410 30 : FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED);
5411 :
5412 30 : ErrorResult rv;
5413 30 : nsCOMPtr<nsIControllers> controllers = GetControllers(rv);
5414 15 : controllers.forget(aResult);
5415 :
5416 15 : return rv.StealNSResult();
5417 : }
5418 :
5419 : nsPIDOMWindowOuter*
5420 19 : nsGlobalWindow::GetSanitizedOpener(nsPIDOMWindowOuter* aOpener)
5421 : {
5422 19 : if (!aOpener) {
5423 19 : return nullptr;
5424 : }
5425 :
5426 0 : nsGlobalWindow* win = nsGlobalWindow::Cast(aOpener);
5427 :
5428 : // First, ensure that we're not handing back a chrome window to content:
5429 0 : if (win->IsChromeWindow()) {
5430 0 : return nullptr;
5431 : }
5432 :
5433 : // We don't want to reveal the opener if the opener is a mail window,
5434 : // because opener can be used to spoof the contents of a message (bug 105050).
5435 : // So, we look in the opener's root docshell to see if it's a mail window.
5436 0 : nsCOMPtr<nsIDocShell> openerDocShell = aOpener->GetDocShell();
5437 :
5438 0 : if (openerDocShell) {
5439 0 : nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
5440 0 : openerDocShell->GetRootTreeItem(getter_AddRefs(openerRootItem));
5441 0 : nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
5442 0 : if (openerRootDocShell) {
5443 : uint32_t appType;
5444 0 : nsresult rv = openerRootDocShell->GetAppType(&appType);
5445 0 : if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
5446 0 : return aOpener;
5447 : }
5448 : }
5449 : }
5450 :
5451 0 : return nullptr;
5452 : }
5453 :
5454 : nsPIDOMWindowOuter*
5455 0 : nsGlobalWindow::GetOpenerWindowOuter()
5456 : {
5457 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5458 :
5459 0 : nsCOMPtr<nsPIDOMWindowOuter> opener = do_QueryReferent(mOpener);
5460 :
5461 0 : if (!opener) {
5462 0 : return nullptr;
5463 : }
5464 :
5465 : // First, check if we were called from a privileged chrome script
5466 0 : if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
5467 : // Catch the case where we're chrome but the opener is not...
5468 0 : if (GetPrincipal() == nsContentUtils::GetSystemPrincipal() &&
5469 0 : nsGlobalWindow::Cast(opener)->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
5470 0 : return nullptr;
5471 : }
5472 0 : return opener;
5473 : }
5474 :
5475 0 : return GetSanitizedOpener(opener);
5476 : }
5477 :
5478 : nsPIDOMWindowOuter*
5479 0 : nsGlobalWindow::GetOpenerWindow(ErrorResult& aError)
5480 : {
5481 0 : FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter, (), aError, nullptr);
5482 : }
5483 :
5484 : void
5485 0 : nsGlobalWindow::GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
5486 : ErrorResult& aError)
5487 : {
5488 0 : MOZ_ASSERT(IsInnerWindow());
5489 :
5490 0 : nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindow(aError);
5491 0 : if (aError.Failed() || !opener) {
5492 0 : aRetval.setNull();
5493 0 : return;
5494 : }
5495 :
5496 0 : aError = nsContentUtils::WrapNative(aCx, opener, aRetval);
5497 : }
5498 :
5499 : already_AddRefed<nsPIDOMWindowOuter>
5500 0 : nsGlobalWindow::GetOpener()
5501 : {
5502 0 : FORWARD_TO_OUTER(GetOpener, (), nullptr);
5503 :
5504 0 : nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindowOuter();
5505 0 : return opener.forget();
5506 : }
5507 :
5508 : void
5509 0 : nsGlobalWindow::SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
5510 : ErrorResult& aError)
5511 : {
5512 : // Check if we were called from a privileged chrome script. If not, and if
5513 : // aOpener is not null, just define aOpener on our inner window's JS object,
5514 : // wrapped into the current compartment so that for Xrays we define on the
5515 : // Xray expando object, but don't set it on the outer window, so that it'll
5516 : // get reset on navigation. This is just like replaceable properties, but
5517 : // we're not quite readonly.
5518 0 : if (!aOpener.isNull() && !nsContentUtils::IsCallerChrome()) {
5519 0 : RedefineProperty(aCx, "opener", aOpener, aError);
5520 0 : return;
5521 : }
5522 :
5523 0 : if (!aOpener.isObjectOrNull()) {
5524 : // Chrome code trying to set some random value as opener
5525 0 : aError.Throw(NS_ERROR_INVALID_ARG);
5526 0 : return;
5527 : }
5528 :
5529 0 : nsPIDOMWindowInner* win = nullptr;
5530 0 : if (aOpener.isObject()) {
5531 0 : JSObject* unwrapped = js::CheckedUnwrap(&aOpener.toObject(),
5532 0 : /* stopAtWindowProxy = */ false);
5533 0 : if (!unwrapped) {
5534 0 : aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
5535 0 : return;
5536 : }
5537 :
5538 0 : auto* globalWindow = xpc::WindowOrNull(unwrapped);
5539 0 : if (!globalWindow) {
5540 : // Wasn't a window
5541 0 : aError.Throw(NS_ERROR_INVALID_ARG);
5542 0 : return;
5543 : }
5544 :
5545 0 : win = globalWindow->AsInner();
5546 : }
5547 :
5548 0 : nsPIDOMWindowOuter* outer = nullptr;
5549 0 : if (win) {
5550 0 : if (!win->IsCurrentInnerWindow()) {
5551 0 : aError.Throw(NS_ERROR_FAILURE);
5552 0 : return;
5553 : }
5554 0 : outer = win->GetOuterWindow();
5555 : }
5556 :
5557 0 : SetOpenerWindow(outer, false);
5558 : }
5559 :
5560 : void
5561 0 : nsGlobalWindow::GetStatusOuter(nsAString& aStatus)
5562 : {
5563 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5564 :
5565 0 : aStatus = mStatus;
5566 0 : }
5567 :
5568 : void
5569 0 : nsGlobalWindow::GetStatus(nsAString& aStatus, ErrorResult& aError)
5570 : {
5571 0 : FORWARD_TO_OUTER_OR_THROW(GetStatusOuter, (aStatus), aError, );
5572 : }
5573 :
5574 : void
5575 8 : nsGlobalWindow::SetStatusOuter(const nsAString& aStatus)
5576 : {
5577 8 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5578 :
5579 8 : mStatus = aStatus;
5580 :
5581 : /*
5582 : * If caller is not chrome and dom.disable_window_status_change is true,
5583 : * prevent propagating window.status to the UI by exiting early
5584 : */
5585 :
5586 8 : if (!CanSetProperty("dom.disable_window_status_change")) {
5587 0 : return;
5588 : }
5589 :
5590 16 : nsCOMPtr<nsIWebBrowserChrome> browserChrome = GetWebBrowserChrome();
5591 8 : if (browserChrome) {
5592 16 : browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
5593 16 : PromiseFlatString(aStatus).get());
5594 : }
5595 : }
5596 :
5597 : void
5598 0 : nsGlobalWindow::SetStatus(const nsAString& aStatus, ErrorResult& aError)
5599 : {
5600 0 : FORWARD_TO_OUTER_OR_THROW(SetStatusOuter, (aStatus), aError, );
5601 : }
5602 :
5603 : void
5604 0 : nsGlobalWindow::GetNameOuter(nsAString& aName)
5605 : {
5606 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5607 :
5608 0 : if (mDocShell) {
5609 0 : mDocShell->GetName(aName);
5610 : }
5611 0 : }
5612 :
5613 : void
5614 0 : nsGlobalWindow::GetName(nsAString& aName, ErrorResult& aError)
5615 : {
5616 0 : FORWARD_TO_OUTER_OR_THROW(GetNameOuter, (aName), aError, );
5617 : }
5618 :
5619 : void
5620 0 : nsGlobalWindow::SetNameOuter(const nsAString& aName, mozilla::ErrorResult& aError)
5621 : {
5622 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5623 :
5624 0 : if (mDocShell) {
5625 0 : aError = mDocShell->SetName(aName);
5626 : }
5627 0 : }
5628 :
5629 : void
5630 0 : nsGlobalWindow::SetName(const nsAString& aName, mozilla::ErrorResult& aError)
5631 : {
5632 0 : FORWARD_TO_OUTER_OR_THROW(SetNameOuter, (aName, aError), aError, );
5633 : }
5634 :
5635 : // Helper functions used by many methods below.
5636 : int32_t
5637 0 : nsGlobalWindow::DevToCSSIntPixels(int32_t px)
5638 : {
5639 0 : if (!mDocShell)
5640 0 : return px; // assume 1:1
5641 :
5642 0 : RefPtr<nsPresContext> presContext;
5643 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
5644 0 : if (!presContext)
5645 0 : return px;
5646 :
5647 0 : return presContext->DevPixelsToIntCSSPixels(px);
5648 : }
5649 :
5650 : int32_t
5651 0 : nsGlobalWindow::CSSToDevIntPixels(int32_t px)
5652 : {
5653 0 : if (!mDocShell)
5654 0 : return px; // assume 1:1
5655 :
5656 0 : RefPtr<nsPresContext> presContext;
5657 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
5658 0 : if (!presContext)
5659 0 : return px;
5660 :
5661 0 : return presContext->CSSPixelsToDevPixels(px);
5662 : }
5663 :
5664 : nsIntSize
5665 0 : nsGlobalWindow::DevToCSSIntPixels(nsIntSize px)
5666 : {
5667 0 : if (!mDocShell)
5668 0 : return px; // assume 1:1
5669 :
5670 0 : RefPtr<nsPresContext> presContext;
5671 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
5672 0 : if (!presContext)
5673 0 : return px;
5674 :
5675 0 : return nsIntSize(
5676 : presContext->DevPixelsToIntCSSPixels(px.width),
5677 0 : presContext->DevPixelsToIntCSSPixels(px.height));
5678 : }
5679 :
5680 : nsIntSize
5681 0 : nsGlobalWindow::CSSToDevIntPixels(nsIntSize px)
5682 : {
5683 0 : if (!mDocShell)
5684 0 : return px; // assume 1:1
5685 :
5686 0 : RefPtr<nsPresContext> presContext;
5687 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
5688 0 : if (!presContext)
5689 0 : return px;
5690 :
5691 0 : return nsIntSize(
5692 : presContext->CSSPixelsToDevPixels(px.width),
5693 0 : presContext->CSSPixelsToDevPixels(px.height));
5694 : }
5695 :
5696 : nsresult
5697 0 : nsGlobalWindow::GetInnerSize(CSSIntSize& aSize)
5698 : {
5699 0 : MOZ_ASSERT(IsOuterWindow());
5700 :
5701 0 : EnsureSizeAndPositionUpToDate();
5702 :
5703 0 : NS_ENSURE_STATE(mDocShell);
5704 :
5705 0 : RefPtr<nsPresContext> presContext;
5706 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
5707 0 : RefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
5708 :
5709 0 : if (!presContext || !presShell) {
5710 0 : aSize = CSSIntSize(0, 0);
5711 0 : return NS_OK;
5712 : }
5713 :
5714 : /*
5715 : * On platforms with resolution-based zooming, the CSS viewport
5716 : * and visual viewport may not be the same. The inner size should
5717 : * be the visual viewport, but we fall back to the CSS viewport
5718 : * if it is not set.
5719 : */
5720 0 : if (presShell->IsScrollPositionClampingScrollPortSizeSet()) {
5721 : aSize = CSSIntRect::FromAppUnitsRounded(
5722 0 : presShell->GetScrollPositionClampingScrollPortSize());
5723 : } else {
5724 0 : RefPtr<nsViewManager> viewManager = presShell->GetViewManager();
5725 0 : if (viewManager) {
5726 0 : viewManager->FlushDelayedResize(false);
5727 : }
5728 :
5729 : aSize = CSSIntRect::FromAppUnitsRounded(
5730 0 : presContext->GetVisibleArea().Size());
5731 : }
5732 0 : return NS_OK;
5733 : }
5734 :
5735 : int32_t
5736 0 : nsGlobalWindow::GetInnerWidthOuter(ErrorResult& aError)
5737 : {
5738 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5739 :
5740 0 : CSSIntSize size;
5741 0 : aError = GetInnerSize(size);
5742 0 : return size.width;
5743 : }
5744 :
5745 : int32_t
5746 0 : nsGlobalWindow::GetInnerWidth(CallerType aCallerType, ErrorResult& aError)
5747 : {
5748 : // We ignore aCallerType; we only have that argument because some other things
5749 : // called by GetReplaceableWindowCoord need it. If this ever changes, fix
5750 : // nsresult nsGlobalWindow::GetInnerWidth(int32_t* aInnerWidth)
5751 : // to actually take a useful CallerType and pass it in here.
5752 0 : FORWARD_TO_OUTER_OR_THROW(GetInnerWidthOuter, (aError), aError, 0);
5753 : }
5754 :
5755 : void
5756 0 : nsGlobalWindow::GetInnerWidth(JSContext* aCx,
5757 : JS::MutableHandle<JS::Value> aValue,
5758 : CallerType aCallerType,
5759 : ErrorResult& aError)
5760 : {
5761 : GetReplaceableWindowCoord(aCx, &nsGlobalWindow::GetInnerWidth, aValue,
5762 0 : aCallerType, aError);
5763 0 : }
5764 :
5765 : nsresult
5766 0 : nsGlobalWindow::GetInnerWidth(int32_t* aInnerWidth)
5767 : {
5768 0 : FORWARD_TO_INNER(GetInnerWidth, (aInnerWidth), NS_ERROR_UNEXPECTED);
5769 :
5770 0 : ErrorResult rv;
5771 : // Callee doesn't care about the caller type, but play it safe.
5772 0 : *aInnerWidth = GetInnerWidth(CallerType::NonSystem, rv);
5773 :
5774 0 : return rv.StealNSResult();
5775 : }
5776 :
5777 : void
5778 0 : nsGlobalWindow::SetInnerWidthOuter(int32_t aInnerWidth,
5779 : CallerType aCallerType,
5780 : ErrorResult& aError)
5781 : {
5782 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5783 :
5784 0 : if (!mDocShell) {
5785 0 : aError.Throw(NS_ERROR_UNEXPECTED);
5786 0 : return;
5787 : }
5788 :
5789 0 : CheckSecurityWidthAndHeight(&aInnerWidth, nullptr, aCallerType);
5790 :
5791 0 : RefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
5792 :
5793 0 : if (presShell && presShell->GetIsViewportOverridden())
5794 : {
5795 0 : nscoord height = 0;
5796 :
5797 0 : RefPtr<nsPresContext> presContext;
5798 0 : presContext = presShell->GetPresContext();
5799 :
5800 0 : nsRect shellArea = presContext->GetVisibleArea();
5801 0 : height = shellArea.height;
5802 0 : SetCSSViewportWidthAndHeight(nsPresContext::CSSPixelsToAppUnits(aInnerWidth),
5803 0 : height);
5804 0 : return;
5805 : }
5806 :
5807 0 : int32_t height = 0;
5808 0 : int32_t unused = 0;
5809 :
5810 0 : nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
5811 0 : docShellAsWin->GetSize(&unused, &height);
5812 0 : aError = SetDocShellWidthAndHeight(CSSToDevIntPixels(aInnerWidth), height);
5813 : }
5814 :
5815 : void
5816 0 : nsGlobalWindow::SetInnerWidth(int32_t aInnerWidth, CallerType aCallerType,
5817 : ErrorResult& aError)
5818 : {
5819 0 : FORWARD_TO_OUTER_OR_THROW(SetInnerWidthOuter,
5820 : (aInnerWidth, aCallerType, aError), aError, );
5821 : }
5822 :
5823 : void
5824 0 : nsGlobalWindow::SetInnerWidth(JSContext* aCx, JS::Handle<JS::Value> aValue,
5825 : CallerType aCallerType,
5826 : ErrorResult& aError)
5827 : {
5828 : SetReplaceableWindowCoord(aCx, &nsGlobalWindow::SetInnerWidth,
5829 0 : aValue, "innerWidth", aCallerType, aError);
5830 0 : }
5831 :
5832 : int32_t
5833 0 : nsGlobalWindow::GetInnerHeightOuter(ErrorResult& aError)
5834 : {
5835 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5836 :
5837 0 : CSSIntSize size;
5838 0 : aError = GetInnerSize(size);
5839 0 : return size.height;
5840 : }
5841 :
5842 : int32_t
5843 0 : nsGlobalWindow::GetInnerHeight(CallerType aCallerType, ErrorResult& aError)
5844 : {
5845 : // We ignore aCallerType; we only have that argument because some other things
5846 : // called by GetReplaceableWindowCoord need it. If this ever changes, fix
5847 : // nsresult nsGlobalWindow::GetInnerHeight(int32_t* aInnerWidth)
5848 : // to actually take a useful CallerType and pass it in here.
5849 0 : FORWARD_TO_OUTER_OR_THROW(GetInnerHeightOuter, (aError), aError, 0);
5850 : }
5851 :
5852 : void
5853 0 : nsGlobalWindow::GetInnerHeight(JSContext* aCx,
5854 : JS::MutableHandle<JS::Value> aValue,
5855 : CallerType aCallerType,
5856 : ErrorResult& aError)
5857 : {
5858 : GetReplaceableWindowCoord(aCx, &nsGlobalWindow::GetInnerHeight, aValue,
5859 0 : aCallerType, aError);
5860 0 : }
5861 :
5862 : nsresult
5863 0 : nsGlobalWindow::GetInnerHeight(int32_t* aInnerHeight)
5864 : {
5865 0 : FORWARD_TO_INNER(GetInnerHeight, (aInnerHeight), NS_ERROR_UNEXPECTED);
5866 :
5867 0 : ErrorResult rv;
5868 : // Callee doesn't care about the caller type, but play it safe.
5869 0 : *aInnerHeight = GetInnerHeight(CallerType::NonSystem, rv);
5870 :
5871 0 : return rv.StealNSResult();
5872 : }
5873 :
5874 : void
5875 0 : nsGlobalWindow::SetInnerHeightOuter(int32_t aInnerHeight,
5876 : CallerType aCallerType,
5877 : ErrorResult& aError)
5878 : {
5879 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5880 :
5881 0 : if (!mDocShell) {
5882 0 : aError.Throw(NS_ERROR_UNEXPECTED);
5883 0 : return;
5884 : }
5885 :
5886 0 : RefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
5887 :
5888 0 : if (presShell && presShell->GetIsViewportOverridden())
5889 : {
5890 0 : RefPtr<nsPresContext> presContext;
5891 0 : presContext = presShell->GetPresContext();
5892 :
5893 0 : nsRect shellArea = presContext->GetVisibleArea();
5894 0 : nscoord height = aInnerHeight;
5895 0 : nscoord width = shellArea.width;
5896 0 : CheckSecurityWidthAndHeight(nullptr, &height, aCallerType);
5897 0 : SetCSSViewportWidthAndHeight(width,
5898 0 : nsPresContext::CSSPixelsToAppUnits(height));
5899 0 : return;
5900 : }
5901 :
5902 0 : int32_t height = 0;
5903 0 : int32_t width = 0;
5904 :
5905 0 : nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
5906 0 : docShellAsWin->GetSize(&width, &height);
5907 0 : CheckSecurityWidthAndHeight(nullptr, &aInnerHeight, aCallerType);
5908 0 : aError = SetDocShellWidthAndHeight(width, CSSToDevIntPixels(aInnerHeight));
5909 : }
5910 :
5911 : void
5912 0 : nsGlobalWindow::SetInnerHeight(int32_t aInnerHeight,
5913 : CallerType aCallerType,
5914 : ErrorResult& aError)
5915 : {
5916 0 : FORWARD_TO_OUTER_OR_THROW(SetInnerHeightOuter,
5917 : (aInnerHeight, aCallerType, aError), aError, );
5918 : }
5919 :
5920 : void
5921 0 : nsGlobalWindow::SetInnerHeight(JSContext* aCx, JS::Handle<JS::Value> aValue,
5922 : CallerType aCallerType, ErrorResult& aError)
5923 : {
5924 : SetReplaceableWindowCoord(aCx, &nsGlobalWindow::SetInnerHeight,
5925 0 : aValue, "innerHeight", aCallerType, aError);
5926 0 : }
5927 :
5928 : nsIntSize
5929 0 : nsGlobalWindow::GetOuterSize(CallerType aCallerType, ErrorResult& aError)
5930 : {
5931 0 : MOZ_ASSERT(IsOuterWindow());
5932 :
5933 0 : if (nsContentUtils::ResistFingerprinting(aCallerType)) {
5934 0 : CSSIntSize size;
5935 0 : aError = GetInnerSize(size);
5936 0 : return nsIntSize(size.width, size.height);
5937 : }
5938 :
5939 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5940 0 : if (!treeOwnerAsWin) {
5941 0 : aError.Throw(NS_ERROR_FAILURE);
5942 0 : return nsIntSize(0, 0);
5943 : }
5944 :
5945 0 : nsIntSize sizeDevPixels;
5946 0 : aError = treeOwnerAsWin->GetSize(&sizeDevPixels.width, &sizeDevPixels.height);
5947 0 : if (aError.Failed()) {
5948 0 : return nsIntSize();
5949 : }
5950 :
5951 0 : return DevToCSSIntPixels(sizeDevPixels);
5952 : }
5953 :
5954 : int32_t
5955 0 : nsGlobalWindow::GetOuterWidthOuter(CallerType aCallerType, ErrorResult& aError)
5956 : {
5957 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5958 0 : return GetOuterSize(aCallerType, aError).width;
5959 : }
5960 :
5961 : int32_t
5962 0 : nsGlobalWindow::GetOuterWidth(CallerType aCallerType, ErrorResult& aError)
5963 : {
5964 0 : FORWARD_TO_OUTER_OR_THROW(GetOuterWidthOuter, (aCallerType, aError),
5965 : aError, 0);
5966 : }
5967 :
5968 : void
5969 0 : nsGlobalWindow::GetOuterWidth(JSContext* aCx,
5970 : JS::MutableHandle<JS::Value> aValue,
5971 : CallerType aCallerType,
5972 : ErrorResult& aError)
5973 : {
5974 : GetReplaceableWindowCoord(aCx, &nsGlobalWindow::GetOuterWidth, aValue,
5975 0 : aCallerType, aError);
5976 0 : }
5977 :
5978 : int32_t
5979 0 : nsGlobalWindow::GetOuterHeightOuter(CallerType aCallerType, ErrorResult& aError)
5980 : {
5981 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
5982 0 : return GetOuterSize(aCallerType, aError).height;
5983 : }
5984 :
5985 : int32_t
5986 0 : nsGlobalWindow::GetOuterHeight(CallerType aCallerType, ErrorResult& aError)
5987 : {
5988 0 : FORWARD_TO_OUTER_OR_THROW(GetOuterHeightOuter, (aCallerType, aError),
5989 : aError, 0);
5990 : }
5991 :
5992 : void
5993 0 : nsGlobalWindow::GetOuterHeight(JSContext* aCx,
5994 : JS::MutableHandle<JS::Value> aValue,
5995 : CallerType aCallerType,
5996 : ErrorResult& aError)
5997 : {
5998 : GetReplaceableWindowCoord(aCx, &nsGlobalWindow::GetOuterHeight, aValue,
5999 0 : aCallerType, aError);
6000 0 : }
6001 :
6002 : void
6003 0 : nsGlobalWindow::SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth,
6004 : CallerType aCallerType, ErrorResult& aError)
6005 : {
6006 0 : MOZ_ASSERT(IsOuterWindow());
6007 :
6008 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6009 0 : if (!treeOwnerAsWin) {
6010 0 : aError.Throw(NS_ERROR_FAILURE);
6011 0 : return;
6012 : }
6013 :
6014 0 : CheckSecurityWidthAndHeight(aIsWidth ? &aLengthCSSPixels : nullptr,
6015 : aIsWidth ? nullptr : &aLengthCSSPixels,
6016 0 : aCallerType);
6017 :
6018 : int32_t width, height;
6019 0 : aError = treeOwnerAsWin->GetSize(&width, &height);
6020 0 : if (aError.Failed()) {
6021 0 : return;
6022 : }
6023 :
6024 0 : int32_t lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
6025 0 : if (aIsWidth) {
6026 0 : width = lengthDevPixels;
6027 : } else {
6028 0 : height = lengthDevPixels;
6029 : }
6030 0 : aError = treeOwnerAsWin->SetSize(width, height, true);
6031 :
6032 0 : CheckForDPIChange();
6033 : }
6034 :
6035 : void
6036 0 : nsGlobalWindow::SetOuterWidthOuter(int32_t aOuterWidth,
6037 : CallerType aCallerType,
6038 : ErrorResult& aError)
6039 : {
6040 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6041 :
6042 0 : SetOuterSize(aOuterWidth, true, aCallerType, aError);
6043 0 : }
6044 :
6045 : void
6046 0 : nsGlobalWindow::SetOuterWidth(int32_t aOuterWidth,
6047 : CallerType aCallerType,
6048 : ErrorResult& aError)
6049 : {
6050 0 : FORWARD_TO_OUTER_OR_THROW(SetOuterWidthOuter,
6051 : (aOuterWidth, aCallerType, aError), aError, );
6052 : }
6053 :
6054 : void
6055 0 : nsGlobalWindow::SetOuterWidth(JSContext* aCx, JS::Handle<JS::Value> aValue,
6056 : CallerType aCallerType,
6057 : ErrorResult& aError)
6058 : {
6059 : SetReplaceableWindowCoord(aCx, &nsGlobalWindow::SetOuterWidth,
6060 0 : aValue, "outerWidth", aCallerType, aError);
6061 0 : }
6062 :
6063 : void
6064 0 : nsGlobalWindow::SetOuterHeightOuter(int32_t aOuterHeight,
6065 : CallerType aCallerType,
6066 : ErrorResult& aError)
6067 : {
6068 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6069 :
6070 0 : SetOuterSize(aOuterHeight, false, aCallerType, aError);
6071 0 : }
6072 :
6073 : void
6074 0 : nsGlobalWindow::SetOuterHeight(int32_t aOuterHeight,
6075 : CallerType aCallerType,
6076 : ErrorResult& aError)
6077 : {
6078 0 : FORWARD_TO_OUTER_OR_THROW(SetOuterHeightOuter,
6079 : (aOuterHeight, aCallerType, aError), aError, );
6080 : }
6081 :
6082 : void
6083 0 : nsGlobalWindow::SetOuterHeight(JSContext* aCx, JS::Handle<JS::Value> aValue,
6084 : CallerType aCallerType,
6085 : ErrorResult& aError)
6086 : {
6087 : SetReplaceableWindowCoord(aCx, &nsGlobalWindow::SetOuterHeight,
6088 0 : aValue, "outerHeight", aCallerType, aError);
6089 0 : }
6090 :
6091 : CSSIntPoint
6092 0 : nsGlobalWindow::GetScreenXY(CallerType aCallerType, ErrorResult& aError)
6093 : {
6094 0 : MOZ_ASSERT(IsOuterWindow());
6095 :
6096 : // When resisting fingerprinting, always return (0,0)
6097 0 : if (nsContentUtils::ResistFingerprinting(aCallerType)) {
6098 0 : return CSSIntPoint(0, 0);
6099 : }
6100 :
6101 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6102 0 : if (!treeOwnerAsWin) {
6103 0 : aError.Throw(NS_ERROR_FAILURE);
6104 0 : return CSSIntPoint(0, 0);
6105 : }
6106 :
6107 0 : int32_t x = 0, y = 0;
6108 0 : aError = treeOwnerAsWin->GetPosition(&x, &y); // LayoutDevice px values
6109 :
6110 0 : RefPtr<nsPresContext> presContext;
6111 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
6112 0 : if (!presContext) {
6113 0 : return CSSIntPoint(x, y);
6114 : }
6115 :
6116 : // Find the global desktop coordinate of the top-left of the screen.
6117 : // We'll use this as a "fake origin" when converting to CSS px units,
6118 : // to avoid overlapping coordinates in cases such as a hi-dpi screen
6119 : // placed to the right of a lo-dpi screen on Windows. (Instead, there
6120 : // may be "gaps" in the resulting CSS px coordinates in some cases.)
6121 0 : nsDeviceContext *dc = presContext->DeviceContext();
6122 0 : nsRect screenRect;
6123 0 : dc->GetRect(screenRect);
6124 : LayoutDeviceRect screenRectDev =
6125 0 : LayoutDevicePixel::FromAppUnits(screenRect, dc->AppUnitsPerDevPixel());
6126 :
6127 0 : DesktopToLayoutDeviceScale scale = dc->GetDesktopToDeviceScale();
6128 0 : DesktopRect screenRectDesk = screenRectDev / scale;
6129 :
6130 : CSSPoint cssPt =
6131 0 : LayoutDevicePoint(x - screenRectDev.x, y - screenRectDev.y) /
6132 0 : presContext->CSSToDevPixelScale();
6133 0 : cssPt.x += screenRectDesk.x;
6134 0 : cssPt.y += screenRectDesk.y;
6135 :
6136 0 : return CSSIntPoint(NSToIntRound(cssPt.x), NSToIntRound(cssPt.y));
6137 : }
6138 :
6139 : int32_t
6140 0 : nsGlobalWindow::GetScreenXOuter(CallerType aCallerType, ErrorResult& aError)
6141 : {
6142 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6143 :
6144 0 : return GetScreenXY(aCallerType, aError).x;
6145 : }
6146 :
6147 : int32_t
6148 0 : nsGlobalWindow::GetScreenX(CallerType aCallerType, ErrorResult& aError)
6149 : {
6150 0 : FORWARD_TO_OUTER_OR_THROW(GetScreenXOuter, (aCallerType, aError), aError, 0);
6151 : }
6152 :
6153 : void
6154 0 : nsGlobalWindow::GetScreenX(JSContext* aCx,
6155 : JS::MutableHandle<JS::Value> aValue,
6156 : CallerType aCallerType,
6157 : ErrorResult& aError)
6158 : {
6159 : GetReplaceableWindowCoord(aCx, &nsGlobalWindow::GetScreenX, aValue,
6160 0 : aCallerType, aError);
6161 0 : }
6162 :
6163 : nsRect
6164 8 : nsGlobalWindow::GetInnerScreenRect()
6165 : {
6166 8 : MOZ_ASSERT(IsOuterWindow());
6167 :
6168 8 : if (!mDocShell) {
6169 0 : return nsRect();
6170 : }
6171 :
6172 8 : EnsureSizeAndPositionUpToDate();
6173 :
6174 8 : if (!mDocShell) {
6175 0 : return nsRect();
6176 : }
6177 :
6178 16 : nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
6179 8 : if (!presShell) {
6180 0 : return nsRect();
6181 : }
6182 8 : nsIFrame* rootFrame = presShell->GetRootFrame();
6183 8 : if (!rootFrame) {
6184 0 : return nsRect();
6185 : }
6186 :
6187 8 : return rootFrame->GetScreenRectInAppUnits();
6188 : }
6189 :
6190 : float
6191 4 : nsGlobalWindow::GetMozInnerScreenXOuter(CallerType aCallerType)
6192 : {
6193 4 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6194 :
6195 : // When resisting fingerprinting, always return 0.
6196 4 : if (nsContentUtils::ResistFingerprinting(aCallerType)) {
6197 0 : return 0.0;
6198 : }
6199 :
6200 8 : nsRect r = GetInnerScreenRect();
6201 4 : return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
6202 : }
6203 :
6204 : float
6205 4 : nsGlobalWindow::GetMozInnerScreenX(CallerType aCallerType, ErrorResult& aError)
6206 : {
6207 4 : FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenXOuter, (aCallerType), aError, 0);
6208 : }
6209 :
6210 : float
6211 4 : nsGlobalWindow::GetMozInnerScreenYOuter(CallerType aCallerType)
6212 : {
6213 4 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6214 :
6215 : // Return 0 to prevent fingerprinting.
6216 4 : if (nsContentUtils::ResistFingerprinting(aCallerType)) {
6217 0 : return 0.0;
6218 : }
6219 :
6220 8 : nsRect r = GetInnerScreenRect();
6221 4 : return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
6222 : }
6223 :
6224 : float
6225 4 : nsGlobalWindow::GetMozInnerScreenY(CallerType aCallerType, ErrorResult& aError)
6226 : {
6227 4 : FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenYOuter, (aCallerType), aError, 0);
6228 : }
6229 :
6230 : float
6231 1 : nsGlobalWindow::GetDevicePixelRatioOuter(CallerType aCallerType)
6232 : {
6233 1 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6234 :
6235 1 : if (!mDocShell) {
6236 0 : return 1.0;
6237 : }
6238 :
6239 2 : RefPtr<nsPresContext> presContext;
6240 1 : mDocShell->GetPresContext(getter_AddRefs(presContext));
6241 1 : if (!presContext) {
6242 0 : return 1.0;
6243 : }
6244 :
6245 1 : if (nsContentUtils::ResistFingerprinting(aCallerType)) {
6246 0 : return 1.0;
6247 : }
6248 :
6249 1 : float overrideDPPX = presContext->GetOverrideDPPX();
6250 :
6251 1 : if (overrideDPPX > 0) {
6252 0 : return overrideDPPX;
6253 : }
6254 :
6255 2 : return float(nsPresContext::AppUnitsPerCSSPixel())/
6256 2 : presContext->AppUnitsPerDevPixel();
6257 : }
6258 :
6259 : float
6260 1 : nsGlobalWindow::GetDevicePixelRatio(CallerType aCallerType, ErrorResult& aError)
6261 : {
6262 1 : FORWARD_TO_OUTER_OR_THROW(GetDevicePixelRatioOuter, (aCallerType), aError, 0.0);
6263 : }
6264 :
6265 : float
6266 0 : nsPIDOMWindowOuter::GetDevicePixelRatio(CallerType aCallerType)
6267 : {
6268 0 : return nsGlobalWindow::Cast(this)->GetDevicePixelRatioOuter(aCallerType);
6269 : }
6270 :
6271 : uint64_t
6272 0 : nsGlobalWindow::GetMozPaintCountOuter()
6273 : {
6274 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6275 :
6276 0 : if (!mDocShell) {
6277 0 : return 0;
6278 : }
6279 :
6280 0 : nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
6281 0 : return presShell ? presShell->GetPaintCount() : 0;
6282 : }
6283 :
6284 : uint64_t
6285 0 : nsGlobalWindow::GetMozPaintCount(ErrorResult& aError)
6286 : {
6287 0 : FORWARD_TO_OUTER_OR_THROW(GetMozPaintCountOuter, (), aError, 0);
6288 : }
6289 :
6290 : int32_t
6291 4 : nsGlobalWindow::RequestAnimationFrame(FrameRequestCallback& aCallback,
6292 : ErrorResult& aError)
6293 : {
6294 4 : MOZ_RELEASE_ASSERT(IsInnerWindow());
6295 :
6296 4 : if (!mDoc) {
6297 0 : return 0;
6298 : }
6299 :
6300 4 : if (GetWrapperPreserveColor()) {
6301 4 : js::NotifyAnimationActivity(GetWrapperPreserveColor());
6302 : }
6303 :
6304 : int32_t handle;
6305 4 : aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle);
6306 4 : return handle;
6307 : }
6308 :
6309 : void
6310 0 : nsGlobalWindow::CancelAnimationFrame(int32_t aHandle, ErrorResult& aError)
6311 : {
6312 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
6313 :
6314 0 : if (!mDoc) {
6315 0 : return;
6316 : }
6317 :
6318 0 : mDoc->CancelFrameRequestCallback(aHandle);
6319 : }
6320 :
6321 : already_AddRefed<MediaQueryList>
6322 3 : nsGlobalWindow::MatchMediaOuter(const nsAString& aMediaQueryList)
6323 : {
6324 3 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6325 :
6326 3 : if (!mDoc) {
6327 0 : return nullptr;
6328 : }
6329 :
6330 3 : return mDoc->MatchMedia(aMediaQueryList);
6331 : }
6332 :
6333 : already_AddRefed<MediaQueryList>
6334 3 : nsGlobalWindow::MatchMedia(const nsAString& aMediaQueryList,
6335 : ErrorResult& aError)
6336 : {
6337 : // FIXME: This whole forward-to-outer and then get a pres
6338 : // shell/context off the docshell dance is sort of silly; it'd make
6339 : // more sense to forward to the inner, but it's what everyone else
6340 : // (GetSelection, GetScrollXY, etc.) does around here.
6341 3 : FORWARD_TO_OUTER_OR_THROW(MatchMediaOuter, (aMediaQueryList), aError, nullptr);
6342 : }
6343 :
6344 : void
6345 0 : nsGlobalWindow::SetScreenXOuter(int32_t aScreenX,
6346 : CallerType aCallerType,
6347 : ErrorResult& aError)
6348 : {
6349 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6350 :
6351 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6352 0 : if (!treeOwnerAsWin) {
6353 0 : aError.Throw(NS_ERROR_FAILURE);
6354 0 : return;
6355 : }
6356 :
6357 : int32_t x, y;
6358 0 : aError = treeOwnerAsWin->GetPosition(&x, &y);
6359 0 : if (aError.Failed()) {
6360 0 : return;
6361 : }
6362 :
6363 0 : CheckSecurityLeftAndTop(&aScreenX, nullptr, aCallerType);
6364 0 : x = CSSToDevIntPixels(aScreenX);
6365 :
6366 0 : aError = treeOwnerAsWin->SetPosition(x, y);
6367 :
6368 0 : CheckForDPIChange();
6369 : }
6370 :
6371 : void
6372 0 : nsGlobalWindow::SetScreenX(int32_t aScreenX,
6373 : CallerType aCallerType,
6374 : ErrorResult& aError)
6375 : {
6376 0 : FORWARD_TO_OUTER_OR_THROW(SetScreenXOuter,
6377 : (aScreenX, aCallerType, aError), aError, );
6378 : }
6379 :
6380 : void
6381 0 : nsGlobalWindow::SetScreenX(JSContext* aCx, JS::Handle<JS::Value> aValue,
6382 : CallerType aCallerType, ErrorResult& aError)
6383 : {
6384 : SetReplaceableWindowCoord(aCx, &nsGlobalWindow::SetScreenX,
6385 0 : aValue, "screenX", aCallerType, aError);
6386 0 : }
6387 :
6388 : int32_t
6389 0 : nsGlobalWindow::GetScreenYOuter(CallerType aCallerType, ErrorResult& aError)
6390 : {
6391 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6392 :
6393 0 : return GetScreenXY(aCallerType, aError).y;
6394 : }
6395 :
6396 : int32_t
6397 0 : nsGlobalWindow::GetScreenY(CallerType aCallerType, ErrorResult& aError)
6398 : {
6399 0 : FORWARD_TO_OUTER_OR_THROW(GetScreenYOuter, (aCallerType, aError), aError, 0);
6400 : }
6401 :
6402 : void
6403 0 : nsGlobalWindow::GetScreenY(JSContext* aCx,
6404 : JS::MutableHandle<JS::Value> aValue,
6405 : CallerType aCallerType, ErrorResult& aError)
6406 : {
6407 : GetReplaceableWindowCoord(aCx, &nsGlobalWindow::GetScreenY, aValue,
6408 0 : aCallerType, aError);
6409 0 : }
6410 :
6411 : void
6412 0 : nsGlobalWindow::SetScreenYOuter(int32_t aScreenY,
6413 : CallerType aCallerType,
6414 : ErrorResult& aError)
6415 : {
6416 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6417 :
6418 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6419 0 : if (!treeOwnerAsWin) {
6420 0 : aError.Throw(NS_ERROR_FAILURE);
6421 0 : return;
6422 : }
6423 :
6424 : int32_t x, y;
6425 0 : aError = treeOwnerAsWin->GetPosition(&x, &y);
6426 0 : if (aError.Failed()) {
6427 0 : return;
6428 : }
6429 :
6430 0 : CheckSecurityLeftAndTop(nullptr, &aScreenY, aCallerType);
6431 0 : y = CSSToDevIntPixels(aScreenY);
6432 :
6433 0 : aError = treeOwnerAsWin->SetPosition(x, y);
6434 :
6435 0 : CheckForDPIChange();
6436 : }
6437 :
6438 : void
6439 0 : nsGlobalWindow::SetScreenY(int32_t aScreenY,
6440 : CallerType aCallerType,
6441 : ErrorResult& aError)
6442 : {
6443 0 : FORWARD_TO_OUTER_OR_THROW(SetScreenYOuter,
6444 : (aScreenY, aCallerType, aError), aError, );
6445 : }
6446 :
6447 : void
6448 0 : nsGlobalWindow::SetScreenY(JSContext* aCx, JS::Handle<JS::Value> aValue,
6449 : CallerType aCallerType,
6450 : ErrorResult& aError)
6451 : {
6452 : SetReplaceableWindowCoord(aCx, &nsGlobalWindow::SetScreenY,
6453 0 : aValue, "screenY", aCallerType, aError);
6454 0 : }
6455 :
6456 : // NOTE: Arguments to this function should have values scaled to
6457 : // CSS pixels, not device pixels.
6458 : void
6459 0 : nsGlobalWindow::CheckSecurityWidthAndHeight(int32_t* aWidth, int32_t* aHeight,
6460 : CallerType aCallerType)
6461 : {
6462 0 : MOZ_ASSERT(IsOuterWindow());
6463 :
6464 : #ifdef MOZ_XUL
6465 0 : if (aCallerType != CallerType::System) {
6466 : // if attempting to resize the window, hide any open popups
6467 0 : nsContentUtils::HidePopupsInDocument(mDoc);
6468 : }
6469 : #endif
6470 :
6471 : // This one is easy. Just ensure the variable is greater than 100;
6472 0 : if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
6473 : // Check security state for use in determing window dimensions
6474 :
6475 0 : if (aCallerType != CallerType::System) {
6476 : //sec check failed
6477 0 : if (aWidth && *aWidth < 100) {
6478 0 : *aWidth = 100;
6479 : }
6480 0 : if (aHeight && *aHeight < 100) {
6481 0 : *aHeight = 100;
6482 : }
6483 : }
6484 : }
6485 0 : }
6486 :
6487 : // NOTE: Arguments to this function should have values in device pixels
6488 : nsresult
6489 0 : nsGlobalWindow::SetDocShellWidthAndHeight(int32_t aInnerWidth, int32_t aInnerHeight)
6490 : {
6491 0 : MOZ_ASSERT(IsOuterWindow());
6492 :
6493 0 : NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
6494 :
6495 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
6496 0 : mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
6497 0 : NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
6498 :
6499 0 : NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(mDocShell, aInnerWidth, aInnerHeight),
6500 : NS_ERROR_FAILURE);
6501 :
6502 0 : return NS_OK;
6503 : }
6504 :
6505 : // NOTE: Arguments to this function should have values in app units
6506 : void
6507 0 : nsGlobalWindow::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
6508 : {
6509 0 : MOZ_ASSERT(IsOuterWindow());
6510 :
6511 0 : RefPtr<nsPresContext> presContext;
6512 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
6513 :
6514 0 : nsRect shellArea = presContext->GetVisibleArea();
6515 0 : shellArea.height = aInnerHeight;
6516 0 : shellArea.width = aInnerWidth;
6517 :
6518 0 : presContext->SetVisibleArea(shellArea);
6519 0 : }
6520 :
6521 : // NOTE: Arguments to this function should have values scaled to
6522 : // CSS pixels, not device pixels.
6523 : void
6524 0 : nsGlobalWindow::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop,
6525 : CallerType aCallerType)
6526 : {
6527 0 : MOZ_ASSERT(IsOuterWindow());
6528 :
6529 : // This one is harder. We have to get the screen size and window dimensions.
6530 :
6531 : // Check security state for use in determing window dimensions
6532 :
6533 0 : if (aCallerType != CallerType::System) {
6534 : #ifdef MOZ_XUL
6535 : // if attempting to move the window, hide any open popups
6536 0 : nsContentUtils::HidePopupsInDocument(mDoc);
6537 : #endif
6538 :
6539 0 : if (nsGlobalWindow* rootWindow = nsGlobalWindow::Cast(GetPrivateRoot())) {
6540 0 : rootWindow->FlushPendingNotifications(FlushType::Layout);
6541 : }
6542 :
6543 0 : nsCOMPtr<nsIBaseWindow> treeOwner = GetTreeOwnerWindow();
6544 :
6545 0 : nsCOMPtr<nsIDOMScreen> screen = GetScreen();
6546 :
6547 0 : if (treeOwner && screen) {
6548 : int32_t screenLeft, screenTop, screenWidth, screenHeight;
6549 : int32_t winLeft, winTop, winWidth, winHeight;
6550 :
6551 : // Get the window size
6552 0 : treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
6553 :
6554 : // convert those values to CSS pixels
6555 : // XXX four separate retrievals of the prescontext
6556 0 : winLeft = DevToCSSIntPixels(winLeft);
6557 0 : winTop = DevToCSSIntPixels(winTop);
6558 0 : winWidth = DevToCSSIntPixels(winWidth);
6559 0 : winHeight = DevToCSSIntPixels(winHeight);
6560 :
6561 : // Get the screen dimensions
6562 : // XXX This should use nsIScreenManager once it's fully fleshed out.
6563 0 : screen->GetAvailLeft(&screenLeft);
6564 0 : screen->GetAvailWidth(&screenWidth);
6565 0 : screen->GetAvailHeight(&screenHeight);
6566 : #if defined(XP_MACOSX)
6567 : /* The mac's coordinate system is different from the assumed Windows'
6568 : system. It offsets by the height of the menubar so that a window
6569 : placed at (0,0) will be entirely visible. Unfortunately that
6570 : correction is made elsewhere (in Widget) and the meaning of
6571 : the Avail... coordinates is overloaded. Here we allow a window
6572 : to be placed at (0,0) because it does make sense to do so.
6573 : */
6574 : screen->GetTop(&screenTop);
6575 : #else
6576 0 : screen->GetAvailTop(&screenTop);
6577 : #endif
6578 :
6579 0 : if (aLeft) {
6580 0 : if (screenLeft+screenWidth < *aLeft+winWidth)
6581 0 : *aLeft = screenLeft+screenWidth - winWidth;
6582 0 : if (screenLeft > *aLeft)
6583 0 : *aLeft = screenLeft;
6584 : }
6585 0 : if (aTop) {
6586 0 : if (screenTop+screenHeight < *aTop+winHeight)
6587 0 : *aTop = screenTop+screenHeight - winHeight;
6588 0 : if (screenTop > *aTop)
6589 0 : *aTop = screenTop;
6590 : }
6591 : } else {
6592 0 : if (aLeft)
6593 0 : *aLeft = 0;
6594 0 : if (aTop)
6595 0 : *aTop = 0;
6596 : }
6597 : }
6598 0 : }
6599 :
6600 : int32_t
6601 0 : nsGlobalWindow::GetScrollBoundaryOuter(Side aSide)
6602 : {
6603 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6604 :
6605 0 : FlushPendingNotifications(FlushType::Layout);
6606 0 : if (nsIScrollableFrame *sf = GetScrollFrame()) {
6607 : return nsPresContext::
6608 0 : AppUnitsToIntCSSPixels(sf->GetScrollRange().Edge(aSide));
6609 : }
6610 0 : return 0;
6611 : }
6612 :
6613 : int32_t
6614 0 : nsGlobalWindow::GetScrollMinX(ErrorResult& aError)
6615 : {
6616 0 : MOZ_ASSERT(IsInnerWindow());
6617 0 : FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideLeft), aError, 0);
6618 : }
6619 :
6620 : int32_t
6621 0 : nsGlobalWindow::GetScrollMinY(ErrorResult& aError)
6622 : {
6623 0 : MOZ_ASSERT(IsInnerWindow());
6624 0 : FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideTop), aError, 0);
6625 : }
6626 :
6627 : int32_t
6628 0 : nsGlobalWindow::GetScrollMaxX(ErrorResult& aError)
6629 : {
6630 0 : MOZ_ASSERT(IsInnerWindow());
6631 0 : FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideRight), aError, 0);
6632 : }
6633 :
6634 : int32_t
6635 0 : nsGlobalWindow::GetScrollMaxY(ErrorResult& aError)
6636 : {
6637 0 : MOZ_ASSERT(IsInnerWindow());
6638 0 : FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideBottom), aError, 0);
6639 : }
6640 :
6641 : CSSPoint
6642 0 : nsGlobalWindow::GetScrollXY(bool aDoFlush)
6643 : {
6644 0 : MOZ_ASSERT(IsOuterWindow());
6645 :
6646 0 : if (aDoFlush) {
6647 0 : FlushPendingNotifications(FlushType::Layout);
6648 : } else {
6649 0 : EnsureSizeAndPositionUpToDate();
6650 : }
6651 :
6652 0 : nsIScrollableFrame *sf = GetScrollFrame();
6653 0 : if (!sf) {
6654 0 : return CSSIntPoint(0, 0);
6655 : }
6656 :
6657 0 : nsPoint scrollPos = sf->GetScrollPosition();
6658 0 : if (scrollPos != nsPoint(0,0) && !aDoFlush) {
6659 : // Oh, well. This is the expensive case -- the window is scrolled and we
6660 : // didn't actually flush yet. Repeat, but with a flush, since the content
6661 : // may get shorter and hence our scroll position may decrease.
6662 0 : return GetScrollXY(true);
6663 : }
6664 :
6665 0 : return CSSPoint::FromAppUnits(scrollPos);
6666 : }
6667 :
6668 : double
6669 0 : nsGlobalWindow::GetScrollXOuter()
6670 : {
6671 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6672 0 : return GetScrollXY(false).x;
6673 : }
6674 :
6675 : double
6676 0 : nsGlobalWindow::GetScrollX(ErrorResult& aError)
6677 : {
6678 0 : FORWARD_TO_OUTER_OR_THROW(GetScrollXOuter, (), aError, 0);
6679 : }
6680 :
6681 : double
6682 0 : nsGlobalWindow::GetScrollYOuter()
6683 : {
6684 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6685 0 : return GetScrollXY(false).y;
6686 : }
6687 :
6688 : double
6689 0 : nsGlobalWindow::GetScrollY(ErrorResult& aError)
6690 : {
6691 0 : FORWARD_TO_OUTER_OR_THROW(GetScrollYOuter, (), aError, 0);
6692 : }
6693 :
6694 : uint32_t
6695 768 : nsGlobalWindow::Length()
6696 : {
6697 768 : FORWARD_TO_OUTER(Length, (), 0);
6698 :
6699 384 : nsDOMWindowList* windows = GetWindowList();
6700 :
6701 384 : return windows ? windows->GetLength() : 0;
6702 : }
6703 :
6704 : already_AddRefed<nsPIDOMWindowOuter>
6705 12 : nsGlobalWindow::GetTopOuter()
6706 : {
6707 12 : MOZ_ASSERT(IsOuterWindow());
6708 :
6709 24 : nsCOMPtr<nsPIDOMWindowOuter> top = GetScriptableTop();
6710 24 : return top.forget();
6711 : }
6712 :
6713 : already_AddRefed<nsPIDOMWindowOuter>
6714 12 : nsGlobalWindow::GetTop(mozilla::ErrorResult& aError)
6715 : {
6716 12 : FORWARD_TO_OUTER_OR_THROW(GetTopOuter, (), aError, nullptr);
6717 : }
6718 :
6719 : nsPIDOMWindowOuter*
6720 80 : nsGlobalWindow::GetChildWindow(const nsAString& aName)
6721 : {
6722 160 : nsCOMPtr<nsIDocShell> docShell(GetDocShell());
6723 80 : NS_ENSURE_TRUE(docShell, nullptr);
6724 :
6725 160 : nsCOMPtr<nsIDocShellTreeItem> child;
6726 160 : docShell->FindChildWithName(aName, false, true, nullptr, nullptr,
6727 160 : getter_AddRefs(child));
6728 :
6729 80 : return child ? child->GetWindow() : nullptr;
6730 : }
6731 :
6732 : bool
6733 1 : nsGlobalWindow::DispatchCustomEvent(const nsAString& aEventName)
6734 : {
6735 1 : MOZ_ASSERT(IsOuterWindow());
6736 :
6737 1 : bool defaultActionEnabled = true;
6738 1 : nsContentUtils::DispatchTrustedEvent(mDoc, ToSupports(this), aEventName,
6739 1 : true, true, &defaultActionEnabled);
6740 :
6741 1 : return defaultActionEnabled;
6742 : }
6743 :
6744 : bool
6745 0 : nsGlobalWindow::DispatchResizeEvent(const CSSIntSize& aSize)
6746 : {
6747 0 : MOZ_ASSERT(IsOuterWindow());
6748 :
6749 0 : ErrorResult res;
6750 : RefPtr<Event> domEvent =
6751 0 : mDoc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), CallerType::System,
6752 0 : res);
6753 0 : if (res.Failed()) {
6754 0 : return false;
6755 : }
6756 :
6757 : // We don't init the AutoJSAPI with ourselves because we don't want it
6758 : // reporting errors to our onerror handlers.
6759 0 : AutoJSAPI jsapi;
6760 0 : jsapi.Init();
6761 0 : JSContext* cx = jsapi.cx();
6762 0 : JSAutoCompartment ac(cx, GetWrapperPreserveColor());
6763 :
6764 0 : DOMWindowResizeEventDetail detail;
6765 0 : detail.mWidth = aSize.width;
6766 0 : detail.mHeight = aSize.height;
6767 0 : JS::Rooted<JS::Value> detailValue(cx);
6768 0 : if (!ToJSValue(cx, detail, &detailValue)) {
6769 0 : return false;
6770 : }
6771 :
6772 0 : CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
6773 0 : customEvent->InitCustomEvent(cx,
6774 0 : NS_LITERAL_STRING("DOMWindowResize"),
6775 : /* aCanBubble = */ true,
6776 : /* aCancelable = */ true,
6777 : detailValue,
6778 0 : res);
6779 0 : if (res.Failed()) {
6780 0 : return false;
6781 : }
6782 :
6783 0 : domEvent->SetTrusted(true);
6784 0 : domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
6785 :
6786 0 : nsCOMPtr<EventTarget> target = do_QueryInterface(GetOuterWindow());
6787 0 : domEvent->SetTarget(target);
6788 :
6789 0 : bool defaultActionEnabled = true;
6790 0 : target->DispatchEvent(domEvent, &defaultActionEnabled);
6791 :
6792 0 : return defaultActionEnabled;
6793 : }
6794 :
6795 : void
6796 0 : nsGlobalWindow::RefreshCompartmentPrincipal()
6797 : {
6798 0 : MOZ_ASSERT(IsInnerWindow());
6799 :
6800 0 : JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),
6801 0 : nsJSPrincipals::get(mDoc->NodePrincipal()));
6802 0 : }
6803 :
6804 : static already_AddRefed<nsIDocShellTreeItem>
6805 0 : GetCallerDocShellTreeItem()
6806 : {
6807 0 : nsCOMPtr<nsIWebNavigation> callerWebNav = do_GetInterface(GetEntryGlobal());
6808 0 : nsCOMPtr<nsIDocShellTreeItem> callerItem = do_QueryInterface(callerWebNav);
6809 :
6810 0 : return callerItem.forget();
6811 : }
6812 :
6813 : bool
6814 0 : nsGlobalWindow::WindowExists(const nsAString& aName,
6815 : bool aForceNoOpener,
6816 : bool aLookForCallerOnJSStack)
6817 : {
6818 0 : NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
6819 0 : NS_PRECONDITION(mDocShell, "Must have docshell");
6820 :
6821 0 : if (aForceNoOpener) {
6822 0 : return aName.LowerCaseEqualsLiteral("_self") ||
6823 0 : aName.LowerCaseEqualsLiteral("_top") ||
6824 0 : aName.LowerCaseEqualsLiteral("_parent");
6825 : }
6826 :
6827 0 : nsCOMPtr<nsIDocShellTreeItem> caller;
6828 0 : if (aLookForCallerOnJSStack) {
6829 0 : caller = GetCallerDocShellTreeItem();
6830 : }
6831 :
6832 0 : if (!caller) {
6833 0 : caller = mDocShell;
6834 : }
6835 :
6836 0 : nsCOMPtr<nsIDocShellTreeItem> namedItem;
6837 0 : mDocShell->FindItemWithName(aName, nullptr, caller,
6838 : /* aSkipTabGroup = */ false,
6839 0 : getter_AddRefs(namedItem));
6840 0 : return namedItem != nullptr;
6841 : }
6842 :
6843 : already_AddRefed<nsIWidget>
6844 18 : nsGlobalWindow::GetMainWidget()
6845 : {
6846 18 : FORWARD_TO_OUTER(GetMainWidget, (), nullptr);
6847 :
6848 22 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6849 :
6850 22 : nsCOMPtr<nsIWidget> widget;
6851 :
6852 11 : if (treeOwnerAsWin) {
6853 11 : treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
6854 : }
6855 :
6856 11 : return widget.forget();
6857 : }
6858 :
6859 : nsIWidget*
6860 0 : nsGlobalWindow::GetNearestWidget() const
6861 : {
6862 0 : nsIDocShell* docShell = GetDocShell();
6863 0 : NS_ENSURE_TRUE(docShell, nullptr);
6864 0 : nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
6865 0 : NS_ENSURE_TRUE(presShell, nullptr);
6866 0 : nsIFrame* rootFrame = presShell->GetRootFrame();
6867 0 : NS_ENSURE_TRUE(rootFrame, nullptr);
6868 0 : return rootFrame->GetView()->GetNearestWidget(nullptr);
6869 : }
6870 :
6871 : void
6872 0 : nsGlobalWindow::SetFullScreenOuter(bool aFullScreen, mozilla::ErrorResult& aError)
6873 : {
6874 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
6875 :
6876 0 : aError = SetFullscreenInternal(FullscreenReason::ForFullscreenMode, aFullScreen);
6877 0 : }
6878 :
6879 : void
6880 0 : nsGlobalWindow::SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError)
6881 : {
6882 0 : FORWARD_TO_OUTER_OR_THROW(SetFullScreenOuter, (aFullScreen, aError), aError, /* void */);
6883 : }
6884 :
6885 : nsresult
6886 0 : nsGlobalWindow::SetFullScreen(bool aFullScreen)
6887 : {
6888 0 : FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
6889 :
6890 0 : return SetFullscreenInternal(FullscreenReason::ForFullscreenMode, aFullScreen);
6891 : }
6892 :
6893 : static void
6894 0 : FinishDOMFullscreenChange(nsIDocument* aDoc, bool aInDOMFullscreen)
6895 : {
6896 0 : if (aInDOMFullscreen) {
6897 : // Ask the document to handle any pending DOM fullscreen change.
6898 0 : if (!nsIDocument::HandlePendingFullscreenRequests(aDoc)) {
6899 : // If we don't end up having anything in fullscreen,
6900 : // async request exiting fullscreen.
6901 0 : nsIDocument::AsyncExitFullscreen(aDoc);
6902 : }
6903 : } else {
6904 : // If the window is leaving fullscreen state, also ask the document
6905 : // to exit from DOM Fullscreen.
6906 0 : nsIDocument::ExitFullscreenInDocTree(aDoc);
6907 : }
6908 0 : }
6909 :
6910 : struct FullscreenTransitionDuration
6911 : {
6912 : // The unit of the durations is millisecond
6913 : uint16_t mFadeIn = 0;
6914 : uint16_t mFadeOut = 0;
6915 0 : bool IsSuppressed() const
6916 : {
6917 0 : return mFadeIn == 0 && mFadeOut == 0;
6918 : }
6919 : };
6920 :
6921 : static void
6922 0 : GetFullscreenTransitionDuration(bool aEnterFullscreen,
6923 : FullscreenTransitionDuration* aDuration)
6924 : {
6925 : const char* pref = aEnterFullscreen ?
6926 : "full-screen-api.transition-duration.enter" :
6927 0 : "full-screen-api.transition-duration.leave";
6928 0 : nsAdoptingCString prefValue = Preferences::GetCString(pref);
6929 0 : if (!prefValue.IsEmpty()) {
6930 0 : sscanf(prefValue.get(), "%hu%hu",
6931 0 : &aDuration->mFadeIn, &aDuration->mFadeOut);
6932 : }
6933 0 : }
6934 :
6935 : class FullscreenTransitionTask : public Runnable
6936 : {
6937 : public:
6938 0 : FullscreenTransitionTask(const FullscreenTransitionDuration& aDuration,
6939 : nsGlobalWindow* aWindow,
6940 : bool aFullscreen,
6941 : nsIWidget* aWidget,
6942 : nsIScreen* aScreen,
6943 : nsISupports* aTransitionData)
6944 0 : : mozilla::Runnable("FullscreenTransitionTask")
6945 : , mWindow(aWindow)
6946 : , mWidget(aWidget)
6947 : , mScreen(aScreen)
6948 : , mTransitionData(aTransitionData)
6949 : , mDuration(aDuration)
6950 : , mStage(eBeforeToggle)
6951 0 : , mFullscreen(aFullscreen)
6952 : {
6953 0 : }
6954 :
6955 : NS_IMETHOD Run() override;
6956 :
6957 : private:
6958 0 : ~FullscreenTransitionTask() override
6959 0 : {
6960 0 : }
6961 :
6962 : /**
6963 : * The flow of fullscreen transition:
6964 : *
6965 : * parent process | child process
6966 : * ----------------------------------------------------------------
6967 : *
6968 : * | request/exit fullscreen
6969 : * <-----|
6970 : * BeforeToggle stage |
6971 : * |
6972 : * ToggleFullscreen stage *1 |----->
6973 : * | HandleFullscreenRequests
6974 : * |
6975 : * <-----| MozAfterPaint event
6976 : * AfterToggle stage *2 |
6977 : * |
6978 : * End stage |
6979 : *
6980 : * Note we also start a timer at *1 so that if we don't get MozAfterPaint
6981 : * from the child process in time, we continue going to *2.
6982 : */
6983 : enum Stage {
6984 : // BeforeToggle stage happens before we enter or leave fullscreen
6985 : // state. In this stage, the task triggers the pre-toggle fullscreen
6986 : // transition on the widget.
6987 : eBeforeToggle,
6988 : // ToggleFullscreen stage actually executes the fullscreen toggle,
6989 : // and wait for the next paint on the content to continue.
6990 : eToggleFullscreen,
6991 : // AfterToggle stage happens after we toggle the fullscreen state.
6992 : // In this stage, the task triggers the post-toggle fullscreen
6993 : // transition on the widget.
6994 : eAfterToggle,
6995 : // End stage is triggered after the final transition finishes.
6996 : eEnd
6997 : };
6998 :
6999 : class Observer final : public nsIObserver
7000 : {
7001 : public:
7002 : NS_DECL_ISUPPORTS
7003 : NS_DECL_NSIOBSERVER
7004 :
7005 0 : explicit Observer(FullscreenTransitionTask* aTask)
7006 0 : : mTask(aTask) { }
7007 :
7008 : private:
7009 0 : ~Observer() = default;
7010 :
7011 : RefPtr<FullscreenTransitionTask> mTask;
7012 : };
7013 :
7014 : static const char* const kPaintedTopic;
7015 :
7016 : RefPtr<nsGlobalWindow> mWindow;
7017 : nsCOMPtr<nsIWidget> mWidget;
7018 : nsCOMPtr<nsIScreen> mScreen;
7019 : nsCOMPtr<nsITimer> mTimer;
7020 : nsCOMPtr<nsISupports> mTransitionData;
7021 :
7022 : TimeStamp mFullscreenChangeStartTime;
7023 : FullscreenTransitionDuration mDuration;
7024 : Stage mStage;
7025 : bool mFullscreen;
7026 : };
7027 :
7028 : const char* const
7029 : FullscreenTransitionTask::kPaintedTopic = "fullscreen-painted";
7030 :
7031 : NS_IMETHODIMP
7032 0 : FullscreenTransitionTask::Run()
7033 : {
7034 0 : Stage stage = mStage;
7035 0 : mStage = Stage(mStage + 1);
7036 0 : if (MOZ_UNLIKELY(mWidget->Destroyed())) {
7037 : // If the widget has been destroyed before we get here, don't try to
7038 : // do anything more. Just let it go and release ourselves.
7039 0 : NS_WARNING("The widget to fullscreen has been destroyed");
7040 0 : return NS_OK;
7041 : }
7042 0 : if (stage == eBeforeToggle) {
7043 0 : profiler_add_marker("Fullscreen transition start");
7044 0 : mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
7045 0 : mDuration.mFadeIn, mTransitionData,
7046 0 : this);
7047 0 : } else if (stage == eToggleFullscreen) {
7048 0 : profiler_add_marker("Fullscreen toggle start");
7049 0 : mFullscreenChangeStartTime = TimeStamp::Now();
7050 0 : if (MOZ_UNLIKELY(mWindow->mFullScreen != mFullscreen)) {
7051 : // This could happen in theory if several fullscreen requests in
7052 : // different direction happen continuously in a short time. We
7053 : // need to ensure the fullscreen state matches our target here,
7054 : // otherwise the widget would change the window state as if we
7055 : // toggle for Fullscreen Mode instead of Fullscreen API.
7056 0 : NS_WARNING("The fullscreen state of the window does not match");
7057 0 : mWindow->mFullScreen = mFullscreen;
7058 : }
7059 : // Toggle the fullscreen state on the widget
7060 0 : if (!mWindow->SetWidgetFullscreen(FullscreenReason::ForFullscreenAPI,
7061 0 : mFullscreen, mWidget, mScreen)) {
7062 : // Fail to setup the widget, call FinishFullscreenChange to
7063 : // complete fullscreen change directly.
7064 0 : mWindow->FinishFullscreenChange(mFullscreen);
7065 : }
7066 : // Set observer for the next content paint.
7067 0 : nsCOMPtr<nsIObserver> observer = new Observer(this);
7068 0 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
7069 0 : obs->AddObserver(observer, kPaintedTopic, false);
7070 : // There are several edge cases where we may never get the paint
7071 : // notification, including:
7072 : // 1. the window/tab is closed before the next paint;
7073 : // 2. the user has switched to another tab before we get here.
7074 : // Completely fixing those cases seems to be tricky, and since they
7075 : // should rarely happen, it probably isn't worth to fix. Hence we
7076 : // simply add a timeout here to ensure we never hang forever.
7077 : // In addition, if the page is complicated or the machine is less
7078 : // powerful, layout could take a long time, in which case, staying
7079 : // in black screen for that long could hurt user experience even
7080 : // more than exposing an intermediate state.
7081 0 : mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
7082 : uint32_t timeout =
7083 0 : Preferences::GetUint("full-screen-api.transition.timeout", 1000);
7084 0 : mTimer->Init(observer, timeout, nsITimer::TYPE_ONE_SHOT);
7085 0 : } else if (stage == eAfterToggle) {
7086 0 : Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
7087 0 : mFullscreenChangeStartTime);
7088 0 : mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
7089 0 : mDuration.mFadeOut, mTransitionData,
7090 0 : this);
7091 0 : } else if (stage == eEnd) {
7092 0 : profiler_add_marker("Fullscreen transition end");
7093 : }
7094 0 : return NS_OK;
7095 : }
7096 :
7097 0 : NS_IMPL_ISUPPORTS(FullscreenTransitionTask::Observer, nsIObserver)
7098 :
7099 : NS_IMETHODIMP
7100 0 : FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
7101 : const char* aTopic,
7102 : const char16_t* aData)
7103 : {
7104 0 : bool shouldContinue = false;
7105 0 : if (strcmp(aTopic, FullscreenTransitionTask::kPaintedTopic) == 0) {
7106 0 : nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aSubject));
7107 0 : nsCOMPtr<nsIWidget> widget = win ?
7108 0 : nsGlobalWindow::Cast(win)->GetMainWidget() : nullptr;
7109 0 : if (widget == mTask->mWidget) {
7110 : // The paint notification arrives first. Cancel the timer.
7111 0 : mTask->mTimer->Cancel();
7112 0 : shouldContinue = true;
7113 0 : profiler_add_marker("Fullscreen toggle end");
7114 : }
7115 : } else {
7116 : #ifdef DEBUG
7117 0 : MOZ_ASSERT(strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC) == 0,
7118 : "Should only get fullscreen-painted or timer-callback");
7119 0 : nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject));
7120 0 : MOZ_ASSERT(timer && timer == mTask->mTimer,
7121 : "Should only trigger this with the timer the task created");
7122 : #endif
7123 0 : shouldContinue = true;
7124 0 : profiler_add_marker("Fullscreen toggle timeout");
7125 : }
7126 0 : if (shouldContinue) {
7127 0 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
7128 0 : obs->RemoveObserver(this, kPaintedTopic);
7129 0 : mTask->mTimer = nullptr;
7130 0 : mTask->Run();
7131 : }
7132 0 : return NS_OK;
7133 : }
7134 :
7135 : static bool
7136 0 : MakeWidgetFullscreen(nsGlobalWindow* aWindow, FullscreenReason aReason,
7137 : bool aFullscreen)
7138 : {
7139 0 : nsCOMPtr<nsIWidget> widget = aWindow->GetMainWidget();
7140 0 : if (!widget) {
7141 0 : return false;
7142 : }
7143 :
7144 0 : FullscreenTransitionDuration duration;
7145 0 : bool performTransition = false;
7146 0 : nsCOMPtr<nsISupports> transitionData;
7147 0 : if (aReason == FullscreenReason::ForFullscreenAPI) {
7148 0 : GetFullscreenTransitionDuration(aFullscreen, &duration);
7149 0 : if (!duration.IsSuppressed()) {
7150 0 : performTransition = widget->
7151 0 : PrepareForFullscreenTransition(getter_AddRefs(transitionData));
7152 : }
7153 : }
7154 : // We pass nullptr as the screen to SetWidgetFullscreen
7155 : // and FullscreenTransitionTask, as we do not wish to override
7156 : // the default screen selection behavior. The screen containing
7157 : // most of the widget will be selected.
7158 0 : if (!performTransition) {
7159 0 : return aWindow->SetWidgetFullscreen(aReason, aFullscreen, widget, nullptr);
7160 : }
7161 : nsCOMPtr<nsIRunnable> task =
7162 : new FullscreenTransitionTask(duration, aWindow, aFullscreen,
7163 0 : widget, nullptr, transitionData);
7164 0 : task->Run();
7165 0 : return true;
7166 : }
7167 :
7168 : nsresult
7169 0 : nsGlobalWindow::SetFullscreenInternal(FullscreenReason aReason,
7170 : bool aFullScreen)
7171 : {
7172 0 : MOZ_ASSERT(IsOuterWindow());
7173 0 : MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),
7174 : "Requires safe to run script as it "
7175 : "may call FinishDOMFullscreenChange");
7176 :
7177 0 : NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
7178 :
7179 0 : MOZ_ASSERT(aReason != FullscreenReason::ForForceExitFullscreen || !aFullScreen,
7180 : "FullscreenReason::ForForceExitFullscreen can "
7181 : "only be used with exiting fullscreen");
7182 :
7183 : // Only chrome can change our fullscreen mode. Otherwise, the state
7184 : // can only be changed for DOM fullscreen.
7185 0 : if (aReason == FullscreenReason::ForFullscreenMode &&
7186 0 : !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
7187 0 : return NS_OK;
7188 : }
7189 :
7190 : // SetFullScreen needs to be called on the root window, so get that
7191 : // via the DocShell tree, and if we are not already the root,
7192 : // call SetFullScreen on that window instead.
7193 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
7194 0 : mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
7195 0 : nsCOMPtr<nsPIDOMWindowOuter> window = rootItem ? rootItem->GetWindow() : nullptr;
7196 0 : if (!window)
7197 0 : return NS_ERROR_FAILURE;
7198 0 : if (rootItem != mDocShell)
7199 0 : return window->SetFullscreenInternal(aReason, aFullScreen);
7200 :
7201 : // make sure we don't try to set full screen on a non-chrome window,
7202 : // which might happen in embedding world
7203 0 : if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
7204 0 : return NS_ERROR_FAILURE;
7205 :
7206 : // If we are already in full screen mode, just return.
7207 0 : if (mFullScreen == aFullScreen)
7208 0 : return NS_OK;
7209 :
7210 : // Note that although entering DOM fullscreen could also cause
7211 : // consequential calls to this method, those calls will be skipped
7212 : // at the condition above.
7213 0 : if (aReason == FullscreenReason::ForFullscreenMode) {
7214 0 : if (!aFullScreen && !mFullscreenMode) {
7215 : // If we are exiting fullscreen mode, but we actually didn't
7216 : // entered fullscreen mode, the fullscreen state was only for
7217 : // the Fullscreen API. Change the reason here so that we can
7218 : // perform transition for it.
7219 0 : aReason = FullscreenReason::ForFullscreenAPI;
7220 : } else {
7221 0 : mFullscreenMode = aFullScreen;
7222 : }
7223 : } else {
7224 : // If we are exiting from DOM fullscreen while we initially make
7225 : // the window fullscreen because of fullscreen mode, don't restore
7226 : // the window. But we still need to exit the DOM fullscreen state.
7227 0 : if (!aFullScreen && mFullscreenMode) {
7228 0 : FinishDOMFullscreenChange(mDoc, false);
7229 0 : return NS_OK;
7230 : }
7231 : }
7232 :
7233 : // Prevent chrome documents which are still loading from resizing
7234 : // the window after we set fullscreen mode.
7235 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
7236 0 : nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
7237 0 : if (aFullScreen && xulWin) {
7238 0 : xulWin->SetIntrinsicallySized(false);
7239 : }
7240 :
7241 : // Set this before so if widget sends an event indicating its
7242 : // gone full screen, the state trap above works.
7243 0 : mFullScreen = aFullScreen;
7244 :
7245 : // Sometimes we don't want the top-level widget to actually go fullscreen,
7246 : // for example in the B2G desktop client, we don't want the emulated screen
7247 : // dimensions to appear to increase when entering fullscreen mode; we just
7248 : // want the content to fill the entire client area of the emulator window.
7249 0 : if (!Preferences::GetBool("full-screen-api.ignore-widgets", false)) {
7250 0 : if (MakeWidgetFullscreen(this, aReason, aFullScreen)) {
7251 : // The rest of code for switching fullscreen is in nsGlobalWindow::
7252 : // FinishFullscreenChange() which will be called after sizemodechange
7253 : // event is dispatched.
7254 0 : return NS_OK;
7255 : }
7256 : }
7257 :
7258 0 : FinishFullscreenChange(aFullScreen);
7259 0 : return NS_OK;
7260 : }
7261 :
7262 : bool
7263 0 : nsGlobalWindow::SetWidgetFullscreen(FullscreenReason aReason, bool aIsFullscreen,
7264 : nsIWidget* aWidget, nsIScreen* aScreen)
7265 : {
7266 0 : MOZ_ASSERT(IsOuterWindow());
7267 0 : MOZ_ASSERT(this == GetTopInternal(), "Only topmost window should call this");
7268 0 : MOZ_ASSERT(!AsOuter()->GetFrameElementInternal(), "Content window should not call this");
7269 0 : MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
7270 :
7271 0 : if (!NS_WARN_IF(!IsChromeWindow())) {
7272 0 : auto chromeWin = static_cast<nsGlobalChromeWindow*>(this);
7273 0 : if (!NS_WARN_IF(chromeWin->mFullscreenPresShell)) {
7274 0 : if (nsIPresShell* shell = mDocShell->GetPresShell()) {
7275 0 : if (nsRefreshDriver* rd = shell->GetRefreshDriver()) {
7276 0 : chromeWin->mFullscreenPresShell = do_GetWeakReference(shell);
7277 0 : MOZ_ASSERT(chromeWin->mFullscreenPresShell);
7278 0 : rd->SetIsResizeSuppressed();
7279 0 : rd->Freeze();
7280 : }
7281 : }
7282 : }
7283 : }
7284 0 : nsresult rv = aReason == FullscreenReason::ForFullscreenMode ?
7285 : // If we enter fullscreen for fullscreen mode, we want
7286 : // the native system behavior.
7287 0 : aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen, aScreen) :
7288 0 : aWidget->MakeFullScreen(aIsFullscreen, aScreen);
7289 0 : return NS_SUCCEEDED(rv);
7290 : }
7291 :
7292 : /* virtual */ void
7293 0 : nsGlobalWindow::FinishFullscreenChange(bool aIsFullscreen)
7294 : {
7295 0 : MOZ_ASSERT(IsOuterWindow());
7296 :
7297 0 : if (aIsFullscreen != mFullScreen) {
7298 0 : NS_WARNING("Failed to toggle fullscreen state of the widget");
7299 : // We failed to make the widget enter fullscreen.
7300 : // Stop further changes and restore the state.
7301 0 : if (!aIsFullscreen) {
7302 0 : mFullScreen = false;
7303 0 : mFullscreenMode = false;
7304 : } else {
7305 0 : MOZ_ASSERT_UNREACHABLE("Failed to exit fullscreen?");
7306 : mFullScreen = true;
7307 : // We don't know how code can reach here. Not sure
7308 : // what value should be set for fullscreen mode.
7309 : mFullscreenMode = false;
7310 : }
7311 0 : return;
7312 : }
7313 :
7314 : // Note that we must call this to toggle the DOM fullscreen state
7315 : // of the document before dispatching the "fullscreen" event, so
7316 : // that the chrome can distinguish between browser fullscreen mode
7317 : // and DOM fullscreen.
7318 0 : FinishDOMFullscreenChange(mDoc, mFullScreen);
7319 :
7320 : // dispatch a "fullscreen" DOM event so that XUL apps can
7321 : // respond visually if we are kicked into full screen mode
7322 0 : DispatchCustomEvent(NS_LITERAL_STRING("fullscreen"));
7323 :
7324 0 : if (!NS_WARN_IF(!IsChromeWindow())) {
7325 0 : auto chromeWin = static_cast<nsGlobalChromeWindow*>(this);
7326 0 : if (nsCOMPtr<nsIPresShell> shell =
7327 0 : do_QueryReferent(chromeWin->mFullscreenPresShell)) {
7328 0 : if (nsRefreshDriver* rd = shell->GetRefreshDriver()) {
7329 0 : rd->Thaw();
7330 : }
7331 0 : chromeWin->mFullscreenPresShell = nullptr;
7332 : }
7333 : }
7334 :
7335 0 : if (!mWakeLock && mFullScreen) {
7336 : RefPtr<power::PowerManagerService> pmService =
7337 0 : power::PowerManagerService::GetInstance();
7338 0 : if (!pmService) {
7339 0 : return;
7340 : }
7341 :
7342 : // XXXkhuey using the inner here, do we need to do something if it changes?
7343 0 : ErrorResult rv;
7344 0 : mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"),
7345 0 : AsOuter()->GetCurrentInnerWindow(), rv);
7346 0 : NS_WARNING_ASSERTION(!rv.Failed(), "Failed to lock the wakelock");
7347 0 : rv.SuppressException();
7348 0 : } else if (mWakeLock && !mFullScreen) {
7349 0 : ErrorResult rv;
7350 0 : mWakeLock->Unlock(rv);
7351 0 : mWakeLock = nullptr;
7352 0 : rv.SuppressException();
7353 : }
7354 : }
7355 :
7356 : bool
7357 5 : nsGlobalWindow::FullScreen() const
7358 : {
7359 5 : MOZ_ASSERT(IsOuterWindow());
7360 :
7361 5 : NS_ENSURE_TRUE(mDocShell, mFullScreen);
7362 :
7363 : // Get the fullscreen value of the root window, to always have the value
7364 : // accurate, even when called from content.
7365 10 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
7366 5 : mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
7367 5 : if (rootItem == mDocShell) {
7368 5 : if (!XRE_IsContentProcess()) {
7369 : // We are the root window. Return our internal value.
7370 5 : return mFullScreen;
7371 : }
7372 0 : if (nsCOMPtr<nsIWidget> widget = GetNearestWidget()) {
7373 : // We are in content process, figure out the value from
7374 : // the sizemode of the puppet widget.
7375 0 : return widget->SizeMode() == nsSizeMode_Fullscreen;
7376 : }
7377 0 : return false;
7378 : }
7379 :
7380 0 : nsCOMPtr<nsPIDOMWindowOuter> window = rootItem->GetWindow();
7381 0 : NS_ENSURE_TRUE(window, mFullScreen);
7382 :
7383 0 : return nsGlobalWindow::Cast(window)->FullScreen();
7384 : }
7385 :
7386 : bool
7387 5 : nsGlobalWindow::GetFullScreenOuter()
7388 : {
7389 5 : MOZ_RELEASE_ASSERT(IsOuterWindow());
7390 5 : return FullScreen();
7391 : }
7392 :
7393 : bool
7394 5 : nsGlobalWindow::GetFullScreen(ErrorResult& aError)
7395 : {
7396 5 : FORWARD_TO_OUTER_OR_THROW(GetFullScreenOuter, (), aError, false);
7397 : }
7398 :
7399 : bool
7400 8 : nsGlobalWindow::GetFullScreen()
7401 : {
7402 8 : FORWARD_TO_INNER(GetFullScreen, (), false);
7403 :
7404 8 : ErrorResult dummy;
7405 4 : bool fullscreen = GetFullScreen(dummy);
7406 4 : dummy.SuppressException();
7407 4 : return fullscreen;
7408 : }
7409 :
7410 : void
7411 1 : nsGlobalWindow::Dump(const nsAString& aStr)
7412 : {
7413 1 : if (!nsContentUtils::DOMWindowDumpEnabled()) {
7414 0 : return;
7415 : }
7416 :
7417 1 : char *cstr = ToNewUTF8String(aStr);
7418 :
7419 : #if defined(XP_MACOSX)
7420 : // have to convert \r to \n so that printing to the console works
7421 : char *c = cstr, *cEnd = cstr + strlen(cstr);
7422 : while (c < cEnd) {
7423 : if (*c == '\r')
7424 : *c = '\n';
7425 : c++;
7426 : }
7427 : #endif
7428 :
7429 1 : if (cstr) {
7430 1 : MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug, ("[Window.Dump] %s", cstr));
7431 : #ifdef XP_WIN
7432 : PrintToDebugger(cstr);
7433 : #endif
7434 : #ifdef ANDROID
7435 : __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
7436 : #endif
7437 1 : FILE *fp = gDumpFile ? gDumpFile : stdout;
7438 1 : fputs(cstr, fp);
7439 1 : fflush(fp);
7440 1 : free(cstr);
7441 : }
7442 : }
7443 :
7444 : void
7445 0 : nsGlobalWindow::EnsureReflowFlushAndPaint()
7446 : {
7447 0 : MOZ_ASSERT(IsOuterWindow());
7448 0 : NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
7449 : "docshell!");
7450 :
7451 0 : if (!mDocShell)
7452 0 : return;
7453 :
7454 0 : nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
7455 :
7456 0 : if (!presShell)
7457 0 : return;
7458 :
7459 : // Flush pending reflows.
7460 0 : if (mDoc) {
7461 0 : mDoc->FlushPendingNotifications(FlushType::Layout);
7462 : }
7463 :
7464 : // Unsuppress painting.
7465 0 : presShell->UnsuppressPainting();
7466 : }
7467 :
7468 : // static
7469 : void
7470 0 : nsGlobalWindow::MakeScriptDialogTitle(nsAString& aOutTitle,
7471 : nsIPrincipal* aSubjectPrincipal)
7472 : {
7473 0 : MOZ_ASSERT(aSubjectPrincipal);
7474 :
7475 0 : aOutTitle.Truncate();
7476 :
7477 : // Try to get a host from the running principal -- this will do the
7478 : // right thing for javascript: and data: documents.
7479 :
7480 0 : nsCOMPtr<nsIURI> uri;
7481 0 : nsresult rv = aSubjectPrincipal->GetURI(getter_AddRefs(uri));
7482 : // Note - The check for the current JSContext here isn't necessarily sensical.
7483 : // It's just designed to preserve existing behavior during a mass-conversion
7484 : // patch.
7485 0 : if (NS_SUCCEEDED(rv) && uri && nsContentUtils::GetCurrentJSContext()) {
7486 : // remove user:pass for privacy and spoof prevention
7487 :
7488 0 : nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
7489 0 : if (fixup) {
7490 0 : nsCOMPtr<nsIURI> fixedURI;
7491 0 : rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
7492 0 : if (NS_SUCCEEDED(rv) && fixedURI) {
7493 0 : nsAutoCString host;
7494 0 : fixedURI->GetHost(host);
7495 :
7496 0 : if (!host.IsEmpty()) {
7497 : // if this URI has a host we'll show it. For other
7498 : // schemes (e.g. file:) we fall back to the localized
7499 : // generic string
7500 :
7501 0 : nsAutoCString prepath;
7502 0 : fixedURI->GetPrePath(prepath);
7503 :
7504 0 : NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
7505 0 : const char16_t *formatStrings[] = { ucsPrePath.get() };
7506 0 : nsXPIDLString tempString;
7507 : nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
7508 : "ScriptDlgHeading",
7509 : formatStrings,
7510 0 : tempString);
7511 0 : aOutTitle = tempString;
7512 : }
7513 : }
7514 : }
7515 : }
7516 :
7517 0 : if (aOutTitle.IsEmpty()) {
7518 : // We didn't find a host so use the generic heading
7519 0 : nsXPIDLString tempString;
7520 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
7521 : "ScriptDlgGenericHeading",
7522 0 : tempString);
7523 0 : aOutTitle = tempString;
7524 : }
7525 :
7526 : // Just in case
7527 0 : if (aOutTitle.IsEmpty()) {
7528 0 : NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
7529 0 : aOutTitle.AssignLiteral("[Script]");
7530 : }
7531 0 : }
7532 :
7533 : bool
7534 0 : nsGlobalWindow::CanMoveResizeWindows(CallerType aCallerType)
7535 : {
7536 0 : MOZ_ASSERT(IsOuterWindow());
7537 :
7538 : // When called from chrome, we can avoid the following checks.
7539 0 : if (aCallerType != CallerType::System) {
7540 : // Don't allow scripts to move or resize windows that were not opened by a
7541 : // script.
7542 0 : if (!mHadOriginalOpener) {
7543 0 : return false;
7544 : }
7545 :
7546 0 : if (!CanSetProperty("dom.disable_window_move_resize")) {
7547 0 : return false;
7548 : }
7549 :
7550 : // Ignore the request if we have more than one tab in the window.
7551 0 : uint32_t itemCount = 0;
7552 0 : if (XRE_IsContentProcess()) {
7553 0 : nsCOMPtr<nsIDocShell> docShell = GetDocShell();
7554 0 : if (docShell) {
7555 0 : nsCOMPtr<nsITabChild> child = docShell->GetTabChild();
7556 0 : if (child) {
7557 0 : child->SendGetTabCount(&itemCount);
7558 : }
7559 : }
7560 : } else {
7561 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
7562 0 : if (!treeOwner || NS_FAILED(treeOwner->GetTabCount(&itemCount))) {
7563 0 : itemCount = 0;
7564 : }
7565 : }
7566 0 : if (itemCount > 1) {
7567 0 : return false;
7568 : }
7569 : }
7570 :
7571 0 : if (mDocShell) {
7572 : bool allow;
7573 0 : nsresult rv = mDocShell->GetAllowWindowControl(&allow);
7574 0 : if (NS_SUCCEEDED(rv) && !allow)
7575 0 : return false;
7576 : }
7577 :
7578 0 : if (gMouseDown && !gDragServiceDisabled) {
7579 : nsCOMPtr<nsIDragService> ds =
7580 0 : do_GetService("@mozilla.org/widget/dragservice;1");
7581 0 : if (ds) {
7582 0 : gDragServiceDisabled = true;
7583 0 : ds->Suppress();
7584 : }
7585 : }
7586 0 : return true;
7587 : }
7588 :
7589 : bool
7590 0 : nsGlobalWindow::AlertOrConfirm(bool aAlert,
7591 : const nsAString& aMessage,
7592 : nsIPrincipal& aSubjectPrincipal,
7593 : ErrorResult& aError)
7594 : {
7595 : // XXX This method is very similar to nsGlobalWindow::Prompt, make
7596 : // sure any modifications here don't need to happen over there!
7597 0 : MOZ_ASSERT(IsOuterWindow());
7598 :
7599 0 : if (!AreDialogsEnabled()) {
7600 : // Just silently return. In the case of alert(), the return value is
7601 : // ignored. In the case of confirm(), returning false is the same thing as
7602 : // would happen if the user cancels.
7603 0 : return false;
7604 : }
7605 :
7606 : // Reset popup state while opening a modal dialog, and firing events
7607 : // about the dialog, to prevent the current state from being active
7608 : // the whole time a modal dialog is open.
7609 0 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
7610 :
7611 : // Before bringing up the window, unsuppress painting and flush
7612 : // pending reflows.
7613 0 : EnsureReflowFlushAndPaint();
7614 :
7615 0 : nsAutoString title;
7616 0 : MakeScriptDialogTitle(title, &aSubjectPrincipal);
7617 :
7618 : // Remove non-terminating null characters from the
7619 : // string. See bug #310037.
7620 0 : nsAutoString final;
7621 0 : nsContentUtils::StripNullChars(aMessage, final);
7622 :
7623 : nsresult rv;
7624 : nsCOMPtr<nsIPromptFactory> promptFac =
7625 0 : do_GetService("@mozilla.org/prompter;1", &rv);
7626 0 : if (NS_FAILED(rv)) {
7627 0 : aError.Throw(rv);
7628 0 : return false;
7629 : }
7630 :
7631 0 : nsCOMPtr<nsIPrompt> prompt;
7632 0 : aError = promptFac->GetPrompt(AsOuter(), NS_GET_IID(nsIPrompt),
7633 0 : getter_AddRefs(prompt));
7634 0 : if (aError.Failed()) {
7635 0 : return false;
7636 : }
7637 :
7638 : // Always allow tab modal prompts for alert and confirm.
7639 0 : if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
7640 0 : promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
7641 : }
7642 :
7643 0 : bool result = false;
7644 0 : nsAutoSyncOperation sync(mDoc);
7645 0 : if (ShouldPromptToBlockDialogs()) {
7646 0 : bool disallowDialog = false;
7647 0 : nsXPIDLString label;
7648 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
7649 0 : "ScriptDialogLabel", label);
7650 :
7651 0 : aError = aAlert ?
7652 0 : prompt->AlertCheck(title.get(), final.get(), label.get(),
7653 0 : &disallowDialog) :
7654 0 : prompt->ConfirmCheck(title.get(), final.get(), label.get(),
7655 0 : &disallowDialog, &result);
7656 :
7657 0 : if (disallowDialog)
7658 0 : DisableDialogs();
7659 : } else {
7660 0 : aError = aAlert ?
7661 0 : prompt->Alert(title.get(), final.get()) :
7662 0 : prompt->Confirm(title.get(), final.get(), &result);
7663 : }
7664 :
7665 0 : return result;
7666 : }
7667 :
7668 : void
7669 0 : nsGlobalWindow::Alert(nsIPrincipal& aSubjectPrincipal,
7670 : ErrorResult& aError)
7671 : {
7672 0 : MOZ_ASSERT(IsInnerWindow());
7673 0 : Alert(EmptyString(), aSubjectPrincipal, aError);
7674 0 : }
7675 :
7676 : void
7677 0 : nsGlobalWindow::AlertOuter(const nsAString& aMessage,
7678 : nsIPrincipal& aSubjectPrincipal,
7679 : ErrorResult& aError)
7680 : {
7681 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
7682 0 : AlertOrConfirm(/* aAlert = */ true, aMessage, aSubjectPrincipal, aError);
7683 0 : }
7684 :
7685 : void
7686 0 : nsGlobalWindow::Alert(const nsAString& aMessage,
7687 : nsIPrincipal& aSubjectPrincipal,
7688 : ErrorResult& aError)
7689 : {
7690 0 : FORWARD_TO_OUTER_OR_THROW(AlertOuter, (aMessage, aSubjectPrincipal, aError),
7691 : aError, );
7692 : }
7693 :
7694 : bool
7695 0 : nsGlobalWindow::ConfirmOuter(const nsAString& aMessage,
7696 : nsIPrincipal& aSubjectPrincipal,
7697 : ErrorResult& aError)
7698 : {
7699 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
7700 :
7701 : return AlertOrConfirm(/* aAlert = */ false, aMessage, aSubjectPrincipal,
7702 0 : aError);
7703 : }
7704 :
7705 : bool
7706 0 : nsGlobalWindow::Confirm(const nsAString& aMessage,
7707 : nsIPrincipal& aSubjectPrincipal,
7708 : ErrorResult& aError)
7709 : {
7710 0 : FORWARD_TO_OUTER_OR_THROW(ConfirmOuter, (aMessage, aSubjectPrincipal, aError),
7711 : aError, false);
7712 : }
7713 :
7714 : already_AddRefed<Promise>
7715 0 : nsGlobalWindow::Fetch(const RequestOrUSVString& aInput,
7716 : const RequestInit& aInit,
7717 : CallerType aCallerType, ErrorResult& aRv)
7718 : {
7719 0 : return FetchRequest(this, aInput, aInit, aCallerType, aRv);
7720 : }
7721 :
7722 : void
7723 0 : nsGlobalWindow::PromptOuter(const nsAString& aMessage,
7724 : const nsAString& aInitial,
7725 : nsAString& aReturn,
7726 : nsIPrincipal& aSubjectPrincipal,
7727 : ErrorResult& aError)
7728 : {
7729 : // XXX This method is very similar to nsGlobalWindow::AlertOrConfirm, make
7730 : // sure any modifications here don't need to happen over there!
7731 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
7732 :
7733 0 : SetDOMStringToNull(aReturn);
7734 :
7735 0 : if (!AreDialogsEnabled()) {
7736 : // Return null, as if the user just canceled the prompt.
7737 0 : return;
7738 : }
7739 :
7740 : // Reset popup state while opening a modal dialog, and firing events
7741 : // about the dialog, to prevent the current state from being active
7742 : // the whole time a modal dialog is open.
7743 0 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
7744 :
7745 : // Before bringing up the window, unsuppress painting and flush
7746 : // pending reflows.
7747 0 : EnsureReflowFlushAndPaint();
7748 :
7749 0 : nsAutoString title;
7750 0 : MakeScriptDialogTitle(title, &aSubjectPrincipal);
7751 :
7752 : // Remove non-terminating null characters from the
7753 : // string. See bug #310037.
7754 0 : nsAutoString fixedMessage, fixedInitial;
7755 0 : nsContentUtils::StripNullChars(aMessage, fixedMessage);
7756 0 : nsContentUtils::StripNullChars(aInitial, fixedInitial);
7757 :
7758 : nsresult rv;
7759 : nsCOMPtr<nsIPromptFactory> promptFac =
7760 0 : do_GetService("@mozilla.org/prompter;1", &rv);
7761 0 : if (NS_FAILED(rv)) {
7762 0 : aError.Throw(rv);
7763 0 : return;
7764 : }
7765 :
7766 0 : nsCOMPtr<nsIPrompt> prompt;
7767 0 : aError = promptFac->GetPrompt(AsOuter(), NS_GET_IID(nsIPrompt),
7768 0 : getter_AddRefs(prompt));
7769 0 : if (aError.Failed()) {
7770 0 : return;
7771 : }
7772 :
7773 : // Always allow tab modal prompts for prompt.
7774 0 : if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
7775 0 : promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
7776 : }
7777 :
7778 : // Pass in the default value, if any.
7779 0 : char16_t *inoutValue = ToNewUnicode(fixedInitial);
7780 0 : bool disallowDialog = false;
7781 :
7782 0 : nsXPIDLString label;
7783 0 : if (ShouldPromptToBlockDialogs()) {
7784 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
7785 0 : "ScriptDialogLabel", label);
7786 : }
7787 :
7788 0 : nsAutoSyncOperation sync(mDoc);
7789 : bool ok;
7790 0 : aError = prompt->Prompt(title.get(), fixedMessage.get(),
7791 0 : &inoutValue, label.get(), &disallowDialog, &ok);
7792 :
7793 0 : if (disallowDialog) {
7794 0 : DisableDialogs();
7795 : }
7796 :
7797 0 : if (aError.Failed()) {
7798 0 : return;
7799 : }
7800 :
7801 0 : nsAdoptingString outValue(inoutValue);
7802 :
7803 0 : if (ok && outValue) {
7804 0 : aReturn.Assign(outValue);
7805 : }
7806 : }
7807 :
7808 : void
7809 0 : nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
7810 : nsAString& aReturn,
7811 : nsIPrincipal& aSubjectPrincipal,
7812 : ErrorResult& aError)
7813 : {
7814 0 : FORWARD_TO_OUTER_OR_THROW(PromptOuter,
7815 : (aMessage, aInitial, aReturn, aSubjectPrincipal,
7816 : aError),
7817 : aError, );
7818 : }
7819 :
7820 : void
7821 0 : nsGlobalWindow::FocusOuter(ErrorResult& aError)
7822 : {
7823 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
7824 :
7825 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7826 0 : if (!fm) {
7827 0 : return;
7828 : }
7829 :
7830 0 : nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
7831 :
7832 0 : bool isVisible = false;
7833 0 : if (baseWin) {
7834 0 : baseWin->GetVisibility(&isVisible);
7835 : }
7836 :
7837 0 : if (!isVisible) {
7838 : // A hidden tab is being focused, ignore this call.
7839 0 : return;
7840 : }
7841 :
7842 0 : nsCOMPtr<nsPIDOMWindowInner> caller = do_QueryInterface(GetEntryGlobal());
7843 0 : nsPIDOMWindowOuter* callerOuter = caller ? caller->GetOuterWindow() : nullptr;
7844 0 : nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpener();
7845 :
7846 : // Enforce dom.disable_window_flip (for non-chrome), but still allow the
7847 : // window which opened us to raise us at times when popups are allowed
7848 : // (bugs 355482 and 369306).
7849 0 : bool canFocus = CanSetProperty("dom.disable_window_flip") ||
7850 0 : (opener == callerOuter &&
7851 0 : RevisePopupAbuseLevel(gPopupControlState) < openAbused);
7852 :
7853 0 : nsCOMPtr<mozIDOMWindowProxy> activeDOMWindow;
7854 0 : fm->GetActiveWindow(getter_AddRefs(activeDOMWindow));
7855 :
7856 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
7857 0 : mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
7858 0 : nsCOMPtr<nsPIDOMWindowOuter> rootWin = rootItem ? rootItem->GetWindow() : nullptr;
7859 0 : auto* activeWindow = nsPIDOMWindowOuter::From(activeDOMWindow);
7860 0 : bool isActive = (rootWin == activeWindow);
7861 :
7862 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
7863 0 : if (treeOwnerAsWin && (canFocus || isActive)) {
7864 0 : bool isEnabled = true;
7865 0 : if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
7866 0 : NS_WARNING( "Should not try to set the focus on a disabled window" );
7867 0 : return;
7868 : }
7869 :
7870 : // XXXndeakin not sure what this is for or if it should go somewhere else
7871 0 : nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
7872 0 : if (embeddingWin)
7873 0 : embeddingWin->SetFocus();
7874 : }
7875 :
7876 0 : if (!mDocShell) {
7877 0 : return;
7878 : }
7879 :
7880 0 : nsCOMPtr<nsIPresShell> presShell;
7881 : // Don't look for a presshell if we're a root chrome window that's got
7882 : // about:blank loaded. We don't want to focus our widget in that case.
7883 : // XXXbz should we really be checking for IsInitialDocument() instead?
7884 0 : bool lookForPresShell = true;
7885 0 : if (mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome &&
7886 0 : GetPrivateRoot() == AsOuter() && mDoc) {
7887 0 : nsIURI* ourURI = mDoc->GetDocumentURI();
7888 0 : if (ourURI) {
7889 0 : lookForPresShell = !NS_IsAboutBlank(ourURI);
7890 : }
7891 : }
7892 :
7893 0 : if (lookForPresShell) {
7894 0 : mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
7895 : }
7896 :
7897 0 : nsCOMPtr<nsIDocShellTreeItem> parentDsti;
7898 0 : mDocShell->GetParent(getter_AddRefs(parentDsti));
7899 :
7900 : // set the parent's current focus to the frame containing this window.
7901 : nsCOMPtr<nsPIDOMWindowOuter> parent =
7902 0 : parentDsti ? parentDsti->GetWindow() : nullptr;
7903 0 : if (parent) {
7904 0 : nsCOMPtr<nsIDocument> parentdoc = parent->GetDoc();
7905 0 : if (!parentdoc) {
7906 0 : return;
7907 : }
7908 :
7909 0 : nsIContent* frame = parentdoc->FindContentForSubDocument(mDoc);
7910 0 : nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
7911 0 : if (frameElement) {
7912 0 : uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
7913 0 : if (canFocus)
7914 0 : flags |= nsIFocusManager::FLAG_RAISE;
7915 0 : aError = fm->SetFocus(frameElement, flags);
7916 : }
7917 0 : return;
7918 : }
7919 :
7920 0 : if (canFocus) {
7921 : // if there is no parent, this must be a toplevel window, so raise the
7922 : // window if canFocus is true. If this is a child process, the raise
7923 : // window request will get forwarded to the parent by the puppet widget.
7924 0 : aError = fm->SetActiveWindow(AsOuter());
7925 : }
7926 : }
7927 :
7928 : void
7929 0 : nsGlobalWindow::Focus(ErrorResult& aError)
7930 : {
7931 0 : FORWARD_TO_OUTER_OR_THROW(FocusOuter, (aError), aError, );
7932 : }
7933 :
7934 : nsresult
7935 0 : nsGlobalWindow::Focus()
7936 : {
7937 0 : FORWARD_TO_INNER(Focus, (), NS_ERROR_UNEXPECTED);
7938 :
7939 0 : ErrorResult rv;
7940 0 : Focus(rv);
7941 :
7942 0 : return rv.StealNSResult();
7943 : }
7944 :
7945 : void
7946 0 : nsGlobalWindow::BlurOuter()
7947 : {
7948 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
7949 :
7950 : // If dom.disable_window_flip == true, then content should not be allowed
7951 : // to call this function (this would allow popunders, bug 369306)
7952 0 : if (!CanSetProperty("dom.disable_window_flip")) {
7953 0 : return;
7954 : }
7955 :
7956 : // If embedding apps don't implement nsIEmbeddingSiteWindow, we
7957 : // shouldn't throw exceptions to web content.
7958 :
7959 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
7960 0 : nsCOMPtr<nsIEmbeddingSiteWindow> siteWindow(do_GetInterface(treeOwner));
7961 0 : if (siteWindow) {
7962 : // This method call may cause mDocShell to become nullptr.
7963 0 : siteWindow->Blur();
7964 :
7965 : // if the root is focused, clear the focus
7966 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7967 0 : if (fm && mDoc) {
7968 0 : nsCOMPtr<nsIDOMElement> element;
7969 0 : fm->GetFocusedElementForWindow(AsOuter(), false, nullptr, getter_AddRefs(element));
7970 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(element);
7971 0 : if (content == mDoc->GetRootElement()) {
7972 0 : fm->ClearFocus(AsOuter());
7973 : }
7974 : }
7975 : }
7976 : }
7977 :
7978 : void
7979 0 : nsGlobalWindow::Blur(ErrorResult& aError)
7980 : {
7981 0 : FORWARD_TO_OUTER_OR_THROW(BlurOuter, (), aError, );
7982 : }
7983 :
7984 : void
7985 0 : nsGlobalWindow::BackOuter(ErrorResult& aError)
7986 : {
7987 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
7988 :
7989 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
7990 0 : if (!webNav) {
7991 0 : aError.Throw(NS_ERROR_FAILURE);
7992 0 : return;
7993 : }
7994 :
7995 0 : aError = webNav->GoBack();
7996 : }
7997 :
7998 : void
7999 0 : nsGlobalWindow::Back(ErrorResult& aError)
8000 : {
8001 0 : FORWARD_TO_OUTER_OR_THROW(BackOuter, (aError), aError, );
8002 : }
8003 :
8004 : void
8005 0 : nsGlobalWindow::ForwardOuter(ErrorResult& aError)
8006 : {
8007 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8008 :
8009 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
8010 0 : if (!webNav) {
8011 0 : aError.Throw(NS_ERROR_FAILURE);
8012 0 : return;
8013 : }
8014 :
8015 0 : aError = webNav->GoForward();
8016 : }
8017 :
8018 : void
8019 0 : nsGlobalWindow::Forward(ErrorResult& aError)
8020 : {
8021 0 : FORWARD_TO_OUTER_OR_THROW(ForwardOuter, (aError), aError, );
8022 : }
8023 :
8024 : void
8025 0 : nsGlobalWindow::HomeOuter(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError)
8026 : {
8027 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8028 :
8029 0 : if (!mDocShell) {
8030 0 : return;
8031 : }
8032 :
8033 : nsAdoptingString homeURL =
8034 0 : Preferences::GetLocalizedString(PREF_BROWSER_STARTUP_HOMEPAGE);
8035 :
8036 0 : if (homeURL.IsEmpty()) {
8037 : // if all else fails, use this
8038 : #ifdef DEBUG_seth
8039 : printf("all else failed. using %s as the home page\n", DEFAULT_HOME_PAGE);
8040 : #endif
8041 0 : CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
8042 : }
8043 :
8044 : #ifdef MOZ_PHOENIX
8045 : {
8046 : // Firefox lets the user specify multiple home pages to open in
8047 : // individual tabs by separating them with '|'. Since we don't
8048 : // have the machinery in place to easily open new tabs from here,
8049 : // simply truncate the homeURL at the first '|' character to
8050 : // prevent any possibilities of leaking the users list of home
8051 : // pages to the first home page.
8052 : //
8053 : // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
8054 : // fixed we can revisit this.
8055 0 : int32_t firstPipe = homeURL.FindChar('|');
8056 :
8057 0 : if (firstPipe > 0) {
8058 0 : homeURL.Truncate(firstPipe);
8059 : }
8060 : }
8061 : #endif
8062 :
8063 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
8064 0 : if (!webNav) {
8065 0 : aError.Throw(NS_ERROR_FAILURE);
8066 0 : return;
8067 : }
8068 :
8069 0 : aError = webNav->LoadURI(homeURL.get(),
8070 : nsIWebNavigation::LOAD_FLAGS_NONE,
8071 : nullptr,
8072 : nullptr,
8073 : nullptr,
8074 0 : &aSubjectPrincipal);
8075 : }
8076 :
8077 : void
8078 0 : nsGlobalWindow::Home(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError)
8079 : {
8080 0 : FORWARD_TO_OUTER_OR_THROW(HomeOuter, (aSubjectPrincipal, aError), aError, );
8081 : }
8082 :
8083 : void
8084 0 : nsGlobalWindow::StopOuter(ErrorResult& aError)
8085 : {
8086 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8087 :
8088 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
8089 0 : if (webNav) {
8090 0 : aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
8091 : }
8092 0 : }
8093 :
8094 : void
8095 0 : nsGlobalWindow::Stop(ErrorResult& aError)
8096 : {
8097 0 : FORWARD_TO_OUTER_OR_THROW(StopOuter, (aError), aError, );
8098 : }
8099 :
8100 : void
8101 0 : nsGlobalWindow::PrintOuter(ErrorResult& aError)
8102 : {
8103 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8104 :
8105 : #ifdef NS_PRINTING
8106 0 : if (Preferences::GetBool("dom.disable_window_print", false)) {
8107 0 : aError.Throw(NS_ERROR_NOT_AVAILABLE);
8108 0 : return;
8109 : }
8110 :
8111 0 : if (!AreDialogsEnabled()) {
8112 : // We probably want to keep throwing here; silently doing nothing is a bit
8113 : // weird given the typical use cases of print().
8114 0 : aError.Throw(NS_ERROR_NOT_AVAILABLE);
8115 0 : return;
8116 : }
8117 :
8118 0 : if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
8119 0 : aError.Throw(NS_ERROR_NOT_AVAILABLE);
8120 0 : return;
8121 : }
8122 :
8123 0 : nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
8124 0 : if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
8125 : getter_AddRefs(webBrowserPrint)))) {
8126 0 : nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ?
8127 0 : GetCurrentInnerWindowInternal()->mDoc.get() :
8128 0 : nullptr);
8129 :
8130 : nsCOMPtr<nsIPrintSettingsService> printSettingsService =
8131 0 : do_GetService("@mozilla.org/gfx/printsettings-service;1");
8132 :
8133 0 : nsCOMPtr<nsIPrintSettings> printSettings;
8134 0 : if (printSettingsService) {
8135 : bool printSettingsAreGlobal =
8136 0 : Preferences::GetBool("print.use_global_printsettings", false);
8137 :
8138 0 : if (printSettingsAreGlobal) {
8139 0 : printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
8140 :
8141 0 : nsXPIDLString printerName;
8142 0 : printSettings->GetPrinterName(getter_Copies(printerName));
8143 :
8144 0 : bool shouldGetDefaultPrinterName = printerName.IsEmpty();
8145 : #ifdef MOZ_X11
8146 : // In Linux, GTK backend does not support per printer settings.
8147 : // Calling GetDefaultPrinterName causes a sandbox violation (see Bug 1329216).
8148 : // The printer name is not needed anywhere else on Linux before it gets to the parent.
8149 : // In the parent, we will then query the default printer name if no name is set.
8150 : // Unless we are in the parent, we will skip this part.
8151 0 : if (!XRE_IsParentProcess()) {
8152 0 : shouldGetDefaultPrinterName = false;
8153 : }
8154 : #endif
8155 0 : if (shouldGetDefaultPrinterName) {
8156 0 : printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
8157 0 : printSettings->SetPrinterName(printerName);
8158 : }
8159 0 : printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
8160 0 : printSettingsService->InitPrintSettingsFromPrefs(printSettings,
8161 : true,
8162 0 : nsIPrintSettings::kInitSaveAll);
8163 : } else {
8164 0 : printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
8165 : }
8166 :
8167 0 : EnterModalState();
8168 0 : webBrowserPrint->Print(printSettings, nullptr);
8169 0 : LeaveModalState();
8170 :
8171 : bool savePrintSettings =
8172 0 : Preferences::GetBool("print.save_print_settings", false);
8173 0 : if (printSettingsAreGlobal && savePrintSettings) {
8174 0 : printSettingsService->
8175 0 : SavePrintSettingsToPrefs(printSettings,
8176 : true,
8177 0 : nsIPrintSettings::kInitSaveAll);
8178 0 : printSettingsService->
8179 0 : SavePrintSettingsToPrefs(printSettings,
8180 : false,
8181 0 : nsIPrintSettings::kInitSavePrinterName);
8182 : }
8183 : } else {
8184 0 : webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
8185 0 : webBrowserPrint->Print(printSettings, nullptr);
8186 : }
8187 : }
8188 : #endif //NS_PRINTING
8189 : }
8190 :
8191 : void
8192 0 : nsGlobalWindow::Print(ErrorResult& aError)
8193 : {
8194 0 : FORWARD_TO_OUTER_OR_THROW(PrintOuter, (aError), aError, );
8195 : }
8196 :
8197 : void
8198 0 : nsGlobalWindow::MoveToOuter(int32_t aXPos, int32_t aYPos,
8199 : CallerType aCallerType, ErrorResult& aError)
8200 : {
8201 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8202 : /*
8203 : * If caller is not chrome and the user has not explicitly exempted the site,
8204 : * prevent window.moveTo() by exiting early
8205 : */
8206 :
8207 0 : if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
8208 0 : return;
8209 : }
8210 :
8211 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
8212 0 : if (!treeOwnerAsWin) {
8213 0 : aError.Throw(NS_ERROR_FAILURE);
8214 0 : return;
8215 : }
8216 :
8217 : nsCOMPtr<nsIScreenManager> screenMgr =
8218 0 : do_GetService("@mozilla.org/gfx/screenmanager;1");
8219 0 : nsCOMPtr<nsIScreen> screen;
8220 0 : if (screenMgr) {
8221 0 : CSSIntSize size;
8222 0 : GetInnerSize(size);
8223 0 : screenMgr->ScreenForRect(aXPos, aYPos, size.width, size.height,
8224 0 : getter_AddRefs(screen));
8225 : }
8226 :
8227 0 : if (screen) {
8228 : // On secondary displays, the "CSS px" coordinates are offset so that they
8229 : // share their origin with global desktop pixels, to avoid ambiguities in
8230 : // the coordinate space when there are displays with different DPIs.
8231 : // (See the corresponding code in GetScreenXY() above.)
8232 : int32_t screenLeftDeskPx, screenTopDeskPx, w, h;
8233 0 : screen->GetRectDisplayPix(&screenLeftDeskPx, &screenTopDeskPx, &w, &h);
8234 0 : CSSIntPoint cssPos(aXPos - screenLeftDeskPx, aYPos - screenTopDeskPx);
8235 0 : CheckSecurityLeftAndTop(&cssPos.x, &cssPos.y, aCallerType);
8236 :
8237 : double scale;
8238 0 : screen->GetDefaultCSSScaleFactor(&scale);
8239 0 : LayoutDevicePoint devPos = cssPos * CSSToLayoutDeviceScale(scale);
8240 :
8241 0 : screen->GetContentsScaleFactor(&scale);
8242 0 : DesktopPoint deskPos = devPos / DesktopToLayoutDeviceScale(scale);
8243 0 : aError = treeOwnerAsWin->SetPositionDesktopPix(screenLeftDeskPx + deskPos.x,
8244 0 : screenTopDeskPx + deskPos.y);
8245 : } else {
8246 : // We couldn't find a screen? Just assume a 1:1 mapping.
8247 0 : CSSIntPoint cssPos(aXPos, aXPos);
8248 0 : CheckSecurityLeftAndTop(&cssPos.x, &cssPos.y, aCallerType);
8249 0 : LayoutDevicePoint devPos = cssPos * CSSToLayoutDeviceScale(1.0);
8250 0 : aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y);
8251 : }
8252 :
8253 0 : CheckForDPIChange();
8254 : }
8255 :
8256 : void
8257 0 : nsGlobalWindow::MoveTo(int32_t aXPos, int32_t aYPos,
8258 : CallerType aCallerType, ErrorResult& aError)
8259 : {
8260 0 : FORWARD_TO_OUTER_OR_THROW(MoveToOuter,
8261 : (aXPos, aYPos, aCallerType, aError), aError, );
8262 : }
8263 :
8264 : void
8265 0 : nsGlobalWindow::MoveByOuter(int32_t aXDif, int32_t aYDif,
8266 : CallerType aCallerType, ErrorResult& aError)
8267 : {
8268 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8269 :
8270 : /*
8271 : * If caller is not chrome and the user has not explicitly exempted the site,
8272 : * prevent window.moveBy() by exiting early
8273 : */
8274 :
8275 0 : if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
8276 0 : return;
8277 : }
8278 :
8279 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
8280 0 : if (!treeOwnerAsWin) {
8281 0 : aError.Throw(NS_ERROR_FAILURE);
8282 0 : return;
8283 : }
8284 :
8285 : // To do this correctly we have to convert what we get from GetPosition
8286 : // into CSS pixels, add the arguments, do the security check, and
8287 : // then convert back to device pixels for the call to SetPosition.
8288 :
8289 : int32_t x, y;
8290 0 : aError = treeOwnerAsWin->GetPosition(&x, &y);
8291 0 : if (aError.Failed()) {
8292 0 : return;
8293 : }
8294 :
8295 : // mild abuse of a "size" object so we don't need more helper functions
8296 0 : nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
8297 :
8298 0 : cssPos.width += aXDif;
8299 0 : cssPos.height += aYDif;
8300 :
8301 0 : CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height, aCallerType);
8302 :
8303 0 : nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
8304 :
8305 0 : aError = treeOwnerAsWin->SetPosition(newDevPos.width, newDevPos.height);
8306 :
8307 0 : CheckForDPIChange();
8308 : }
8309 :
8310 : void
8311 0 : nsGlobalWindow::MoveBy(int32_t aXDif, int32_t aYDif,
8312 : CallerType aCallerType, ErrorResult& aError)
8313 : {
8314 0 : FORWARD_TO_OUTER_OR_THROW(MoveByOuter,
8315 : (aXDif, aYDif, aCallerType, aError), aError, );
8316 : }
8317 :
8318 : nsresult
8319 0 : nsGlobalWindow::MoveBy(int32_t aXDif, int32_t aYDif)
8320 : {
8321 0 : FORWARD_TO_OUTER(MoveBy, (aXDif, aYDif), NS_ERROR_UNEXPECTED);
8322 :
8323 0 : ErrorResult rv;
8324 0 : MoveByOuter(aXDif, aYDif, CallerType::System, rv);
8325 :
8326 0 : return rv.StealNSResult();
8327 : }
8328 :
8329 : void
8330 0 : nsGlobalWindow::ResizeToOuter(int32_t aWidth, int32_t aHeight,
8331 : CallerType aCallerType,
8332 : ErrorResult& aError)
8333 : {
8334 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8335 :
8336 : /*
8337 : * If caller is a browser-element then dispatch a resize event to
8338 : * the embedder.
8339 : */
8340 0 : if (mDocShell && mDocShell->GetIsMozBrowser()) {
8341 0 : CSSIntSize size(aWidth, aHeight);
8342 0 : if (!DispatchResizeEvent(size)) {
8343 : // The embedder chose to prevent the default action for this
8344 : // event, so let's not resize this window after all...
8345 0 : return;
8346 : }
8347 : }
8348 :
8349 : /*
8350 : * If caller is not chrome and the user has not explicitly exempted the site,
8351 : * prevent window.resizeTo() by exiting early
8352 : */
8353 :
8354 0 : if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
8355 0 : return;
8356 : }
8357 :
8358 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
8359 0 : if (!treeOwnerAsWin) {
8360 0 : aError.Throw(NS_ERROR_FAILURE);
8361 0 : return;
8362 : }
8363 :
8364 0 : nsIntSize cssSize(aWidth, aHeight);
8365 0 : CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
8366 :
8367 0 : nsIntSize devSz(CSSToDevIntPixels(cssSize));
8368 :
8369 0 : aError = treeOwnerAsWin->SetSize(devSz.width, devSz.height, true);
8370 :
8371 0 : CheckForDPIChange();
8372 : }
8373 :
8374 : void
8375 0 : nsGlobalWindow::ResizeTo(int32_t aWidth, int32_t aHeight,
8376 : CallerType aCallerType, ErrorResult& aError)
8377 : {
8378 0 : FORWARD_TO_OUTER_OR_THROW(ResizeToOuter,
8379 : (aWidth, aHeight, aCallerType, aError), aError, );
8380 : }
8381 :
8382 : void
8383 0 : nsGlobalWindow::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
8384 : CallerType aCallerType, ErrorResult& aError)
8385 : {
8386 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8387 :
8388 : /*
8389 : * If caller is a browser-element then dispatch a resize event to
8390 : * parent.
8391 : */
8392 0 : if (mDocShell && mDocShell->GetIsMozBrowser()) {
8393 0 : CSSIntSize size;
8394 0 : if (NS_FAILED(GetInnerSize(size))) {
8395 0 : return;
8396 : }
8397 :
8398 0 : size.width += aWidthDif;
8399 0 : size.height += aHeightDif;
8400 :
8401 0 : if (!DispatchResizeEvent(size)) {
8402 : // The embedder chose to prevent the default action for this
8403 : // event, so let's not resize this window after all...
8404 0 : return;
8405 : }
8406 : }
8407 :
8408 : /*
8409 : * If caller is not chrome and the user has not explicitly exempted the site,
8410 : * prevent window.resizeBy() by exiting early
8411 : */
8412 :
8413 0 : if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
8414 0 : return;
8415 : }
8416 :
8417 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
8418 0 : if (!treeOwnerAsWin) {
8419 0 : aError.Throw(NS_ERROR_FAILURE);
8420 0 : return;
8421 : }
8422 :
8423 : int32_t width, height;
8424 0 : aError = treeOwnerAsWin->GetSize(&width, &height);
8425 0 : if (aError.Failed()) {
8426 0 : return;
8427 : }
8428 :
8429 : // To do this correctly we have to convert what we got from GetSize
8430 : // into CSS pixels, add the arguments, do the security check, and
8431 : // then convert back to device pixels for the call to SetSize.
8432 :
8433 0 : nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
8434 :
8435 0 : cssSize.width += aWidthDif;
8436 0 : cssSize.height += aHeightDif;
8437 :
8438 0 : CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
8439 :
8440 0 : nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
8441 :
8442 0 : aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
8443 :
8444 0 : CheckForDPIChange();
8445 : }
8446 :
8447 : void
8448 0 : nsGlobalWindow::ResizeBy(int32_t aWidthDif, int32_t aHeightDif,
8449 : CallerType aCallerType, ErrorResult& aError)
8450 : {
8451 0 : FORWARD_TO_OUTER_OR_THROW(ResizeByOuter,
8452 : (aWidthDif, aHeightDif, aCallerType, aError),
8453 : aError, );
8454 : }
8455 :
8456 : void
8457 0 : nsGlobalWindow::SizeToContentOuter(CallerType aCallerType, ErrorResult& aError)
8458 : {
8459 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8460 :
8461 0 : if (!mDocShell) {
8462 0 : return;
8463 : }
8464 :
8465 : /*
8466 : * If caller is not chrome and the user has not explicitly exempted the site,
8467 : * prevent window.sizeToContent() by exiting early
8468 : */
8469 :
8470 0 : if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
8471 0 : return;
8472 : }
8473 :
8474 : // The content viewer does a check to make sure that it's a content
8475 : // viewer for a toplevel docshell.
8476 0 : nsCOMPtr<nsIContentViewer> cv;
8477 0 : mDocShell->GetContentViewer(getter_AddRefs(cv));
8478 0 : if (!cv) {
8479 0 : aError.Throw(NS_ERROR_FAILURE);
8480 0 : return;
8481 : }
8482 :
8483 : int32_t width, height;
8484 0 : aError = cv->GetContentSize(&width, &height);
8485 0 : if (aError.Failed()) {
8486 0 : return;
8487 : }
8488 :
8489 : // Make sure the new size is following the CheckSecurityWidthAndHeight
8490 : // rules.
8491 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
8492 0 : if (!treeOwner) {
8493 0 : aError.Throw(NS_ERROR_FAILURE);
8494 0 : return;
8495 : }
8496 :
8497 0 : nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
8498 0 : CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
8499 :
8500 0 : nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
8501 :
8502 0 : aError = treeOwner->SizeShellTo(mDocShell, newDevSize.width,
8503 0 : newDevSize.height);
8504 : }
8505 :
8506 : void
8507 0 : nsGlobalWindow::SizeToContent(CallerType aCallerType, ErrorResult& aError)
8508 : {
8509 0 : FORWARD_TO_OUTER_OR_THROW(SizeToContentOuter, (aCallerType, aError),
8510 : aError, );
8511 : }
8512 :
8513 : already_AddRefed<nsPIWindowRoot>
8514 35 : nsGlobalWindow::GetTopWindowRoot()
8515 : {
8516 35 : nsPIDOMWindowOuter* piWin = GetPrivateRoot();
8517 35 : if (!piWin) {
8518 0 : return nullptr;
8519 : }
8520 :
8521 70 : nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
8522 35 : return window.forget();
8523 : }
8524 :
8525 : void
8526 0 : nsGlobalWindow::Scroll(double aXScroll, double aYScroll)
8527 : {
8528 : // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
8529 0 : auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),
8530 0 : mozilla::ToZeroIfNonfinite(aYScroll));
8531 0 : ScrollTo(scrollPos, ScrollOptions());
8532 0 : }
8533 :
8534 : void
8535 0 : nsGlobalWindow::ScrollTo(double aXScroll, double aYScroll)
8536 : {
8537 : // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
8538 0 : auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),
8539 0 : mozilla::ToZeroIfNonfinite(aYScroll));
8540 0 : ScrollTo(scrollPos, ScrollOptions());
8541 0 : }
8542 :
8543 : void
8544 0 : nsGlobalWindow::ScrollTo(const ScrollToOptions& aOptions)
8545 : {
8546 : // When scrolling to a non-zero offset, we need to determine whether that
8547 : // position is within our scrollable range, so we need updated layout
8548 : // information which requires a layout flush, otherwise all we need is to
8549 : // flush frames to be able to access our scrollable frame here.
8550 0 : FlushType flushType = ((aOptions.mLeft.WasPassed() &&
8551 0 : aOptions.mLeft.Value() > 0) ||
8552 0 : (aOptions.mTop.WasPassed() &&
8553 0 : aOptions.mTop.Value() > 0)) ?
8554 : FlushType::Layout :
8555 0 : FlushType::Frames;
8556 0 : FlushPendingNotifications(flushType);
8557 0 : nsIScrollableFrame *sf = GetScrollFrame();
8558 :
8559 0 : if (sf) {
8560 0 : CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
8561 0 : if (aOptions.mLeft.WasPassed()) {
8562 0 : scrollPos.x = mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
8563 : }
8564 0 : if (aOptions.mTop.WasPassed()) {
8565 0 : scrollPos.y = mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
8566 : }
8567 :
8568 0 : ScrollTo(scrollPos, aOptions);
8569 : }
8570 0 : }
8571 :
8572 : void
8573 0 : nsGlobalWindow::Scroll(const ScrollToOptions& aOptions)
8574 : {
8575 0 : ScrollTo(aOptions);
8576 0 : }
8577 :
8578 : void
8579 0 : nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll,
8580 : const ScrollOptions& aOptions)
8581 : {
8582 : // When scrolling to a non-zero offset, we need to determine whether that
8583 : // position is within our scrollable range, so we need updated layout
8584 : // information which requires a layout flush, otherwise all we need is to
8585 : // flush frames to be able to access our scrollable frame here.
8586 0 : FlushType flushType = (aScroll.x || aScroll.y) ?
8587 : FlushType::Layout :
8588 0 : FlushType::Frames;
8589 0 : FlushPendingNotifications(flushType);
8590 0 : nsIScrollableFrame *sf = GetScrollFrame();
8591 :
8592 0 : if (sf) {
8593 : // Here we calculate what the max pixel value is that we can
8594 : // scroll to, we do this by dividing maxint with the pixel to
8595 : // twips conversion factor, and subtracting 4, the 4 comes from
8596 : // experimenting with this value, anything less makes the view
8597 : // code not scroll correctly, I have no idea why. -- jst
8598 0 : const int32_t maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
8599 :
8600 0 : CSSIntPoint scroll(aScroll);
8601 0 : if (scroll.x > maxpx) {
8602 0 : scroll.x = maxpx;
8603 : }
8604 :
8605 0 : if (scroll.y > maxpx) {
8606 0 : scroll.y = maxpx;
8607 : }
8608 :
8609 0 : bool smoothScroll = sf->GetScrollbarStyles().IsSmoothScroll(aOptions.mBehavior);
8610 :
8611 0 : sf->ScrollToCSSPixels(scroll, smoothScroll
8612 : ? nsIScrollableFrame::SMOOTH_MSD
8613 0 : : nsIScrollableFrame::INSTANT);
8614 : }
8615 0 : }
8616 :
8617 : void
8618 0 : nsGlobalWindow::ScrollBy(double aXScrollDif, double aYScrollDif)
8619 : {
8620 0 : FlushPendingNotifications(FlushType::Layout);
8621 0 : nsIScrollableFrame *sf = GetScrollFrame();
8622 :
8623 0 : if (sf) {
8624 : // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
8625 0 : auto scrollDif = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScrollDif),
8626 0 : mozilla::ToZeroIfNonfinite(aYScrollDif));
8627 : // It seems like it would make more sense for ScrollBy to use
8628 : // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
8629 : // Perhaps Web content does too.
8630 0 : ScrollTo(sf->GetScrollPositionCSSPixels() + scrollDif, ScrollOptions());
8631 : }
8632 0 : }
8633 :
8634 : void
8635 0 : nsGlobalWindow::ScrollBy(const ScrollToOptions& aOptions)
8636 : {
8637 0 : FlushPendingNotifications(FlushType::Layout);
8638 0 : nsIScrollableFrame *sf = GetScrollFrame();
8639 :
8640 0 : if (sf) {
8641 0 : CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
8642 0 : if (aOptions.mLeft.WasPassed()) {
8643 0 : scrollPos.x += mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
8644 : }
8645 0 : if (aOptions.mTop.WasPassed()) {
8646 0 : scrollPos.y += mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
8647 : }
8648 :
8649 0 : ScrollTo(scrollPos, aOptions);
8650 : }
8651 0 : }
8652 :
8653 : void
8654 0 : nsGlobalWindow::ScrollByLines(int32_t numLines,
8655 : const ScrollOptions& aOptions)
8656 : {
8657 0 : MOZ_ASSERT(IsInnerWindow());
8658 :
8659 0 : FlushPendingNotifications(FlushType::Layout);
8660 0 : nsIScrollableFrame *sf = GetScrollFrame();
8661 0 : if (sf) {
8662 : // It seems like it would make more sense for ScrollByLines to use
8663 : // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
8664 : // Perhaps Web content does too.
8665 0 : bool smoothScroll = sf->GetScrollbarStyles().IsSmoothScroll(aOptions.mBehavior);
8666 :
8667 0 : sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
8668 : smoothScroll
8669 : ? nsIScrollableFrame::SMOOTH_MSD
8670 0 : : nsIScrollableFrame::INSTANT);
8671 : }
8672 0 : }
8673 :
8674 : void
8675 0 : nsGlobalWindow::ScrollByPages(int32_t numPages,
8676 : const ScrollOptions& aOptions)
8677 : {
8678 0 : MOZ_ASSERT(IsInnerWindow());
8679 :
8680 0 : FlushPendingNotifications(FlushType::Layout);
8681 0 : nsIScrollableFrame *sf = GetScrollFrame();
8682 0 : if (sf) {
8683 : // It seems like it would make more sense for ScrollByPages to use
8684 : // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
8685 : // Perhaps Web content does too.
8686 0 : bool smoothScroll = sf->GetScrollbarStyles().IsSmoothScroll(aOptions.mBehavior);
8687 :
8688 0 : sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
8689 : smoothScroll
8690 : ? nsIScrollableFrame::SMOOTH_MSD
8691 0 : : nsIScrollableFrame::INSTANT);
8692 : }
8693 0 : }
8694 :
8695 : void
8696 0 : nsGlobalWindow::MozScrollSnap()
8697 : {
8698 0 : MOZ_ASSERT(IsInnerWindow());
8699 :
8700 0 : FlushPendingNotifications(FlushType::Layout);
8701 0 : nsIScrollableFrame *sf = GetScrollFrame();
8702 0 : if (sf) {
8703 0 : sf->ScrollSnap();
8704 : }
8705 0 : }
8706 :
8707 : void
8708 3 : nsGlobalWindow::ClearTimeout(int32_t aHandle)
8709 : {
8710 3 : MOZ_RELEASE_ASSERT(IsInnerWindow());
8711 :
8712 3 : if (aHandle > 0) {
8713 1 : mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
8714 : }
8715 3 : }
8716 :
8717 : void
8718 0 : nsGlobalWindow::ClearInterval(int32_t aHandle)
8719 : {
8720 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
8721 :
8722 0 : if (aHandle > 0) {
8723 0 : mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
8724 : }
8725 0 : }
8726 :
8727 : void
8728 0 : nsGlobalWindow::SetResizable(bool aResizable) const
8729 : {
8730 : // nop
8731 0 : }
8732 :
8733 : void
8734 0 : nsGlobalWindow::CaptureEvents()
8735 : {
8736 0 : if (mDoc) {
8737 0 : mDoc->WarnOnceAbout(nsIDocument::eUseOfCaptureEvents);
8738 : }
8739 0 : }
8740 :
8741 : void
8742 0 : nsGlobalWindow::ReleaseEvents()
8743 : {
8744 0 : if (mDoc) {
8745 0 : mDoc->WarnOnceAbout(nsIDocument::eUseOfReleaseEvents);
8746 : }
8747 0 : }
8748 :
8749 : static
8750 0 : bool IsPopupBlocked(nsIDocument* aDoc)
8751 : {
8752 : nsCOMPtr<nsIPopupWindowManager> pm =
8753 0 : do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
8754 :
8755 0 : if (!pm) {
8756 0 : return false;
8757 : }
8758 :
8759 0 : if (!aDoc) {
8760 0 : return true;
8761 : }
8762 :
8763 0 : uint32_t permission = nsIPopupWindowManager::ALLOW_POPUP;
8764 0 : pm->TestPermission(aDoc->NodePrincipal(), &permission);
8765 0 : return permission == nsIPopupWindowManager::DENY_POPUP;
8766 : }
8767 :
8768 : void
8769 0 : nsGlobalWindow::FirePopupBlockedEvent(nsIDocument* aDoc,
8770 : nsIURI* aPopupURI,
8771 : const nsAString& aPopupWindowName,
8772 : const nsAString& aPopupWindowFeatures)
8773 : {
8774 0 : MOZ_ASSERT(aDoc);
8775 :
8776 : // Fire a "DOMPopupBlocked" event so that the UI can hear about
8777 : // blocked popups.
8778 0 : PopupBlockedEventInit init;
8779 0 : init.mBubbles = true;
8780 0 : init.mCancelable = true;
8781 0 : init.mRequestingWindow = this;
8782 0 : init.mPopupWindowURI = aPopupURI;
8783 0 : init.mPopupWindowName = aPopupWindowName;
8784 0 : init.mPopupWindowFeatures = aPopupWindowFeatures;
8785 :
8786 : RefPtr<PopupBlockedEvent> event =
8787 0 : PopupBlockedEvent::Constructor(aDoc,
8788 0 : NS_LITERAL_STRING("DOMPopupBlocked"),
8789 0 : init);
8790 :
8791 0 : event->SetTrusted(true);
8792 :
8793 : bool defaultActionEnabled;
8794 0 : aDoc->DispatchEvent(event, &defaultActionEnabled);
8795 0 : }
8796 :
8797 : // static
8798 : bool
8799 8 : nsGlobalWindow::CanSetProperty(const char *aPrefName)
8800 : {
8801 : // Chrome can set any property.
8802 8 : if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
8803 8 : return true;
8804 : }
8805 :
8806 : // If the pref is set to true, we can not set the property
8807 : // and vice versa.
8808 0 : return !Preferences::GetBool(aPrefName, true);
8809 : }
8810 :
8811 : bool
8812 0 : nsGlobalWindow::PopupWhitelisted()
8813 : {
8814 0 : if (!IsPopupBlocked(mDoc))
8815 0 : return true;
8816 :
8817 0 : nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
8818 0 : if (parent == AsOuter())
8819 : {
8820 0 : return false;
8821 : }
8822 :
8823 0 : return nsGlobalWindow::Cast(parent)->PopupWhitelisted();
8824 : }
8825 :
8826 : /*
8827 : * Examine the current document state to see if we're in a way that is
8828 : * typically abused by web designers. The window.open code uses this
8829 : * routine to determine whether to allow the new window.
8830 : * Returns a value from the PopupControlState enum.
8831 : */
8832 : PopupControlState
8833 0 : nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
8834 : {
8835 0 : MOZ_ASSERT(IsOuterWindow());
8836 :
8837 0 : NS_ASSERTION(mDocShell, "Must have docshell");
8838 :
8839 0 : if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
8840 0 : return openAllowed;
8841 : }
8842 :
8843 0 : PopupControlState abuse = aControl;
8844 0 : switch (abuse) {
8845 : case openControlled:
8846 : case openAbused:
8847 : case openOverridden:
8848 0 : if (PopupWhitelisted())
8849 0 : abuse = PopupControlState(abuse - 1);
8850 0 : break;
8851 0 : case openAllowed: break;
8852 : default:
8853 0 : NS_WARNING("Strange PopupControlState!");
8854 : }
8855 :
8856 : // limit the number of simultaneously open popups
8857 0 : if (abuse == openAbused || abuse == openControlled) {
8858 0 : int32_t popupMax = Preferences::GetInt("dom.popup_maximum", -1);
8859 0 : if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
8860 0 : abuse = openOverridden;
8861 : }
8862 :
8863 0 : return abuse;
8864 : }
8865 :
8866 : /* If a window open is blocked, fire the appropriate DOM events. */
8867 : void
8868 0 : nsGlobalWindow::FireAbuseEvents(const nsAString &aPopupURL,
8869 : const nsAString &aPopupWindowName,
8870 : const nsAString &aPopupWindowFeatures)
8871 : {
8872 : // fetch the URI of the window requesting the opened window
8873 :
8874 0 : nsCOMPtr<nsPIDOMWindowOuter> window = GetTop();
8875 0 : if (!window) {
8876 0 : return;
8877 : }
8878 :
8879 0 : nsCOMPtr<nsIDocument> topDoc = window->GetDoc();
8880 0 : nsCOMPtr<nsIURI> popupURI;
8881 :
8882 : // build the URI of the would-have-been popup window
8883 : // (see nsWindowWatcher::URIfromURL)
8884 :
8885 : // first, fetch the opener's base URI
8886 :
8887 0 : nsIURI *baseURL = nullptr;
8888 :
8889 0 : nsCOMPtr<nsIDocument> doc = GetEntryDocument();
8890 0 : if (doc)
8891 0 : baseURL = doc->GetDocBaseURI();
8892 :
8893 : // use the base URI to build what would have been the popup's URI
8894 0 : nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
8895 0 : if (ios)
8896 0 : ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), nullptr, baseURL,
8897 0 : getter_AddRefs(popupURI));
8898 :
8899 : // fire an event chock full of informative URIs
8900 0 : FirePopupBlockedEvent(topDoc, popupURI, aPopupWindowName,
8901 0 : aPopupWindowFeatures);
8902 : }
8903 :
8904 : already_AddRefed<nsPIDOMWindowOuter>
8905 0 : nsGlobalWindow::OpenOuter(const nsAString& aUrl, const nsAString& aName,
8906 : const nsAString& aOptions, ErrorResult& aError)
8907 : {
8908 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
8909 0 : nsCOMPtr<nsPIDOMWindowOuter> window;
8910 0 : aError = OpenJS(aUrl, aName, aOptions, getter_AddRefs(window));
8911 0 : return window.forget();
8912 : }
8913 :
8914 :
8915 : already_AddRefed<nsPIDOMWindowOuter>
8916 0 : nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
8917 : const nsAString& aOptions, ErrorResult& aError)
8918 : {
8919 0 : FORWARD_TO_OUTER_OR_THROW(OpenOuter, (aUrl, aName, aOptions, aError), aError,
8920 : nullptr);
8921 : }
8922 :
8923 : nsresult
8924 0 : nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
8925 : const nsAString& aOptions, nsIDocShellLoadInfo* aLoadInfo,
8926 : bool aForceNoOpener, nsPIDOMWindowOuter **_retval)
8927 : {
8928 0 : FORWARD_TO_OUTER(Open, (aUrl, aName, aOptions, aLoadInfo, aForceNoOpener,
8929 : _retval),
8930 : NS_ERROR_NOT_INITIALIZED);
8931 0 : return OpenInternal(aUrl, aName, aOptions,
8932 : false, // aDialog
8933 : false, // aContentModal
8934 : true, // aCalledNoScript
8935 : false, // aDoJSFixups
8936 : true, // aNavigate
8937 : nullptr, nullptr, // No args
8938 : aLoadInfo,
8939 : aForceNoOpener,
8940 0 : _retval);
8941 : }
8942 :
8943 : nsresult
8944 0 : nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
8945 : const nsAString& aOptions, nsPIDOMWindowOuter **_retval)
8946 : {
8947 0 : MOZ_ASSERT(IsOuterWindow());
8948 : return OpenInternal(aUrl, aName, aOptions,
8949 : false, // aDialog
8950 : false, // aContentModal
8951 : false, // aCalledNoScript
8952 : true, // aDoJSFixups
8953 : true, // aNavigate
8954 : nullptr, nullptr, // No args
8955 : nullptr, // aLoadInfo
8956 : false, // aForceNoOpener
8957 0 : _retval);
8958 : }
8959 :
8960 : // like Open, but attaches to the new window any extra parameters past
8961 : // [features] as a JS property named "arguments"
8962 : nsresult
8963 0 : nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
8964 : const nsAString& aOptions,
8965 : nsISupports* aExtraArgument,
8966 : nsPIDOMWindowOuter** _retval)
8967 : {
8968 0 : MOZ_ASSERT(IsOuterWindow());
8969 : return OpenInternal(aUrl, aName, aOptions,
8970 : true, // aDialog
8971 : false, // aContentModal
8972 : true, // aCalledNoScript
8973 : false, // aDoJSFixups
8974 : true, // aNavigate
8975 : nullptr, aExtraArgument, // Arguments
8976 : nullptr, // aLoadInfo
8977 : false, // aForceNoOpener
8978 0 : _retval);
8979 : }
8980 :
8981 : // Like Open, but passes aNavigate=false.
8982 : /* virtual */ nsresult
8983 0 : nsGlobalWindow::OpenNoNavigate(const nsAString& aUrl,
8984 : const nsAString& aName,
8985 : const nsAString& aOptions,
8986 : nsPIDOMWindowOuter **_retval)
8987 : {
8988 0 : MOZ_ASSERT(IsOuterWindow());
8989 : return OpenInternal(aUrl, aName, aOptions,
8990 : false, // aDialog
8991 : false, // aContentModal
8992 : true, // aCalledNoScript
8993 : false, // aDoJSFixups
8994 : false, // aNavigate
8995 : nullptr, nullptr, // No args
8996 : nullptr, // aLoadInfo
8997 : false, // aForceNoOpener
8998 0 : _retval);
8999 :
9000 : }
9001 :
9002 : already_AddRefed<nsPIDOMWindowOuter>
9003 0 : nsGlobalWindow::OpenDialogOuter(JSContext* aCx, const nsAString& aUrl,
9004 : const nsAString& aName, const nsAString& aOptions,
9005 : const Sequence<JS::Value>& aExtraArgument,
9006 : ErrorResult& aError)
9007 : {
9008 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
9009 :
9010 0 : nsCOMPtr<nsIJSArgArray> argvArray;
9011 0 : aError = NS_CreateJSArgv(aCx, aExtraArgument.Length(),
9012 : aExtraArgument.Elements(),
9013 0 : getter_AddRefs(argvArray));
9014 0 : if (aError.Failed()) {
9015 0 : return nullptr;
9016 : }
9017 :
9018 0 : nsCOMPtr<nsPIDOMWindowOuter> dialog;
9019 0 : aError = OpenInternal(aUrl, aName, aOptions,
9020 : true, // aDialog
9021 : false, // aContentModal
9022 : false, // aCalledNoScript
9023 : false, // aDoJSFixups
9024 : true, // aNavigate
9025 : argvArray, nullptr, // Arguments
9026 : nullptr, // aLoadInfo
9027 : false, // aForceNoOpener
9028 0 : getter_AddRefs(dialog));
9029 0 : return dialog.forget();
9030 : }
9031 :
9032 : already_AddRefed<nsPIDOMWindowOuter>
9033 0 : nsGlobalWindow::OpenDialog(JSContext* aCx, const nsAString& aUrl,
9034 : const nsAString& aName, const nsAString& aOptions,
9035 : const Sequence<JS::Value>& aExtraArgument,
9036 : ErrorResult& aError)
9037 : {
9038 0 : FORWARD_TO_OUTER_OR_THROW(OpenDialogOuter,
9039 : (aCx, aUrl, aName, aOptions, aExtraArgument, aError),
9040 : aError, nullptr);
9041 : }
9042 :
9043 : already_AddRefed<nsPIDOMWindowOuter>
9044 8 : nsGlobalWindow::GetFramesOuter()
9045 : {
9046 16 : RefPtr<nsPIDOMWindowOuter> frames(AsOuter());
9047 8 : FlushPendingNotifications(FlushType::ContentAndNotify);
9048 16 : return frames.forget();
9049 : }
9050 :
9051 : already_AddRefed<nsPIDOMWindowOuter>
9052 8 : nsGlobalWindow::GetFrames(ErrorResult& aError)
9053 : {
9054 8 : FORWARD_TO_OUTER_OR_THROW(GetFramesOuter, (), aError, nullptr);
9055 : }
9056 :
9057 : nsGlobalWindow*
9058 0 : nsGlobalWindow::CallerInnerWindow()
9059 : {
9060 0 : JSContext *cx = nsContentUtils::GetCurrentJSContext();
9061 0 : NS_ENSURE_TRUE(cx, nullptr);
9062 0 : nsIGlobalObject* global = GetIncumbentGlobal();
9063 0 : NS_ENSURE_TRUE(global, nullptr);
9064 0 : JS::Rooted<JSObject*> scope(cx, global->GetGlobalJSObject());
9065 0 : NS_ENSURE_TRUE(scope, nullptr);
9066 :
9067 : // When Jetpack runs content scripts inside a sandbox, it uses
9068 : // sandboxPrototype to make them appear as though they're running in the
9069 : // scope of the page. So when a content script invokes postMessage, it expects
9070 : // the |source| of the received message to be the window set as the
9071 : // sandboxPrototype. This used to work incidentally for unrelated reasons, but
9072 : // now we need to do some special handling to support it.
9073 0 : if (xpc::IsSandbox(scope)) {
9074 0 : JSAutoCompartment ac(cx, scope);
9075 0 : JS::Rooted<JSObject*> scopeProto(cx);
9076 0 : bool ok = JS_GetPrototype(cx, scope, &scopeProto);
9077 0 : NS_ENSURE_TRUE(ok, nullptr);
9078 0 : if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
9079 0 : (scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtWindowProxy = */ false)))
9080 : {
9081 0 : global = xpc::NativeGlobal(scopeProto);
9082 0 : NS_ENSURE_TRUE(global, nullptr);
9083 : }
9084 : }
9085 :
9086 : // The calling window must be holding a reference, so we can return a weak
9087 : // pointer.
9088 0 : nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(global);
9089 0 : return nsGlobalWindow::Cast(win);
9090 : }
9091 :
9092 : void
9093 0 : nsGlobalWindow::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessage,
9094 : const nsAString& aTargetOrigin,
9095 : JS::Handle<JS::Value> aTransfer,
9096 : nsIPrincipal& aSubjectPrincipal,
9097 : ErrorResult& aError)
9098 : {
9099 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
9100 :
9101 : //
9102 : // Window.postMessage is an intentional subversion of the same-origin policy.
9103 : // As such, this code must be particularly careful in the information it
9104 : // exposes to calling code.
9105 : //
9106 : // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
9107 : //
9108 :
9109 : // First, get the caller's window
9110 0 : RefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
9111 : nsIPrincipal* callerPrin;
9112 0 : if (callerInnerWin) {
9113 0 : MOZ_ASSERT(callerInnerWin->IsInnerWindow(),
9114 : "should have gotten an inner window here");
9115 :
9116 : // Compute the caller's origin either from its principal or, in the case the
9117 : // principal doesn't carry a URI (e.g. the system principal), the caller's
9118 : // document. We must get this now instead of when the event is created and
9119 : // dispatched, because ultimately it is the identity of the calling window
9120 : // *now* that determines who sent the message (and not an identity which might
9121 : // have changed due to intervening navigations).
9122 0 : callerPrin = callerInnerWin->GetPrincipal();
9123 : }
9124 : else {
9125 : // In case the global is not a window, it can be a sandbox, and the sandbox's
9126 : // principal can be used for the security check.
9127 0 : nsIGlobalObject* global = GetIncumbentGlobal();
9128 0 : NS_ASSERTION(global, "Why is there no global object?");
9129 0 : callerPrin = global->PrincipalOrNull();
9130 : }
9131 0 : if (!callerPrin) {
9132 0 : return;
9133 : }
9134 :
9135 0 : nsCOMPtr<nsIURI> callerOuterURI;
9136 0 : if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI)))) {
9137 0 : return;
9138 : }
9139 :
9140 0 : nsAutoString origin;
9141 0 : if (callerOuterURI) {
9142 : // if the principal has a URI, use that to generate the origin
9143 0 : nsContentUtils::GetUTFOrigin(callerPrin, origin);
9144 : }
9145 0 : else if (callerInnerWin) {
9146 : // otherwise use the URI of the document to generate origin
9147 0 : nsCOMPtr<nsIDocument> doc = callerInnerWin->GetExtantDoc();
9148 0 : if (!doc) {
9149 0 : return;
9150 : }
9151 0 : callerOuterURI = doc->GetDocumentURI();
9152 : // if the principal has a URI, use that to generate the origin
9153 0 : nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
9154 : }
9155 : else {
9156 : // in case of a sandbox with a system principal origin can be empty
9157 0 : if (!nsContentUtils::IsSystemPrincipal(callerPrin)) {
9158 0 : return;
9159 : }
9160 : }
9161 :
9162 : // Convert the provided origin string into a URI for comparison purposes.
9163 0 : nsCOMPtr<nsIPrincipal> providedPrincipal;
9164 :
9165 0 : if (aTargetOrigin.EqualsASCII("/")) {
9166 0 : providedPrincipal = callerPrin;
9167 : }
9168 : // "*" indicates no specific origin is required.
9169 0 : else if (!aTargetOrigin.EqualsASCII("*")) {
9170 0 : nsCOMPtr<nsIURI> originURI;
9171 0 : if (NS_FAILED(NS_NewURI(getter_AddRefs(originURI), aTargetOrigin))) {
9172 0 : aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
9173 0 : return;
9174 : }
9175 :
9176 0 : if (NS_FAILED(originURI->SetUserPass(EmptyCString())) ||
9177 0 : NS_FAILED(originURI->SetPath(EmptyCString()))) {
9178 0 : return;
9179 : }
9180 :
9181 0 : OriginAttributes attrs = aSubjectPrincipal.OriginAttributesRef();
9182 0 : if (aSubjectPrincipal.GetIsSystemPrincipal()) {
9183 0 : auto principal = BasePrincipal::Cast(GetPrincipal());
9184 :
9185 0 : if (attrs != principal->OriginAttributesRef()) {
9186 0 : nsCOMPtr<nsIURI> targetURI;
9187 0 : nsAutoCString targetURL;
9188 0 : nsAutoCString sourceOrigin;
9189 0 : nsAutoCString targetOrigin;
9190 :
9191 0 : if (NS_FAILED(principal->GetURI(getter_AddRefs(targetURI))) ||
9192 0 : NS_FAILED(targetURI->GetAsciiSpec(targetURL)) ||
9193 0 : NS_FAILED(principal->GetOrigin(targetOrigin)) ||
9194 0 : NS_FAILED(aSubjectPrincipal.GetOrigin(sourceOrigin))) {
9195 0 : NS_WARNING("Failed to get source and target origins");
9196 0 : return;
9197 : }
9198 :
9199 : nsContentUtils::LogSimpleConsoleError(
9200 0 : NS_ConvertUTF8toUTF16(nsPrintfCString(
9201 : R"(Attempting to post a message to window with url "%s" and )"
9202 : R"(origin "%s" from a system principal scope with mismatched )"
9203 : R"(origin "%s".)",
9204 : targetURL.get(), targetOrigin.get(), sourceOrigin.get())),
9205 0 : "DOM");
9206 :
9207 0 : attrs = principal->OriginAttributesRef();
9208 : }
9209 : }
9210 :
9211 : // Create a nsIPrincipal inheriting the app/browser attributes from the
9212 : // caller.
9213 0 : providedPrincipal = BasePrincipal::CreateCodebasePrincipal(originURI, attrs);
9214 0 : if (NS_WARN_IF(!providedPrincipal)) {
9215 0 : return;
9216 : }
9217 : }
9218 :
9219 : // Create and asynchronously dispatch a runnable which will handle actual DOM
9220 : // event creation and dispatch.
9221 : RefPtr<PostMessageEvent> event =
9222 0 : new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin
9223 0 : ? nullptr
9224 0 : : callerInnerWin->GetOuterWindowInternal(),
9225 : origin,
9226 : this,
9227 : providedPrincipal,
9228 : callerInnerWin
9229 0 : ? callerInnerWin->GetDoc()
9230 0 : : nullptr,
9231 0 : nsContentUtils::IsCallerChrome());
9232 :
9233 0 : JS::Rooted<JS::Value> message(aCx, aMessage);
9234 0 : JS::Rooted<JS::Value> transfer(aCx, aTransfer);
9235 :
9236 0 : event->Write(aCx, message, transfer, JS::CloneDataPolicy(), aError);
9237 0 : if (NS_WARN_IF(aError.Failed())) {
9238 0 : return;
9239 : }
9240 :
9241 0 : aError = Dispatch("PostMessageEvent", TaskCategory::Other, event.forget());
9242 : }
9243 :
9244 : void
9245 0 : nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
9246 : const nsAString& aTargetOrigin,
9247 : JS::Handle<JS::Value> aTransfer,
9248 : nsIPrincipal& aSubjectPrincipal,
9249 : ErrorResult& aError)
9250 : {
9251 0 : FORWARD_TO_OUTER_OR_THROW(PostMessageMozOuter,
9252 : (aCx, aMessage, aTargetOrigin, aTransfer,
9253 : aSubjectPrincipal, aError),
9254 : aError, );
9255 : }
9256 :
9257 : void
9258 0 : nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
9259 : const nsAString& aTargetOrigin,
9260 : const Sequence<JSObject*>& aTransfer,
9261 : nsIPrincipal& aSubjectPrincipal,
9262 : ErrorResult& aRv)
9263 : {
9264 0 : JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
9265 :
9266 0 : aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransfer,
9267 0 : &transferArray);
9268 0 : if (NS_WARN_IF(aRv.Failed())) {
9269 0 : return;
9270 : }
9271 :
9272 0 : PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray,
9273 0 : aSubjectPrincipal, aRv);
9274 : }
9275 :
9276 0 : class nsCloseEvent : public Runnable {
9277 :
9278 : RefPtr<nsGlobalWindow> mWindow;
9279 : bool mIndirect;
9280 :
9281 0 : nsCloseEvent(nsGlobalWindow* aWindow, bool aIndirect)
9282 0 : : mozilla::Runnable("nsCloseEvent")
9283 : , mWindow(aWindow)
9284 0 : , mIndirect(aIndirect)
9285 0 : {}
9286 :
9287 : public:
9288 :
9289 : static nsresult
9290 0 : PostCloseEvent(nsGlobalWindow* aWindow, bool aIndirect) {
9291 0 : nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
9292 : nsresult rv =
9293 0 : aWindow->Dispatch("nsCloseEvent", TaskCategory::Other, ev.forget());
9294 0 : if (NS_SUCCEEDED(rv))
9295 0 : aWindow->MaybeForgiveSpamCount();
9296 0 : return rv;
9297 : }
9298 :
9299 0 : NS_IMETHOD Run() override {
9300 0 : if (mWindow) {
9301 0 : if (mIndirect) {
9302 0 : return PostCloseEvent(mWindow, false);
9303 : }
9304 0 : mWindow->ReallyCloseWindow();
9305 : }
9306 0 : return NS_OK;
9307 : }
9308 :
9309 : };
9310 :
9311 : bool
9312 0 : nsGlobalWindow::CanClose()
9313 : {
9314 0 : MOZ_ASSERT(IsOuterWindow());
9315 :
9316 0 : if (mIsChrome) {
9317 0 : nsCOMPtr<nsIBrowserDOMWindow> bwin;
9318 0 : nsIDOMChromeWindow* chromeWin = static_cast<nsGlobalChromeWindow*>(this);
9319 0 : chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
9320 :
9321 0 : bool canClose = true;
9322 0 : if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))) {
9323 0 : return canClose;
9324 : }
9325 : }
9326 :
9327 0 : if (!mDocShell) {
9328 0 : return true;
9329 : }
9330 :
9331 : // Ask the content viewer whether the toplevel window can close.
9332 : // If the content viewer returns false, it is responsible for calling
9333 : // Close() as soon as it is possible for the window to close.
9334 : // This allows us to not close the window while printing is happening.
9335 :
9336 0 : nsCOMPtr<nsIContentViewer> cv;
9337 0 : mDocShell->GetContentViewer(getter_AddRefs(cv));
9338 0 : if (cv) {
9339 : bool canClose;
9340 0 : nsresult rv = cv->PermitUnload(&canClose);
9341 0 : if (NS_SUCCEEDED(rv) && !canClose)
9342 0 : return false;
9343 :
9344 0 : rv = cv->RequestWindowClose(&canClose);
9345 0 : if (NS_SUCCEEDED(rv) && !canClose)
9346 0 : return false;
9347 : }
9348 :
9349 0 : return true;
9350 : }
9351 :
9352 : void
9353 0 : nsGlobalWindow::CloseOuter(bool aTrustedCaller)
9354 : {
9355 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
9356 :
9357 0 : if (!mDocShell || IsInModalState() ||
9358 0 : (IsFrame() && !mDocShell->GetIsMozBrowser())) {
9359 : // window.close() is called on a frame in a frameset, on a window
9360 : // that's already closed, or on a window for which there's
9361 : // currently a modal dialog open. Ignore such calls.
9362 0 : return;
9363 : }
9364 :
9365 0 : if (mHavePendingClose) {
9366 : // We're going to be closed anyway; do nothing since we don't want
9367 : // to double-close
9368 0 : return;
9369 : }
9370 :
9371 0 : if (mBlockScriptedClosingFlag)
9372 : {
9373 : // A script's popup has been blocked and we don't want
9374 : // the window to be closed directly after this event,
9375 : // so the user can see that there was a blocked popup.
9376 0 : return;
9377 : }
9378 :
9379 : // Don't allow scripts from content to close non-neterror windows that
9380 : // were not opened by script.
9381 0 : nsAutoString url;
9382 0 : nsresult rv = mDoc->GetURL(url);
9383 0 : NS_ENSURE_SUCCESS_VOID(rv);
9384 :
9385 0 : if (!StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
9386 0 : !mHadOriginalOpener && !aTrustedCaller) {
9387 0 : bool allowClose = mAllowScriptsToClose ||
9388 0 : Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
9389 0 : if (!allowClose) {
9390 : // We're blocking the close operation
9391 : // report localized error msg in JS console
9392 0 : nsContentUtils::ReportToConsole(
9393 : nsIScriptError::warningFlag,
9394 0 : NS_LITERAL_CSTRING("DOM Window"), mDoc, // Better name for the category?
9395 : nsContentUtils::eDOM_PROPERTIES,
9396 0 : "WindowCloseBlockedWarning");
9397 :
9398 0 : return;
9399 : }
9400 : }
9401 :
9402 0 : if (!mInClose && !mIsClosed && !CanClose()) {
9403 0 : return;
9404 : }
9405 :
9406 : // Fire a DOM event notifying listeners that this window is about to
9407 : // be closed. The tab UI code may choose to cancel the default
9408 : // action for this event, if so, we won't actually close the window
9409 : // (since the tab UI code will close the tab in stead). Sure, this
9410 : // could be abused by content code, but do we care? I don't think
9411 : // so...
9412 :
9413 0 : bool wasInClose = mInClose;
9414 0 : mInClose = true;
9415 :
9416 0 : if (!DispatchCustomEvent(NS_LITERAL_STRING("DOMWindowClose"))) {
9417 : // Someone chose to prevent the default action for this event, if
9418 : // so, let's not close this window after all...
9419 :
9420 0 : mInClose = wasInClose;
9421 0 : return;
9422 : }
9423 :
9424 0 : FinalClose();
9425 : }
9426 :
9427 : void
9428 0 : nsGlobalWindow::Close(ErrorResult& aError)
9429 : {
9430 0 : FORWARD_TO_OUTER_OR_THROW(CloseOuter, (nsContentUtils::IsCallerChrome()), aError, );
9431 : }
9432 :
9433 : nsresult
9434 0 : nsGlobalWindow::Close()
9435 : {
9436 0 : FORWARD_TO_OUTER(Close, (), NS_ERROR_UNEXPECTED);
9437 0 : CloseOuter(/* aTrustedCaller = */ true);
9438 0 : return NS_OK;
9439 : }
9440 :
9441 : void
9442 0 : nsGlobalWindow::ForceClose()
9443 : {
9444 0 : MOZ_ASSERT(IsOuterWindow());
9445 0 : MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
9446 :
9447 0 : if (IsFrame() || !mDocShell) {
9448 : // This may be a frame in a frameset, or a window that's already closed.
9449 : // Ignore such calls.
9450 0 : return;
9451 : }
9452 :
9453 0 : if (mHavePendingClose) {
9454 : // We're going to be closed anyway; do nothing since we don't want
9455 : // to double-close
9456 0 : return;
9457 : }
9458 :
9459 0 : mInClose = true;
9460 :
9461 0 : DispatchCustomEvent(NS_LITERAL_STRING("DOMWindowClose"));
9462 :
9463 0 : FinalClose();
9464 : }
9465 :
9466 : void
9467 0 : nsGlobalWindow::FinalClose()
9468 : {
9469 0 : MOZ_ASSERT(IsOuterWindow());
9470 :
9471 : // Flag that we were closed.
9472 0 : mIsClosed = true;
9473 :
9474 : // If we get here from CloseOuter then it means that the parent process is
9475 : // going to close our window for us. It's just important to set mIsClosed.
9476 0 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
9477 0 : return;
9478 : }
9479 :
9480 : // This stuff is non-sensical but incredibly fragile. The reasons for the
9481 : // behavior here don't make sense today and may not have ever made sense,
9482 : // but various bits of frontend code break when you change them. If you need
9483 : // to fix up this behavior, feel free to. It's a righteous task, but involves
9484 : // wrestling with various download manager tests, frontend code, and possible
9485 : // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
9486 : // testing ground.
9487 : //
9488 : // In particular, if some inner of |win| is the entry global, we must
9489 : // complete _two_ round-trips to the event loop before the call to
9490 : // ReallyCloseWindow. This allows setTimeout handlers that are set after
9491 : // FinalClose() is called to run before the window is torn down.
9492 : nsCOMPtr<nsPIDOMWindowInner> entryWindow =
9493 0 : do_QueryInterface(GetEntryGlobal());
9494 : bool indirect =
9495 0 : entryWindow && entryWindow->GetOuterWindow() == this->AsOuter();
9496 0 : if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))) {
9497 0 : ReallyCloseWindow();
9498 : } else {
9499 0 : mHavePendingClose = true;
9500 : }
9501 : }
9502 :
9503 :
9504 : void
9505 0 : nsGlobalWindow::ReallyCloseWindow()
9506 : {
9507 0 : FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
9508 :
9509 : // Make sure we never reenter this method.
9510 0 : mHavePendingClose = true;
9511 :
9512 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
9513 :
9514 : // If there's no treeOwnerAsWin, this window must already be closed.
9515 :
9516 0 : if (treeOwnerAsWin) {
9517 :
9518 : // but if we're a browser window we could be in some nasty
9519 : // self-destroying cascade that we should mostly ignore
9520 :
9521 0 : if (mDocShell) {
9522 0 : nsCOMPtr<nsIBrowserDOMWindow> bwin;
9523 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
9524 0 : mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
9525 : nsCOMPtr<nsPIDOMWindowOuter> rootWin =
9526 0 : rootItem ? rootItem->GetWindow() : nullptr;
9527 0 : nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
9528 0 : if (chromeWin)
9529 0 : chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
9530 :
9531 0 : if (rootWin) {
9532 : /* Normally we destroy the entire window, but not if
9533 : this DOM window belongs to a tabbed browser and doesn't
9534 : correspond to a tab. This allows a well-behaved tab
9535 : to destroy the container as it should but is a final measure
9536 : to prevent an errant tab from doing so when it shouldn't.
9537 : This works because we reach this code when we shouldn't only
9538 : in the particular circumstance that we belong to a tab
9539 : that has just been closed (and is therefore already missing
9540 : from the list of browsers) (and has an unload handler
9541 : that closes the window). */
9542 : // XXXbz now that we have mHavePendingClose, is this needed?
9543 : bool isTab;
9544 0 : if (rootWin == AsOuter() ||
9545 0 : !bwin ||
9546 0 : (NS_SUCCEEDED(bwin->IsTabContentWindow(GetOuterWindowInternal(),
9547 0 : &isTab)) && isTab)) {
9548 0 : treeOwnerAsWin->Destroy();
9549 : }
9550 : }
9551 : }
9552 :
9553 0 : CleanUp();
9554 : }
9555 : }
9556 :
9557 : void
9558 0 : nsGlobalWindow::EnterModalState()
9559 : {
9560 0 : MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
9561 :
9562 : // GetScriptableTop, not GetTop, so that EnterModalState works properly with
9563 : // <iframe mozbrowser>.
9564 0 : nsGlobalWindow* topWin = GetScriptableTopInternal();
9565 :
9566 0 : if (!topWin) {
9567 0 : NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
9568 0 : return;
9569 : }
9570 :
9571 : // If there is an active ESM in this window, clear it. Otherwise, this can
9572 : // cause a problem if a modal state is entered during a mouseup event.
9573 : EventStateManager* activeESM =
9574 : static_cast<EventStateManager*>(
9575 0 : EventStateManager::GetActiveEventStateManager());
9576 0 : if (activeESM && activeESM->GetPresContext()) {
9577 0 : nsIPresShell* activeShell = activeESM->GetPresContext()->GetPresShell();
9578 0 : if (activeShell && (
9579 0 : nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(), mDoc) ||
9580 0 : nsContentUtils::ContentIsCrossDocDescendantOf(mDoc, activeShell->GetDocument()))) {
9581 0 : EventStateManager::ClearGlobalActiveContent(activeESM);
9582 :
9583 0 : activeShell->SetCapturingContent(nullptr, 0);
9584 :
9585 0 : if (activeShell) {
9586 0 : RefPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
9587 0 : frameSelection->SetDragState(false);
9588 : }
9589 : }
9590 : }
9591 :
9592 : // If there are any drag and drop operations in flight, try to end them.
9593 : nsCOMPtr<nsIDragService> ds =
9594 0 : do_GetService("@mozilla.org/widget/dragservice;1");
9595 0 : if (ds) {
9596 0 : ds->EndDragSession(true, 0);
9597 : }
9598 :
9599 : // Clear the capturing content if it is under topDoc.
9600 : // Usually the activeESM check above does that, but there are cases when
9601 : // we don't have activeESM, or it is for different document.
9602 0 : nsIDocument* topDoc = topWin->GetExtantDoc();
9603 0 : nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
9604 0 : if (capturingContent && topDoc &&
9605 0 : nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
9606 0 : nsIPresShell::SetCapturingContent(nullptr, 0);
9607 : }
9608 :
9609 0 : if (topWin->mModalStateDepth == 0) {
9610 0 : NS_ASSERTION(!topWin->mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
9611 :
9612 0 : topWin->mSuspendedDoc = topDoc;
9613 0 : if (topDoc) {
9614 0 : topDoc->SuppressEventHandling();
9615 : }
9616 :
9617 0 : nsGlobalWindow* inner = topWin->GetCurrentInnerWindowInternal();
9618 0 : if (inner) {
9619 0 : topWin->GetCurrentInnerWindowInternal()->Suspend();
9620 : }
9621 : }
9622 0 : topWin->mModalStateDepth++;
9623 : }
9624 :
9625 : void
9626 0 : nsGlobalWindow::LeaveModalState()
9627 : {
9628 0 : MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
9629 :
9630 0 : nsGlobalWindow* topWin = GetScriptableTopInternal();
9631 :
9632 0 : if (!topWin) {
9633 0 : NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
9634 0 : return;
9635 : }
9636 :
9637 0 : MOZ_ASSERT(topWin->mModalStateDepth != 0);
9638 0 : MOZ_ASSERT(IsSuspended());
9639 0 : MOZ_ASSERT(topWin->IsSuspended());
9640 0 : topWin->mModalStateDepth--;
9641 :
9642 0 : nsGlobalWindow* inner = topWin->GetCurrentInnerWindowInternal();
9643 :
9644 0 : if (topWin->mModalStateDepth == 0) {
9645 0 : if (inner) {
9646 0 : inner->Resume();
9647 : }
9648 :
9649 0 : if (topWin->mSuspendedDoc) {
9650 0 : nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
9651 0 : topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc == topWin->mSuspendedDoc);
9652 0 : topWin->mSuspendedDoc = nullptr;
9653 : }
9654 : }
9655 :
9656 : // Remember the time of the last dialog quit.
9657 0 : if (inner) {
9658 0 : inner->mLastDialogQuitTime = TimeStamp::Now();
9659 : }
9660 :
9661 0 : if (topWin->mModalStateDepth == 0) {
9662 0 : RefPtr<Event> event = NS_NewDOMEvent(inner, nullptr, nullptr);
9663 0 : event->InitEvent(NS_LITERAL_STRING("endmodalstate"), true, false);
9664 0 : event->SetTrusted(true);
9665 0 : event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
9666 : bool dummy;
9667 0 : topWin->DispatchEvent(event, &dummy);
9668 : }
9669 : }
9670 :
9671 : bool
9672 9 : nsGlobalWindow::IsInModalState()
9673 : {
9674 9 : nsGlobalWindow *topWin = GetScriptableTopInternal();
9675 :
9676 9 : if (!topWin) {
9677 : // IsInModalState() getting called w/o a reachable top window is a bit
9678 : // iffy, but valid enough not to make noise about it. See bug 404828
9679 0 : return false;
9680 : }
9681 :
9682 9 : return topWin->mModalStateDepth != 0;
9683 : }
9684 :
9685 : // static
9686 : void
9687 3 : nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
9688 : nsCOMPtr<nsIObserverService> observerService =
9689 6 : services::GetObserverService();
9690 3 : if (observerService) {
9691 3 : observerService->
9692 3 : NotifyObservers(ToSupports(aWindow),
9693 6 : DOM_WINDOW_DESTROYED_TOPIC, nullptr);
9694 : }
9695 3 : }
9696 :
9697 : // Try to match compartments that are not web content by matching compartments
9698 : // with principals that are either the system principal or an expanded principal.
9699 : // This may not return true for all non-web-content compartments.
9700 3 : struct BrowserCompartmentMatcher : public js::CompartmentFilter {
9701 437 : bool match(JSCompartment* aC) const override
9702 : {
9703 874 : nsCOMPtr<nsIPrincipal> pc = nsJSPrincipals::get(JS_GetCompartmentPrincipals(aC));
9704 874 : return nsContentUtils::IsSystemOrExpandedPrincipal(pc);
9705 : }
9706 : };
9707 :
9708 :
9709 12 : class WindowDestroyedEvent final : public Runnable
9710 : {
9711 : public:
9712 4 : WindowDestroyedEvent(nsIDOMWindow* aWindow, uint64_t aID, const char* aTopic)
9713 4 : : mozilla::Runnable("WindowDestroyedEvent")
9714 : , mID(aID)
9715 : , mPhase(Phase::Destroying)
9716 4 : , mTopic(aTopic)
9717 : {
9718 4 : mWindow = do_GetWeakReference(aWindow);
9719 4 : }
9720 :
9721 : enum class Phase
9722 : {
9723 : Destroying,
9724 : Nuking
9725 : };
9726 :
9727 8 : NS_IMETHOD Run() override
9728 : {
9729 16 : AUTO_PROFILER_LABEL("WindowDestroyedEvent::Run", OTHER);
9730 :
9731 : nsCOMPtr<nsIObserverService> observerService =
9732 16 : services::GetObserverService();
9733 8 : if (!observerService) {
9734 0 : return NS_OK;
9735 : }
9736 :
9737 : nsCOMPtr<nsISupportsPRUint64> wrapper =
9738 16 : do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
9739 8 : if (wrapper) {
9740 8 : wrapper->SetData(mID);
9741 8 : observerService->NotifyObservers(wrapper, mTopic.get(), nullptr);
9742 : }
9743 :
9744 8 : switch (mPhase) {
9745 : case Phase::Destroying:
9746 : {
9747 4 : bool skipNukeCrossCompartment = false;
9748 : #ifndef DEBUG
9749 : nsCOMPtr<nsIAppStartup> appStartup =
9750 : do_GetService(NS_APPSTARTUP_CONTRACTID);
9751 :
9752 : if (appStartup) {
9753 : appStartup->GetShuttingDown(&skipNukeCrossCompartment);
9754 : }
9755 : #endif
9756 :
9757 4 : if (!skipNukeCrossCompartment) {
9758 : // The compartment nuking phase might be too expensive, so do that
9759 : // part off of idle dispatch.
9760 :
9761 : // For the compartment nuking phase, we dispatch either an
9762 : // inner-window-nuked or an outer-window-nuked notification.
9763 : // This will allow tests to wait for compartment nuking to happen.
9764 4 : if (mTopic.EqualsLiteral("inner-window-destroyed")) {
9765 3 : mTopic.AssignLiteral("inner-window-nuked");
9766 1 : } else if (mTopic.EqualsLiteral("outer-window-destroyed")) {
9767 1 : mTopic.AssignLiteral("outer-window-nuked");
9768 : }
9769 4 : mPhase = Phase::Nuking;
9770 :
9771 8 : nsCOMPtr<nsIRunnable> copy(this);
9772 4 : NS_IdleDispatchToCurrentThread(copy.forget(), 1000);
9773 : }
9774 : }
9775 4 : break;
9776 :
9777 : case Phase::Nuking:
9778 : {
9779 8 : nsCOMPtr<nsISupports> window = do_QueryReferent(mWindow);
9780 4 : if (window) {
9781 4 : nsGlobalWindow* win = nsGlobalWindow::FromSupports(window);
9782 4 : nsGlobalWindow* currentInner = win->IsInnerWindow() ? win : win->GetCurrentInnerWindowInternal();
9783 4 : NS_ENSURE_TRUE(currentInner, NS_OK);
9784 :
9785 8 : AutoSafeJSContext cx;
9786 8 : JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
9787 4 : if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
9788 3 : JSCompartment* cpt = js::GetObjectCompartment(obj);
9789 6 : nsCOMPtr<nsIPrincipal> pc = nsJSPrincipals::get(JS_GetCompartmentPrincipals(cpt));
9790 :
9791 6 : nsAutoString addonId;
9792 3 : if (NS_SUCCEEDED(pc->GetAddonId(addonId)) && !addonId.IsEmpty()) {
9793 : // We want to nuke all references to the add-on compartment.
9794 0 : xpc::NukeAllWrappersForCompartment(cx, cpt,
9795 0 : win->IsInnerWindow() ? js::DontNukeWindowReferences
9796 0 : : js::NukeWindowReferences);
9797 : } else {
9798 : // We only want to nuke wrappers for the chrome->content case
9799 9 : js::NukeCrossCompartmentWrappers(cx, BrowserCompartmentMatcher(), cpt,
9800 3 : win->IsInnerWindow() ? js::DontNukeWindowReferences
9801 : : js::NukeWindowReferences,
9802 6 : js::NukeIncomingReferences);
9803 : }
9804 : }
9805 : }
9806 : }
9807 4 : break;
9808 : }
9809 :
9810 8 : return NS_OK;
9811 : }
9812 :
9813 : private:
9814 : uint64_t mID;
9815 : Phase mPhase;
9816 : nsCString mTopic;
9817 : nsWeakPtr mWindow;
9818 : };
9819 :
9820 : void
9821 4 : nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
9822 : {
9823 8 : nsCOMPtr<nsIRunnable> runnable = new WindowDestroyedEvent(this, mWindowID, aTopic);
9824 : nsresult rv =
9825 4 : Dispatch("WindowDestroyedEvent", TaskCategory::Other, runnable.forget());
9826 4 : if (NS_SUCCEEDED(rv)) {
9827 4 : mNotifiedIDDestroyed = true;
9828 : }
9829 4 : }
9830 :
9831 : // static
9832 : void
9833 0 : nsGlobalWindow::NotifyDOMWindowFrozen(nsGlobalWindow* aWindow) {
9834 0 : if (aWindow && aWindow->IsInnerWindow()) {
9835 : nsCOMPtr<nsIObserverService> observerService =
9836 0 : services::GetObserverService();
9837 0 : if (observerService) {
9838 0 : observerService->
9839 0 : NotifyObservers(ToSupports(aWindow),
9840 0 : DOM_WINDOW_FROZEN_TOPIC, nullptr);
9841 : }
9842 : }
9843 0 : }
9844 :
9845 : // static
9846 : void
9847 0 : nsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindow* aWindow) {
9848 0 : if (aWindow && aWindow->IsInnerWindow()) {
9849 : nsCOMPtr<nsIObserverService> observerService =
9850 0 : services::GetObserverService();
9851 0 : if (observerService) {
9852 0 : observerService->
9853 0 : NotifyObservers(ToSupports(aWindow),
9854 0 : DOM_WINDOW_THAWED_TOPIC, nullptr);
9855 : }
9856 : }
9857 0 : }
9858 :
9859 : JSObject*
9860 6 : nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
9861 : {
9862 12 : JS::Rooted<JSObject*> handler(RootingCx());
9863 6 : if (mCachedXBLPrototypeHandlers) {
9864 5 : mCachedXBLPrototypeHandlers->Get(aKey, handler.address());
9865 : }
9866 12 : return handler;
9867 : }
9868 :
9869 : void
9870 4 : nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
9871 : JS::Handle<JSObject*> aHandler)
9872 : {
9873 4 : if (!mCachedXBLPrototypeHandlers) {
9874 1 : mCachedXBLPrototypeHandlers = new XBLPrototypeHandlerTable();
9875 1 : PreserveWrapper(ToSupports(this));
9876 : }
9877 :
9878 4 : mCachedXBLPrototypeHandlers->Put(aKey, aHandler);
9879 4 : }
9880 :
9881 : Element*
9882 0 : nsGlobalWindow::GetFrameElementOuter(nsIPrincipal& aSubjectPrincipal)
9883 : {
9884 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
9885 :
9886 0 : if (!mDocShell || mDocShell->GetIsMozBrowser()) {
9887 0 : return nullptr;
9888 : }
9889 :
9890 : // Per HTML5, the frameElement getter returns null in cross-origin situations.
9891 0 : Element* element = GetRealFrameElementOuter();
9892 0 : if (!element) {
9893 0 : return nullptr;
9894 : }
9895 :
9896 0 : if (!aSubjectPrincipal.SubsumesConsideringDomain(element->NodePrincipal())) {
9897 0 : return nullptr;
9898 : }
9899 :
9900 0 : return element;
9901 : }
9902 :
9903 : Element*
9904 0 : nsGlobalWindow::GetFrameElement(nsIPrincipal& aSubjectPrincipal,
9905 : ErrorResult& aError)
9906 : {
9907 0 : FORWARD_TO_OUTER_OR_THROW(GetFrameElementOuter, (aSubjectPrincipal), aError,
9908 : nullptr);
9909 : }
9910 :
9911 : Element*
9912 0 : nsGlobalWindow::GetRealFrameElementOuter()
9913 : {
9914 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
9915 :
9916 0 : if (!mDocShell) {
9917 0 : return nullptr;
9918 : }
9919 :
9920 0 : nsCOMPtr<nsIDocShell> parent;
9921 0 : mDocShell->GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent));
9922 :
9923 0 : if (!parent || parent == mDocShell) {
9924 : // We're at a chrome boundary, don't expose the chrome iframe
9925 : // element to content code.
9926 0 : return nullptr;
9927 : }
9928 :
9929 0 : return mFrameElement;
9930 : }
9931 :
9932 : Element*
9933 0 : nsGlobalWindow::GetRealFrameElement(ErrorResult& aError)
9934 : {
9935 0 : FORWARD_TO_OUTER_OR_THROW(GetRealFrameElementOuter, (), aError, nullptr);
9936 : }
9937 :
9938 : /**
9939 : * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper
9940 : * around GetRealFrameElement.
9941 : */
9942 : already_AddRefed<nsIDOMElement>
9943 0 : nsGlobalWindow::GetFrameElement()
9944 : {
9945 0 : FORWARD_TO_INNER(GetFrameElement, (), nullptr);
9946 :
9947 0 : ErrorResult dummy;
9948 : nsCOMPtr<nsIDOMElement> frameElement =
9949 0 : do_QueryInterface(GetRealFrameElement(dummy));
9950 0 : dummy.SuppressException();
9951 0 : return frameElement.forget();
9952 : }
9953 :
9954 : /* static */ bool
9955 0 : nsGlobalWindow::TokenizeDialogOptions(nsAString& aToken,
9956 : nsAString::const_iterator& aIter,
9957 : nsAString::const_iterator aEnd)
9958 : {
9959 0 : while (aIter != aEnd && nsCRT::IsAsciiSpace(*aIter)) {
9960 0 : ++aIter;
9961 : }
9962 :
9963 0 : if (aIter == aEnd) {
9964 0 : return false;
9965 : }
9966 :
9967 0 : if (*aIter == ';' || *aIter == ':' || *aIter == '=') {
9968 0 : aToken.Assign(*aIter);
9969 0 : ++aIter;
9970 0 : return true;
9971 : }
9972 :
9973 0 : nsAString::const_iterator start = aIter;
9974 :
9975 : // Skip characters until we find whitespace, ';', ':', or '='
9976 0 : while (aIter != aEnd && !nsCRT::IsAsciiSpace(*aIter) &&
9977 0 : *aIter != ';' &&
9978 0 : *aIter != ':' &&
9979 0 : *aIter != '=') {
9980 0 : ++aIter;
9981 : }
9982 :
9983 0 : aToken.Assign(Substring(start, aIter));
9984 0 : return true;
9985 : }
9986 :
9987 : // Helper for converting window.showModalDialog() options (list of ';'
9988 : // separated name (:|=) value pairs) to a format that's parsable by
9989 : // our normal window opening code.
9990 :
9991 : /* static */
9992 : void
9993 0 : nsGlobalWindow::ConvertDialogOptions(const nsAString& aOptions,
9994 : nsAString& aResult)
9995 : {
9996 0 : nsAString::const_iterator end;
9997 0 : aOptions.EndReading(end);
9998 :
9999 0 : nsAString::const_iterator iter;
10000 0 : aOptions.BeginReading(iter);
10001 :
10002 0 : nsAutoString token;
10003 0 : nsAutoString name;
10004 0 : nsAutoString value;
10005 :
10006 : while (true) {
10007 0 : if (!TokenizeDialogOptions(name, iter, end)) {
10008 0 : break;
10009 : }
10010 :
10011 : // Invalid name.
10012 0 : if (name.EqualsLiteral("=") ||
10013 0 : name.EqualsLiteral(":") ||
10014 0 : name.EqualsLiteral(";")) {
10015 0 : break;
10016 : }
10017 :
10018 0 : if (!TokenizeDialogOptions(token, iter, end)) {
10019 0 : break;
10020 : }
10021 :
10022 0 : if (!token.EqualsLiteral(":") && !token.EqualsLiteral("=")) {
10023 0 : continue;
10024 : }
10025 :
10026 : // We found name followed by ':' or '='. Look for a value.
10027 0 : if (!TokenizeDialogOptions(value, iter, end)) {
10028 0 : break;
10029 : }
10030 :
10031 0 : if (name.LowerCaseEqualsLiteral("center")) {
10032 0 : if (value.LowerCaseEqualsLiteral("on") ||
10033 0 : value.LowerCaseEqualsLiteral("yes") ||
10034 0 : value.LowerCaseEqualsLiteral("1")) {
10035 0 : aResult.AppendLiteral(",centerscreen=1");
10036 : }
10037 0 : } else if (name.LowerCaseEqualsLiteral("dialogwidth")) {
10038 0 : if (!value.IsEmpty()) {
10039 0 : aResult.AppendLiteral(",width=");
10040 0 : aResult.Append(value);
10041 : }
10042 0 : } else if (name.LowerCaseEqualsLiteral("dialogheight")) {
10043 0 : if (!value.IsEmpty()) {
10044 0 : aResult.AppendLiteral(",height=");
10045 0 : aResult.Append(value);
10046 : }
10047 0 : } else if (name.LowerCaseEqualsLiteral("dialogtop")) {
10048 0 : if (!value.IsEmpty()) {
10049 0 : aResult.AppendLiteral(",top=");
10050 0 : aResult.Append(value);
10051 : }
10052 0 : } else if (name.LowerCaseEqualsLiteral("dialogleft")) {
10053 0 : if (!value.IsEmpty()) {
10054 0 : aResult.AppendLiteral(",left=");
10055 0 : aResult.Append(value);
10056 : }
10057 0 : } else if (name.LowerCaseEqualsLiteral("resizable")) {
10058 0 : if (value.LowerCaseEqualsLiteral("on") ||
10059 0 : value.LowerCaseEqualsLiteral("yes") ||
10060 0 : value.LowerCaseEqualsLiteral("1")) {
10061 0 : aResult.AppendLiteral(",resizable=1");
10062 : }
10063 0 : } else if (name.LowerCaseEqualsLiteral("scroll")) {
10064 0 : if (value.LowerCaseEqualsLiteral("off") ||
10065 0 : value.LowerCaseEqualsLiteral("no") ||
10066 0 : value.LowerCaseEqualsLiteral("0")) {
10067 0 : aResult.AppendLiteral(",scrollbars=0");
10068 : }
10069 : }
10070 :
10071 0 : if (iter == end ||
10072 0 : !TokenizeDialogOptions(token, iter, end) ||
10073 0 : !token.EqualsLiteral(";")) {
10074 0 : break;
10075 : }
10076 : }
10077 0 : }
10078 :
10079 : already_AddRefed<nsIVariant>
10080 0 : nsGlobalWindow::ShowModalDialogOuter(const nsAString& aUrl,
10081 : nsIVariant* aArgument,
10082 : const nsAString& aOptions,
10083 : nsIPrincipal& aSubjectPrincipal,
10084 : ErrorResult& aError)
10085 : {
10086 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
10087 :
10088 0 : if (mDoc) {
10089 0 : mDoc->WarnOnceAbout(nsIDocument::eShowModalDialog);
10090 : }
10091 :
10092 0 : if (!IsShowModalDialogEnabled()) {
10093 0 : aError.Throw(NS_ERROR_NOT_AVAILABLE);
10094 0 : return nullptr;
10095 : }
10096 :
10097 : RefPtr<DialogValueHolder> argHolder =
10098 0 : new DialogValueHolder(&aSubjectPrincipal, aArgument);
10099 :
10100 : // Before bringing up the window/dialog, unsuppress painting and flush
10101 : // pending reflows.
10102 0 : EnsureReflowFlushAndPaint();
10103 :
10104 0 : if (!AreDialogsEnabled()) {
10105 : // We probably want to keep throwing here; silently doing nothing is a bit
10106 : // weird given the typical use cases of showModalDialog().
10107 0 : aError.Throw(NS_ERROR_NOT_AVAILABLE);
10108 0 : return nullptr;
10109 : }
10110 :
10111 0 : if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
10112 0 : aError.Throw(NS_ERROR_NOT_AVAILABLE);
10113 0 : return nullptr;
10114 : }
10115 :
10116 0 : nsCOMPtr<nsPIDOMWindowOuter> dlgWin;
10117 0 : nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
10118 :
10119 0 : ConvertDialogOptions(aOptions, options);
10120 :
10121 0 : options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
10122 :
10123 0 : EnterModalState();
10124 0 : uint32_t oldMicroTaskLevel = nsContentUtils::MicroTaskLevel();
10125 0 : nsContentUtils::SetMicroTaskLevel(0);
10126 0 : aError = OpenInternal(aUrl, EmptyString(), options,
10127 : false, // aDialog
10128 : true, // aContentModal
10129 : true, // aCalledNoScript
10130 : true, // aDoJSFixups
10131 : true, // aNavigate
10132 : nullptr, argHolder, // args
10133 : nullptr, // aLoadInfo
10134 : false, // aForceNoOpener
10135 0 : getter_AddRefs(dlgWin));
10136 0 : nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel);
10137 0 : LeaveModalState();
10138 0 : if (aError.Failed()) {
10139 0 : return nullptr;
10140 : }
10141 :
10142 0 : nsCOMPtr<nsIDOMModalContentWindow> dialog = do_QueryInterface(dlgWin);
10143 0 : if (!dialog) {
10144 0 : return nullptr;
10145 : }
10146 :
10147 0 : nsCOMPtr<nsIVariant> retVal;
10148 0 : aError = dialog->GetReturnValue(getter_AddRefs(retVal));
10149 0 : MOZ_ASSERT(!aError.Failed());
10150 :
10151 0 : return retVal.forget();
10152 : }
10153 :
10154 : already_AddRefed<nsIVariant>
10155 0 : nsGlobalWindow::ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument,
10156 : const nsAString& aOptions,
10157 : nsIPrincipal& aSubjectPrincipal,
10158 : ErrorResult& aError)
10159 : {
10160 0 : FORWARD_TO_OUTER_OR_THROW(ShowModalDialogOuter,
10161 : (aUrl, aArgument, aOptions, aSubjectPrincipal,
10162 : aError), aError, nullptr);
10163 : }
10164 :
10165 : void
10166 0 : nsGlobalWindow::ShowModalDialog(JSContext* aCx, const nsAString& aUrl,
10167 : JS::Handle<JS::Value> aArgument,
10168 : const nsAString& aOptions,
10169 : JS::MutableHandle<JS::Value> aRetval,
10170 : nsIPrincipal& aSubjectPrincipal,
10171 : ErrorResult& aError)
10172 : {
10173 0 : MOZ_ASSERT(IsInnerWindow());
10174 :
10175 0 : nsCOMPtr<nsIVariant> args;
10176 0 : aError = nsContentUtils::XPConnect()->JSToVariant(aCx,
10177 : aArgument,
10178 0 : getter_AddRefs(args));
10179 0 : if (aError.Failed()) {
10180 0 : return;
10181 : }
10182 :
10183 : nsCOMPtr<nsIVariant> retVal =
10184 0 : ShowModalDialog(aUrl, args, aOptions, aSubjectPrincipal, aError);
10185 0 : if (aError.Failed()) {
10186 0 : return;
10187 : }
10188 :
10189 0 : JS::Rooted<JS::Value> result(aCx);
10190 0 : if (retVal) {
10191 0 : JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
10192 0 : if (!global) {
10193 0 : global = FastGetGlobalJSObject();
10194 : }
10195 0 : aError = nsContentUtils::XPConnect()->VariantToJS(aCx,
10196 : global,
10197 0 : retVal, aRetval);
10198 : } else {
10199 0 : aRetval.setNull();
10200 : }
10201 : }
10202 :
10203 6 : class ChildCommandDispatcher : public Runnable
10204 : {
10205 : public:
10206 2 : ChildCommandDispatcher(nsGlobalWindow* aWindow,
10207 : nsITabChild* aTabChild,
10208 : const nsAString& aAction)
10209 2 : : mozilla::Runnable("ChildCommandDispatcher")
10210 : , mWindow(aWindow)
10211 : , mTabChild(aTabChild)
10212 2 : , mAction(aAction)
10213 : {
10214 2 : }
10215 :
10216 2 : NS_IMETHOD Run() override
10217 : {
10218 4 : nsCOMPtr<nsPIWindowRoot> root = mWindow->GetTopWindowRoot();
10219 2 : if (!root) {
10220 0 : return NS_OK;
10221 : }
10222 :
10223 4 : nsTArray<nsCString> enabledCommands, disabledCommands;
10224 2 : root->GetEnabledDisabledCommands(enabledCommands, disabledCommands);
10225 2 : if (enabledCommands.Length() || disabledCommands.Length()) {
10226 2 : mTabChild->EnableDisableCommands(mAction, enabledCommands, disabledCommands);
10227 : }
10228 :
10229 2 : return NS_OK;
10230 : }
10231 :
10232 : private:
10233 : RefPtr<nsGlobalWindow> mWindow;
10234 : nsCOMPtr<nsITabChild> mTabChild;
10235 : nsString mAction;
10236 : };
10237 :
10238 9 : class CommandDispatcher : public Runnable
10239 : {
10240 : public:
10241 3 : CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
10242 : const nsAString& aAction)
10243 3 : : mozilla::Runnable("CommandDispatcher")
10244 : , mDispatcher(aDispatcher)
10245 3 : , mAction(aAction)
10246 : {
10247 3 : }
10248 :
10249 3 : NS_IMETHOD Run() override
10250 : {
10251 3 : return mDispatcher->UpdateCommands(mAction);
10252 : }
10253 :
10254 : nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
10255 : nsString mAction;
10256 : };
10257 :
10258 : nsresult
10259 5 : nsGlobalWindow::UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason)
10260 : {
10261 : // If this is a child process, redirect to the parent process.
10262 5 : if (nsIDocShell* docShell = GetDocShell()) {
10263 8 : if (nsCOMPtr<nsITabChild> child = docShell->GetTabChild()) {
10264 : nsContentUtils::AddScriptRunner(new ChildCommandDispatcher(this, child,
10265 4 : anAction));
10266 2 : return NS_OK;
10267 : }
10268 : }
10269 :
10270 3 : nsPIDOMWindowOuter *rootWindow = nsGlobalWindow::GetPrivateRoot();
10271 3 : if (!rootWindow)
10272 0 : return NS_OK;
10273 :
10274 : nsCOMPtr<nsIDOMXULDocument> xulDoc =
10275 6 : do_QueryInterface(rootWindow->GetExtantDoc());
10276 : // See if we contain a XUL document.
10277 : // selectionchange action is only used for mozbrowser, not for XUL. So we bypass
10278 : // XUL command dispatch if anAction is "selectionchange".
10279 3 : if (xulDoc && !anAction.EqualsLiteral("selectionchange")) {
10280 : // Retrieve the command dispatcher and call updateCommands on it.
10281 6 : nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
10282 3 : xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
10283 3 : if (xulCommandDispatcher) {
10284 : nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
10285 6 : anAction));
10286 : }
10287 : }
10288 :
10289 3 : return NS_OK;
10290 : }
10291 :
10292 : Selection*
10293 0 : nsGlobalWindow::GetSelectionOuter()
10294 : {
10295 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
10296 :
10297 0 : if (!mDocShell) {
10298 0 : return nullptr;
10299 : }
10300 :
10301 0 : nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
10302 0 : if (!presShell) {
10303 0 : return nullptr;
10304 : }
10305 : nsISelection* domSelection =
10306 0 : presShell->GetCurrentSelection(SelectionType::eNormal);
10307 0 : return domSelection ? domSelection->AsSelection() : nullptr;
10308 : }
10309 :
10310 : Selection*
10311 0 : nsGlobalWindow::GetSelection(ErrorResult& aError)
10312 : {
10313 0 : FORWARD_TO_OUTER_OR_THROW(GetSelectionOuter, (), aError, nullptr);
10314 : }
10315 :
10316 : already_AddRefed<nsISelection>
10317 0 : nsGlobalWindow::GetSelection()
10318 : {
10319 0 : nsCOMPtr<nsISelection> selection = GetSelectionOuter();
10320 0 : return selection.forget();
10321 : }
10322 :
10323 : bool
10324 0 : nsGlobalWindow::FindOuter(const nsAString& aString, bool aCaseSensitive,
10325 : bool aBackwards, bool aWrapAround, bool aWholeWord,
10326 : bool aSearchInFrames, bool aShowDialog,
10327 : ErrorResult& aError)
10328 : {
10329 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
10330 :
10331 : Unused << aShowDialog;
10332 :
10333 0 : if (Preferences::GetBool("dom.disable_window_find", false)) {
10334 0 : aError.Throw(NS_ERROR_NOT_AVAILABLE);
10335 0 : return false;
10336 : }
10337 :
10338 0 : nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
10339 0 : if (!finder) {
10340 0 : aError.Throw(NS_ERROR_NOT_AVAILABLE);
10341 0 : return false;
10342 : }
10343 :
10344 : // Set the options of the search
10345 0 : aError = finder->SetSearchString(PromiseFlatString(aString).get());
10346 0 : if (aError.Failed()) {
10347 0 : return false;
10348 : }
10349 0 : finder->SetMatchCase(aCaseSensitive);
10350 0 : finder->SetFindBackwards(aBackwards);
10351 0 : finder->SetWrapFind(aWrapAround);
10352 0 : finder->SetEntireWord(aWholeWord);
10353 0 : finder->SetSearchFrames(aSearchInFrames);
10354 :
10355 : // the nsIWebBrowserFind is initialized to use this window
10356 : // as the search root, but uses focus to set the current search
10357 : // frame. If we're being called from JS (as here), this window
10358 : // should be the current search frame.
10359 0 : nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
10360 0 : if (framesFinder) {
10361 0 : framesFinder->SetRootSearchFrame(AsOuter()); // paranoia
10362 0 : framesFinder->SetCurrentSearchFrame(AsOuter());
10363 : }
10364 :
10365 0 : if (aString.IsEmpty()) {
10366 0 : return false;
10367 : }
10368 :
10369 : // Launch the search with the passed in search string
10370 0 : bool didFind = false;
10371 0 : aError = finder->FindNext(&didFind);
10372 0 : return didFind;
10373 : }
10374 :
10375 : bool
10376 0 : nsGlobalWindow::Find(const nsAString& aString, bool aCaseSensitive,
10377 : bool aBackwards, bool aWrapAround, bool aWholeWord,
10378 : bool aSearchInFrames, bool aShowDialog,
10379 : ErrorResult& aError)
10380 : {
10381 0 : FORWARD_TO_OUTER_OR_THROW(FindOuter,
10382 : (aString, aCaseSensitive, aBackwards, aWrapAround,
10383 : aWholeWord, aSearchInFrames, aShowDialog, aError),
10384 : aError, false);
10385 : }
10386 :
10387 : void
10388 0 : nsGlobalWindow::GetOrigin(nsAString& aOrigin)
10389 : {
10390 0 : MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());
10391 0 : nsContentUtils::GetUTFOrigin(GetPrincipal(), aOrigin);
10392 0 : }
10393 :
10394 : void
10395 0 : nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
10396 : nsAString& aBinaryData, ErrorResult& aError)
10397 : {
10398 0 : MOZ_ASSERT(IsInnerWindow());
10399 0 : aError = nsContentUtils::Atob(aAsciiBase64String, aBinaryData);
10400 0 : }
10401 :
10402 : void
10403 0 : nsGlobalWindow::Btoa(const nsAString& aBinaryData,
10404 : nsAString& aAsciiBase64String, ErrorResult& aError)
10405 : {
10406 0 : MOZ_ASSERT(IsInnerWindow());
10407 0 : aError = nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
10408 0 : }
10409 :
10410 : //*****************************************************************************
10411 : // nsGlobalWindow::nsIDOMEventTarget
10412 : //*****************************************************************************
10413 :
10414 : nsPIDOMWindowOuter*
10415 0 : nsGlobalWindow::GetOwnerGlobalForBindings()
10416 : {
10417 0 : if (IsOuterWindow()) {
10418 0 : return AsOuter();
10419 : }
10420 :
10421 0 : return nsPIDOMWindowOuter::GetFromCurrentInner(AsInner());
10422 : }
10423 :
10424 : NS_IMETHODIMP
10425 0 : nsGlobalWindow::RemoveEventListener(const nsAString& aType,
10426 : nsIDOMEventListener* aListener,
10427 : bool aUseCapture)
10428 : {
10429 0 : if (RefPtr<EventListenerManager> elm = GetExistingListenerManager()) {
10430 0 : elm->RemoveEventListener(aType, aListener, aUseCapture);
10431 : }
10432 0 : return NS_OK;
10433 : }
10434 :
10435 0 : NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)
10436 :
10437 : NS_IMETHODIMP
10438 8 : nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
10439 : {
10440 8 : FORWARD_TO_INNER(DispatchEvent, (aEvent, aRetVal), NS_OK);
10441 :
10442 7 : if (!AsInner()->IsCurrentInnerWindow()) {
10443 : NS_WARNING("DispatchEvent called on non-current inner window, dropping. "
10444 0 : "Please check the window in the caller instead.");
10445 0 : return NS_ERROR_FAILURE;
10446 : }
10447 :
10448 7 : if (!mDoc) {
10449 0 : return NS_ERROR_FAILURE;
10450 : }
10451 :
10452 : // Obtain a presentation shell
10453 7 : nsIPresShell *shell = mDoc->GetShell();
10454 14 : RefPtr<nsPresContext> presContext;
10455 7 : if (shell) {
10456 : // Retrieve the context
10457 7 : presContext = shell->GetPresContext();
10458 : }
10459 :
10460 7 : nsEventStatus status = nsEventStatus_eIgnore;
10461 7 : nsresult rv = EventDispatcher::DispatchDOMEvent(AsInner(), nullptr, aEvent,
10462 7 : presContext, &status);
10463 :
10464 7 : *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
10465 7 : return rv;
10466 : }
10467 :
10468 : NS_IMETHODIMP
10469 0 : nsGlobalWindow::AddEventListener(const nsAString& aType,
10470 : nsIDOMEventListener *aListener,
10471 : bool aUseCapture, bool aWantsUntrusted,
10472 : uint8_t aOptionalArgc)
10473 : {
10474 0 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
10475 : "Won't check if this is chrome, you want to set "
10476 : "aWantsUntrusted to false or make the aWantsUntrusted "
10477 : "explicit by making optional_argc non-zero.");
10478 :
10479 0 : if (!aWantsUntrusted &&
10480 0 : (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
10481 0 : aWantsUntrusted = true;
10482 : }
10483 :
10484 0 : EventListenerManager* manager = GetOrCreateListenerManager();
10485 0 : NS_ENSURE_STATE(manager);
10486 0 : manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
10487 0 : return NS_OK;
10488 : }
10489 :
10490 : void
10491 49 : nsGlobalWindow::AddEventListener(const nsAString& aType,
10492 : EventListener* aListener,
10493 : const AddEventListenerOptionsOrBoolean& aOptions,
10494 : const Nullable<bool>& aWantsUntrusted,
10495 : ErrorResult& aRv)
10496 : {
10497 49 : if (IsOuterWindow() && mInnerWindow &&
10498 0 : !nsContentUtils::CanCallerAccess(mInnerWindow)) {
10499 0 : aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
10500 0 : return;
10501 : }
10502 :
10503 : bool wantsUntrusted;
10504 49 : if (aWantsUntrusted.IsNull()) {
10505 47 : wantsUntrusted = !nsContentUtils::IsChromeDoc(mDoc);
10506 : } else {
10507 2 : wantsUntrusted = aWantsUntrusted.Value();
10508 : }
10509 :
10510 49 : EventListenerManager* manager = GetOrCreateListenerManager();
10511 49 : if (!manager) {
10512 0 : aRv.Throw(NS_ERROR_UNEXPECTED);
10513 0 : return;
10514 : }
10515 :
10516 49 : manager->AddEventListener(aType, aListener, aOptions, wantsUntrusted);
10517 : }
10518 :
10519 : NS_IMETHODIMP
10520 0 : nsGlobalWindow::AddSystemEventListener(const nsAString& aType,
10521 : nsIDOMEventListener *aListener,
10522 : bool aUseCapture,
10523 : bool aWantsUntrusted,
10524 : uint8_t aOptionalArgc)
10525 : {
10526 0 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
10527 : "Won't check if this is chrome, you want to set "
10528 : "aWantsUntrusted to false or make the aWantsUntrusted "
10529 : "explicit by making optional_argc non-zero.");
10530 :
10531 0 : if (IsOuterWindow() && mInnerWindow &&
10532 0 : !nsContentUtils::LegacyIsCallerNativeCode() &&
10533 0 : !nsContentUtils::CanCallerAccess(mInnerWindow)) {
10534 0 : return NS_ERROR_DOM_SECURITY_ERR;
10535 : }
10536 :
10537 0 : if (!aWantsUntrusted &&
10538 0 : (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
10539 0 : aWantsUntrusted = true;
10540 : }
10541 :
10542 0 : return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
10543 0 : aWantsUntrusted);
10544 : }
10545 :
10546 : EventListenerManager*
10547 52 : nsGlobalWindow::GetOrCreateListenerManager()
10548 : {
10549 52 : FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager, (), nullptr);
10550 :
10551 52 : if (!mListenerManager) {
10552 : mListenerManager =
10553 2 : new EventListenerManager(static_cast<EventTarget*>(this));
10554 : }
10555 :
10556 52 : return mListenerManager;
10557 : }
10558 :
10559 : EventListenerManager*
10560 347 : nsGlobalWindow::GetExistingListenerManager() const
10561 : {
10562 347 : FORWARD_TO_INNER(GetExistingListenerManager, (), nullptr);
10563 :
10564 294 : return mListenerManager;
10565 : }
10566 :
10567 : nsIScriptContext*
10568 0 : nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
10569 : {
10570 0 : *aRv = NS_ERROR_UNEXPECTED;
10571 0 : NS_ENSURE_TRUE(!IsInnerWindow() || AsInner()->IsCurrentInnerWindow(), nullptr);
10572 :
10573 : nsIScriptContext* scx;
10574 0 : if ((scx = GetContext())) {
10575 0 : *aRv = NS_OK;
10576 0 : return scx;
10577 : }
10578 0 : return nullptr;
10579 : }
10580 :
10581 : //*****************************************************************************
10582 : // nsGlobalWindow::nsPIDOMWindow
10583 : //*****************************************************************************
10584 :
10585 : nsPIDOMWindowOuter*
10586 27 : nsGlobalWindow::GetPrivateParent()
10587 : {
10588 27 : MOZ_ASSERT(IsOuterWindow());
10589 :
10590 54 : nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
10591 :
10592 27 : if (AsOuter() == parent) {
10593 54 : nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
10594 27 : if (!chromeElement)
10595 27 : return nullptr; // This is ok, just means a null parent.
10596 :
10597 0 : nsIDocument* doc = chromeElement->GetComposedDoc();
10598 0 : if (!doc)
10599 0 : return nullptr; // This is ok, just means a null parent.
10600 :
10601 0 : return doc->GetWindow();
10602 : }
10603 :
10604 0 : return parent;
10605 : }
10606 :
10607 : nsPIDOMWindowOuter*
10608 60 : nsGlobalWindow::GetPrivateRoot()
10609 : {
10610 60 : if (IsInnerWindow()) {
10611 2 : nsGlobalWindow* outer = GetOuterWindowInternal();
10612 2 : if (!outer) {
10613 0 : NS_WARNING("No outer window available!");
10614 0 : return nullptr;
10615 : }
10616 2 : return outer->GetPrivateRoot();
10617 : }
10618 :
10619 116 : nsCOMPtr<nsPIDOMWindowOuter> top = GetTop();
10620 :
10621 116 : nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
10622 58 : if (chromeElement) {
10623 2 : nsIDocument* doc = chromeElement->GetComposedDoc();
10624 2 : if (doc) {
10625 4 : nsCOMPtr<nsPIDOMWindowOuter> parent = doc->GetWindow();
10626 2 : if (parent) {
10627 2 : top = parent->GetTop();
10628 : }
10629 : }
10630 : }
10631 :
10632 58 : return top;
10633 : }
10634 :
10635 : Location*
10636 8 : nsGlobalWindow::GetLocation()
10637 : {
10638 : // This method can be called on the outer window as well.
10639 8 : FORWARD_TO_INNER(GetLocation, (), nullptr);
10640 :
10641 8 : MOZ_RELEASE_ASSERT(IsInnerWindow());
10642 :
10643 8 : if (!mLocation) {
10644 6 : mLocation = new dom::Location(AsInner(), GetDocShell());
10645 : }
10646 :
10647 8 : return mLocation;
10648 : }
10649 :
10650 : void
10651 4 : nsGlobalWindow::ActivateOrDeactivate(bool aActivate)
10652 : {
10653 4 : MOZ_ASSERT(IsOuterWindow());
10654 :
10655 4 : if (!mDoc) {
10656 0 : return;
10657 : }
10658 :
10659 : // Set / unset mIsActive on the top level window, which is used for the
10660 : // :-moz-window-inactive pseudoclass, and its sheet (if any).
10661 8 : nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
10662 8 : nsCOMPtr<nsIWidget> topLevelWidget;
10663 4 : if (mainWidget) {
10664 : // Get the top level widget (if the main widget is a sheet, this will
10665 : // be the sheet's top (non-sheet) parent).
10666 1 : topLevelWidget = mainWidget->GetSheetWindowParent();
10667 1 : if (!topLevelWidget) {
10668 1 : topLevelWidget = mainWidget;
10669 : }
10670 : }
10671 :
10672 4 : SetActive(aActivate);
10673 :
10674 4 : if (mainWidget != topLevelWidget) {
10675 : // This is a workaround for the following problem:
10676 : // When a window with an open sheet gains or loses focus, only the sheet
10677 : // window receives the NS_ACTIVATE/NS_DEACTIVATE event. However the
10678 : // styling of the containing top level window also needs to change. We
10679 : // get around this by calling nsPIDOMWindow::SetActive() on both windows.
10680 :
10681 : // Get the top level widget's nsGlobalWindow
10682 0 : nsCOMPtr<nsPIDOMWindowOuter> topLevelWindow;
10683 :
10684 : // widgetListener should be a nsXULWindow
10685 0 : nsIWidgetListener* listener = topLevelWidget->GetWidgetListener();
10686 0 : if (listener) {
10687 0 : nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
10688 0 : nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
10689 0 : topLevelWindow = do_GetInterface(req);
10690 : }
10691 :
10692 0 : if (topLevelWindow) {
10693 0 : topLevelWindow->SetActive(aActivate);
10694 : }
10695 : }
10696 : }
10697 :
10698 : static bool
10699 5 : NotifyDocumentTree(nsIDocument* aDocument, void* aData)
10700 : {
10701 5 : aDocument->EnumerateSubDocuments(NotifyDocumentTree, nullptr);
10702 5 : aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
10703 5 : return true;
10704 : }
10705 :
10706 : void
10707 4 : nsGlobalWindow::SetActive(bool aActive)
10708 : {
10709 4 : nsPIDOMWindow::SetActive(aActive);
10710 4 : if (mDoc) {
10711 4 : NotifyDocumentTree(mDoc, nullptr);
10712 : }
10713 4 : }
10714 :
10715 : bool
10716 0 : nsGlobalWindow::IsTopLevelWindowActive()
10717 : {
10718 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem(GetDocShell());
10719 0 : if (!treeItem) {
10720 0 : return false;
10721 : }
10722 :
10723 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
10724 0 : treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
10725 0 : if (!rootItem) {
10726 0 : return false;
10727 : }
10728 :
10729 0 : nsCOMPtr<nsPIDOMWindowOuter> domWindow = rootItem->GetWindow();
10730 0 : return domWindow && domWindow->IsActive();
10731 : }
10732 :
10733 0 : void nsGlobalWindow::SetIsBackground(bool aIsBackground)
10734 : {
10735 0 : MOZ_ASSERT(IsOuterWindow());
10736 :
10737 0 : bool changed = aIsBackground != AsOuter()->IsBackground();
10738 0 : SetIsBackgroundInternal(aIsBackground);
10739 :
10740 0 : nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
10741 :
10742 0 : if (inner && changed) {
10743 0 : inner->mTimeoutManager->UpdateBackgroundState();
10744 : }
10745 :
10746 0 : if (aIsBackground) {
10747 : // Notify gamepadManager we are at the background window,
10748 : // we need to stop vibrate.
10749 0 : if (inner) {
10750 0 : inner->StopGamepadHaptics();
10751 : }
10752 0 : return;
10753 : }
10754 :
10755 0 : if (inner) {
10756 0 : inner->SyncGamepadState();
10757 : }
10758 : }
10759 :
10760 : void
10761 5 : nsGlobalWindow::SetIsBackgroundInternal(bool aIsBackground)
10762 : {
10763 5 : if (mIsBackground != aIsBackground) {
10764 0 : TabGroup()->WindowChangedBackgroundStatus(aIsBackground);
10765 : }
10766 5 : mIsBackground = aIsBackground;
10767 5 : }
10768 :
10769 1 : void nsGlobalWindow::MaybeUpdateTouchState()
10770 : {
10771 1 : FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
10772 :
10773 1 : if (mMayHaveTouchEventListener) {
10774 : nsCOMPtr<nsIObserverService> observerService =
10775 2 : services::GetObserverService();
10776 :
10777 1 : if (observerService) {
10778 2 : observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
10779 : DOM_TOUCH_LISTENER_ADDED,
10780 2 : nullptr);
10781 : }
10782 : }
10783 : }
10784 :
10785 : void
10786 0 : nsGlobalWindow::EnableGamepadUpdates()
10787 : {
10788 0 : MOZ_ASSERT(IsInnerWindow());
10789 :
10790 0 : if (mHasGamepad) {
10791 0 : RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
10792 0 : if (gamepadManager) {
10793 0 : gamepadManager->AddListener(this);
10794 : }
10795 : }
10796 0 : }
10797 :
10798 : void
10799 4 : nsGlobalWindow::DisableGamepadUpdates()
10800 : {
10801 4 : MOZ_ASSERT(IsInnerWindow());
10802 :
10803 4 : if (mHasGamepad) {
10804 0 : RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
10805 0 : if (gamepadManager) {
10806 0 : gamepadManager->RemoveListener(this);
10807 : }
10808 : }
10809 4 : }
10810 :
10811 : void
10812 0 : nsGlobalWindow::EnableVRUpdates()
10813 : {
10814 0 : MOZ_ASSERT(IsInnerWindow());
10815 :
10816 0 : if (mHasVREvents && !mVREventObserver) {
10817 0 : mVREventObserver = new VREventObserver(this);
10818 : }
10819 0 : }
10820 :
10821 : void
10822 4 : nsGlobalWindow::DisableVRUpdates()
10823 : {
10824 4 : MOZ_ASSERT(IsInnerWindow());
10825 4 : if (mVREventObserver) {
10826 0 : mVREventObserver->DisconnectFromOwner();
10827 0 : mVREventObserver = nullptr;
10828 : }
10829 4 : }
10830 :
10831 : void
10832 1 : nsGlobalWindow::SetChromeEventHandler(EventTarget* aChromeEventHandler)
10833 : {
10834 1 : MOZ_ASSERT(IsOuterWindow());
10835 :
10836 1 : SetChromeEventHandlerInternal(aChromeEventHandler);
10837 : // update the chrome event handler on all our inner windows
10838 1 : for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
10839 1 : inner != this;
10840 0 : inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
10841 0 : NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == AsOuter(),
10842 : "bad outer window pointer");
10843 0 : inner->SetChromeEventHandlerInternal(aChromeEventHandler);
10844 : }
10845 1 : }
10846 :
10847 0 : static bool IsLink(nsIContent* aContent)
10848 : {
10849 0 : return aContent && (aContent->IsHTMLElement(nsGkAtoms::a) ||
10850 0 : aContent->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
10851 0 : nsGkAtoms::simple, eCaseMatters));
10852 : }
10853 :
10854 0 : static bool ShouldShowFocusRingIfFocusedByMouse(nsIContent* aNode)
10855 : {
10856 0 : if (!aNode) {
10857 0 : return true;
10858 : }
10859 0 : return !IsLink(aNode) &&
10860 0 : !aNode->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio);
10861 : }
10862 :
10863 : void
10864 4 : nsGlobalWindow::SetFocusedNode(nsIContent* aNode,
10865 : uint32_t aFocusMethod,
10866 : bool aNeedsFocus)
10867 : {
10868 4 : FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
10869 :
10870 2 : if (aNode && aNode->GetComposedDoc() != mDoc) {
10871 0 : NS_WARNING("Trying to set focus to a node from a wrong document");
10872 0 : return;
10873 : }
10874 :
10875 2 : if (mCleanedUp) {
10876 0 : NS_ASSERTION(!aNode, "Trying to focus cleaned up window!");
10877 0 : aNode = nullptr;
10878 0 : aNeedsFocus = false;
10879 : }
10880 2 : if (mFocusedNode != aNode) {
10881 1 : UpdateCanvasFocus(false, aNode);
10882 1 : mFocusedNode = aNode;
10883 1 : mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
10884 1 : mShowFocusRingForContent = false;
10885 : }
10886 :
10887 2 : if (mFocusedNode) {
10888 : // if a node was focused by a keypress, turn on focus rings for the
10889 : // window.
10890 2 : if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
10891 0 : mFocusByKeyOccurred = true;
10892 2 : } else if (
10893 : // otherwise, we set mShowFocusRingForContent, as we don't want this to
10894 : // be permanent for the window. On Windows, focus rings are only shown
10895 : // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
10896 : // are only visible on some elements.
10897 : #ifndef XP_WIN
10898 2 : !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) ||
10899 2 : ShouldShowFocusRingIfFocusedByMouse(aNode) ||
10900 : #endif
10901 0 : aFocusMethod & nsIFocusManager::FLAG_SHOWRING) {
10902 2 : mShowFocusRingForContent = true;
10903 : }
10904 : }
10905 :
10906 2 : if (aNeedsFocus)
10907 0 : mNeedsFocus = aNeedsFocus;
10908 : }
10909 :
10910 : uint32_t
10911 6 : nsGlobalWindow::GetFocusMethod()
10912 : {
10913 6 : FORWARD_TO_INNER(GetFocusMethod, (), 0);
10914 :
10915 3 : return mFocusMethod;
10916 : }
10917 :
10918 : bool
10919 2 : nsGlobalWindow::ShouldShowFocusRing()
10920 : {
10921 2 : FORWARD_TO_INNER(ShouldShowFocusRing, (), false);
10922 :
10923 1 : if (mShowFocusRingForContent || mFocusByKeyOccurred) {
10924 1 : return true;
10925 : }
10926 :
10927 0 : nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
10928 0 : return root ? root->ShowFocusRings() : false;
10929 : }
10930 :
10931 : void
10932 0 : nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
10933 : UIStateChangeType aShowFocusRings)
10934 : {
10935 0 : MOZ_ASSERT(IsOuterWindow());
10936 :
10937 0 : nsPIDOMWindowOuter* piWin = GetPrivateRoot();
10938 0 : if (!piWin) {
10939 0 : return;
10940 : }
10941 :
10942 0 : MOZ_ASSERT(piWin == AsOuter());
10943 :
10944 0 : bool oldShouldShowFocusRing = ShouldShowFocusRing();
10945 :
10946 : // only change the flags that have been modified
10947 0 : nsCOMPtr<nsPIWindowRoot> windowRoot = do_QueryInterface(mChromeEventHandler);
10948 0 : if (!windowRoot) {
10949 0 : return;
10950 : }
10951 :
10952 0 : if (aShowAccelerators != UIStateChangeType_NoChange) {
10953 0 : windowRoot->SetShowAccelerators(aShowAccelerators == UIStateChangeType_Set);
10954 : }
10955 0 : if (aShowFocusRings != UIStateChangeType_NoChange) {
10956 0 : windowRoot->SetShowFocusRings(aShowFocusRings == UIStateChangeType_Set);
10957 : }
10958 :
10959 0 : nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(GetOuterWindow(),
10960 : aShowAccelerators,
10961 0 : aShowFocusRings);
10962 :
10963 0 : bool newShouldShowFocusRing = ShouldShowFocusRing();
10964 0 : if (mHasFocus && mFocusedNode &&
10965 0 : oldShouldShowFocusRing != newShouldShowFocusRing &&
10966 0 : mFocusedNode->IsElement()) {
10967 : // Update mFocusedNode's state.
10968 0 : if (newShouldShowFocusRing) {
10969 0 : mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);
10970 : } else {
10971 0 : mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);
10972 : }
10973 : }
10974 : }
10975 :
10976 : bool
10977 6 : nsGlobalWindow::TakeFocus(bool aFocus, uint32_t aFocusMethod)
10978 : {
10979 6 : FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false);
10980 :
10981 3 : if (mCleanedUp) {
10982 0 : return false;
10983 : }
10984 :
10985 3 : if (aFocus)
10986 3 : mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
10987 :
10988 3 : if (mHasFocus != aFocus) {
10989 3 : mHasFocus = aFocus;
10990 3 : UpdateCanvasFocus(true, mFocusedNode);
10991 : }
10992 :
10993 : // if mNeedsFocus is true, then the document has not yet received a
10994 : // document-level focus event. If there is a root content node, then return
10995 : // true to tell the calling focus manager that a focus event is expected. If
10996 : // there is no root content node, the document hasn't loaded enough yet, or
10997 : // there isn't one and there is no point in firing a focus event.
10998 3 : if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nullptr) {
10999 1 : mNeedsFocus = false;
11000 1 : return true;
11001 : }
11002 :
11003 2 : mNeedsFocus = false;
11004 2 : return false;
11005 : }
11006 :
11007 : void
11008 6 : nsGlobalWindow::SetReadyForFocus()
11009 : {
11010 6 : FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
11011 :
11012 3 : bool oldNeedsFocus = mNeedsFocus;
11013 3 : mNeedsFocus = false;
11014 :
11015 3 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
11016 3 : if (fm) {
11017 3 : fm->WindowShown(GetOuterWindow(), oldNeedsFocus);
11018 : }
11019 : }
11020 :
11021 : void
11022 8 : nsGlobalWindow::PageHidden()
11023 : {
11024 8 : FORWARD_TO_INNER_VOID(PageHidden, ());
11025 :
11026 : // the window is being hidden, so tell the focus manager that the frame is
11027 : // no longer valid. Use the persisted field to determine if the document
11028 : // is being destroyed.
11029 :
11030 4 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
11031 4 : if (fm) {
11032 4 : fm->WindowHidden(GetOuterWindow());
11033 : }
11034 :
11035 4 : mNeedsFocus = true;
11036 : }
11037 :
11038 0 : class HashchangeCallback : public Runnable
11039 : {
11040 : public:
11041 0 : HashchangeCallback(const nsAString& aOldURL,
11042 : const nsAString& aNewURL,
11043 : nsGlobalWindow* aWindow)
11044 0 : : mozilla::Runnable("HashchangeCallback")
11045 0 : , mWindow(aWindow)
11046 : {
11047 0 : MOZ_ASSERT(mWindow);
11048 0 : MOZ_ASSERT(mWindow->IsInnerWindow());
11049 0 : mOldURL.Assign(aOldURL);
11050 0 : mNewURL.Assign(aNewURL);
11051 0 : }
11052 :
11053 0 : NS_IMETHOD Run() override
11054 : {
11055 0 : NS_PRECONDITION(NS_IsMainThread(), "Should be called on the main thread.");
11056 0 : return mWindow->FireHashchange(mOldURL, mNewURL);
11057 : }
11058 :
11059 : private:
11060 : nsString mOldURL;
11061 : nsString mNewURL;
11062 : RefPtr<nsGlobalWindow> mWindow;
11063 : };
11064 :
11065 : nsresult
11066 0 : nsGlobalWindow::DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI)
11067 : {
11068 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
11069 :
11070 : // Make sure that aOldURI and aNewURI are identical up to the '#', and that
11071 : // their hashes are different.
11072 0 : bool equal = false;
11073 0 : NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->EqualsExceptRef(aNewURI, &equal)) && equal);
11074 0 : nsAutoCString oldHash, newHash;
11075 : bool oldHasHash, newHasHash;
11076 0 : NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->GetRef(oldHash)) &&
11077 : NS_SUCCEEDED(aNewURI->GetRef(newHash)) &&
11078 : NS_SUCCEEDED(aOldURI->GetHasRef(&oldHasHash)) &&
11079 : NS_SUCCEEDED(aNewURI->GetHasRef(&newHasHash)) &&
11080 : (oldHasHash != newHasHash || !oldHash.Equals(newHash)));
11081 :
11082 0 : nsAutoCString oldSpec, newSpec;
11083 0 : nsresult rv = aOldURI->GetSpec(oldSpec);
11084 0 : NS_ENSURE_SUCCESS(rv, rv);
11085 0 : rv = aNewURI->GetSpec(newSpec);
11086 0 : NS_ENSURE_SUCCESS(rv, rv);
11087 :
11088 0 : NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
11089 0 : NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
11090 :
11091 : nsCOMPtr<nsIRunnable> callback =
11092 0 : new HashchangeCallback(oldWideSpec, newWideSpec, this);
11093 0 : return Dispatch("HashchangeCallback", TaskCategory::Other, callback.forget());
11094 : }
11095 :
11096 : nsresult
11097 0 : nsGlobalWindow::FireHashchange(const nsAString &aOldURL,
11098 : const nsAString &aNewURL)
11099 : {
11100 0 : MOZ_ASSERT(IsInnerWindow());
11101 :
11102 : // Don't do anything if the window is frozen.
11103 0 : if (IsFrozen()) {
11104 0 : return NS_OK;
11105 : }
11106 :
11107 : // Get a presentation shell for use in creating the hashchange event.
11108 0 : NS_ENSURE_STATE(AsInner()->IsCurrentInnerWindow());
11109 :
11110 0 : nsIPresShell *shell = mDoc->GetShell();
11111 0 : RefPtr<nsPresContext> presContext;
11112 0 : if (shell) {
11113 0 : presContext = shell->GetPresContext();
11114 : }
11115 :
11116 0 : HashChangeEventInit init;
11117 0 : init.mBubbles = true;
11118 0 : init.mCancelable = false;
11119 0 : init.mNewURL = aNewURL;
11120 0 : init.mOldURL = aOldURL;
11121 :
11122 : RefPtr<HashChangeEvent> event =
11123 0 : HashChangeEvent::Constructor(this, NS_LITERAL_STRING("hashchange"),
11124 0 : init);
11125 :
11126 0 : event->SetTrusted(true);
11127 :
11128 : bool dummy;
11129 0 : return DispatchEvent(event, &dummy);
11130 : }
11131 :
11132 : nsresult
11133 0 : nsGlobalWindow::DispatchSyncPopState()
11134 : {
11135 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
11136 0 : NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
11137 : "Must be safe to run script here.");
11138 :
11139 0 : nsresult rv = NS_OK;
11140 :
11141 : // Bail if the window is frozen.
11142 0 : if (IsFrozen()) {
11143 0 : return NS_OK;
11144 : }
11145 :
11146 : // Get the document's pending state object -- it contains the data we're
11147 : // going to send along with the popstate event. The object is serialized
11148 : // using structured clone.
11149 0 : nsCOMPtr<nsIVariant> stateObj;
11150 0 : rv = mDoc->GetStateObject(getter_AddRefs(stateObj));
11151 0 : NS_ENSURE_SUCCESS(rv, rv);
11152 :
11153 : // Obtain a presentation shell for use in creating a popstate event.
11154 0 : nsIPresShell *shell = mDoc->GetShell();
11155 0 : RefPtr<nsPresContext> presContext;
11156 0 : if (shell) {
11157 0 : presContext = shell->GetPresContext();
11158 : }
11159 :
11160 0 : bool result = true;
11161 0 : AutoJSAPI jsapi;
11162 0 : result = jsapi.Init(AsInner());
11163 0 : NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
11164 :
11165 0 : JSContext* cx = jsapi.cx();
11166 0 : JS::Rooted<JS::Value> stateJSValue(cx, JS::NullValue());
11167 0 : result = stateObj ? VariantToJsval(cx, stateObj, &stateJSValue) : true;
11168 0 : NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
11169 :
11170 0 : RootedDictionary<PopStateEventInit> init(cx);
11171 0 : init.mBubbles = true;
11172 0 : init.mCancelable = false;
11173 0 : init.mState = stateJSValue;
11174 :
11175 : RefPtr<PopStateEvent> event =
11176 0 : PopStateEvent::Constructor(this, NS_LITERAL_STRING("popstate"),
11177 0 : init);
11178 0 : event->SetTrusted(true);
11179 0 : event->SetTarget(this);
11180 :
11181 : bool dummy; // default action
11182 0 : return DispatchEvent(event, &dummy);
11183 : }
11184 :
11185 : // Find an nsICanvasFrame under aFrame. Only search the principal
11186 : // child lists. aFrame must be non-null.
11187 0 : static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
11188 : {
11189 0 : nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
11190 0 : if (canvasFrame) {
11191 0 : return canvasFrame;
11192 : }
11193 :
11194 0 : for (nsIFrame* kid : aFrame->PrincipalChildList()) {
11195 0 : canvasFrame = FindCanvasFrame(kid);
11196 0 : if (canvasFrame) {
11197 0 : return canvasFrame;
11198 : }
11199 : }
11200 :
11201 0 : return nullptr;
11202 : }
11203 :
11204 : //-------------------------------------------------------
11205 : // Tells the HTMLFrame/CanvasFrame that is now has focus
11206 : void
11207 4 : nsGlobalWindow::UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent)
11208 : {
11209 4 : MOZ_ASSERT(IsInnerWindow());
11210 :
11211 : // this is called from the inner window so use GetDocShell
11212 4 : nsIDocShell* docShell = GetDocShell();
11213 4 : if (!docShell)
11214 0 : return;
11215 :
11216 : bool editable;
11217 4 : docShell->GetEditable(&editable);
11218 4 : if (editable)
11219 0 : return;
11220 :
11221 8 : nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
11222 4 : if (!presShell || !mDoc)
11223 0 : return;
11224 :
11225 4 : Element *rootElement = mDoc->GetRootElement();
11226 4 : if (rootElement) {
11227 7 : if ((mHasFocus || aFocusChanged) &&
11228 6 : (mFocusedNode == rootElement || aNewContent == rootElement)) {
11229 0 : nsIFrame* frame = rootElement->GetPrimaryFrame();
11230 0 : if (frame) {
11231 0 : frame = frame->GetParent();
11232 0 : nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
11233 0 : if (canvasFrame) {
11234 0 : canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
11235 : }
11236 : }
11237 : }
11238 : } else {
11239 : // Look for the frame the hard way
11240 0 : nsIFrame* frame = presShell->GetRootFrame();
11241 0 : if (frame) {
11242 0 : nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
11243 0 : if (canvasFrame) {
11244 0 : canvasFrame->SetHasFocus(false);
11245 : }
11246 : }
11247 : }
11248 : }
11249 :
11250 : already_AddRefed<nsICSSDeclaration>
11251 4 : nsGlobalWindow::GetComputedStyle(Element& aElt, const nsAString& aPseudoElt,
11252 : ErrorResult& aError)
11253 : {
11254 4 : MOZ_ASSERT(IsInnerWindow());
11255 4 : return GetComputedStyleHelper(aElt, aPseudoElt, false, aError);
11256 : }
11257 :
11258 : already_AddRefed<nsICSSDeclaration>
11259 0 : nsGlobalWindow::GetDefaultComputedStyle(Element& aElt,
11260 : const nsAString& aPseudoElt,
11261 : ErrorResult& aError)
11262 : {
11263 0 : MOZ_ASSERT(IsInnerWindow());
11264 0 : return GetComputedStyleHelper(aElt, aPseudoElt, true, aError);
11265 : }
11266 :
11267 : nsresult
11268 0 : nsGlobalWindow::GetComputedStyleHelper(nsIDOMElement* aElt,
11269 : const nsAString& aPseudoElt,
11270 : bool aDefaultStylesOnly,
11271 : nsIDOMCSSStyleDeclaration** aReturn)
11272 : {
11273 0 : MOZ_ASSERT(IsInnerWindow());
11274 :
11275 0 : NS_ENSURE_ARG_POINTER(aReturn);
11276 0 : *aReturn = nullptr;
11277 :
11278 0 : nsCOMPtr<dom::Element> element = do_QueryInterface(aElt);
11279 0 : if (!element) {
11280 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
11281 : }
11282 :
11283 0 : ErrorResult rv;
11284 : nsCOMPtr<nsIDOMCSSStyleDeclaration> declaration =
11285 0 : GetComputedStyleHelper(*element, aPseudoElt, aDefaultStylesOnly, rv);
11286 0 : declaration.forget(aReturn);
11287 :
11288 0 : return rv.StealNSResult();
11289 : }
11290 :
11291 : already_AddRefed<nsICSSDeclaration>
11292 4 : nsGlobalWindow::GetComputedStyleHelperOuter(Element& aElt,
11293 : const nsAString& aPseudoElt,
11294 : bool aDefaultStylesOnly)
11295 : {
11296 4 : MOZ_RELEASE_ASSERT(IsOuterWindow());
11297 :
11298 4 : if (!mDocShell) {
11299 0 : return nullptr;
11300 : }
11301 :
11302 8 : nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
11303 :
11304 4 : if (!presShell) {
11305 : // Try flushing frames on our parent in case there's a pending
11306 : // style change that will create the presshell.
11307 0 : auto* parent = nsGlobalWindow::Cast(GetPrivateParent());
11308 0 : if (!parent) {
11309 0 : return nullptr;
11310 : }
11311 :
11312 0 : parent->FlushPendingNotifications(FlushType::Frames);
11313 :
11314 : // Might have killed mDocShell
11315 0 : if (!mDocShell) {
11316 0 : return nullptr;
11317 : }
11318 :
11319 0 : presShell = mDocShell->GetPresShell();
11320 0 : if (!presShell) {
11321 0 : return nullptr;
11322 : }
11323 : }
11324 :
11325 : RefPtr<nsComputedDOMStyle> compStyle =
11326 8 : NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell,
11327 : aDefaultStylesOnly ? nsComputedDOMStyle::eDefaultOnly :
11328 8 : nsComputedDOMStyle::eAll);
11329 :
11330 4 : return compStyle.forget();
11331 : }
11332 :
11333 : already_AddRefed<nsICSSDeclaration>
11334 4 : nsGlobalWindow::GetComputedStyleHelper(Element& aElt,
11335 : const nsAString& aPseudoElt,
11336 : bool aDefaultStylesOnly,
11337 : ErrorResult& aError)
11338 : {
11339 4 : FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelperOuter,
11340 : (aElt, aPseudoElt, aDefaultStylesOnly),
11341 : aError, nullptr);
11342 : }
11343 :
11344 : Storage*
11345 0 : nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
11346 : {
11347 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
11348 :
11349 0 : nsIPrincipal *principal = GetPrincipal();
11350 0 : nsIDocShell* docShell = GetDocShell();
11351 :
11352 0 : if (!principal || !docShell || !Preferences::GetBool(kStorageEnabled)) {
11353 0 : return nullptr;
11354 : }
11355 :
11356 0 : if (mSessionStorage) {
11357 0 : MOZ_LOG(gDOMLeakPRLog, LogLevel::Debug,
11358 : ("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get()));
11359 0 : bool canAccess = principal->Subsumes(mSessionStorage->Principal());
11360 0 : NS_ASSERTION(canAccess,
11361 : "This window owned sessionStorage "
11362 : "that could not be accessed!");
11363 0 : if (!canAccess) {
11364 0 : mSessionStorage = nullptr;
11365 : }
11366 : }
11367 :
11368 0 : if (!mSessionStorage) {
11369 0 : nsString documentURI;
11370 0 : if (mDoc) {
11371 0 : aError = mDoc->GetDocumentURI(documentURI);
11372 0 : if (NS_WARN_IF(aError.Failed())) {
11373 0 : return nullptr;
11374 : }
11375 : }
11376 :
11377 : // If the document has the sandboxed origin flag set
11378 : // don't allow access to sessionStorage.
11379 0 : if (!mDoc) {
11380 0 : aError.Throw(NS_ERROR_FAILURE);
11381 0 : return nullptr;
11382 : }
11383 :
11384 0 : if (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
11385 0 : aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
11386 0 : return nullptr;
11387 : }
11388 :
11389 : nsresult rv;
11390 :
11391 0 : nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(docShell, &rv);
11392 0 : if (NS_FAILED(rv)) {
11393 0 : aError.Throw(rv);
11394 0 : return nullptr;
11395 : }
11396 :
11397 0 : nsCOMPtr<nsIDOMStorage> storage;
11398 0 : aError = storageManager->CreateStorage(AsInner(), principal, documentURI,
11399 0 : IsPrivateBrowsing(),
11400 0 : getter_AddRefs(storage));
11401 0 : if (aError.Failed()) {
11402 0 : return nullptr;
11403 : }
11404 :
11405 0 : mSessionStorage = static_cast<Storage*>(storage.get());
11406 0 : MOZ_ASSERT(mSessionStorage);
11407 :
11408 0 : MOZ_LOG(gDOMLeakPRLog, LogLevel::Debug,
11409 : ("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get()));
11410 :
11411 0 : if (!mSessionStorage) {
11412 0 : aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
11413 0 : return nullptr;
11414 : }
11415 : }
11416 :
11417 0 : MOZ_LOG(gDOMLeakPRLog, LogLevel::Debug,
11418 : ("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get()));
11419 :
11420 0 : return mSessionStorage;
11421 : }
11422 :
11423 : Storage*
11424 0 : nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
11425 : {
11426 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
11427 :
11428 0 : if (!Preferences::GetBool(kStorageEnabled)) {
11429 0 : return nullptr;
11430 : }
11431 :
11432 0 : if (!mLocalStorage) {
11433 0 : if (nsContentUtils::StorageAllowedForWindow(AsInner()) ==
11434 : nsContentUtils::StorageAccess::eDeny) {
11435 0 : aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
11436 0 : return nullptr;
11437 : }
11438 :
11439 0 : nsIPrincipal *principal = GetPrincipal();
11440 0 : if (!principal) {
11441 0 : return nullptr;
11442 : }
11443 :
11444 : nsresult rv;
11445 : nsCOMPtr<nsIDOMStorageManager> storageManager =
11446 0 : do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
11447 0 : if (NS_FAILED(rv)) {
11448 0 : aError.Throw(rv);
11449 0 : return nullptr;
11450 : }
11451 :
11452 0 : nsString documentURI;
11453 0 : if (mDoc) {
11454 0 : aError = mDoc->GetDocumentURI(documentURI);
11455 0 : if (NS_WARN_IF(aError.Failed())) {
11456 0 : return nullptr;
11457 : }
11458 : }
11459 :
11460 0 : nsCOMPtr<nsIDOMStorage> storage;
11461 0 : aError = storageManager->CreateStorage(AsInner(), principal, documentURI,
11462 0 : IsPrivateBrowsing(),
11463 0 : getter_AddRefs(storage));
11464 0 : if (aError.Failed()) {
11465 0 : return nullptr;
11466 : }
11467 :
11468 0 : mLocalStorage = static_cast<Storage*>(storage.get());
11469 0 : MOZ_ASSERT(mLocalStorage);
11470 : }
11471 :
11472 0 : return mLocalStorage;
11473 : }
11474 :
11475 : IDBFactory*
11476 0 : nsGlobalWindow::GetIndexedDB(ErrorResult& aError)
11477 : {
11478 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
11479 0 : if (!mIndexedDB) {
11480 : // This may keep mIndexedDB null without setting an error.
11481 0 : aError = IDBFactory::CreateForWindow(AsInner(),
11482 0 : getter_AddRefs(mIndexedDB));
11483 : }
11484 :
11485 0 : return mIndexedDB;
11486 : }
11487 :
11488 : //*****************************************************************************
11489 : // nsGlobalWindow::nsIInterfaceRequestor
11490 : //*****************************************************************************
11491 :
11492 : NS_IMETHODIMP
11493 53 : nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
11494 : {
11495 53 : NS_ENSURE_ARG_POINTER(aSink);
11496 53 : *aSink = nullptr;
11497 :
11498 53 : if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
11499 0 : nsGlobalWindow* outer = GetOuterWindowInternal();
11500 0 : NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
11501 :
11502 0 : NS_WARNING("Using deprecated nsIDocCharset: use nsIDocShell.GetCharset() instead ");
11503 0 : nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(outer->mDocShell));
11504 0 : docCharset.forget(aSink);
11505 : }
11506 53 : else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
11507 37 : nsGlobalWindow* outer = GetOuterWindowInternal();
11508 37 : NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
11509 :
11510 74 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(outer->mDocShell));
11511 37 : webNav.forget(aSink);
11512 : }
11513 16 : else if (aIID.Equals(NS_GET_IID(nsIDocShell))) {
11514 1 : nsGlobalWindow* outer = GetOuterWindowInternal();
11515 1 : NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
11516 :
11517 2 : nsCOMPtr<nsIDocShell> docShell = outer->mDocShell;
11518 1 : docShell.forget(aSink);
11519 : }
11520 : #ifdef NS_PRINTING
11521 15 : else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
11522 0 : nsGlobalWindow* outer = GetOuterWindowInternal();
11523 0 : NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
11524 :
11525 0 : if (outer->mDocShell) {
11526 0 : nsCOMPtr<nsIContentViewer> viewer;
11527 0 : outer->mDocShell->GetContentViewer(getter_AddRefs(viewer));
11528 0 : if (viewer) {
11529 0 : nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
11530 0 : webBrowserPrint.forget(aSink);
11531 : }
11532 : }
11533 : }
11534 : #endif
11535 15 : else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
11536 15 : nsGlobalWindow* outer = GetOuterWindowInternal();
11537 15 : NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
11538 :
11539 15 : if (!mWindowUtils) {
11540 4 : mWindowUtils = new nsDOMWindowUtils(outer);
11541 : }
11542 :
11543 15 : *aSink = mWindowUtils;
11544 15 : NS_ADDREF(((nsISupports *) *aSink));
11545 : }
11546 0 : else if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
11547 0 : nsGlobalWindow* outer = GetOuterWindowInternal();
11548 0 : NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
11549 :
11550 0 : nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(outer->mDocShell));
11551 0 : loadContext.forget(aSink);
11552 : }
11553 : else {
11554 0 : return QueryInterface(aIID, aSink);
11555 : }
11556 :
11557 53 : return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
11558 : }
11559 :
11560 : void
11561 39 : nsGlobalWindow::GetInterface(JSContext* aCx, nsIJSID* aIID,
11562 : JS::MutableHandle<JS::Value> aRetval,
11563 : ErrorResult& aError)
11564 : {
11565 39 : MOZ_ASSERT(IsInnerWindow());
11566 39 : dom::GetInterface(aCx, this, aIID, aRetval, aError);
11567 39 : }
11568 :
11569 : already_AddRefed<CacheStorage>
11570 0 : nsGlobalWindow::GetCaches(ErrorResult& aRv)
11571 : {
11572 0 : MOZ_ASSERT(IsInnerWindow());
11573 :
11574 0 : if (!mCacheStorage) {
11575 : bool forceTrustedOrigin =
11576 0 : GetOuterWindow()->GetServiceWorkersTestingEnabled();
11577 :
11578 : nsContentUtils::StorageAccess access =
11579 0 : nsContentUtils::StorageAllowedForWindow(AsInner());
11580 :
11581 : // We don't block the cache API when being told to only allow storage for the
11582 : // current session.
11583 0 : bool storageBlocked = access <= nsContentUtils::StorageAccess::ePrivateBrowsing;
11584 :
11585 0 : mCacheStorage = CacheStorage::CreateOnMainThread(cache::DEFAULT_NAMESPACE,
11586 0 : this, GetPrincipal(),
11587 : storageBlocked,
11588 0 : forceTrustedOrigin, aRv);
11589 : }
11590 :
11591 0 : RefPtr<CacheStorage> ref = mCacheStorage;
11592 0 : return ref.forget();
11593 : }
11594 :
11595 : already_AddRefed<ServiceWorkerRegistration>
11596 0 : nsPIDOMWindowInner::GetServiceWorkerRegistration(const nsAString& aScope)
11597 : {
11598 0 : RefPtr<ServiceWorkerRegistration> registration;
11599 0 : if (!mServiceWorkerRegistrationTable.Get(aScope,
11600 0 : getter_AddRefs(registration))) {
11601 : registration =
11602 0 : ServiceWorkerRegistration::CreateForMainThread(this, aScope);
11603 0 : mServiceWorkerRegistrationTable.Put(aScope, registration);
11604 : }
11605 0 : return registration.forget();
11606 : }
11607 :
11608 : void
11609 0 : nsPIDOMWindowInner::InvalidateServiceWorkerRegistration(const nsAString& aScope)
11610 : {
11611 0 : mServiceWorkerRegistrationTable.Remove(aScope);
11612 0 : }
11613 :
11614 : void
11615 0 : nsGlobalWindow::FireOfflineStatusEventIfChanged()
11616 : {
11617 0 : if (!AsInner()->IsCurrentInnerWindow())
11618 0 : return;
11619 :
11620 : // Don't fire an event if the status hasn't changed
11621 0 : if (mWasOffline == NS_IsOffline()) {
11622 0 : return;
11623 : }
11624 :
11625 0 : mWasOffline = !mWasOffline;
11626 :
11627 0 : nsAutoString name;
11628 0 : if (mWasOffline) {
11629 0 : name.AssignLiteral("offline");
11630 : } else {
11631 0 : name.AssignLiteral("online");
11632 : }
11633 : // The event is fired at the body element, or if there is no body element,
11634 : // at the document.
11635 0 : nsCOMPtr<EventTarget> eventTarget = mDoc.get();
11636 0 : nsHTMLDocument* htmlDoc = mDoc->AsHTMLDocument();
11637 0 : if (htmlDoc) {
11638 0 : Element* body = htmlDoc->GetBody();
11639 0 : if (body) {
11640 0 : eventTarget = body;
11641 : }
11642 : } else {
11643 0 : Element* documentElement = mDoc->GetDocumentElement();
11644 0 : if (documentElement) {
11645 0 : eventTarget = documentElement;
11646 : }
11647 : }
11648 0 : nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, true, false);
11649 : }
11650 :
11651 0 : class NotifyIdleObserverRunnable : public Runnable
11652 : {
11653 : public:
11654 0 : NotifyIdleObserverRunnable(nsIIdleObserver* aIdleObserver,
11655 : uint32_t aTimeInS,
11656 : bool aCallOnidle,
11657 : nsGlobalWindow* aIdleWindow)
11658 0 : : mozilla::Runnable("NotifyIdleObserverRunnable")
11659 : , mIdleObserver(aIdleObserver)
11660 : , mTimeInS(aTimeInS)
11661 : , mIdleWindow(aIdleWindow)
11662 0 : , mCallOnidle(aCallOnidle)
11663 0 : { }
11664 :
11665 0 : NS_IMETHOD Run() override
11666 : {
11667 0 : if (mIdleWindow->ContainsIdleObserver(mIdleObserver, mTimeInS)) {
11668 0 : return mCallOnidle ? mIdleObserver->Onidle() : mIdleObserver->Onactive();
11669 : }
11670 0 : return NS_OK;
11671 : }
11672 :
11673 : private:
11674 : nsCOMPtr<nsIIdleObserver> mIdleObserver;
11675 : uint32_t mTimeInS;
11676 : RefPtr<nsGlobalWindow> mIdleWindow;
11677 :
11678 : // If false then call on active
11679 : bool mCallOnidle;
11680 : };
11681 :
11682 : void
11683 0 : nsGlobalWindow::NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
11684 : bool aCallOnidle)
11685 : {
11686 0 : MOZ_ASSERT(aIdleObserverHolder);
11687 0 : aIdleObserverHolder->mPrevNotificationIdle = aCallOnidle;
11688 :
11689 : nsCOMPtr<nsIRunnable> caller =
11690 : new NotifyIdleObserverRunnable(aIdleObserverHolder->mIdleObserver,
11691 : aIdleObserverHolder->mTimeInS,
11692 0 : aCallOnidle, this);
11693 0 : if (NS_FAILED(Dispatch("NotifyIdleObserverRunnable", TaskCategory::Other,
11694 : caller.forget()))) {
11695 0 : NS_WARNING("Failed to dispatch thread for idle observer notification.");
11696 : }
11697 0 : }
11698 :
11699 : bool
11700 0 : nsGlobalWindow::ContainsIdleObserver(nsIIdleObserver* aIdleObserver, uint32_t aTimeInS)
11701 : {
11702 0 : MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
11703 0 : bool found = false;
11704 0 : nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
11705 0 : while (iter.HasMore()) {
11706 0 : IdleObserverHolder& idleObserver = iter.GetNext();
11707 0 : if (idleObserver.mIdleObserver == aIdleObserver &&
11708 0 : idleObserver.mTimeInS == aTimeInS) {
11709 0 : found = true;
11710 0 : break;
11711 : }
11712 : }
11713 0 : return found;
11714 : }
11715 :
11716 : void
11717 0 : IdleActiveTimerCallback(nsITimer* aTimer, void* aClosure)
11718 : {
11719 0 : RefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
11720 0 : MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
11721 0 : idleWindow->HandleIdleActiveEvent();
11722 0 : }
11723 :
11724 : void
11725 0 : IdleObserverTimerCallback(nsITimer* aTimer, void* aClosure)
11726 : {
11727 0 : RefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
11728 0 : MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
11729 0 : idleWindow->HandleIdleObserverCallback();
11730 0 : }
11731 :
11732 : void
11733 0 : nsGlobalWindow::HandleIdleObserverCallback()
11734 : {
11735 0 : MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
11736 0 : MOZ_ASSERT(static_cast<uint32_t>(mIdleCallbackIndex) < mIdleObservers.Length(),
11737 : "Idle callback index exceeds array bounds!");
11738 0 : IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(mIdleCallbackIndex);
11739 0 : NotifyIdleObserver(&idleObserver, true);
11740 0 : mIdleCallbackIndex++;
11741 0 : if (NS_FAILED(ScheduleNextIdleObserverCallback())) {
11742 0 : NS_WARNING("Failed to set next idle observer callback.");
11743 : }
11744 0 : }
11745 :
11746 : nsresult
11747 0 : nsGlobalWindow::ScheduleNextIdleObserverCallback()
11748 : {
11749 0 : MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
11750 0 : MOZ_ASSERT(mIdleService, "No idle service!");
11751 :
11752 0 : if (mIdleCallbackIndex < 0 ||
11753 0 : static_cast<uint32_t>(mIdleCallbackIndex) >= mIdleObservers.Length()) {
11754 0 : return NS_OK;
11755 : }
11756 :
11757 : IdleObserverHolder& idleObserver =
11758 0 : mIdleObservers.ElementAt(mIdleCallbackIndex);
11759 :
11760 0 : uint32_t userIdleTimeMS = 0;
11761 0 : nsresult rv = mIdleService->GetIdleTime(&userIdleTimeMS);
11762 0 : NS_ENSURE_SUCCESS(rv, rv);
11763 :
11764 0 : uint32_t callbackTimeMS = 0;
11765 0 : if (idleObserver.mTimeInS * 1000 + mIdleFuzzFactor > userIdleTimeMS) {
11766 0 : callbackTimeMS = idleObserver.mTimeInS * 1000 - userIdleTimeMS + mIdleFuzzFactor;
11767 : }
11768 :
11769 0 : mIdleTimer->Cancel();
11770 0 : rv = mIdleTimer->InitWithNamedFuncCallback(
11771 : IdleObserverTimerCallback,
11772 : this,
11773 : callbackTimeMS,
11774 : nsITimer::TYPE_ONE_SHOT,
11775 0 : "nsGlobalWindow::ScheduleNextIdleObserverCallback");
11776 0 : NS_ENSURE_SUCCESS(rv, rv);
11777 :
11778 0 : return NS_OK;
11779 : }
11780 :
11781 : uint32_t
11782 0 : nsGlobalWindow::GetFuzzTimeMS()
11783 : {
11784 0 : MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
11785 :
11786 0 : if (sIdleObserversAPIFuzzTimeDisabled) {
11787 0 : return 0;
11788 : }
11789 :
11790 0 : uint32_t randNum = MAX_IDLE_FUZZ_TIME_MS;
11791 0 : size_t nbytes = PR_GetRandomNoise(&randNum, sizeof(randNum));
11792 0 : if (nbytes != sizeof(randNum)) {
11793 0 : NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!");
11794 0 : return MAX_IDLE_FUZZ_TIME_MS;
11795 : }
11796 :
11797 0 : if (randNum > MAX_IDLE_FUZZ_TIME_MS) {
11798 0 : randNum %= MAX_IDLE_FUZZ_TIME_MS;
11799 : }
11800 :
11801 0 : return randNum;
11802 : }
11803 :
11804 : nsresult
11805 0 : nsGlobalWindow::ScheduleActiveTimerCallback()
11806 : {
11807 0 : MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
11808 :
11809 0 : if (!mAddActiveEventFuzzTime) {
11810 0 : return HandleIdleActiveEvent();
11811 : }
11812 :
11813 0 : MOZ_ASSERT(mIdleTimer);
11814 0 : mIdleTimer->Cancel();
11815 :
11816 0 : uint32_t fuzzFactorInMS = GetFuzzTimeMS();
11817 0 : nsresult rv = mIdleTimer->InitWithNamedFuncCallback(
11818 : IdleActiveTimerCallback,
11819 : this,
11820 : fuzzFactorInMS,
11821 : nsITimer::TYPE_ONE_SHOT,
11822 0 : "nsGlobalWindow::ScheduleActiveTimerCallback");
11823 0 : NS_ENSURE_SUCCESS(rv, rv);
11824 0 : return NS_OK;
11825 : }
11826 :
11827 : nsresult
11828 0 : nsGlobalWindow::HandleIdleActiveEvent()
11829 : {
11830 0 : MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
11831 :
11832 0 : if (mCurrentlyIdle) {
11833 0 : mIdleCallbackIndex = 0;
11834 0 : mIdleFuzzFactor = GetFuzzTimeMS();
11835 0 : nsresult rv = ScheduleNextIdleObserverCallback();
11836 0 : NS_ENSURE_SUCCESS(rv, rv);
11837 0 : return NS_OK;
11838 : }
11839 :
11840 0 : mIdleCallbackIndex = -1;
11841 0 : MOZ_ASSERT(mIdleTimer);
11842 0 : mIdleTimer->Cancel();
11843 0 : nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
11844 0 : while (iter.HasMore()) {
11845 0 : IdleObserverHolder& idleObserver = iter.GetNext();
11846 0 : if (idleObserver.mPrevNotificationIdle) {
11847 0 : NotifyIdleObserver(&idleObserver, false);
11848 : }
11849 : }
11850 :
11851 0 : return NS_OK;
11852 : }
11853 :
11854 : nsGlobalWindow::SlowScriptResponse
11855 0 : nsGlobalWindow::ShowSlowScriptDialog()
11856 : {
11857 0 : MOZ_ASSERT(IsInnerWindow());
11858 :
11859 : nsresult rv;
11860 0 : AutoJSContext cx;
11861 :
11862 0 : if (Preferences::GetBool("dom.always_stop_slow_scripts")) {
11863 0 : return KillSlowScript;
11864 : }
11865 :
11866 : // If it isn't safe to run script, then it isn't safe to bring up the prompt
11867 : // (since that spins the event loop). In that (rare) case, we just kill the
11868 : // script and report a warning.
11869 0 : if (!nsContentUtils::IsSafeToRunScript()) {
11870 0 : JS_ReportWarningASCII(cx, "A long running script was terminated");
11871 0 : return KillSlowScript;
11872 : }
11873 :
11874 : // If our document is not active, just kill the script: we've been unloaded
11875 0 : if (!AsInner()->HasActiveDocument()) {
11876 0 : return KillSlowScript;
11877 : }
11878 :
11879 : // Check if we should offer the option to debug
11880 0 : JS::AutoFilename filename;
11881 : unsigned lineno;
11882 : // Computing the line number can be very expensive (see bug 1330231 for
11883 : // example), and we don't use the line number anywhere except than in the
11884 : // parent process, so we avoid computing it elsewhere. This gives us most of
11885 : // the wins we are interested in, since the source of the slowness here is
11886 : // minified scripts which is more common in Web content that is loaded in the
11887 : // content process.
11888 0 : unsigned* linenop = XRE_IsParentProcess() ? &lineno : nullptr;
11889 0 : bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, linenop);
11890 :
11891 : // Record the slow script event if we haven't done so already for this inner window
11892 : // (which represents a particular page to the user).
11893 0 : if (!mHasHadSlowScript) {
11894 0 : Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT, 1);
11895 : }
11896 0 : mHasHadSlowScript = true;
11897 :
11898 0 : if (XRE_IsContentProcess() &&
11899 0 : ProcessHangMonitor::Get()) {
11900 : ProcessHangMonitor::SlowScriptAction action;
11901 0 : RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
11902 0 : nsIDocShell* docShell = GetDocShell();
11903 0 : nsCOMPtr<nsITabChild> child = docShell ? docShell->GetTabChild() : nullptr;
11904 0 : action = monitor->NotifySlowScript(child,
11905 0 : filename.get());
11906 0 : if (action == ProcessHangMonitor::Terminate) {
11907 0 : return KillSlowScript;
11908 : }
11909 :
11910 0 : if (action == ProcessHangMonitor::StartDebugger) {
11911 : // Spin a nested event loop so that the debugger in the parent can fetch
11912 : // any information it needs. Once the debugger has started, return to the
11913 : // script.
11914 0 : RefPtr<nsGlobalWindow> outer = GetOuterWindowInternal();
11915 0 : outer->EnterModalState();
11916 0 : SpinEventLoopUntil([&]() { return monitor->IsDebuggerStartupComplete(); });
11917 0 : outer->LeaveModalState();
11918 0 : return ContinueSlowScript;
11919 : }
11920 :
11921 0 : return ContinueSlowScriptAndKeepNotifying;
11922 : }
11923 :
11924 : // Reached only on non-e10s - once per slow script dialog.
11925 : // On e10s - we probe once at ProcessHangsMonitor.jsm
11926 0 : Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTICE_COUNT, 1);
11927 :
11928 : // Get the nsIPrompt interface from the docshell
11929 0 : nsCOMPtr<nsIDocShell> ds = GetDocShell();
11930 0 : NS_ENSURE_TRUE(ds, KillSlowScript);
11931 0 : nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
11932 0 : NS_ENSURE_TRUE(prompt, KillSlowScript);
11933 :
11934 : // Prioritize the SlowScriptDebug interface over JSD1.
11935 0 : nsCOMPtr<nsISlowScriptDebugCallback> debugCallback;
11936 :
11937 0 : if (hasFrame) {
11938 0 : const char *debugCID = "@mozilla.org/dom/slow-script-debug;1";
11939 0 : nsCOMPtr<nsISlowScriptDebug> debugService = do_GetService(debugCID, &rv);
11940 0 : if (NS_SUCCEEDED(rv)) {
11941 0 : debugService->GetActivationHandler(getter_AddRefs(debugCallback));
11942 : }
11943 : }
11944 :
11945 0 : bool showDebugButton = !!debugCallback;
11946 :
11947 : // Get localizable strings
11948 0 : nsXPIDLString title, msg, stopButton, waitButton, debugButton, neverShowDlg;
11949 :
11950 0 : rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
11951 : "KillScriptTitle",
11952 : title);
11953 :
11954 : nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
11955 : "StopScriptButton",
11956 0 : stopButton);
11957 0 : if (NS_FAILED(tmp)) {
11958 0 : rv = tmp;
11959 : }
11960 :
11961 : tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
11962 : "WaitForScriptButton",
11963 0 : waitButton);
11964 0 : if (NS_FAILED(tmp)) {
11965 0 : rv = tmp;
11966 : }
11967 :
11968 : tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
11969 : "DontAskAgain",
11970 0 : neverShowDlg);
11971 0 : if (NS_FAILED(tmp)) {
11972 0 : rv = tmp;
11973 : }
11974 :
11975 :
11976 0 : if (showDebugButton) {
11977 : tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
11978 : "DebugScriptButton",
11979 0 : debugButton);
11980 0 : if (NS_FAILED(tmp)) {
11981 0 : rv = tmp;
11982 : }
11983 :
11984 : tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
11985 : "KillScriptWithDebugMessage",
11986 0 : msg);
11987 0 : if (NS_FAILED(tmp)) {
11988 0 : rv = tmp;
11989 : }
11990 : }
11991 : else {
11992 : tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
11993 : "KillScriptMessage",
11994 0 : msg);
11995 0 : if (NS_FAILED(tmp)) {
11996 0 : rv = tmp;
11997 : }
11998 : }
11999 :
12000 : // GetStringFromName can return NS_OK and still give nullptr string
12001 0 : if (NS_FAILED(rv) || !title || !msg || !stopButton || !waitButton ||
12002 0 : (!debugButton && showDebugButton) || !neverShowDlg) {
12003 0 : NS_ERROR("Failed to get localized strings.");
12004 0 : return ContinueSlowScript;
12005 : }
12006 :
12007 : // Append file and line number information, if available
12008 0 : if (filename.get()) {
12009 0 : nsXPIDLString scriptLocation;
12010 : // We want to drop the middle part of too-long locations. We'll
12011 : // define "too-long" as longer than 60 UTF-16 code units. Just
12012 : // have to be a bit careful about unpaired surrogates.
12013 0 : NS_ConvertUTF8toUTF16 filenameUTF16(filename.get());
12014 0 : if (filenameUTF16.Length() > 60) {
12015 : // XXXbz Do we need to insert any bidi overrides here?
12016 0 : size_t cutStart = 30;
12017 0 : size_t cutLength = filenameUTF16.Length() - 60;
12018 0 : MOZ_ASSERT(cutLength > 0);
12019 0 : if (NS_IS_LOW_SURROGATE(filenameUTF16[cutStart])) {
12020 : // Don't truncate before the low surrogate, in case it's preceded by a
12021 : // high surrogate and forms a single Unicode character. Instead, just
12022 : // include the low surrogate.
12023 0 : ++cutStart;
12024 0 : --cutLength;
12025 : }
12026 0 : if (NS_IS_LOW_SURROGATE(filenameUTF16[cutStart + cutLength])) {
12027 : // Likewise, don't drop a trailing low surrogate here. We want to
12028 : // increase cutLength, since it might be 0 already so we can't very well
12029 : // decrease it.
12030 0 : ++cutLength;
12031 : }
12032 :
12033 : // Insert U+2026 HORIZONTAL ELLIPSIS
12034 0 : filenameUTF16.Replace(cutStart, cutLength, NS_LITERAL_STRING(u"\x2026"));
12035 : }
12036 0 : const char16_t *formatParams[] = { filenameUTF16.get() };
12037 0 : rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
12038 : "KillScriptLocation",
12039 : formatParams,
12040 : scriptLocation);
12041 :
12042 0 : if (NS_SUCCEEDED(rv) && scriptLocation) {
12043 0 : msg.AppendLiteral("\n\n");
12044 0 : msg.Append(scriptLocation);
12045 0 : msg.Append(':');
12046 0 : msg.AppendInt(lineno);
12047 : }
12048 : }
12049 :
12050 0 : int32_t buttonPressed = 0; // In case the user exits dialog by clicking X.
12051 0 : bool neverShowDlgChk = false;
12052 : uint32_t buttonFlags = nsIPrompt::BUTTON_POS_1_DEFAULT +
12053 : (nsIPrompt::BUTTON_TITLE_IS_STRING *
12054 0 : (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
12055 :
12056 : // Add a third button if necessary.
12057 0 : if (showDebugButton)
12058 0 : buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
12059 :
12060 : // Null out the operation callback while we're re-entering JS here.
12061 0 : bool old = JS_DisableInterruptCallback(cx);
12062 :
12063 : // Open the dialog.
12064 0 : rv = prompt->ConfirmEx(title, msg, buttonFlags, waitButton, stopButton,
12065 : debugButton, neverShowDlg, &neverShowDlgChk,
12066 0 : &buttonPressed);
12067 :
12068 0 : JS_ResetInterruptCallback(cx, old);
12069 :
12070 0 : if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) {
12071 0 : return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript;
12072 : }
12073 0 : if (buttonPressed == 2) {
12074 0 : if (debugCallback) {
12075 0 : rv = debugCallback->HandleSlowScriptDebug(this);
12076 0 : return NS_SUCCEEDED(rv) ? ContinueSlowScript : KillSlowScript;
12077 : }
12078 : }
12079 0 : JS_ClearPendingException(cx);
12080 0 : return KillSlowScript;
12081 : }
12082 :
12083 : uint32_t
12084 0 : nsGlobalWindow::FindInsertionIndex(IdleObserverHolder* aIdleObserver)
12085 : {
12086 0 : MOZ_ASSERT(IsInnerWindow());
12087 0 : MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
12088 :
12089 0 : uint32_t i = 0;
12090 0 : nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
12091 0 : while (iter.HasMore()) {
12092 0 : IdleObserverHolder& idleObserver = iter.GetNext();
12093 0 : if (idleObserver.mTimeInS > aIdleObserver->mTimeInS) {
12094 0 : break;
12095 : }
12096 0 : i++;
12097 0 : MOZ_ASSERT(i <= mIdleObservers.Length(), "Array index out of bounds error.");
12098 : }
12099 :
12100 0 : return i;
12101 : }
12102 :
12103 : nsresult
12104 0 : nsGlobalWindow::RegisterIdleObserver(nsIIdleObserver* aIdleObserver)
12105 : {
12106 0 : MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
12107 :
12108 : nsresult rv;
12109 0 : if (mIdleObservers.IsEmpty()) {
12110 0 : mIdleService = do_GetService("@mozilla.org/widget/idleservice;1", &rv);
12111 0 : NS_ENSURE_SUCCESS(rv, rv);
12112 :
12113 0 : rv = mIdleService->AddIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
12114 0 : NS_ENSURE_SUCCESS(rv, rv);
12115 :
12116 0 : if (!mIdleTimer) {
12117 0 : mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
12118 0 : NS_ENSURE_SUCCESS(rv, rv);
12119 : } else {
12120 0 : mIdleTimer->Cancel();
12121 : }
12122 : }
12123 :
12124 0 : MOZ_ASSERT(mIdleService);
12125 0 : MOZ_ASSERT(mIdleTimer);
12126 :
12127 0 : IdleObserverHolder tmpIdleObserver;
12128 0 : tmpIdleObserver.mIdleObserver = aIdleObserver;
12129 0 : rv = aIdleObserver->GetTime(&tmpIdleObserver.mTimeInS);
12130 0 : NS_ENSURE_SUCCESS(rv, rv);
12131 0 : NS_ENSURE_ARG_MAX(tmpIdleObserver.mTimeInS, UINT32_MAX / 1000);
12132 0 : NS_ENSURE_ARG_MIN(tmpIdleObserver.mTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
12133 :
12134 0 : uint32_t insertAtIndex = FindInsertionIndex(&tmpIdleObserver);
12135 0 : if (insertAtIndex == mIdleObservers.Length()) {
12136 0 : mIdleObservers.AppendElement(tmpIdleObserver);
12137 : }
12138 : else {
12139 0 : mIdleObservers.InsertElementAt(insertAtIndex, tmpIdleObserver);
12140 : }
12141 :
12142 0 : bool userIsIdle = false;
12143 0 : rv = nsContentUtils::IsUserIdle(MIN_IDLE_NOTIFICATION_TIME_S, &userIsIdle);
12144 0 : NS_ENSURE_SUCCESS(rv, rv);
12145 :
12146 : // Special case. First idle observer added to empty list while the user is idle.
12147 : // Haven't received 'idle' topic notification from slow idle service yet.
12148 : // Need to wait for the idle notification and then notify idle observers in the list.
12149 0 : if (userIsIdle && mIdleCallbackIndex == -1) {
12150 0 : return NS_OK;
12151 : }
12152 :
12153 0 : if (!mCurrentlyIdle) {
12154 0 : return NS_OK;
12155 : }
12156 :
12157 0 : MOZ_ASSERT(mIdleCallbackIndex >= 0);
12158 :
12159 0 : if (static_cast<int32_t>(insertAtIndex) < mIdleCallbackIndex) {
12160 0 : IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(insertAtIndex);
12161 0 : NotifyIdleObserver(&idleObserver, true);
12162 0 : mIdleCallbackIndex++;
12163 0 : return NS_OK;
12164 : }
12165 :
12166 0 : if (static_cast<int32_t>(insertAtIndex) == mIdleCallbackIndex) {
12167 0 : mIdleTimer->Cancel();
12168 0 : rv = ScheduleNextIdleObserverCallback();
12169 0 : NS_ENSURE_SUCCESS(rv, rv);
12170 : }
12171 0 : return NS_OK;
12172 : }
12173 :
12174 : nsresult
12175 0 : nsGlobalWindow::FindIndexOfElementToRemove(nsIIdleObserver* aIdleObserver,
12176 : int32_t* aRemoveElementIndex)
12177 : {
12178 0 : MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
12179 0 : MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
12180 :
12181 0 : *aRemoveElementIndex = 0;
12182 0 : if (mIdleObservers.IsEmpty()) {
12183 0 : return NS_ERROR_FAILURE;
12184 : }
12185 :
12186 : uint32_t aIdleObserverTimeInS;
12187 0 : nsresult rv = aIdleObserver->GetTime(&aIdleObserverTimeInS);
12188 0 : NS_ENSURE_SUCCESS(rv, rv);
12189 0 : NS_ENSURE_ARG_MIN(aIdleObserverTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
12190 :
12191 0 : nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
12192 0 : while (iter.HasMore()) {
12193 0 : IdleObserverHolder& idleObserver = iter.GetNext();
12194 0 : if (idleObserver.mTimeInS == aIdleObserverTimeInS &&
12195 0 : idleObserver.mIdleObserver == aIdleObserver ) {
12196 0 : break;
12197 : }
12198 0 : (*aRemoveElementIndex)++;
12199 : }
12200 0 : return static_cast<uint32_t>(*aRemoveElementIndex) >= mIdleObservers.Length() ?
12201 0 : NS_ERROR_FAILURE : NS_OK;
12202 : }
12203 :
12204 : nsresult
12205 0 : nsGlobalWindow::UnregisterIdleObserver(nsIIdleObserver* aIdleObserver)
12206 : {
12207 0 : MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
12208 :
12209 : int32_t removeElementIndex;
12210 0 : nsresult rv = FindIndexOfElementToRemove(aIdleObserver, &removeElementIndex);
12211 0 : if (NS_FAILED(rv)) {
12212 0 : NS_WARNING("Idle observer not found in list of idle observers. No idle observer removed.");
12213 0 : return NS_OK;
12214 : }
12215 0 : mIdleObservers.RemoveElementAt(removeElementIndex);
12216 :
12217 0 : MOZ_ASSERT(mIdleTimer);
12218 0 : if (mIdleObservers.IsEmpty() && mIdleService) {
12219 0 : rv = mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
12220 0 : NS_ENSURE_SUCCESS(rv, rv);
12221 0 : mIdleService = nullptr;
12222 :
12223 0 : mIdleTimer->Cancel();
12224 0 : mIdleCallbackIndex = -1;
12225 0 : return NS_OK;
12226 : }
12227 :
12228 0 : if (!mCurrentlyIdle) {
12229 0 : return NS_OK;
12230 : }
12231 :
12232 0 : if (removeElementIndex < mIdleCallbackIndex) {
12233 0 : mIdleCallbackIndex--;
12234 0 : return NS_OK;
12235 : }
12236 :
12237 0 : if (removeElementIndex != mIdleCallbackIndex) {
12238 0 : return NS_OK;
12239 : }
12240 :
12241 0 : mIdleTimer->Cancel();
12242 :
12243 : // If the last element in the array had been notified then decrement
12244 : // mIdleCallbackIndex because an idle was removed from the list of
12245 : // idle observers.
12246 : // Example: add idle observer with time 1, 2, 3,
12247 : // Idle notifications for idle observers with time 1, 2, 3 are complete
12248 : // Remove idle observer with time 3 while the user is still idle.
12249 : // The user never transitioned to active state.
12250 : // Add an idle observer with idle time 4
12251 0 : if (static_cast<uint32_t>(mIdleCallbackIndex) == mIdleObservers.Length()) {
12252 0 : mIdleCallbackIndex--;
12253 : }
12254 0 : rv = ScheduleNextIdleObserverCallback();
12255 0 : NS_ENSURE_SUCCESS(rv, rv);
12256 :
12257 0 : return NS_OK;
12258 : }
12259 :
12260 : nsresult
12261 0 : nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
12262 : const char16_t* aData)
12263 : {
12264 0 : if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
12265 0 : if (!IsFrozen()) {
12266 : // Fires an offline status event if the offline status has changed
12267 0 : FireOfflineStatusEventIfChanged();
12268 : }
12269 0 : return NS_OK;
12270 : }
12271 :
12272 0 : if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE)) {
12273 0 : mCurrentlyIdle = true;
12274 0 : if (IsFrozen()) {
12275 : // need to fire only one idle event while the window is frozen.
12276 0 : mNotifyIdleObserversIdleOnThaw = true;
12277 0 : mNotifyIdleObserversActiveOnThaw = false;
12278 0 : } else if (AsInner()->IsCurrentInnerWindow()) {
12279 0 : HandleIdleActiveEvent();
12280 : }
12281 0 : return NS_OK;
12282 : }
12283 :
12284 0 : if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_ACTIVE)) {
12285 0 : mCurrentlyIdle = false;
12286 0 : if (IsFrozen()) {
12287 0 : mNotifyIdleObserversActiveOnThaw = true;
12288 0 : mNotifyIdleObserversIdleOnThaw = false;
12289 0 : } else if (AsInner()->IsCurrentInnerWindow()) {
12290 0 : MOZ_ASSERT(IsInnerWindow());
12291 0 : ScheduleActiveTimerCallback();
12292 : }
12293 0 : return NS_OK;
12294 : }
12295 :
12296 0 : if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) {
12297 0 : if (mApplicationCache)
12298 0 : return NS_OK;
12299 :
12300 : // Instantiate the application object now. It observes update belonging to
12301 : // this window's document and correctly updates the applicationCache object
12302 : // state.
12303 0 : nsCOMPtr<nsIDOMOfflineResourceList> applicationCache = GetApplicationCache();
12304 0 : nsCOMPtr<nsIObserver> observer = do_QueryInterface(applicationCache);
12305 0 : if (observer)
12306 0 : observer->Observe(aSubject, aTopic, aData);
12307 :
12308 0 : return NS_OK;
12309 : }
12310 :
12311 : #ifdef MOZ_B2G
12312 : if (!nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC) ||
12313 : !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC)) {
12314 : MOZ_ASSERT(IsInnerWindow());
12315 : if (!AsInner()->IsCurrentInnerWindow()) {
12316 : return NS_OK;
12317 : }
12318 :
12319 : RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
12320 : event->InitEvent(
12321 : !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC)
12322 : ? NETWORK_UPLOAD_EVENT_NAME
12323 : : NETWORK_DOWNLOAD_EVENT_NAME,
12324 : false, false);
12325 : event->SetTrusted(true);
12326 :
12327 : bool dummy;
12328 : return DispatchEvent(event, &dummy);
12329 : }
12330 : #endif // MOZ_B2G
12331 :
12332 0 : if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
12333 0 : MOZ_ASSERT(!NS_strcmp(aData, u"intl.accept_languages"));
12334 0 : MOZ_ASSERT(IsInnerWindow());
12335 :
12336 : // The user preferred languages have changed, we need to fire an event on
12337 : // Window object and invalidate the cache for navigator.languages. It is
12338 : // done for every change which can be a waste of cycles but those should be
12339 : // fairly rare.
12340 : // We MUST invalidate navigator.languages before sending the event in the
12341 : // very likely situation where an event handler will try to read its value.
12342 :
12343 0 : if (mNavigator) {
12344 0 : NavigatorBinding::ClearCachedLanguageValue(mNavigator);
12345 0 : NavigatorBinding::ClearCachedLanguagesValue(mNavigator);
12346 : }
12347 :
12348 : // The event has to be dispatched only to the current inner window.
12349 0 : if (!AsInner()->IsCurrentInnerWindow()) {
12350 0 : return NS_OK;
12351 : }
12352 :
12353 0 : RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
12354 0 : event->InitEvent(NS_LITERAL_STRING("languagechange"), false, false);
12355 0 : event->SetTrusted(true);
12356 :
12357 : bool dummy;
12358 0 : return DispatchEvent(event, &dummy);
12359 : }
12360 :
12361 0 : NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
12362 0 : return NS_ERROR_FAILURE;
12363 : }
12364 :
12365 : void
12366 0 : nsGlobalWindow::ObserveStorageNotification(StorageEvent* aEvent,
12367 : const char16_t* aStorageType,
12368 : bool aPrivateBrowsing)
12369 : {
12370 0 : MOZ_ASSERT(aEvent);
12371 :
12372 : // Enforce that the source storage area's private browsing state matches
12373 : // this window's state. These flag checks and their maintenance independent
12374 : // from the principal's OriginAttributes matter because chrome docshells
12375 : // that are part of private browsing windows can be private browsing without
12376 : // having their OriginAttributes set (because they have the system
12377 : // principal).
12378 0 : bool isPrivateBrowsing = IsPrivateBrowsing();
12379 0 : if (isPrivateBrowsing != aPrivateBrowsing) {
12380 0 : return;
12381 : }
12382 :
12383 : // LocalStorage can only exist on an inner window, and we don't want to
12384 : // generate events on frozen or otherwise-navigated-away from windows.
12385 : // (Actually, this code used to try and buffer events for frozen windows,
12386 : // but it never worked, so we've removed it. See bug 1285898.)
12387 0 : if (!IsInnerWindow() || !AsInner()->IsCurrentInnerWindow() || IsFrozen()) {
12388 0 : return;
12389 : }
12390 :
12391 0 : nsIPrincipal *principal = GetPrincipal();
12392 0 : if (!principal) {
12393 0 : return;
12394 : }
12395 :
12396 0 : bool fireMozStorageChanged = false;
12397 0 : nsAutoString eventType;
12398 0 : eventType.AssignLiteral("storage");
12399 :
12400 0 : if (!NS_strcmp(aStorageType, u"sessionStorage")) {
12401 0 : nsCOMPtr<nsIDOMStorage> changingStorage = aEvent->GetStorageArea();
12402 0 : MOZ_ASSERT(changingStorage);
12403 :
12404 0 : bool check = false;
12405 :
12406 0 : nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(GetDocShell());
12407 0 : if (storageManager) {
12408 0 : nsresult rv = storageManager->CheckStorage(principal, changingStorage,
12409 0 : &check);
12410 0 : if (NS_FAILED(rv)) {
12411 0 : return;
12412 : }
12413 : }
12414 :
12415 0 : if (!check) {
12416 : // This storage event is not coming from our storage or is coming
12417 : // from a different docshell, i.e. it is a clone, ignore this event.
12418 0 : return;
12419 : }
12420 :
12421 0 : MOZ_LOG(gDOMLeakPRLog, LogLevel::Debug,
12422 : ("nsGlobalWindow %p with sessionStorage %p passing event from %p",
12423 : this, mSessionStorage.get(), changingStorage.get()));
12424 :
12425 0 : fireMozStorageChanged = mSessionStorage == changingStorage;
12426 0 : if (fireMozStorageChanged) {
12427 0 : eventType.AssignLiteral("MozSessionStorageChanged");
12428 : }
12429 : }
12430 :
12431 : else {
12432 0 : MOZ_ASSERT(!NS_strcmp(aStorageType, u"localStorage"));
12433 0 : nsIPrincipal* storagePrincipal = aEvent->GetPrincipal();
12434 0 : if (!storagePrincipal) {
12435 0 : return;
12436 : }
12437 :
12438 0 : bool equals = false;
12439 0 : nsresult rv = storagePrincipal->Equals(principal, &equals);
12440 0 : NS_ENSURE_SUCCESS_VOID(rv);
12441 :
12442 0 : if (!equals) {
12443 0 : return;
12444 : }
12445 :
12446 0 : fireMozStorageChanged = mLocalStorage == aEvent->GetStorageArea();
12447 :
12448 0 : if (fireMozStorageChanged) {
12449 0 : eventType.AssignLiteral("MozLocalStorageChanged");
12450 : }
12451 : }
12452 :
12453 : // Clone the storage event included in the observer notification. We want
12454 : // to dispatch clones rather than the original event.
12455 0 : IgnoredErrorResult error;
12456 : RefPtr<StorageEvent> clonedEvent =
12457 0 : CloneStorageEvent(eventType, aEvent, error);
12458 0 : if (error.Failed()) {
12459 0 : return;
12460 : }
12461 :
12462 0 : clonedEvent->SetTrusted(true);
12463 :
12464 0 : if (fireMozStorageChanged) {
12465 0 : WidgetEvent* internalEvent = clonedEvent->WidgetEventPtr();
12466 0 : internalEvent->mFlags.mOnlyChromeDispatch = true;
12467 : }
12468 :
12469 : bool defaultActionEnabled;
12470 0 : DispatchEvent(clonedEvent, &defaultActionEnabled);
12471 : }
12472 :
12473 : already_AddRefed<StorageEvent>
12474 0 : nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
12475 : const RefPtr<StorageEvent>& aEvent,
12476 : ErrorResult& aRv)
12477 : {
12478 0 : MOZ_ASSERT(IsInnerWindow());
12479 :
12480 0 : StorageEventInit dict;
12481 :
12482 0 : dict.mBubbles = aEvent->Bubbles();
12483 0 : dict.mCancelable = aEvent->Cancelable();
12484 0 : aEvent->GetKey(dict.mKey);
12485 0 : aEvent->GetOldValue(dict.mOldValue);
12486 0 : aEvent->GetNewValue(dict.mNewValue);
12487 0 : aEvent->GetUrl(dict.mUrl);
12488 :
12489 0 : RefPtr<Storage> storageArea = aEvent->GetStorageArea();
12490 :
12491 0 : RefPtr<Storage> storage;
12492 :
12493 : // If null, this is a localStorage event received by IPC.
12494 0 : if (!storageArea) {
12495 0 : storage = GetLocalStorage(aRv);
12496 0 : if (aRv.Failed() || !storage) {
12497 0 : return nullptr;
12498 : }
12499 :
12500 0 : MOZ_ASSERT(storage->Type() == Storage::eLocalStorage);
12501 : RefPtr<LocalStorage> localStorage =
12502 0 : static_cast<LocalStorage*>(storage.get());
12503 :
12504 : // We must apply the current change to the 'local' localStorage.
12505 0 : localStorage->ApplyEvent(aEvent);
12506 0 : } else if (storageArea->Type() == Storage::eSessionStorage) {
12507 0 : storage = GetSessionStorage(aRv);
12508 : } else {
12509 0 : MOZ_ASSERT(storageArea->Type() == Storage::eLocalStorage);
12510 0 : storage = GetLocalStorage(aRv);
12511 : }
12512 :
12513 0 : if (aRv.Failed() || !storage) {
12514 0 : return nullptr;
12515 : }
12516 :
12517 0 : MOZ_ASSERT(storage);
12518 0 : MOZ_ASSERT_IF(storageArea, storage->IsForkOf(storageArea));
12519 :
12520 0 : dict.mStorageArea = storage;
12521 :
12522 0 : RefPtr<StorageEvent> event = StorageEvent::Constructor(this, aType, dict);
12523 0 : return event.forget();
12524 : }
12525 :
12526 : void
12527 0 : nsGlobalWindow::Suspend()
12528 : {
12529 0 : MOZ_ASSERT(NS_IsMainThread());
12530 0 : MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());
12531 :
12532 : // We can only safely suspend windows that are the current inner window. If
12533 : // its not the current inner, then we are in one of two different cases.
12534 : // Either we are in the bfcache or we are doomed window that is going away.
12535 : // When a window becomes inactive we purposely avoid placing already suspended
12536 : // windows into the bfcache. It only expects windows suspended due to the
12537 : // Freeze() method which occurs while the window is still the current inner.
12538 : // So we must not call Suspend() on bfcache windows at this point or this
12539 : // invariant will be broken. If the window is doomed there is no point in
12540 : // suspending it since it will soon be gone.
12541 0 : if (!AsInner()->IsCurrentInnerWindow()) {
12542 0 : return;
12543 : }
12544 :
12545 : // All children are also suspended. This ensure mSuspendDepth is
12546 : // set properly and the timers are properly canceled for each child.
12547 0 : CallOnChildren(&nsGlobalWindow::Suspend);
12548 :
12549 0 : mSuspendDepth += 1;
12550 0 : if (mSuspendDepth != 1) {
12551 0 : return;
12552 : }
12553 :
12554 0 : nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
12555 0 : if (ac) {
12556 0 : for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
12557 0 : ac->RemoveWindowListener(mEnabledSensors[i], this);
12558 : }
12559 0 : DisableGamepadUpdates();
12560 0 : DisableVRUpdates();
12561 :
12562 0 : mozilla::dom::workers::SuspendWorkersForWindow(AsInner());
12563 :
12564 0 : SuspendIdleRequests();
12565 :
12566 0 : mTimeoutManager->Suspend();
12567 :
12568 : // Suspend all of the AudioContexts for this window
12569 0 : for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
12570 0 : ErrorResult dummy;
12571 0 : RefPtr<Promise> d = mAudioContexts[i]->Suspend(dummy);
12572 : }
12573 : }
12574 :
12575 : void
12576 0 : nsGlobalWindow::Resume()
12577 : {
12578 0 : MOZ_ASSERT(NS_IsMainThread());
12579 0 : MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());
12580 :
12581 : // We can only safely resume a window if its the current inner window. If
12582 : // its not the current inner, then we are in one of two different cases.
12583 : // Either we are in the bfcache or we are doomed window that is going away.
12584 : // If a window is suspended when it becomes inactive we purposely do not
12585 : // put it in the bfcache, so Resume should never be needed in that case.
12586 : // If the window is doomed then there is no point in resuming it.
12587 0 : if (!AsInner()->IsCurrentInnerWindow()) {
12588 0 : return;
12589 : }
12590 :
12591 : // Resume all children. This restores timers recursively canceled
12592 : // in Suspend() and ensures all children have the correct mSuspendDepth.
12593 0 : CallOnChildren(&nsGlobalWindow::Resume);
12594 :
12595 0 : MOZ_ASSERT(mSuspendDepth != 0);
12596 0 : mSuspendDepth -= 1;
12597 0 : if (mSuspendDepth != 0) {
12598 0 : return;
12599 : }
12600 :
12601 : // We should not be able to resume a frozen window. It must be Thaw()'d first.
12602 0 : MOZ_ASSERT(mFreezeDepth == 0);
12603 :
12604 0 : nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
12605 0 : if (ac) {
12606 0 : for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
12607 0 : ac->AddWindowListener(mEnabledSensors[i], this);
12608 : }
12609 0 : EnableGamepadUpdates();
12610 0 : EnableVRUpdates();
12611 :
12612 : // Resume all of the AudioContexts for this window
12613 0 : for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
12614 0 : ErrorResult dummy;
12615 0 : RefPtr<Promise> d = mAudioContexts[i]->Resume(dummy);
12616 : }
12617 :
12618 0 : mTimeoutManager->Resume();
12619 :
12620 0 : ResumeIdleRequests();
12621 :
12622 : // Resume all of the workers for this window. We must do this
12623 : // after timeouts since workers may have queued events that can trigger
12624 : // a setTimeout().
12625 0 : mozilla::dom::workers::ResumeWorkersForWindow(AsInner());
12626 : }
12627 :
12628 : bool
12629 49 : nsGlobalWindow::IsSuspended() const
12630 : {
12631 49 : MOZ_ASSERT(NS_IsMainThread());
12632 : // No inner means we are effectively suspended
12633 49 : if (IsOuterWindow()) {
12634 0 : if (!mInnerWindow) {
12635 0 : return true;
12636 : }
12637 0 : return mInnerWindow->IsSuspended();
12638 : }
12639 49 : return mSuspendDepth != 0;
12640 : }
12641 :
12642 : void
12643 0 : nsGlobalWindow::Freeze()
12644 : {
12645 0 : MOZ_ASSERT(NS_IsMainThread());
12646 0 : Suspend();
12647 0 : FreezeInternal();
12648 0 : }
12649 :
12650 : void
12651 0 : nsGlobalWindow::FreezeInternal()
12652 : {
12653 0 : MOZ_ASSERT(NS_IsMainThread());
12654 0 : MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());
12655 0 : MOZ_DIAGNOSTIC_ASSERT(AsInner()->IsCurrentInnerWindow());
12656 0 : MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
12657 :
12658 0 : CallOnChildren(&nsGlobalWindow::FreezeInternal);
12659 :
12660 0 : mFreezeDepth += 1;
12661 0 : MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
12662 0 : if (mFreezeDepth != 1) {
12663 0 : return;
12664 : }
12665 :
12666 0 : mozilla::dom::workers::FreezeWorkersForWindow(AsInner());
12667 :
12668 0 : mTimeoutManager->Freeze();
12669 :
12670 0 : NotifyDOMWindowFrozen(this);
12671 : }
12672 :
12673 : void
12674 0 : nsGlobalWindow::Thaw()
12675 : {
12676 0 : MOZ_ASSERT(NS_IsMainThread());
12677 0 : ThawInternal();
12678 0 : Resume();
12679 0 : }
12680 :
12681 : void
12682 0 : nsGlobalWindow::ThawInternal()
12683 : {
12684 0 : MOZ_ASSERT(NS_IsMainThread());
12685 0 : MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());
12686 0 : MOZ_DIAGNOSTIC_ASSERT(AsInner()->IsCurrentInnerWindow());
12687 0 : MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
12688 :
12689 0 : CallOnChildren(&nsGlobalWindow::ThawInternal);
12690 :
12691 0 : MOZ_ASSERT(mFreezeDepth != 0);
12692 0 : mFreezeDepth -= 1;
12693 0 : MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
12694 0 : if (mFreezeDepth != 0) {
12695 0 : return;
12696 : }
12697 :
12698 0 : mTimeoutManager->Thaw();
12699 :
12700 0 : mozilla::dom::workers::ThawWorkersForWindow(AsInner());
12701 :
12702 0 : NotifyDOMWindowThawed(this);
12703 : }
12704 :
12705 : bool
12706 71 : nsGlobalWindow::IsFrozen() const
12707 : {
12708 71 : MOZ_ASSERT(NS_IsMainThread());
12709 : // No inner means we are effectively frozen
12710 71 : if (IsOuterWindow()) {
12711 12 : if (!mInnerWindow) {
12712 5 : return true;
12713 : }
12714 7 : return mInnerWindow->IsFrozen();
12715 : }
12716 59 : bool frozen = mFreezeDepth != 0;
12717 59 : MOZ_ASSERT_IF(frozen, IsSuspended());
12718 59 : return frozen;
12719 : }
12720 :
12721 : void
12722 7 : nsGlobalWindow::SyncStateFromParentWindow()
12723 : {
12724 : // This method should only be called on an inner window that has been
12725 : // assigned to an outer window already.
12726 7 : MOZ_ASSERT(IsInnerWindow());
12727 7 : MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());
12728 7 : nsPIDOMWindowOuter* outer = GetOuterWindow();
12729 7 : MOZ_ASSERT(outer);
12730 :
12731 : // Attempt to find our parent windows.
12732 14 : nsCOMPtr<Element> frame = outer->GetFrameElementInternal();
12733 7 : nsPIDOMWindowOuter* parentOuter = frame ? frame->OwnerDoc()->GetWindow()
12734 14 : : nullptr;
12735 : nsGlobalWindow* parentInner =
12736 7 : parentOuter ? nsGlobalWindow::Cast(parentOuter->GetCurrentInnerWindow())
12737 7 : : nullptr;
12738 :
12739 : // If our outer is in a modal state, but our parent is not in a modal
12740 : // state, then we must apply the suspend directly. If our parent is
12741 : // in a modal state then we should get the suspend automatically
12742 : // via the parentSuspendDepth application below.
12743 7 : if ((!parentInner || !parentInner->IsInModalState()) && IsInModalState()) {
12744 0 : Suspend();
12745 : }
12746 :
12747 7 : uint32_t parentFreezeDepth = parentInner ? parentInner->mFreezeDepth : 0;
12748 7 : uint32_t parentSuspendDepth = parentInner ? parentInner->mSuspendDepth : 0;
12749 :
12750 : // Since every Freeze() calls Suspend(), the suspend count must
12751 : // be equal or greater to the freeze count.
12752 7 : MOZ_ASSERT(parentFreezeDepth <= parentSuspendDepth);
12753 :
12754 : // First apply the Freeze() calls.
12755 7 : for (uint32_t i = 0; i < parentFreezeDepth; ++i) {
12756 0 : Freeze();
12757 : }
12758 :
12759 : // Now apply only the number of Suspend() calls to reach the target
12760 : // suspend count after applying the Freeze() calls.
12761 7 : for (uint32_t i = 0; i < (parentSuspendDepth - parentFreezeDepth); ++i) {
12762 0 : Suspend();
12763 : }
12764 7 : }
12765 :
12766 : template<typename Method>
12767 : void
12768 0 : nsGlobalWindow::CallOnChildren(Method aMethod)
12769 : {
12770 0 : MOZ_ASSERT(NS_IsMainThread());
12771 0 : MOZ_ASSERT(IsInnerWindow());
12772 0 : MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());
12773 :
12774 0 : nsCOMPtr<nsIDocShell> docShell = GetDocShell();
12775 0 : if (!docShell) {
12776 0 : return;
12777 : }
12778 :
12779 0 : int32_t childCount = 0;
12780 0 : docShell->GetChildCount(&childCount);
12781 :
12782 0 : for (int32_t i = 0; i < childCount; ++i) {
12783 0 : nsCOMPtr<nsIDocShellTreeItem> childShell;
12784 0 : docShell->GetChildAt(i, getter_AddRefs(childShell));
12785 0 : NS_ASSERTION(childShell, "null child shell");
12786 :
12787 0 : nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow();
12788 0 : if (!pWin) {
12789 0 : continue;
12790 : }
12791 :
12792 0 : auto* win = nsGlobalWindow::Cast(pWin);
12793 0 : nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
12794 :
12795 : // This is a bit hackish. Only freeze/suspend windows which are truly our
12796 : // subwindows.
12797 0 : nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
12798 0 : if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
12799 0 : continue;
12800 : }
12801 :
12802 0 : (inner->*aMethod)();
12803 : }
12804 : }
12805 :
12806 : nsresult
12807 0 : nsGlobalWindow::FireDelayedDOMEvents()
12808 : {
12809 0 : FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
12810 :
12811 0 : if (mApplicationCache) {
12812 0 : static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
12813 : }
12814 :
12815 : // Fires an offline status event if the offline status has changed
12816 0 : FireOfflineStatusEventIfChanged();
12817 :
12818 0 : if (mNotifyIdleObserversIdleOnThaw) {
12819 0 : mNotifyIdleObserversIdleOnThaw = false;
12820 0 : HandleIdleActiveEvent();
12821 : }
12822 :
12823 0 : if (mNotifyIdleObserversActiveOnThaw) {
12824 0 : mNotifyIdleObserversActiveOnThaw = false;
12825 0 : ScheduleActiveTimerCallback();
12826 : }
12827 :
12828 0 : nsCOMPtr<nsIDocShell> docShell = GetDocShell();
12829 0 : if (docShell) {
12830 0 : int32_t childCount = 0;
12831 0 : docShell->GetChildCount(&childCount);
12832 :
12833 0 : for (int32_t i = 0; i < childCount; ++i) {
12834 0 : nsCOMPtr<nsIDocShellTreeItem> childShell;
12835 0 : docShell->GetChildAt(i, getter_AddRefs(childShell));
12836 0 : NS_ASSERTION(childShell, "null child shell");
12837 :
12838 0 : if (nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow()) {
12839 0 : auto* win = nsGlobalWindow::Cast(pWin);
12840 0 : win->FireDelayedDOMEvents();
12841 : }
12842 : }
12843 : }
12844 :
12845 0 : return NS_OK;
12846 : }
12847 :
12848 : //*****************************************************************************
12849 : // nsGlobalWindow: Window Control Functions
12850 : //*****************************************************************************
12851 :
12852 : nsPIDOMWindowOuter*
12853 7 : nsGlobalWindow::GetParentInternal()
12854 : {
12855 7 : if (IsInnerWindow()) {
12856 1 : nsGlobalWindow* outer = GetOuterWindowInternal();
12857 1 : if (!outer) {
12858 0 : NS_WARNING("No outer window available!");
12859 0 : return nullptr;
12860 : }
12861 1 : return outer->GetParentInternal();
12862 : }
12863 :
12864 12 : nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
12865 :
12866 6 : if (parent && parent != AsOuter()) {
12867 2 : return parent;
12868 : }
12869 :
12870 4 : return nullptr;
12871 : }
12872 :
12873 : void
12874 0 : nsGlobalWindow::UnblockScriptedClosing()
12875 : {
12876 0 : MOZ_ASSERT(IsOuterWindow());
12877 0 : mBlockScriptedClosingFlag = false;
12878 0 : }
12879 :
12880 : class AutoUnblockScriptClosing
12881 : {
12882 : private:
12883 : RefPtr<nsGlobalWindow> mWin;
12884 : public:
12885 0 : explicit AutoUnblockScriptClosing(nsGlobalWindow* aWin)
12886 0 : : mWin(aWin)
12887 : {
12888 0 : MOZ_ASSERT(mWin);
12889 0 : MOZ_ASSERT(mWin->IsOuterWindow());
12890 0 : }
12891 0 : ~AutoUnblockScriptClosing()
12892 0 : {
12893 0 : void (nsGlobalWindow::*run)() = &nsGlobalWindow::UnblockScriptedClosing;
12894 0 : nsCOMPtr<nsIRunnable> caller = NewRunnableMethod(
12895 0 : "AutoUnblockScriptClosing::~AutoUnblockScriptClosing", mWin, run);
12896 0 : mWin->Dispatch("nsGlobalWindow::UnblockScriptedClosing",
12897 0 : TaskCategory::Other, caller.forget());
12898 0 : }
12899 : };
12900 :
12901 : nsresult
12902 0 : nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
12903 : const nsAString& aOptions, bool aDialog,
12904 : bool aContentModal, bool aCalledNoScript,
12905 : bool aDoJSFixups, bool aNavigate,
12906 : nsIArray *argv,
12907 : nsISupports *aExtraArgument,
12908 : nsIDocShellLoadInfo* aLoadInfo,
12909 : bool aForceNoOpener,
12910 : nsPIDOMWindowOuter **aReturn)
12911 : {
12912 0 : MOZ_ASSERT(IsOuterWindow());
12913 :
12914 : #ifdef DEBUG
12915 0 : uint32_t argc = 0;
12916 0 : if (argv)
12917 0 : argv->GetLength(&argc);
12918 : #endif
12919 0 : NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
12920 : "Can't pass in arguments both ways");
12921 0 : NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
12922 : "Can't pass JS args when called via the noscript methods");
12923 :
12924 0 : mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
12925 :
12926 : // Calls to window.open from script should navigate.
12927 0 : MOZ_ASSERT(aCalledNoScript || aNavigate);
12928 :
12929 0 : *aReturn = nullptr;
12930 :
12931 0 : nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
12932 0 : if (!chrome) {
12933 : // No chrome means we don't want to go through with this open call
12934 : // -- see nsIWindowWatcher.idl
12935 0 : return NS_ERROR_NOT_AVAILABLE;
12936 : }
12937 :
12938 0 : NS_ASSERTION(mDocShell, "Must have docshell here");
12939 :
12940 0 : bool forceNoOpener = aForceNoOpener;
12941 0 : if (!forceNoOpener) {
12942 : // Unlike other window flags, "noopener" comes from splitting on commas with
12943 : // HTML whitespace trimming...
12944 : nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(
12945 0 : aOptions, ',');
12946 0 : while (tok.hasMoreTokens()) {
12947 0 : if (tok.nextToken().EqualsLiteral("noopener")) {
12948 0 : forceNoOpener = true;
12949 0 : break;
12950 : }
12951 : }
12952 : }
12953 :
12954 : // XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
12955 : // (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
12956 : // But note that if you change this to GetEntryGlobal(), say, then
12957 : // OnLinkClickEvent::Run will need a full-blown AutoEntryScript.
12958 0 : const bool checkForPopup = !nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
12959 0 : !aDialog && !WindowExists(aName, forceNoOpener, !aCalledNoScript);
12960 :
12961 : // Note: it's very important that this be an nsXPIDLCString, since we want
12962 : // .get() on it to return nullptr until we write stuff to it. The window
12963 : // watcher expects a null URL string if there is no URL to load.
12964 0 : nsXPIDLCString url;
12965 0 : nsresult rv = NS_OK;
12966 :
12967 : // It's important to do this security check before determining whether this
12968 : // window opening should be blocked, to ensure that we don't FireAbuseEvents
12969 : // for a window opening that wouldn't have succeeded in the first place.
12970 0 : if (!aUrl.IsEmpty()) {
12971 0 : AppendUTF16toUTF8(aUrl, url);
12972 :
12973 : // It's safe to skip the security check below if we're not a dialog
12974 : // because window.openDialog is not callable from content script. See bug
12975 : // 56851.
12976 : //
12977 : // If we're not navigating, we assume that whoever *does* navigate the
12978 : // window will do a security check of their own.
12979 0 : if (url.get() && !aDialog && aNavigate)
12980 0 : rv = SecurityCheckURL(url.get());
12981 : }
12982 :
12983 0 : if (NS_FAILED(rv))
12984 0 : return rv;
12985 :
12986 0 : PopupControlState abuseLevel = gPopupControlState;
12987 0 : if (checkForPopup) {
12988 0 : abuseLevel = RevisePopupAbuseLevel(abuseLevel);
12989 0 : if (abuseLevel >= openAbused) {
12990 0 : if (!aCalledNoScript) {
12991 : // If script in some other window is doing a window.open on us and
12992 : // it's being blocked, then it's OK to close us afterwards, probably.
12993 : // But if we're doing a window.open on ourselves and block the popup,
12994 : // prevent this window from closing until after this script terminates
12995 : // so that whatever popup blocker UI the app has will be visible.
12996 : nsCOMPtr<nsPIDOMWindowInner> entryWindow =
12997 0 : do_QueryInterface(GetEntryGlobal());
12998 : // Note that entryWindow can be null here if some JS component was the
12999 : // place where script was entered for this JS execution.
13000 0 : if (entryWindow &&
13001 0 : entryWindow->GetOuterWindow() == this->AsOuter()) {
13002 0 : mBlockScriptedClosingFlag = true;
13003 0 : closeUnblocker.emplace(this);
13004 : }
13005 : }
13006 :
13007 0 : FireAbuseEvents(aUrl, aName, aOptions);
13008 0 : return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
13009 : }
13010 : }
13011 :
13012 0 : nsCOMPtr<mozIDOMWindowProxy> domReturn;
13013 :
13014 : nsCOMPtr<nsIWindowWatcher> wwatch =
13015 0 : do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
13016 0 : NS_ENSURE_TRUE(wwatch, rv);
13017 :
13018 0 : NS_ConvertUTF16toUTF8 options(aOptions);
13019 0 : NS_ConvertUTF16toUTF8 name(aName);
13020 :
13021 0 : const char *options_ptr = aOptions.IsEmpty() ? nullptr : options.get();
13022 0 : const char *name_ptr = aName.IsEmpty() ? nullptr : name.get();
13023 :
13024 0 : nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
13025 0 : NS_ENSURE_STATE(pwwatch);
13026 :
13027 0 : MOZ_ASSERT_IF(checkForPopup, abuseLevel < openAbused);
13028 : // At this point we should know for a fact that if checkForPopup then
13029 : // abuseLevel < openAbused, so we could just check for abuseLevel ==
13030 : // openControlled. But let's be defensive just in case and treat anything
13031 : // that fails the above assert as a spam popup too, if it ever happens.
13032 0 : bool isPopupSpamWindow = checkForPopup && (abuseLevel >= openControlled);
13033 :
13034 : {
13035 : // Reset popup state while opening a window to prevent the
13036 : // current state from being active the whole time a modal
13037 : // dialog is open.
13038 0 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
13039 :
13040 0 : if (!aCalledNoScript) {
13041 : // We asserted at the top of this function that aNavigate is true for
13042 : // !aCalledNoScript.
13043 0 : rv = pwwatch->OpenWindow2(AsOuter(), url.get(), name_ptr,
13044 : options_ptr, /* aCalledFromScript = */ true,
13045 : aDialog, aNavigate, argv,
13046 : isPopupSpamWindow,
13047 : forceNoOpener,
13048 : aLoadInfo,
13049 0 : getter_AddRefs(domReturn));
13050 : } else {
13051 : // Force a system caller here so that the window watcher won't screw us
13052 : // up. We do NOT want this case looking at the JS context on the stack
13053 : // when searching. Compare comments on
13054 : // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
13055 :
13056 : // Note: Because nsWindowWatcher is so broken, it's actually important
13057 : // that we don't force a system caller here, because that screws it up
13058 : // when it tries to compute the caller principal to associate with dialog
13059 : // arguments. That whole setup just really needs to be rewritten. :-(
13060 0 : Maybe<AutoNoJSAPI> nojsapi;
13061 0 : if (!aContentModal) {
13062 0 : nojsapi.emplace();
13063 : }
13064 :
13065 0 : rv = pwwatch->OpenWindow2(AsOuter(), url.get(), name_ptr,
13066 : options_ptr, /* aCalledFromScript = */ false,
13067 : aDialog, aNavigate, aExtraArgument,
13068 : isPopupSpamWindow,
13069 : forceNoOpener,
13070 : aLoadInfo,
13071 0 : getter_AddRefs(domReturn));
13072 :
13073 : }
13074 : }
13075 :
13076 0 : NS_ENSURE_SUCCESS(rv, rv);
13077 :
13078 : // success!
13079 :
13080 0 : NS_ENSURE_TRUE(domReturn, NS_OK);
13081 : nsCOMPtr<nsPIDOMWindowOuter> outerReturn =
13082 0 : nsPIDOMWindowOuter::From(domReturn);
13083 0 : outerReturn.swap(*aReturn);
13084 :
13085 0 : if (aDoJSFixups) {
13086 0 : nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
13087 0 : if (!chrome_win) {
13088 : // A new non-chrome window was created from a call to
13089 : // window.open() from JavaScript, make sure there's a document in
13090 : // the new window. We do this by simply asking the new window for
13091 : // its document, this will synchronously create an empty document
13092 : // if there is no document in the window.
13093 : // XXXbz should this just use EnsureInnerWindow()?
13094 :
13095 : // Force document creation.
13096 0 : nsCOMPtr<nsIDocument> doc = (*aReturn)->GetDoc();
13097 : Unused << doc;
13098 : }
13099 : }
13100 :
13101 0 : return rv;
13102 : }
13103 :
13104 : //*****************************************************************************
13105 : // nsGlobalWindow: Timeout Functions
13106 : //*****************************************************************************
13107 :
13108 : nsGlobalWindow*
13109 11 : nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult& aError)
13110 : {
13111 : nsGlobalWindow* currentInner;
13112 : nsGlobalWindow* forwardTo;
13113 11 : if (IsInnerWindow()) {
13114 11 : nsGlobalWindow* outer = GetOuterWindowInternal();
13115 11 : currentInner = outer ? outer->GetCurrentInnerWindowInternal() : this;
13116 :
13117 11 : forwardTo = this;
13118 : } else {
13119 0 : currentInner = GetCurrentInnerWindowInternal();
13120 :
13121 : // This needs to forward to the inner window, but since the current
13122 : // inner may not be the inner in the calling scope, we need to treat
13123 : // this specially here as we don't want timeouts registered in a
13124 : // dying inner window to get registered and run on the current inner
13125 : // window. To get this right, we need to forward this call to the
13126 : // inner window that's calling window.setTimeout().
13127 :
13128 0 : forwardTo = CallerInnerWindow();
13129 0 : if (!forwardTo && nsContentUtils::IsCallerChrome()) {
13130 0 : forwardTo = currentInner;
13131 : }
13132 0 : if (!forwardTo) {
13133 0 : aError.Throw(NS_ERROR_NOT_AVAILABLE);
13134 0 : return nullptr;
13135 : }
13136 :
13137 : // If the caller and the callee share the same outer window, forward to the
13138 : // caller inner. Else, we forward to the current inner (e.g. someone is
13139 : // calling setTimeout() on a reference to some other window).
13140 0 : if (forwardTo->GetOuterWindow() != AsOuter() ||
13141 0 : !forwardTo->IsInnerWindow()) {
13142 0 : if (!currentInner) {
13143 0 : NS_WARNING("No inner window available!");
13144 0 : aError.Throw(NS_ERROR_NOT_INITIALIZED);
13145 0 : return nullptr;
13146 : }
13147 :
13148 0 : return currentInner;
13149 : }
13150 : }
13151 :
13152 : // If forwardTo is not the window with an active document then we want the
13153 : // call to setTimeout/Interval to be a noop, so return null but don't set an
13154 : // error.
13155 11 : return forwardTo->AsInner()->HasActiveDocument() ? currentInner : nullptr;
13156 : }
13157 :
13158 : int32_t
13159 11 : nsGlobalWindow::SetTimeout(JSContext* aCx, Function& aFunction,
13160 : int32_t aTimeout,
13161 : const Sequence<JS::Value>& aArguments,
13162 : ErrorResult& aError)
13163 : {
13164 : return SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments, false,
13165 11 : aError);
13166 : }
13167 :
13168 : int32_t
13169 0 : nsGlobalWindow::SetTimeout(JSContext* aCx, const nsAString& aHandler,
13170 : int32_t aTimeout,
13171 : const Sequence<JS::Value>& /* unused */,
13172 : ErrorResult& aError)
13173 : {
13174 0 : return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError);
13175 : }
13176 :
13177 : static bool
13178 0 : IsInterval(const Optional<int32_t>& aTimeout, int32_t& aResultTimeout)
13179 : {
13180 0 : if (aTimeout.WasPassed()) {
13181 0 : aResultTimeout = aTimeout.Value();
13182 0 : return true;
13183 : }
13184 :
13185 : // If no interval was specified, treat this like a timeout, to avoid setting
13186 : // an interval of 0 milliseconds.
13187 0 : aResultTimeout = 0;
13188 0 : return false;
13189 : }
13190 :
13191 : int32_t
13192 0 : nsGlobalWindow::SetInterval(JSContext* aCx, Function& aFunction,
13193 : const Optional<int32_t>& aTimeout,
13194 : const Sequence<JS::Value>& aArguments,
13195 : ErrorResult& aError)
13196 : {
13197 : int32_t timeout;
13198 0 : bool isInterval = IsInterval(aTimeout, timeout);
13199 0 : return SetTimeoutOrInterval(aCx, aFunction, timeout, aArguments, isInterval,
13200 0 : aError);
13201 : }
13202 :
13203 : int32_t
13204 0 : nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler,
13205 : const Optional<int32_t>& aTimeout,
13206 : const Sequence<JS::Value>& /* unused */,
13207 : ErrorResult& aError)
13208 : {
13209 : int32_t timeout;
13210 0 : bool isInterval = IsInterval(aTimeout, timeout);
13211 0 : return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError);
13212 : }
13213 :
13214 : int32_t
13215 11 : nsGlobalWindow::SetTimeoutOrInterval(JSContext *aCx, Function& aFunction,
13216 : int32_t aTimeout,
13217 : const Sequence<JS::Value>& aArguments,
13218 : bool aIsInterval, ErrorResult& aError)
13219 : {
13220 11 : nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
13221 11 : if (!inner) {
13222 0 : return -1;
13223 : }
13224 :
13225 11 : if (inner != this) {
13226 0 : return inner->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
13227 0 : aIsInterval, aError);
13228 : }
13229 :
13230 : nsCOMPtr<nsIScriptTimeoutHandler> handler =
13231 22 : NS_CreateJSTimeoutHandler(aCx, this, aFunction, aArguments, aError);
13232 11 : if (!handler) {
13233 0 : return 0;
13234 : }
13235 :
13236 : int32_t result;
13237 22 : aError = mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval,
13238 : Timeout::Reason::eTimeoutOrInterval,
13239 22 : &result);
13240 11 : return result;
13241 : }
13242 :
13243 : int32_t
13244 0 : nsGlobalWindow::SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
13245 : int32_t aTimeout, bool aIsInterval,
13246 : ErrorResult& aError)
13247 : {
13248 0 : nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
13249 0 : if (!inner) {
13250 0 : return -1;
13251 : }
13252 :
13253 0 : if (inner != this) {
13254 0 : return inner->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
13255 0 : aError);
13256 : }
13257 :
13258 : nsCOMPtr<nsIScriptTimeoutHandler> handler =
13259 0 : NS_CreateJSTimeoutHandler(aCx, this, aHandler, aError);
13260 0 : if (!handler) {
13261 0 : return 0;
13262 : }
13263 :
13264 : int32_t result;
13265 0 : aError = mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval,
13266 : Timeout::Reason::eTimeoutOrInterval,
13267 0 : &result);
13268 0 : return result;
13269 : }
13270 :
13271 : bool
13272 8 : nsGlobalWindow::RunTimeoutHandler(Timeout* aTimeout,
13273 : nsIScriptContext* aScx)
13274 : {
13275 8 : MOZ_ASSERT(IsInnerWindow());
13276 :
13277 : // Hold on to the timeout in case mExpr or mFunObj releases its
13278 : // doc.
13279 16 : RefPtr<Timeout> timeout = aTimeout;
13280 8 : Timeout* last_running_timeout = mTimeoutManager->BeginRunningTimeout(timeout);
13281 8 : timeout->mRunning = true;
13282 :
13283 : // Push this timeout's popup control state, which should only be
13284 : // eabled the first time a timeout fires that was created while
13285 : // popups were enabled and with a delay less than
13286 : // "dom.disable_open_click_delay".
13287 16 : nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
13288 :
13289 : // Clear the timeout's popup state, if any, to prevent interval
13290 : // timeouts from repeatedly opening poups.
13291 8 : timeout->mPopupState = openAbused;
13292 :
13293 8 : bool trackNestingLevel = !timeout->mIsInterval;
13294 : uint32_t nestingLevel;
13295 8 : if (trackNestingLevel) {
13296 8 : nestingLevel = TimeoutManager::GetNestingLevel();
13297 8 : TimeoutManager::SetNestingLevel(timeout->mNestingLevel);
13298 : }
13299 :
13300 : const char *reason;
13301 8 : if (timeout->mIsInterval) {
13302 0 : reason = "setInterval handler";
13303 : } else {
13304 8 : reason = "setTimeout handler";
13305 : }
13306 :
13307 8 : bool abortIntervalHandler = false;
13308 16 : nsCOMPtr<nsIScriptTimeoutHandler> handler(do_QueryInterface(timeout->mScriptHandler));
13309 8 : if (handler) {
13310 14 : RefPtr<Function> callback = handler->GetCallback();
13311 :
13312 7 : if (!callback) {
13313 : // Evaluate the timeout expression.
13314 0 : const nsAString& script = handler->GetHandlerText();
13315 :
13316 0 : const char* filename = nullptr;
13317 0 : uint32_t lineNo = 0, dummyColumn = 0;
13318 0 : handler->GetLocation(&filename, &lineNo, &dummyColumn);
13319 :
13320 : // New script entry point required, due to the "Create a script" sub-step of
13321 : // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
13322 0 : nsAutoMicroTask mt;
13323 0 : AutoEntryScript aes(this, reason, true);
13324 0 : JS::CompileOptions options(aes.cx());
13325 0 : options.setFileAndLine(filename, lineNo).setVersion(JSVERSION_DEFAULT);
13326 0 : options.setNoScriptRval(true);
13327 0 : JS::Rooted<JSObject*> global(aes.cx(), FastGetGlobalJSObject());
13328 0 : nsresult rv = NS_OK;
13329 : {
13330 0 : nsJSUtils::ExecutionContext exec(aes.cx(), global);
13331 0 : rv = exec.CompileAndExec(options, script);
13332 : }
13333 :
13334 0 : if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
13335 0 : abortIntervalHandler = true;
13336 : }
13337 : } else {
13338 : // Hold strong ref to ourselves while we call the callback.
13339 14 : nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow*>(this));
13340 14 : ErrorResult rv;
13341 14 : JS::Rooted<JS::Value> ignoredVal(RootingCx());
13342 7 : callback->Call(me, handler->GetArgs(), &ignoredVal, rv, reason);
13343 7 : if (rv.IsUncatchableException()) {
13344 0 : abortIntervalHandler = true;
13345 : }
13346 :
13347 7 : rv.SuppressException();
13348 : }
13349 : } else {
13350 2 : nsCOMPtr<nsITimeoutHandler> basicHandler(timeout->mScriptHandler);
13351 2 : nsCOMPtr<nsISupports> kungFuDeathGrip(static_cast<nsIDOMWindow*>(this));
13352 : mozilla::Unused << kungFuDeathGrip;
13353 1 : basicHandler->Call();
13354 : }
13355 :
13356 : // If we received an uncatchable exception, do not schedule the timeout again.
13357 : // This allows the slow script dialog to break easy DoS attacks like
13358 : // setInterval(function() { while(1); }, 100);
13359 8 : if (abortIntervalHandler) {
13360 : // If it wasn't an interval timer to begin with, this does nothing. If it
13361 : // was, we'll treat it as a timeout that we just ran and discard it when
13362 : // we return.
13363 0 : timeout->mIsInterval = false;
13364 : }
13365 :
13366 : // We ignore any failures from calling EvaluateString() on the context or
13367 : // Call() on a Function here since we're in a loop
13368 : // where we're likely to be running timeouts whose OS timers
13369 : // didn't fire in time and we don't want to not fire those timers
13370 : // now just because execution of one timer failed. We can't
13371 : // propagate the error to anyone who cares about it from this
13372 : // point anyway, and the script context should have already reported
13373 : // the script error in the usual way - so we just drop it.
13374 :
13375 : // Since we might be processing more timeouts, go ahead and flush the promise
13376 : // queue now before we do that. We need to do that while we're still in our
13377 : // "running JS is safe" state (e.g. mRunningTimeout is set, timeout->mRunning
13378 : // is false).
13379 8 : Promise::PerformMicroTaskCheckpoint();
13380 :
13381 8 : if (trackNestingLevel) {
13382 8 : TimeoutManager::SetNestingLevel(nestingLevel);
13383 : }
13384 :
13385 8 : mTimeoutManager->EndRunningTimeout(last_running_timeout);
13386 8 : timeout->mRunning = false;
13387 :
13388 16 : return timeout->mCleared;
13389 : }
13390 :
13391 : //*****************************************************************************
13392 : // nsGlobalWindow: Helper Functions
13393 : //*****************************************************************************
13394 :
13395 : already_AddRefed<nsIDocShellTreeOwner>
13396 18 : nsGlobalWindow::GetTreeOwner()
13397 : {
13398 18 : FORWARD_TO_OUTER(GetTreeOwner, (), nullptr);
13399 :
13400 : // If there's no docShellAsItem, this window must have been closed,
13401 : // in that case there is no tree owner.
13402 :
13403 13 : if (!mDocShell) {
13404 0 : return nullptr;
13405 : }
13406 :
13407 26 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
13408 13 : mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
13409 13 : return treeOwner.forget();
13410 : }
13411 :
13412 : already_AddRefed<nsIBaseWindow>
13413 11 : nsGlobalWindow::GetTreeOwnerWindow()
13414 : {
13415 11 : MOZ_ASSERT(IsOuterWindow());
13416 :
13417 22 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
13418 :
13419 : // If there's no mDocShell, this window must have been closed,
13420 : // in that case there is no tree owner.
13421 :
13422 11 : if (mDocShell) {
13423 11 : mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
13424 : }
13425 :
13426 22 : nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
13427 22 : return baseWindow.forget();
13428 : }
13429 :
13430 : already_AddRefed<nsIWebBrowserChrome>
13431 13 : nsGlobalWindow::GetWebBrowserChrome()
13432 : {
13433 26 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
13434 :
13435 26 : nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
13436 26 : return browserChrome.forget();
13437 : }
13438 :
13439 : nsIScrollableFrame *
13440 0 : nsGlobalWindow::GetScrollFrame()
13441 : {
13442 0 : FORWARD_TO_OUTER(GetScrollFrame, (), nullptr);
13443 :
13444 0 : if (!mDocShell) {
13445 0 : return nullptr;
13446 : }
13447 :
13448 0 : nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
13449 0 : if (presShell) {
13450 0 : return presShell->GetRootScrollFrameAsScrollable();
13451 : }
13452 0 : return nullptr;
13453 : }
13454 :
13455 : nsresult
13456 0 : nsGlobalWindow::SecurityCheckURL(const char *aURL)
13457 : {
13458 0 : nsCOMPtr<nsPIDOMWindowInner> sourceWindow = do_QueryInterface(GetEntryGlobal());
13459 0 : if (!sourceWindow) {
13460 0 : sourceWindow = AsOuter()->GetCurrentInnerWindow();
13461 : }
13462 0 : AutoJSContext cx;
13463 0 : nsGlobalWindow* sourceWin = nsGlobalWindow::Cast(sourceWindow);
13464 0 : JSAutoCompartment ac(cx, sourceWin->GetGlobalJSObject());
13465 :
13466 : // Resolve the baseURI, which could be relative to the calling window.
13467 : //
13468 : // Note the algorithm to get the base URI should match the one
13469 : // used to actually kick off the load in nsWindowWatcher.cpp.
13470 0 : nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
13471 0 : nsIURI* baseURI = nullptr;
13472 0 : auto encoding = UTF_8_ENCODING; // default to utf-8
13473 0 : if (doc) {
13474 0 : baseURI = doc->GetDocBaseURI();
13475 0 : encoding = doc->GetDocumentCharacterSet();
13476 : }
13477 0 : nsCOMPtr<nsIURI> uri;
13478 0 : nsresult rv = NS_NewURI(getter_AddRefs(uri), nsDependentCString(aURL),
13479 0 : encoding, baseURI);
13480 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
13481 0 : return rv;
13482 : }
13483 :
13484 0 : if (NS_FAILED(nsContentUtils::GetSecurityManager()->
13485 : CheckLoadURIFromScript(cx, uri))) {
13486 0 : return NS_ERROR_FAILURE;
13487 : }
13488 :
13489 0 : return NS_OK;
13490 : }
13491 :
13492 : bool
13493 0 : nsGlobalWindow::IsPrivateBrowsing()
13494 : {
13495 0 : nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell());
13496 0 : return loadContext && loadContext->UsePrivateBrowsing();
13497 : }
13498 :
13499 : void
13500 8 : nsGlobalWindow::FlushPendingNotifications(FlushType aType)
13501 : {
13502 8 : if (mDoc) {
13503 8 : mDoc->FlushPendingNotifications(aType);
13504 : }
13505 8 : }
13506 :
13507 : void
13508 18 : nsGlobalWindow::EnsureSizeAndPositionUpToDate()
13509 : {
13510 18 : MOZ_ASSERT(IsOuterWindow());
13511 :
13512 : // If we're a subframe, make sure our size is up to date. It's OK that this
13513 : // crosses the content/chrome boundary, since chrome can have pending reflows
13514 : // too.
13515 18 : nsGlobalWindow *parent = nsGlobalWindow::Cast(GetPrivateParent());
13516 18 : if (parent) {
13517 0 : parent->FlushPendingNotifications(FlushType::Layout);
13518 : }
13519 18 : }
13520 :
13521 : already_AddRefed<nsISupports>
13522 0 : nsGlobalWindow::SaveWindowState()
13523 : {
13524 0 : NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
13525 :
13526 0 : if (!mContext || !GetWrapperPreserveColor()) {
13527 : // The window may be getting torn down; don't bother saving state.
13528 0 : return nullptr;
13529 : }
13530 :
13531 0 : nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
13532 0 : NS_ASSERTION(inner, "No inner window to save");
13533 :
13534 : // Don't do anything else to this inner window! After this point, all
13535 : // calls to SetTimeoutOrInterval will create entries in the timeout
13536 : // list that will only run after this window has come out of the bfcache.
13537 : // Also, while we're frozen, we won't dispatch online/offline events
13538 : // to the page.
13539 0 : inner->Freeze();
13540 :
13541 0 : nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
13542 :
13543 : #ifdef DEBUG_PAGE_CACHE
13544 : printf("saving window state, state = %p\n", (void*)state);
13545 : #endif
13546 :
13547 0 : return state.forget();
13548 : }
13549 :
13550 : nsresult
13551 0 : nsGlobalWindow::RestoreWindowState(nsISupports *aState)
13552 : {
13553 0 : NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
13554 :
13555 0 : if (!mContext || !GetWrapperPreserveColor()) {
13556 : // The window may be getting torn down; don't bother restoring state.
13557 0 : return NS_OK;
13558 : }
13559 :
13560 0 : nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
13561 0 : NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
13562 :
13563 : #ifdef DEBUG_PAGE_CACHE
13564 : printf("restoring window state, state = %p\n", (void*)holder);
13565 : #endif
13566 :
13567 : // And we're ready to go!
13568 0 : nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
13569 :
13570 : // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
13571 : // it easy to tell which link was last clicked when going back a page.
13572 0 : nsIContent* focusedNode = inner->GetFocusedNode();
13573 0 : if (IsLink(focusedNode)) {
13574 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
13575 0 : if (fm) {
13576 0 : nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
13577 0 : fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
13578 0 : nsIFocusManager::FLAG_SHOWRING);
13579 : }
13580 : }
13581 :
13582 0 : inner->Thaw();
13583 :
13584 0 : holder->DidRestoreWindow();
13585 :
13586 0 : return NS_OK;
13587 : }
13588 :
13589 : void
13590 0 : nsGlobalWindow::EnableDeviceSensor(uint32_t aType)
13591 : {
13592 0 : MOZ_ASSERT(IsInnerWindow());
13593 :
13594 0 : bool alreadyEnabled = false;
13595 0 : for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
13596 0 : if (mEnabledSensors[i] == aType) {
13597 0 : alreadyEnabled = true;
13598 0 : break;
13599 : }
13600 : }
13601 :
13602 0 : mEnabledSensors.AppendElement(aType);
13603 :
13604 0 : if (alreadyEnabled) {
13605 0 : return;
13606 : }
13607 :
13608 0 : nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
13609 0 : if (ac) {
13610 0 : ac->AddWindowListener(aType, this);
13611 : }
13612 : }
13613 :
13614 : void
13615 0 : nsGlobalWindow::DisableDeviceSensor(uint32_t aType)
13616 : {
13617 0 : MOZ_ASSERT(IsInnerWindow());
13618 :
13619 0 : int32_t doomedElement = -1;
13620 0 : int32_t listenerCount = 0;
13621 0 : for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
13622 0 : if (mEnabledSensors[i] == aType) {
13623 0 : doomedElement = i;
13624 0 : listenerCount++;
13625 : }
13626 : }
13627 :
13628 0 : if (doomedElement == -1) {
13629 0 : return;
13630 : }
13631 :
13632 0 : mEnabledSensors.RemoveElementAt(doomedElement);
13633 :
13634 0 : if (listenerCount > 1) {
13635 0 : return;
13636 : }
13637 :
13638 0 : nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
13639 0 : if (ac) {
13640 0 : ac->RemoveWindowListener(aType, this);
13641 : }
13642 : }
13643 :
13644 : #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
13645 : void
13646 : nsGlobalWindow::EnableOrientationChangeListener()
13647 : {
13648 : MOZ_ASSERT(IsInnerWindow());
13649 : if (!nsContentUtils::ShouldResistFingerprinting(mDocShell) &&
13650 : !mOrientationChangeObserver) {
13651 : mOrientationChangeObserver =
13652 : new WindowOrientationObserver(this);
13653 : }
13654 : }
13655 :
13656 : void
13657 : nsGlobalWindow::DisableOrientationChangeListener()
13658 : {
13659 : MOZ_ASSERT(IsInnerWindow());
13660 :
13661 : mOrientationChangeObserver = nullptr;
13662 : }
13663 : #endif
13664 :
13665 : void
13666 0 : nsGlobalWindow::SetHasGamepadEventListener(bool aHasGamepad/* = true*/)
13667 : {
13668 0 : MOZ_ASSERT(IsInnerWindow());
13669 0 : mHasGamepad = aHasGamepad;
13670 0 : if (aHasGamepad) {
13671 0 : EnableGamepadUpdates();
13672 : }
13673 0 : }
13674 :
13675 :
13676 : void
13677 52 : nsGlobalWindow::EventListenerAdded(nsIAtom* aType)
13678 : {
13679 104 : if (aType == nsGkAtoms::onvrdisplayactivate ||
13680 104 : aType == nsGkAtoms::onvrdisplayconnect ||
13681 104 : aType == nsGkAtoms::onvrdisplaydeactivate ||
13682 104 : aType == nsGkAtoms::onvrdisplaydisconnect ||
13683 52 : aType == nsGkAtoms::onvrdisplaypresentchange) {
13684 0 : NotifyVREventListenerAdded();
13685 : }
13686 :
13687 52 : if (aType == nsGkAtoms::onvrdisplayactivate) {
13688 0 : mHasVRDisplayActivateEvents = true;
13689 : }
13690 :
13691 104 : if (aType == nsGkAtoms::onbeforeunload &&
13692 52 : mTabChild &&
13693 0 : (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
13694 0 : MOZ_ASSERT(IsInnerWindow());
13695 0 : mBeforeUnloadListenerCount++;
13696 0 : MOZ_ASSERT(mBeforeUnloadListenerCount > 0);
13697 0 : mTabChild->BeforeUnloadAdded();
13698 : }
13699 :
13700 : // We need to initialize localStorage in order to receive notifications.
13701 52 : if (aType == nsGkAtoms::onstorage) {
13702 0 : ErrorResult rv;
13703 0 : GetLocalStorage(rv);
13704 0 : rv.SuppressException();
13705 : }
13706 52 : }
13707 :
13708 : void
13709 4 : nsGlobalWindow::EventListenerRemoved(nsIAtom* aType)
13710 : {
13711 8 : if (aType == nsGkAtoms::onbeforeunload &&
13712 4 : mTabChild &&
13713 0 : (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
13714 0 : MOZ_ASSERT(IsInnerWindow());
13715 0 : mBeforeUnloadListenerCount--;
13716 0 : MOZ_ASSERT(mBeforeUnloadListenerCount >= 0);
13717 0 : mTabChild->BeforeUnloadRemoved();
13718 : }
13719 4 : }
13720 :
13721 : void
13722 0 : nsGlobalWindow::NotifyVREventListenerAdded()
13723 : {
13724 0 : MOZ_ASSERT(IsInnerWindow());
13725 0 : mHasVREvents = true;
13726 0 : EnableVRUpdates();
13727 0 : }
13728 :
13729 : bool
13730 0 : nsGlobalWindow::HasUsedVR() const
13731 : {
13732 0 : MOZ_ASSERT(IsInnerWindow());
13733 :
13734 : // Returns true only if any WebVR API call or related event
13735 : // has been used
13736 0 : return mHasVREvents;
13737 : }
13738 :
13739 : bool
13740 0 : nsGlobalWindow::IsVRContentDetected() const
13741 : {
13742 0 : MOZ_ASSERT(IsInnerWindow());
13743 :
13744 : // Returns true only if the content will respond to
13745 : // the VRDisplayActivate event.
13746 0 : return mHasVRDisplayActivateEvents;
13747 : }
13748 :
13749 : bool
13750 0 : nsGlobalWindow::IsVRContentPresenting() const
13751 : {
13752 0 : for (const auto& display : mVRDisplays) {
13753 0 : if (display->IsAnyPresenting(gfx::kVRGroupAll)) {
13754 0 : return true;
13755 : }
13756 : }
13757 0 : return false;
13758 : }
13759 :
13760 : void
13761 0 : nsGlobalWindow::EnableTimeChangeNotifications()
13762 : {
13763 0 : mozilla::time::AddWindowListener(AsInner());
13764 0 : }
13765 :
13766 : void
13767 0 : nsGlobalWindow::DisableTimeChangeNotifications()
13768 : {
13769 0 : mozilla::time::RemoveWindowListener(AsInner());
13770 0 : }
13771 :
13772 : void
13773 0 : nsGlobalWindow::AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
13774 : {
13775 0 : aWindowSizes->mDOMOtherSize += aWindowSizes->mMallocSizeOf(this);
13776 :
13777 0 : if (IsInnerWindow()) {
13778 0 : EventListenerManager* elm = GetExistingListenerManager();
13779 0 : if (elm) {
13780 0 : aWindowSizes->mDOMOtherSize +=
13781 0 : elm->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
13782 0 : aWindowSizes->mDOMEventListenersCount +=
13783 0 : elm->ListenerCount();
13784 : }
13785 0 : if (mDoc) {
13786 : // Multiple global windows can share a document. So only measure the
13787 : // document if it (a) doesn't have a global window, or (b) it's the
13788 : // primary document for the window.
13789 0 : if (!mDoc->GetInnerWindow() ||
13790 0 : mDoc->GetInnerWindow() == AsInner()) {
13791 0 : mDoc->DocAddSizeOfIncludingThis(aWindowSizes);
13792 : }
13793 : }
13794 : }
13795 :
13796 0 : if (mNavigator) {
13797 0 : aWindowSizes->mDOMOtherSize +=
13798 0 : mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
13799 : }
13800 :
13801 0 : aWindowSizes->mDOMEventTargetsSize +=
13802 0 : mEventTargetObjects.ShallowSizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
13803 :
13804 0 : for (auto iter = mEventTargetObjects.ConstIter(); !iter.Done(); iter.Next()) {
13805 0 : DOMEventTargetHelper* et = iter.Get()->GetKey();
13806 0 : if (nsCOMPtr<nsISizeOfEventTarget> iSizeOf = do_QueryObject(et)) {
13807 0 : aWindowSizes->mDOMEventTargetsSize +=
13808 0 : iSizeOf->SizeOfEventTargetIncludingThis(aWindowSizes->mMallocSizeOf);
13809 : }
13810 0 : if (EventListenerManager* elm = et->GetExistingListenerManager()) {
13811 0 : aWindowSizes->mDOMEventListenersCount += elm->ListenerCount();
13812 : }
13813 0 : ++aWindowSizes->mDOMEventTargetsCount;
13814 : }
13815 0 : }
13816 :
13817 : void
13818 0 : nsGlobalWindow::AddGamepad(uint32_t aIndex, Gamepad* aGamepad)
13819 : {
13820 0 : MOZ_ASSERT(IsInnerWindow());
13821 : // Create the index we will present to content based on which indices are
13822 : // already taken, as required by the spec.
13823 : // https://w3c.github.io/gamepad/gamepad.html#widl-Gamepad-index
13824 0 : int index = 0;
13825 0 : while(mGamepadIndexSet.Contains(index)) {
13826 0 : ++index;
13827 : }
13828 0 : mGamepadIndexSet.Put(index);
13829 0 : aGamepad->SetIndex(index);
13830 0 : mGamepads.Put(aIndex, aGamepad);
13831 0 : }
13832 :
13833 : void
13834 0 : nsGlobalWindow::RemoveGamepad(uint32_t aIndex)
13835 : {
13836 0 : MOZ_ASSERT(IsInnerWindow());
13837 0 : RefPtr<Gamepad> gamepad;
13838 0 : if (!mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
13839 0 : return;
13840 : }
13841 : // Free up the index we were using so it can be reused
13842 0 : mGamepadIndexSet.Remove(gamepad->Index());
13843 0 : mGamepads.Remove(aIndex);
13844 : }
13845 :
13846 : void
13847 0 : nsGlobalWindow::GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads)
13848 : {
13849 0 : MOZ_ASSERT(IsInnerWindow());
13850 0 : aGamepads.Clear();
13851 :
13852 : // navigator.getGamepads() always returns an empty array when
13853 : // privacy.resistFingerprinting is true.
13854 0 : if (nsContentUtils::ShouldResistFingerprinting()) {
13855 0 : return;
13856 : }
13857 :
13858 : // mGamepads.Count() may not be sufficient, but it's not harmful.
13859 0 : aGamepads.SetCapacity(mGamepads.Count());
13860 0 : for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
13861 0 : Gamepad* gamepad = iter.UserData();
13862 0 : aGamepads.EnsureLengthAtLeast(gamepad->Index() + 1);
13863 0 : aGamepads[gamepad->Index()] = gamepad;
13864 : }
13865 : }
13866 :
13867 : already_AddRefed<Gamepad>
13868 0 : nsGlobalWindow::GetGamepad(uint32_t aIndex)
13869 : {
13870 0 : MOZ_ASSERT(IsInnerWindow());
13871 0 : RefPtr<Gamepad> gamepad;
13872 :
13873 0 : if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
13874 0 : return gamepad.forget();
13875 : }
13876 :
13877 0 : return nullptr;
13878 : }
13879 :
13880 : void
13881 0 : nsGlobalWindow::SetHasSeenGamepadInput(bool aHasSeen)
13882 : {
13883 0 : MOZ_ASSERT(IsInnerWindow());
13884 0 : mHasSeenGamepadInput = aHasSeen;
13885 0 : }
13886 :
13887 : bool
13888 0 : nsGlobalWindow::HasSeenGamepadInput()
13889 : {
13890 0 : MOZ_ASSERT(IsInnerWindow());
13891 0 : return mHasSeenGamepadInput;
13892 : }
13893 :
13894 : void
13895 0 : nsGlobalWindow::SyncGamepadState()
13896 : {
13897 0 : MOZ_ASSERT(IsInnerWindow());
13898 0 : if (mHasSeenGamepadInput) {
13899 0 : RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
13900 0 : for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
13901 0 : gamepadManager->SyncGamepadState(iter.Key(), iter.UserData());
13902 : }
13903 : }
13904 0 : }
13905 :
13906 : void
13907 0 : nsGlobalWindow::StopGamepadHaptics()
13908 : {
13909 0 : MOZ_ASSERT(IsInnerWindow());
13910 0 : if (mHasSeenGamepadInput) {
13911 0 : RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
13912 0 : gamepadManager->StopHaptics();
13913 : }
13914 0 : }
13915 :
13916 : bool
13917 0 : nsGlobalWindow::UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDevices)
13918 : {
13919 0 : FORWARD_TO_INNER(UpdateVRDisplays, (aDevices), false);
13920 :
13921 0 : VRDisplay::UpdateVRDisplays(mVRDisplays, AsInner());
13922 0 : aDevices = mVRDisplays;
13923 0 : return true;
13924 : }
13925 :
13926 : void
13927 0 : nsGlobalWindow::NotifyActiveVRDisplaysChanged()
13928 : {
13929 0 : MOZ_ASSERT(IsInnerWindow());
13930 :
13931 0 : if (mNavigator) {
13932 0 : mNavigator->NotifyActiveVRDisplaysChanged();
13933 : }
13934 0 : }
13935 :
13936 : uint32_t
13937 4 : nsGlobalWindow::GetAutoActivateVRDisplayID()
13938 : {
13939 4 : MOZ_ASSERT(IsOuterWindow());
13940 4 : uint32_t retVal = mAutoActivateVRDisplayID;
13941 4 : mAutoActivateVRDisplayID = 0;
13942 4 : return retVal;
13943 : }
13944 :
13945 : void
13946 0 : nsGlobalWindow::SetAutoActivateVRDisplayID(uint32_t aAutoActivateVRDisplayID)
13947 : {
13948 0 : MOZ_ASSERT(IsOuterWindow());
13949 0 : mAutoActivateVRDisplayID = aAutoActivateVRDisplayID;
13950 0 : }
13951 :
13952 : void
13953 0 : nsGlobalWindow::DispatchVRDisplayActivate(uint32_t aDisplayID,
13954 : mozilla::dom::VRDisplayEventReason aReason)
13955 : {
13956 : // Search for the display identified with aDisplayID and fire the
13957 : // event if found.
13958 0 : for (const auto& display : mVRDisplays) {
13959 0 : if (display->DisplayId() == aDisplayID) {
13960 0 : if (aReason != VRDisplayEventReason::Navigation &&
13961 0 : display->IsAnyPresenting(gfx::kVRGroupContent)) {
13962 : // We only want to trigger this event if nobody is presenting to the
13963 : // display already or when a page is loaded by navigating away
13964 : // from a page with an active VR Presentation.
13965 0 : continue;
13966 : }
13967 :
13968 0 : VRDisplayEventInit init;
13969 0 : init.mBubbles = false;
13970 0 : init.mCancelable = false;
13971 0 : init.mDisplay = display;
13972 0 : init.mReason.Construct(aReason);
13973 :
13974 : RefPtr<VRDisplayEvent> event =
13975 0 : VRDisplayEvent::Constructor(this,
13976 0 : NS_LITERAL_STRING("vrdisplayactivate"),
13977 0 : init);
13978 : // vrdisplayactivate is a trusted event, allowing VRDisplay.requestPresent
13979 : // to be used in response to link traversal, user request (chrome UX), and
13980 : // HMD mounting detection sensors.
13981 0 : event->SetTrusted(true);
13982 : bool defaultActionEnabled;
13983 : // VRDisplay.requestPresent normally requires a user gesture; however, an
13984 : // exception is made to allow it to be called in response to vrdisplayactivate
13985 : // during VR link traversal.
13986 0 : display->StartHandlingVRNavigationEvent();
13987 0 : Unused << DispatchEvent(event, &defaultActionEnabled);
13988 0 : display->StopHandlingVRNavigationEvent();
13989 : // Once we dispatch the event, we must not access any members as an event
13990 : // listener can do anything, including closing windows.
13991 0 : return;
13992 : }
13993 : }
13994 : }
13995 :
13996 : void
13997 0 : nsGlobalWindow::DispatchVRDisplayDeactivate(uint32_t aDisplayID,
13998 : mozilla::dom::VRDisplayEventReason aReason)
13999 : {
14000 : // Search for the display identified with aDisplayID and fire the
14001 : // event if found.
14002 0 : for (const auto& display : mVRDisplays) {
14003 0 : if (display->DisplayId() == aDisplayID && display->IsPresenting()) {
14004 : // We only want to trigger this event to content that is presenting to
14005 : // the display already.
14006 :
14007 0 : VRDisplayEventInit init;
14008 0 : init.mBubbles = false;
14009 0 : init.mCancelable = false;
14010 0 : init.mDisplay = display;
14011 0 : init.mReason.Construct(aReason);
14012 :
14013 : RefPtr<VRDisplayEvent> event =
14014 0 : VRDisplayEvent::Constructor(this,
14015 0 : NS_LITERAL_STRING("vrdisplaydeactivate"),
14016 0 : init);
14017 0 : event->SetTrusted(true);
14018 : bool defaultActionEnabled;
14019 0 : Unused << DispatchEvent(event, &defaultActionEnabled);
14020 : // Once we dispatch the event, we must not access any members as an event
14021 : // listener can do anything, including closing windows.
14022 0 : return;
14023 : }
14024 : }
14025 : }
14026 :
14027 : void
14028 0 : nsGlobalWindow::DispatchVRDisplayConnect(uint32_t aDisplayID)
14029 : {
14030 : // Search for the display identified with aDisplayID and fire the
14031 : // event if found.
14032 0 : for (const auto& display : mVRDisplays) {
14033 0 : if (display->DisplayId() == aDisplayID) {
14034 : // Fire event even if not presenting to the display.
14035 0 : VRDisplayEventInit init;
14036 0 : init.mBubbles = false;
14037 0 : init.mCancelable = false;
14038 0 : init.mDisplay = display;
14039 : // VRDisplayEvent.reason is not set for vrdisplayconnect
14040 :
14041 : RefPtr<VRDisplayEvent> event =
14042 0 : VRDisplayEvent::Constructor(this,
14043 0 : NS_LITERAL_STRING("vrdisplayconnect"),
14044 0 : init);
14045 0 : event->SetTrusted(true);
14046 : bool defaultActionEnabled;
14047 0 : Unused << DispatchEvent(event, &defaultActionEnabled);
14048 : // Once we dispatch the event, we must not access any members as an event
14049 : // listener can do anything, including closing windows.
14050 0 : return;
14051 : }
14052 : }
14053 : }
14054 :
14055 : void
14056 0 : nsGlobalWindow::DispatchVRDisplayDisconnect(uint32_t aDisplayID)
14057 : {
14058 : // Search for the display identified with aDisplayID and fire the
14059 : // event if found.
14060 0 : for (const auto& display : mVRDisplays) {
14061 0 : if (display->DisplayId() == aDisplayID) {
14062 : // Fire event even if not presenting to the display.
14063 0 : VRDisplayEventInit init;
14064 0 : init.mBubbles = false;
14065 0 : init.mCancelable = false;
14066 0 : init.mDisplay = display;
14067 : // VRDisplayEvent.reason is not set for vrdisplaydisconnect
14068 :
14069 : RefPtr<VRDisplayEvent> event =
14070 0 : VRDisplayEvent::Constructor(this,
14071 0 : NS_LITERAL_STRING("vrdisplaydisconnect"),
14072 0 : init);
14073 0 : event->SetTrusted(true);
14074 : bool defaultActionEnabled;
14075 0 : Unused << DispatchEvent(event, &defaultActionEnabled);
14076 : // Once we dispatch the event, we must not access any members as an event
14077 : // listener can do anything, including closing windows.
14078 0 : return;
14079 : }
14080 : }
14081 : }
14082 :
14083 : void
14084 0 : nsGlobalWindow::DispatchVRDisplayPresentChange(uint32_t aDisplayID)
14085 : {
14086 : // Search for the display identified with aDisplayID and fire the
14087 : // event if found.
14088 0 : for (const auto& display : mVRDisplays) {
14089 0 : if (display->DisplayId() == aDisplayID) {
14090 : // Fire event even if not presenting to the display.
14091 0 : VRDisplayEventInit init;
14092 0 : init.mBubbles = false;
14093 0 : init.mCancelable = false;
14094 0 : init.mDisplay = display;
14095 : // VRDisplayEvent.reason is not set for vrdisplaypresentchange
14096 : RefPtr<VRDisplayEvent> event =
14097 0 : VRDisplayEvent::Constructor(this,
14098 0 : NS_LITERAL_STRING("vrdisplaypresentchange"),
14099 0 : init);
14100 0 : event->SetTrusted(true);
14101 : bool defaultActionEnabled;
14102 0 : Unused << DispatchEvent(event, &defaultActionEnabled);
14103 : // Once we dispatch the event, we must not access any members as an event
14104 : // listener can do anything, including closing windows.
14105 0 : return;
14106 : }
14107 : }
14108 : }
14109 :
14110 : // nsGlobalChromeWindow implementation
14111 :
14112 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
14113 :
14114 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
14115 : nsGlobalWindow)
14116 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserDOMWindow)
14117 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
14118 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGroupMessageManagers)
14119 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerForInitialContentBrowser)
14120 1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
14121 :
14122 :
14123 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow,
14124 : nsGlobalWindow)
14125 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserDOMWindow)
14126 0 : if (tmp->mMessageManager) {
14127 : static_cast<nsFrameMessageManager*>(
14128 0 : tmp->mMessageManager.get())->Disconnect();
14129 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
14130 : }
14131 0 : tmp->DisconnectAndClearGroupMessageManagers();
14132 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mGroupMessageManagers)
14133 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenerForInitialContentBrowser)
14134 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
14135 :
14136 : // QueryInterface implementation for nsGlobalChromeWindow
14137 12275 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
14138 12262 : NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
14139 12235 : NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
14140 :
14141 16881 : NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
14142 16677 : NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
14143 :
14144 : /* static */ already_AddRefed<nsGlobalChromeWindow>
14145 7 : nsGlobalChromeWindow::Create(nsGlobalWindow *aOuterWindow)
14146 : {
14147 14 : RefPtr<nsGlobalChromeWindow> window = new nsGlobalChromeWindow(aOuterWindow);
14148 7 : window->InitWasOffline();
14149 14 : return window.forget();
14150 : }
14151 :
14152 : NS_IMETHODIMP
14153 0 : nsGlobalChromeWindow::GetWindowState(uint16_t* aWindowState)
14154 : {
14155 0 : FORWARD_TO_INNER_CHROME(GetWindowState, (aWindowState), NS_ERROR_UNEXPECTED);
14156 :
14157 0 : *aWindowState = WindowState();
14158 0 : return NS_OK;
14159 : }
14160 :
14161 : uint16_t
14162 4 : nsGlobalWindow::WindowState()
14163 : {
14164 4 : MOZ_ASSERT(IsInnerWindow());
14165 8 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
14166 :
14167 4 : int32_t mode = widget ? widget->SizeMode() : 0;
14168 :
14169 4 : switch (mode) {
14170 : case nsSizeMode_Minimized:
14171 0 : return nsIDOMChromeWindow::STATE_MINIMIZED;
14172 : case nsSizeMode_Maximized:
14173 3 : return nsIDOMChromeWindow::STATE_MAXIMIZED;
14174 : case nsSizeMode_Fullscreen:
14175 0 : return nsIDOMChromeWindow::STATE_FULLSCREEN;
14176 : case nsSizeMode_Normal:
14177 1 : return nsIDOMChromeWindow::STATE_NORMAL;
14178 : default:
14179 0 : NS_WARNING("Illegal window state for this chrome window");
14180 0 : break;
14181 : }
14182 :
14183 0 : return nsIDOMChromeWindow::STATE_NORMAL;
14184 : }
14185 :
14186 : bool
14187 3 : nsGlobalWindow::IsFullyOccluded()
14188 : {
14189 3 : MOZ_ASSERT(IsInnerWindow());
14190 :
14191 6 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
14192 6 : return widget && widget->IsFullyOccluded();
14193 : }
14194 :
14195 : NS_IMETHODIMP
14196 0 : nsGlobalChromeWindow::Maximize()
14197 : {
14198 0 : FORWARD_TO_INNER_CHROME(Maximize, (), NS_ERROR_UNEXPECTED);
14199 :
14200 0 : nsGlobalWindow::Maximize();
14201 0 : return NS_OK;
14202 : }
14203 :
14204 : void
14205 0 : nsGlobalWindow::Maximize()
14206 : {
14207 0 : MOZ_ASSERT(IsInnerWindow());
14208 :
14209 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
14210 :
14211 0 : if (widget) {
14212 0 : widget->SetSizeMode(nsSizeMode_Maximized);
14213 : }
14214 0 : }
14215 :
14216 : NS_IMETHODIMP
14217 0 : nsGlobalChromeWindow::Minimize()
14218 : {
14219 0 : FORWARD_TO_INNER_CHROME(Minimize, (), NS_ERROR_UNEXPECTED);
14220 :
14221 0 : nsGlobalWindow::Minimize();
14222 0 : return NS_OK;
14223 : }
14224 :
14225 : void
14226 0 : nsGlobalWindow::Minimize()
14227 : {
14228 0 : MOZ_ASSERT(IsInnerWindow());
14229 :
14230 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
14231 :
14232 0 : if (widget) {
14233 0 : widget->SetSizeMode(nsSizeMode_Minimized);
14234 : }
14235 0 : }
14236 :
14237 : NS_IMETHODIMP
14238 0 : nsGlobalChromeWindow::Restore()
14239 : {
14240 0 : FORWARD_TO_INNER_CHROME(Restore, (), NS_ERROR_UNEXPECTED);
14241 :
14242 0 : nsGlobalWindow::Restore();
14243 0 : return NS_OK;
14244 : }
14245 :
14246 : void
14247 0 : nsGlobalWindow::Restore()
14248 : {
14249 0 : MOZ_ASSERT(IsInnerWindow());
14250 :
14251 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
14252 :
14253 0 : if (widget) {
14254 0 : widget->SetSizeMode(nsSizeMode_Normal);
14255 : }
14256 0 : }
14257 :
14258 : NS_IMETHODIMP
14259 0 : nsGlobalChromeWindow::GetAttention()
14260 : {
14261 0 : FORWARD_TO_INNER_CHROME(GetAttention, (), NS_ERROR_UNEXPECTED);
14262 :
14263 0 : ErrorResult rv;
14264 0 : GetAttention(rv);
14265 0 : return rv.StealNSResult();
14266 : }
14267 :
14268 : void
14269 0 : nsGlobalWindow::GetAttention(ErrorResult& aResult)
14270 : {
14271 0 : MOZ_ASSERT(IsInnerWindow());
14272 0 : return GetAttentionWithCycleCount(-1, aResult);
14273 : }
14274 :
14275 : NS_IMETHODIMP
14276 0 : nsGlobalChromeWindow::GetAttentionWithCycleCount(int32_t aCycleCount)
14277 : {
14278 0 : FORWARD_TO_INNER_CHROME(GetAttentionWithCycleCount, (aCycleCount), NS_ERROR_UNEXPECTED);
14279 :
14280 0 : ErrorResult rv;
14281 0 : GetAttentionWithCycleCount(aCycleCount, rv);
14282 0 : return rv.StealNSResult();
14283 : }
14284 :
14285 : void
14286 0 : nsGlobalWindow::GetAttentionWithCycleCount(int32_t aCycleCount,
14287 : ErrorResult& aError)
14288 : {
14289 0 : MOZ_ASSERT(IsInnerWindow());
14290 :
14291 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
14292 :
14293 0 : if (widget) {
14294 0 : aError = widget->GetAttention(aCycleCount);
14295 : }
14296 0 : }
14297 :
14298 : NS_IMETHODIMP
14299 0 : nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent, nsIDOMElement* aPanel)
14300 : {
14301 0 : FORWARD_TO_INNER_CHROME(BeginWindowMove, (aMouseDownEvent, aPanel), NS_ERROR_UNEXPECTED);
14302 :
14303 0 : NS_ENSURE_TRUE(aMouseDownEvent, NS_ERROR_FAILURE);
14304 0 : Event* mouseDownEvent = aMouseDownEvent->InternalDOMEvent();
14305 0 : NS_ENSURE_TRUE(mouseDownEvent, NS_ERROR_FAILURE);
14306 :
14307 0 : nsCOMPtr<Element> panel = do_QueryInterface(aPanel);
14308 0 : NS_ENSURE_TRUE(panel || !aPanel, NS_ERROR_FAILURE);
14309 :
14310 0 : ErrorResult rv;
14311 0 : BeginWindowMove(*mouseDownEvent, panel, rv);
14312 0 : return rv.StealNSResult();
14313 : }
14314 :
14315 : void
14316 0 : nsGlobalWindow::BeginWindowMove(Event& aMouseDownEvent, Element* aPanel,
14317 : ErrorResult& aError)
14318 : {
14319 0 : MOZ_ASSERT(IsInnerWindow());
14320 :
14321 0 : nsCOMPtr<nsIWidget> widget;
14322 :
14323 : // if a panel was supplied, use its widget instead.
14324 : #ifdef MOZ_XUL
14325 0 : if (aPanel) {
14326 0 : nsIFrame* frame = aPanel->GetPrimaryFrame();
14327 0 : if (!frame || !frame->IsMenuPopupFrame()) {
14328 0 : return;
14329 : }
14330 :
14331 0 : widget = (static_cast<nsMenuPopupFrame*>(frame))->GetWidget();
14332 : }
14333 : else {
14334 : #endif
14335 0 : widget = GetMainWidget();
14336 : #ifdef MOZ_XUL
14337 : }
14338 : #endif
14339 :
14340 0 : if (!widget) {
14341 0 : return;
14342 : }
14343 :
14344 : WidgetMouseEvent* mouseEvent =
14345 0 : aMouseDownEvent.WidgetEventPtr()->AsMouseEvent();
14346 0 : if (!mouseEvent || mouseEvent->mClass != eMouseEventClass) {
14347 0 : aError.Throw(NS_ERROR_FAILURE);
14348 0 : return;
14349 : }
14350 :
14351 0 : aError = widget->BeginMoveDrag(mouseEvent);
14352 : }
14353 :
14354 : already_AddRefed<nsWindowRoot>
14355 0 : nsGlobalWindow::GetWindowRootOuter()
14356 : {
14357 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14358 0 : nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
14359 0 : return root.forget().downcast<nsWindowRoot>();
14360 : }
14361 :
14362 : already_AddRefed<nsWindowRoot>
14363 0 : nsGlobalWindow::GetWindowRoot(mozilla::ErrorResult& aError)
14364 : {
14365 0 : FORWARD_TO_OUTER_OR_THROW(GetWindowRootOuter, (), aError, nullptr);
14366 : }
14367 :
14368 : //Note: This call will lock the cursor, it will not change as it moves.
14369 : //To unlock, the cursor must be set back to CURSOR_AUTO.
14370 : NS_IMETHODIMP
14371 0 : nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
14372 : {
14373 0 : FORWARD_TO_INNER_CHROME(SetCursor, (aCursor), NS_ERROR_UNEXPECTED);
14374 :
14375 0 : ErrorResult rv;
14376 0 : SetCursor(aCursor, rv);
14377 0 : return rv.StealNSResult();
14378 : }
14379 :
14380 : void
14381 0 : nsGlobalWindow::SetCursorOuter(const nsAString& aCursor, ErrorResult& aError)
14382 : {
14383 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14384 :
14385 : int32_t cursor;
14386 :
14387 0 : if (aCursor.EqualsLiteral("auto"))
14388 0 : cursor = NS_STYLE_CURSOR_AUTO;
14389 : else {
14390 0 : nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
14391 0 : if (!nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
14392 0 : return;
14393 : }
14394 : }
14395 :
14396 0 : RefPtr<nsPresContext> presContext;
14397 0 : if (mDocShell) {
14398 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
14399 : }
14400 :
14401 0 : if (presContext) {
14402 : // Need root widget.
14403 0 : nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
14404 0 : if (!presShell) {
14405 0 : aError.Throw(NS_ERROR_FAILURE);
14406 0 : return;
14407 : }
14408 :
14409 0 : nsViewManager* vm = presShell->GetViewManager();
14410 0 : if (!vm) {
14411 0 : aError.Throw(NS_ERROR_FAILURE);
14412 0 : return;
14413 : }
14414 :
14415 0 : nsView* rootView = vm->GetRootView();
14416 0 : if (!rootView) {
14417 0 : aError.Throw(NS_ERROR_FAILURE);
14418 0 : return;
14419 : }
14420 :
14421 0 : nsIWidget* widget = rootView->GetNearestWidget(nullptr);
14422 0 : if (!widget) {
14423 0 : aError.Throw(NS_ERROR_FAILURE);
14424 0 : return;
14425 : }
14426 :
14427 : // Call esm and set cursor.
14428 0 : aError = presContext->EventStateManager()->SetCursor(cursor, nullptr,
14429 : false, 0.0f, 0.0f,
14430 0 : widget, true);
14431 : }
14432 : }
14433 :
14434 : void
14435 0 : nsGlobalWindow::SetCursor(const nsAString& aCursor, ErrorResult& aError)
14436 : {
14437 0 : FORWARD_TO_OUTER_OR_THROW(SetCursorOuter, (aCursor, aError), aError, );
14438 : }
14439 :
14440 : NS_IMETHODIMP
14441 2 : nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
14442 : {
14443 2 : FORWARD_TO_INNER_CHROME(GetBrowserDOMWindow, (aBrowserWindow), NS_ERROR_UNEXPECTED);
14444 :
14445 2 : ErrorResult rv;
14446 1 : NS_IF_ADDREF(*aBrowserWindow = GetBrowserDOMWindow(rv));
14447 1 : return rv.StealNSResult();
14448 : }
14449 :
14450 : nsIBrowserDOMWindow*
14451 1 : nsGlobalWindow::GetBrowserDOMWindowOuter()
14452 : {
14453 1 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14454 1 : MOZ_ASSERT(IsChromeWindow());
14455 1 : return static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow;
14456 : }
14457 :
14458 : nsIBrowserDOMWindow*
14459 1 : nsGlobalWindow::GetBrowserDOMWindow(ErrorResult& aError)
14460 : {
14461 1 : FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindowOuter, (), aError, nullptr);
14462 : }
14463 :
14464 : NS_IMETHODIMP
14465 0 : nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
14466 : {
14467 0 : FORWARD_TO_INNER_CHROME(SetBrowserDOMWindow, (aBrowserWindow), NS_ERROR_UNEXPECTED);
14468 :
14469 0 : ErrorResult rv;
14470 0 : SetBrowserDOMWindow(aBrowserWindow, rv);
14471 0 : return rv.StealNSResult();
14472 : }
14473 :
14474 : void
14475 1 : nsGlobalWindow::SetBrowserDOMWindowOuter(nsIBrowserDOMWindow* aBrowserWindow)
14476 : {
14477 1 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14478 1 : MOZ_ASSERT(IsChromeWindow());
14479 1 : static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow = aBrowserWindow;
14480 1 : }
14481 :
14482 : void
14483 1 : nsGlobalWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow,
14484 : ErrorResult& aError)
14485 : {
14486 1 : FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindowOuter, (aBrowserWindow), aError, );
14487 : }
14488 :
14489 : NS_IMETHODIMP
14490 0 : nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement* aDefaultButton)
14491 : {
14492 0 : FORWARD_TO_INNER_CHROME(NotifyDefaultButtonLoaded,
14493 : (aDefaultButton), NS_ERROR_UNEXPECTED);
14494 :
14495 0 : nsCOMPtr<Element> defaultButton = do_QueryInterface(aDefaultButton);
14496 0 : NS_ENSURE_ARG(defaultButton);
14497 :
14498 0 : ErrorResult rv;
14499 0 : NotifyDefaultButtonLoaded(*defaultButton, rv);
14500 0 : return rv.StealNSResult();
14501 : }
14502 :
14503 : void
14504 0 : nsGlobalWindow::NotifyDefaultButtonLoaded(Element& aDefaultButton,
14505 : ErrorResult& aError)
14506 : {
14507 0 : MOZ_ASSERT(IsInnerWindow());
14508 : #ifdef MOZ_XUL
14509 : // Don't snap to a disabled button.
14510 : nsCOMPtr<nsIDOMXULControlElement> xulControl =
14511 0 : do_QueryInterface(&aDefaultButton);
14512 0 : if (!xulControl) {
14513 0 : aError.Throw(NS_ERROR_FAILURE);
14514 0 : return;
14515 : }
14516 : bool disabled;
14517 0 : aError = xulControl->GetDisabled(&disabled);
14518 0 : if (aError.Failed() || disabled) {
14519 0 : return;
14520 : }
14521 :
14522 : // Get the button rect in screen coordinates.
14523 0 : nsIFrame *frame = aDefaultButton.GetPrimaryFrame();
14524 0 : if (!frame) {
14525 0 : aError.Throw(NS_ERROR_FAILURE);
14526 0 : return;
14527 : }
14528 : LayoutDeviceIntRect buttonRect =
14529 : LayoutDeviceIntRect::FromAppUnitsToNearest(
14530 0 : frame->GetScreenRectInAppUnits(),
14531 0 : frame->PresContext()->AppUnitsPerDevPixel());
14532 :
14533 : // Get the widget rect in screen coordinates.
14534 0 : nsIWidget *widget = GetNearestWidget();
14535 0 : if (!widget) {
14536 0 : aError.Throw(NS_ERROR_FAILURE);
14537 0 : return;
14538 : }
14539 0 : LayoutDeviceIntRect widgetRect = widget->GetScreenBounds();
14540 :
14541 : // Convert the buttonRect coordinates from screen to the widget.
14542 0 : buttonRect -= widgetRect.TopLeft();
14543 0 : nsresult rv = widget->OnDefaultButtonLoaded(buttonRect);
14544 0 : if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
14545 0 : aError.Throw(rv);
14546 : }
14547 : #else
14548 : aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
14549 : #endif
14550 : }
14551 :
14552 : NS_IMETHODIMP
14553 4 : nsGlobalChromeWindow::GetMessageManager(nsIMessageBroadcaster** aManager)
14554 : {
14555 4 : FORWARD_TO_INNER_CHROME(GetMessageManager, (aManager), NS_ERROR_UNEXPECTED);
14556 :
14557 4 : ErrorResult rv;
14558 2 : NS_IF_ADDREF(*aManager = GetMessageManager(rv));
14559 2 : return rv.StealNSResult();
14560 : }
14561 :
14562 : nsIMessageBroadcaster*
14563 29 : nsGlobalWindow::GetMessageManager(ErrorResult& aError)
14564 : {
14565 29 : MOZ_ASSERT(IsChromeWindow());
14566 29 : MOZ_RELEASE_ASSERT(IsInnerWindow());
14567 29 : nsGlobalChromeWindow* myself = static_cast<nsGlobalChromeWindow*>(this);
14568 29 : if (!myself->mMessageManager) {
14569 : nsCOMPtr<nsIMessageBroadcaster> globalMM =
14570 2 : do_GetService("@mozilla.org/globalmessagemanager;1");
14571 : myself->mMessageManager =
14572 1 : new nsFrameMessageManager(nullptr,
14573 1 : static_cast<nsFrameMessageManager*>(globalMM.get()),
14574 2 : MM_CHROME | MM_BROADCASTER);
14575 : }
14576 29 : return myself->mMessageManager;
14577 : }
14578 :
14579 : NS_IMETHODIMP
14580 4 : nsGlobalChromeWindow::GetGroupMessageManager(const nsAString& aGroup,
14581 : nsIMessageBroadcaster** aManager)
14582 : {
14583 4 : FORWARD_TO_INNER_CHROME(GetGroupMessageManager, (aGroup, aManager), NS_ERROR_UNEXPECTED);
14584 :
14585 4 : ErrorResult rv;
14586 2 : NS_IF_ADDREF(*aManager = GetGroupMessageManager(aGroup, rv));
14587 2 : return rv.StealNSResult();
14588 : }
14589 :
14590 : nsIMessageBroadcaster*
14591 7 : nsGlobalWindow::GetGroupMessageManager(const nsAString& aGroup,
14592 : ErrorResult& aError)
14593 : {
14594 7 : MOZ_ASSERT(IsChromeWindow());
14595 7 : MOZ_RELEASE_ASSERT(IsInnerWindow());
14596 :
14597 7 : nsGlobalChromeWindow* myself = static_cast<nsGlobalChromeWindow*>(this);
14598 : nsCOMPtr<nsIMessageBroadcaster> messageManager =
14599 14 : myself->mGroupMessageManagers.LookupForAdd(aGroup).OrInsert(
14600 1 : [this, &aError] () {
14601 : nsFrameMessageManager* parent =
14602 1 : static_cast<nsFrameMessageManager*>(GetMessageManager(aError));
14603 :
14604 : return new nsFrameMessageManager(nullptr,
14605 : parent,
14606 1 : MM_CHROME | MM_BROADCASTER);
14607 21 : });
14608 14 : return messageManager;
14609 : }
14610 :
14611 : nsresult
14612 0 : nsGlobalChromeWindow::SetOpenerForInitialContentBrowser(mozIDOMWindowProxy* aOpenerWindow)
14613 : {
14614 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14615 0 : MOZ_ASSERT(!mOpenerForInitialContentBrowser);
14616 0 : mOpenerForInitialContentBrowser = aOpenerWindow;
14617 0 : return NS_OK;
14618 : }
14619 :
14620 : nsresult
14621 2 : nsGlobalChromeWindow::TakeOpenerForInitialContentBrowser(mozIDOMWindowProxy** aOpenerWindow)
14622 : {
14623 2 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14624 : // Intentionally forget our own member
14625 2 : mOpenerForInitialContentBrowser.forget(aOpenerWindow);
14626 2 : return NS_OK;
14627 : }
14628 :
14629 : // nsGlobalModalWindow implementation
14630 :
14631 : // QueryInterface implementation for nsGlobalModalWindow
14632 0 : NS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow)
14633 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
14634 0 : NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
14635 :
14636 0 : NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
14637 0 : NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
14638 :
14639 :
14640 : void
14641 0 : nsGlobalWindow::GetDialogArgumentsOuter(JSContext* aCx,
14642 : JS::MutableHandle<JS::Value> aRetval,
14643 : nsIPrincipal& aSubjectPrincipal,
14644 : ErrorResult& aError)
14645 : {
14646 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14647 0 : MOZ_ASSERT(IsModalContentWindow(),
14648 : "This should only be called on modal windows!");
14649 :
14650 0 : if (!mDialogArguments) {
14651 0 : MOZ_ASSERT(mIsClosed, "This window should be closed!");
14652 0 : aRetval.setUndefined();
14653 0 : return;
14654 : }
14655 :
14656 : // This does an internal origin check, and returns undefined if the subject
14657 : // does not subsumes the origin of the arguments.
14658 0 : JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
14659 0 : JSAutoCompartment ac(aCx, wrapper);
14660 0 : mDialogArguments->Get(aCx, wrapper, &aSubjectPrincipal, aRetval, aError);
14661 : }
14662 :
14663 : void
14664 0 : nsGlobalWindow::GetDialogArguments(JSContext* aCx,
14665 : JS::MutableHandle<JS::Value> aRetval,
14666 : nsIPrincipal& aSubjectPrincipal,
14667 : ErrorResult& aError)
14668 : {
14669 0 : FORWARD_TO_OUTER_OR_THROW(GetDialogArgumentsOuter,
14670 : (aCx, aRetval, aSubjectPrincipal, aError),
14671 : aError, );
14672 : }
14673 :
14674 : /* static */ already_AddRefed<nsGlobalModalWindow>
14675 0 : nsGlobalModalWindow::Create(nsGlobalWindow *aOuterWindow)
14676 : {
14677 0 : RefPtr<nsGlobalModalWindow> window = new nsGlobalModalWindow(aOuterWindow);
14678 0 : window->InitWasOffline();
14679 0 : return window.forget();
14680 : }
14681 :
14682 : NS_IMETHODIMP
14683 0 : nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments)
14684 : {
14685 0 : FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
14686 : NS_ERROR_NOT_INITIALIZED);
14687 :
14688 : // This does an internal origin check, and returns undefined if the subject
14689 : // does not subsumes the origin of the arguments.
14690 0 : return mDialogArguments->Get(nsContentUtils::SubjectPrincipal(), aArguments);
14691 : }
14692 :
14693 : /* static */ already_AddRefed<nsGlobalWindow>
14694 5 : nsGlobalWindow::Create(nsGlobalWindow *aOuterWindow)
14695 : {
14696 10 : RefPtr<nsGlobalWindow> window = new nsGlobalWindow(aOuterWindow);
14697 5 : window->InitWasOffline();
14698 10 : return window.forget();
14699 : }
14700 :
14701 : void
14702 12 : nsGlobalWindow::InitWasOffline()
14703 : {
14704 12 : mWasOffline = NS_IsOffline();
14705 12 : }
14706 :
14707 : void
14708 0 : nsGlobalWindow::GetReturnValueOuter(JSContext* aCx,
14709 : JS::MutableHandle<JS::Value> aReturnValue,
14710 : nsIPrincipal& aSubjectPrincipal,
14711 : ErrorResult& aError)
14712 : {
14713 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14714 0 : MOZ_ASSERT(IsModalContentWindow(),
14715 : "This should only be called on modal windows!");
14716 :
14717 0 : if (mReturnValue) {
14718 0 : JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
14719 0 : JSAutoCompartment ac(aCx, wrapper);
14720 0 : mReturnValue->Get(aCx, wrapper, &aSubjectPrincipal, aReturnValue, aError);
14721 : } else {
14722 0 : aReturnValue.setUndefined();
14723 : }
14724 0 : }
14725 :
14726 : void
14727 0 : nsGlobalWindow::GetReturnValue(JSContext* aCx,
14728 : JS::MutableHandle<JS::Value> aReturnValue,
14729 : nsIPrincipal& aSubjectPrincipal,
14730 : ErrorResult& aError)
14731 : {
14732 0 : FORWARD_TO_OUTER_OR_THROW(GetReturnValueOuter,
14733 : (aCx, aReturnValue, aSubjectPrincipal, aError),
14734 : aError, );
14735 : }
14736 :
14737 : NS_IMETHODIMP
14738 0 : nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
14739 : {
14740 0 : FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
14741 :
14742 0 : if (!mReturnValue) {
14743 0 : nsCOMPtr<nsIVariant> variant = CreateVoidVariant();
14744 0 : variant.forget(aRetVal);
14745 0 : return NS_OK;
14746 : }
14747 0 : return mReturnValue->Get(nsContentUtils::SubjectPrincipal(), aRetVal);
14748 : }
14749 :
14750 : void
14751 0 : nsGlobalWindow::SetReturnValueOuter(JSContext* aCx,
14752 : JS::Handle<JS::Value> aReturnValue,
14753 : nsIPrincipal& aSubjectPrincipal,
14754 : ErrorResult& aError)
14755 : {
14756 0 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14757 0 : MOZ_ASSERT(IsModalContentWindow(),
14758 : "This should only be called on modal windows!");
14759 :
14760 0 : nsCOMPtr<nsIVariant> returnValue;
14761 0 : aError =
14762 0 : nsContentUtils::XPConnect()->JSToVariant(aCx, aReturnValue,
14763 0 : getter_AddRefs(returnValue));
14764 0 : if (!aError.Failed()) {
14765 0 : mReturnValue = new DialogValueHolder(&aSubjectPrincipal, returnValue);
14766 : }
14767 0 : }
14768 :
14769 : void
14770 0 : nsGlobalWindow::SetReturnValue(JSContext* aCx,
14771 : JS::Handle<JS::Value> aReturnValue,
14772 : nsIPrincipal& aSubjectPrincipal,
14773 : ErrorResult& aError)
14774 : {
14775 0 : FORWARD_TO_OUTER_OR_THROW(SetReturnValueOuter,
14776 : (aCx, aReturnValue, aSubjectPrincipal, aError),
14777 : aError, );
14778 : }
14779 :
14780 : NS_IMETHODIMP
14781 0 : nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
14782 : {
14783 0 : FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
14784 :
14785 0 : mReturnValue = new DialogValueHolder(nsContentUtils::SubjectPrincipal(),
14786 0 : aRetVal);
14787 0 : return NS_OK;
14788 : }
14789 :
14790 : /* static */
14791 : bool
14792 7 : nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
14793 : {
14794 7 : return xpc::WindowOrNull(aGlobal)->IsModalContentWindow();
14795 : }
14796 :
14797 : #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
14798 : int16_t
14799 : nsGlobalWindow::Orientation(CallerType aCallerType) const
14800 : {
14801 : return nsContentUtils::ResistFingerprinting(aCallerType) ?
14802 : 0 : WindowOrientationObserver::OrientationAngle();
14803 : }
14804 : #endif
14805 :
14806 : Console*
14807 1 : nsGlobalWindow::GetConsole(ErrorResult& aRv)
14808 : {
14809 1 : MOZ_RELEASE_ASSERT(IsInnerWindow());
14810 :
14811 1 : if (!mConsole) {
14812 1 : mConsole = Console::Create(AsInner(), aRv);
14813 1 : if (NS_WARN_IF(aRv.Failed())) {
14814 0 : return nullptr;
14815 : }
14816 : }
14817 :
14818 1 : return mConsole;
14819 : }
14820 :
14821 : bool
14822 0 : nsGlobalWindow::IsSecureContext() const
14823 : {
14824 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
14825 :
14826 0 : return JS_GetIsSecureContext(js::GetObjectCompartment(GetWrapperPreserveColor()));
14827 : }
14828 :
14829 : bool
14830 0 : nsGlobalWindow::IsSecureContextIfOpenerIgnored() const
14831 : {
14832 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
14833 :
14834 0 : return mIsSecureContextIfOpenerIgnored;
14835 : }
14836 :
14837 : already_AddRefed<External>
14838 0 : nsGlobalWindow::GetExternal(ErrorResult& aRv)
14839 : {
14840 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
14841 :
14842 : #ifdef HAVE_SIDEBAR
14843 0 : if (!mExternal) {
14844 0 : AutoJSContext cx;
14845 0 : JS::Rooted<JSObject*> jsImplObj(cx);
14846 0 : ConstructJSImplementation("@mozilla.org/sidebar;1", this, &jsImplObj, aRv);
14847 0 : if (aRv.Failed()) {
14848 0 : return nullptr;
14849 : }
14850 0 : mExternal = new External(jsImplObj, this);
14851 : }
14852 :
14853 0 : RefPtr<External> external = static_cast<External*>(mExternal.get());
14854 0 : return external.forget();
14855 : #else
14856 : aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
14857 : return nullptr;
14858 : #endif
14859 : }
14860 :
14861 : void
14862 0 : nsGlobalWindow::GetSidebar(OwningExternalOrWindowProxy& aResult,
14863 : ErrorResult& aRv)
14864 : {
14865 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
14866 :
14867 : #ifdef HAVE_SIDEBAR
14868 : // First check for a named frame named "sidebar"
14869 0 : nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetChildWindow(NS_LITERAL_STRING("sidebar"));
14870 0 : if (domWindow) {
14871 0 : aResult.SetAsWindowProxy() = domWindow.forget();
14872 0 : return;
14873 : }
14874 :
14875 0 : RefPtr<External> external = GetExternal(aRv);
14876 0 : if (external) {
14877 0 : aResult.SetAsExternal() = external;
14878 : }
14879 : #else
14880 : aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
14881 : #endif
14882 : }
14883 :
14884 : void
14885 8 : nsGlobalWindow::ClearDocumentDependentSlots(JSContext* aCx)
14886 : {
14887 8 : MOZ_ASSERT(IsInnerWindow());
14888 :
14889 : // If JSAPI OOMs here, there is basically nothing we can do to recover safely.
14890 16 : if (!WindowBinding::ClearCachedDocumentValue(aCx, this) ||
14891 8 : !WindowBinding::ClearCachedPerformanceValue(aCx, this)) {
14892 0 : MOZ_CRASH("Unhandlable OOM while clearing document dependent slots.");
14893 : }
14894 8 : }
14895 :
14896 : /* static */
14897 : JSObject*
14898 7 : nsGlobalWindow::CreateNamedPropertiesObject(JSContext *aCx,
14899 : JS::Handle<JSObject*> aProto)
14900 : {
14901 7 : return WindowNamedPropertiesHandler::Create(aCx, aProto);
14902 : }
14903 :
14904 : bool
14905 1 : nsGlobalWindow::GetIsPrerendered()
14906 : {
14907 1 : nsIDocShell* docShell = GetDocShell();
14908 1 : return docShell && docShell->GetIsPrerendered();
14909 : }
14910 :
14911 : void
14912 0 : nsPIDOMWindowOuter::SetLargeAllocStatus(LargeAllocStatus aStatus)
14913 : {
14914 0 : MOZ_ASSERT(mLargeAllocStatus == LargeAllocStatus::NONE);
14915 0 : mLargeAllocStatus = aStatus;
14916 0 : }
14917 :
14918 : bool
14919 0 : nsPIDOMWindowOuter::IsTopLevelWindow()
14920 : {
14921 0 : return nsGlobalWindow::Cast(this)->IsTopLevelWindow();
14922 : }
14923 :
14924 : bool
14925 0 : nsPIDOMWindowOuter::HadOriginalOpener() const
14926 : {
14927 0 : return nsGlobalWindow::Cast(this)->HadOriginalOpener();
14928 : }
14929 :
14930 : void
14931 8 : nsGlobalWindow::ReportLargeAllocStatus()
14932 : {
14933 8 : MOZ_RELEASE_ASSERT(IsOuterWindow());
14934 :
14935 8 : uint32_t errorFlags = nsIScriptError::warningFlag;
14936 8 : const char* message = nullptr;
14937 :
14938 8 : switch (mLargeAllocStatus) {
14939 : case LargeAllocStatus::SUCCESS:
14940 : // Override the error flags such that the success message isn't reported
14941 : // as a warning.
14942 0 : errorFlags = nsIScriptError::infoFlag;
14943 0 : message = "LargeAllocationSuccess";
14944 0 : break;
14945 : case LargeAllocStatus::NON_WIN32:
14946 0 : errorFlags = nsIScriptError::infoFlag;
14947 0 : message = "LargeAllocationNonWin32";
14948 0 : break;
14949 : case LargeAllocStatus::NON_GET:
14950 0 : message = "LargeAllocationNonGetRequest";
14951 0 : break;
14952 : case LargeAllocStatus::NON_E10S:
14953 0 : message = "LargeAllocationNonE10S";
14954 0 : break;
14955 : case LargeAllocStatus::NOT_ONLY_TOPLEVEL_IN_TABGROUP:
14956 0 : message = "LargeAllocationNotOnlyToplevelInTabGroup";
14957 0 : break;
14958 : default: // LargeAllocStatus::NONE
14959 8 : return; // Don't report a message to the console
14960 : }
14961 :
14962 0 : nsContentUtils::ReportToConsole(errorFlags,
14963 0 : NS_LITERAL_CSTRING("DOM"),
14964 : mDoc,
14965 : nsContentUtils::eDOM_PROPERTIES,
14966 0 : message);
14967 : }
14968 :
14969 : #ifdef MOZ_B2G
14970 : void
14971 : nsGlobalWindow::EnableNetworkEvent(EventMessage aEventMessage)
14972 : {
14973 : MOZ_ASSERT(IsInnerWindow());
14974 :
14975 : nsCOMPtr<nsIPermissionManager> permMgr =
14976 : services::GetPermissionManager();
14977 : if (!permMgr) {
14978 : NS_ERROR("No PermissionManager available!");
14979 : return;
14980 : }
14981 :
14982 : uint32_t permission = nsIPermissionManager::DENY_ACTION;
14983 : permMgr->TestExactPermissionFromPrincipal(GetPrincipal(), "network-events",
14984 : &permission);
14985 :
14986 : if (permission != nsIPermissionManager::ALLOW_ACTION) {
14987 : return;
14988 : }
14989 :
14990 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
14991 : if (!os) {
14992 : NS_ERROR("ObserverService should be available!");
14993 : return;
14994 : }
14995 :
14996 : switch (aEventMessage) {
14997 : case eNetworkUpload:
14998 : if (!mNetworkUploadObserverEnabled) {
14999 : mNetworkUploadObserverEnabled = true;
15000 : os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC, false);
15001 : }
15002 : break;
15003 : case eNetworkDownload:
15004 : if (!mNetworkDownloadObserverEnabled) {
15005 : mNetworkDownloadObserverEnabled = true;
15006 : os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC, false);
15007 : }
15008 : break;
15009 : default:
15010 : break;
15011 : }
15012 : }
15013 :
15014 : void
15015 : nsGlobalWindow::DisableNetworkEvent(EventMessage aEventMessage)
15016 : {
15017 : MOZ_ASSERT(IsInnerWindow());
15018 :
15019 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
15020 : if (!os) {
15021 : return;
15022 : }
15023 :
15024 : switch (aEventMessage) {
15025 : case eNetworkUpload:
15026 : if (mNetworkUploadObserverEnabled) {
15027 : mNetworkUploadObserverEnabled = false;
15028 : os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC);
15029 : }
15030 : break;
15031 : case eNetworkDownload:
15032 : if (mNetworkDownloadObserverEnabled) {
15033 : mNetworkDownloadObserverEnabled = false;
15034 : os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC);
15035 : }
15036 : break;
15037 : default:
15038 : break;
15039 : }
15040 : }
15041 : #endif // MOZ_B2G
15042 :
15043 : void
15044 0 : nsGlobalWindow::RedefineProperty(JSContext* aCx, const char* aPropName,
15045 : JS::Handle<JS::Value> aValue,
15046 : ErrorResult& aError)
15047 : {
15048 0 : JS::Rooted<JSObject*> thisObj(aCx, GetWrapperPreserveColor());
15049 0 : if (!thisObj) {
15050 0 : aError.Throw(NS_ERROR_UNEXPECTED);
15051 0 : return;
15052 : }
15053 :
15054 0 : if (!JS_WrapObject(aCx, &thisObj) ||
15055 0 : !JS_DefineProperty(aCx, thisObj, aPropName, aValue, JSPROP_ENUMERATE,
15056 : JS_STUBGETTER, JS_STUBSETTER)) {
15057 0 : aError.Throw(NS_ERROR_FAILURE);
15058 : }
15059 : }
15060 :
15061 : void
15062 0 : nsGlobalWindow::GetReplaceableWindowCoord(JSContext* aCx,
15063 : nsGlobalWindow::WindowCoordGetter aGetter,
15064 : JS::MutableHandle<JS::Value> aRetval,
15065 : CallerType aCallerType,
15066 : ErrorResult& aError)
15067 : {
15068 0 : MOZ_ASSERT(IsInnerWindow());
15069 :
15070 0 : int32_t coord = (this->*aGetter)(aCallerType, aError);
15071 0 : if (!aError.Failed() &&
15072 0 : !ToJSValue(aCx, coord, aRetval)) {
15073 0 : aError.Throw(NS_ERROR_FAILURE);
15074 : }
15075 0 : }
15076 :
15077 : void
15078 0 : nsGlobalWindow::SetReplaceableWindowCoord(JSContext* aCx,
15079 : nsGlobalWindow::WindowCoordSetter aSetter,
15080 : JS::Handle<JS::Value> aValue,
15081 : const char* aPropName,
15082 : CallerType aCallerType,
15083 : ErrorResult& aError)
15084 : {
15085 0 : MOZ_ASSERT(IsInnerWindow());
15086 :
15087 : /*
15088 : * If caller is not chrome and the user has not explicitly exempted the site,
15089 : * just treat this the way we would an IDL replaceable property.
15090 : */
15091 0 : nsGlobalWindow* outer = GetOuterWindowInternal();
15092 0 : if (!outer ||
15093 0 : !outer->CanMoveResizeWindows(aCallerType) ||
15094 0 : outer->IsFrame()) {
15095 0 : RedefineProperty(aCx, aPropName, aValue, aError);
15096 0 : return;
15097 : }
15098 :
15099 : int32_t value;
15100 0 : if (!ValueToPrimitive<int32_t, eDefault>(aCx, aValue, &value)) {
15101 0 : aError.Throw(NS_ERROR_UNEXPECTED);
15102 0 : return;
15103 : }
15104 :
15105 0 : if (nsContentUtils::ShouldResistFingerprinting(GetDocShell())) {
15106 0 : bool innerWidthSpecified = false;
15107 0 : bool innerHeightSpecified = false;
15108 0 : bool outerWidthSpecified = false;
15109 0 : bool outerHeightSpecified = false;
15110 :
15111 0 : if (strcmp(aPropName, "innerWidth") == 0) {
15112 0 : innerWidthSpecified = true;
15113 0 : } else if (strcmp(aPropName, "innerHeight") == 0) {
15114 0 : innerHeightSpecified = true;
15115 0 : } else if (strcmp(aPropName, "outerWidth") == 0) {
15116 0 : outerWidthSpecified = true;
15117 0 : } else if (strcmp(aPropName, "outerHeight") == 0) {
15118 0 : outerHeightSpecified = true;
15119 : }
15120 :
15121 0 : if (innerWidthSpecified || innerHeightSpecified ||
15122 0 : outerWidthSpecified || outerHeightSpecified)
15123 : {
15124 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = outer->GetTreeOwnerWindow();
15125 0 : nsCOMPtr<nsIScreen> screen;
15126 : nsCOMPtr<nsIScreenManager> screenMgr(
15127 0 : do_GetService("@mozilla.org/gfx/screenmanager;1"));
15128 0 : int32_t winLeft = 0;
15129 0 : int32_t winTop = 0;
15130 0 : int32_t winWidth = 0;
15131 0 : int32_t winHeight = 0;
15132 0 : double scale = 1.0;
15133 :
15134 :
15135 0 : if (treeOwnerAsWin && screenMgr) {
15136 : // Acquire current window size.
15137 0 : treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);
15138 0 : treeOwnerAsWin->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
15139 0 : winLeft = NSToIntRound(winHeight / scale);
15140 0 : winTop = NSToIntRound(winWidth / scale);
15141 0 : winWidth = NSToIntRound(winWidth / scale);
15142 0 : winHeight = NSToIntRound(winHeight / scale);
15143 :
15144 : // Acquire content window size.
15145 0 : CSSIntSize contentSize;
15146 0 : outer->GetInnerSize(contentSize);
15147 :
15148 0 : screenMgr->ScreenForRect(winLeft, winTop, winWidth, winHeight,
15149 0 : getter_AddRefs(screen));
15150 :
15151 0 : if (screen) {
15152 0 : int32_t* targetContentWidth = nullptr;
15153 0 : int32_t* targetContentHeight = nullptr;
15154 0 : int32_t screenWidth = 0;
15155 0 : int32_t screenHeight = 0;
15156 0 : int32_t chromeWidth = 0;
15157 0 : int32_t chromeHeight = 0;
15158 0 : int32_t inputWidth = 0;
15159 0 : int32_t inputHeight = 0;
15160 0 : int32_t unused = 0;
15161 :
15162 : // Get screen dimensions (in device pixels)
15163 0 : screen->GetAvailRect(&unused, &unused, &screenWidth,
15164 0 : &screenHeight);
15165 : // Convert them to CSS pixels
15166 0 : screenWidth = NSToIntRound(screenWidth / scale);
15167 0 : screenHeight = NSToIntRound(screenHeight / scale);
15168 :
15169 : // Calculate the chrome UI size.
15170 0 : chromeWidth = winWidth - contentSize.width;
15171 0 : chromeHeight = winHeight - contentSize.height;
15172 :
15173 0 : if (innerWidthSpecified || outerWidthSpecified) {
15174 0 : inputWidth = value;
15175 0 : targetContentWidth = &value;
15176 0 : targetContentHeight = &unused;
15177 0 : } else if (innerHeightSpecified || outerHeightSpecified) {
15178 0 : inputHeight = value;
15179 0 : targetContentWidth = &unused;
15180 0 : targetContentHeight = &value;
15181 : }
15182 :
15183 0 : nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
15184 : chromeWidth,
15185 : chromeHeight,
15186 : screenWidth,
15187 : screenHeight,
15188 : inputWidth,
15189 : inputHeight,
15190 : outerWidthSpecified,
15191 : outerHeightSpecified,
15192 : targetContentWidth,
15193 : targetContentHeight
15194 0 : );
15195 : }
15196 : }
15197 : }
15198 : }
15199 :
15200 0 : (this->*aSetter)(value, aCallerType, aError);
15201 : }
15202 :
15203 : void
15204 7 : nsGlobalWindow::FireOnNewGlobalObject()
15205 : {
15206 7 : MOZ_ASSERT(IsInnerWindow());
15207 :
15208 : // AutoEntryScript required to invoke debugger hook, which is a
15209 : // Gecko-specific concept at present.
15210 14 : AutoEntryScript aes(this, "nsGlobalWindow report new global");
15211 14 : JS::Rooted<JSObject*> global(aes.cx(), GetWrapper());
15212 7 : JS_FireOnNewGlobalObject(aes.cx(), global);
15213 7 : }
15214 :
15215 : #ifdef _WINDOWS_
15216 : #error "Never include windows.h in this file!"
15217 : #endif
15218 :
15219 : already_AddRefed<Promise>
15220 0 : nsGlobalWindow::CreateImageBitmap(JSContext* aCx,
15221 : const ImageBitmapSource& aImage,
15222 : ErrorResult& aRv)
15223 : {
15224 0 : if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
15225 0 : aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
15226 0 : return nullptr;
15227 : }
15228 :
15229 0 : return ImageBitmap::Create(this, aImage, Nothing(), aRv);
15230 : }
15231 :
15232 : already_AddRefed<Promise>
15233 0 : nsGlobalWindow::CreateImageBitmap(JSContext* aCx,
15234 : const ImageBitmapSource& aImage,
15235 : int32_t aSx, int32_t aSy, int32_t aSw, int32_t aSh,
15236 : ErrorResult& aRv)
15237 : {
15238 0 : if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
15239 0 : aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
15240 0 : return nullptr;
15241 : }
15242 :
15243 0 : return ImageBitmap::Create(this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aRv);
15244 : }
15245 :
15246 : already_AddRefed<mozilla::dom::Promise>
15247 0 : nsGlobalWindow::CreateImageBitmap(JSContext* aCx,
15248 : const ImageBitmapSource& aImage,
15249 : int32_t aOffset, int32_t aLength,
15250 : ImageBitmapFormat aFormat,
15251 : const Sequence<ChannelPixelLayout>& aLayout,
15252 : ErrorResult& aRv)
15253 : {
15254 0 : if (!ImageBitmap::ExtensionsEnabled(aCx)) {
15255 0 : aRv.Throw(NS_ERROR_TYPE_ERR);
15256 0 : return nullptr;
15257 : }
15258 0 : if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
15259 : return ImageBitmap::Create(this, aImage, aOffset, aLength, aFormat, aLayout,
15260 0 : aRv);
15261 : }
15262 0 : aRv.Throw(NS_ERROR_TYPE_ERR);
15263 0 : return nullptr;
15264 : }
15265 :
15266 : // Helper called by methods that move/resize the window,
15267 : // to ensure the presContext (if any) is aware of resolution
15268 : // change that may happen in multi-monitor configuration.
15269 : void
15270 0 : nsGlobalWindow::CheckForDPIChange()
15271 : {
15272 0 : if (mDocShell) {
15273 0 : RefPtr<nsPresContext> presContext;
15274 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
15275 0 : if (presContext) {
15276 0 : if (presContext->DeviceContext()->CheckDPIChange()) {
15277 0 : presContext->UIResolutionChanged();
15278 : }
15279 : }
15280 : }
15281 0 : }
15282 :
15283 : mozilla::dom::TabGroup*
15284 27 : nsGlobalWindow::TabGroupOuter()
15285 : {
15286 27 : MOZ_RELEASE_ASSERT(IsOuterWindow());
15287 :
15288 : // Outer windows lazily join TabGroups when requested. This is usually done
15289 : // because a document is getting its NodePrincipal, and asking for the
15290 : // TabGroup to determine its DocGroup.
15291 27 : if (!mTabGroup) {
15292 : // Get mOpener ourselves, instead of relying on GetOpenerWindowOuter,
15293 : // because that way we dodge the LegacyIsCallerChromeOrNativeCode() call
15294 : // which we want to return false.
15295 10 : nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
15296 5 : nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
15297 5 : nsPIDOMWindowOuter* parent = GetScriptableParentOrNull();
15298 5 : MOZ_ASSERT(!parent || !opener, "Only one of parent and opener may be provided");
15299 :
15300 5 : mozilla::dom::TabGroup* toJoin = nullptr;
15301 5 : if (GetDocShell()->ItemType() == nsIDocShellTreeItem::typeChrome) {
15302 3 : toJoin = TabGroup::GetChromeTabGroup();
15303 2 : } else if (opener) {
15304 0 : toJoin = opener->TabGroup();
15305 2 : } else if (parent) {
15306 0 : toJoin = parent->TabGroup();
15307 : } else {
15308 2 : toJoin = TabGroup::GetFromWindow(AsOuter());
15309 : }
15310 :
15311 : #ifdef DEBUG
15312 : // Make sure that, if we have a tab group from the actor, it matches the one
15313 : // we're planning to join.
15314 5 : mozilla::dom::TabGroup* testGroup = TabGroup::GetFromWindow(AsOuter());
15315 5 : MOZ_ASSERT_IF(testGroup, testGroup == toJoin);
15316 : #endif
15317 :
15318 5 : mTabGroup = mozilla::dom::TabGroup::Join(AsOuter(), toJoin);
15319 : }
15320 27 : MOZ_ASSERT(mTabGroup);
15321 :
15322 : #ifdef DEBUG
15323 : // Ensure that we don't recurse forever
15324 27 : if (!mIsValidatingTabGroup) {
15325 27 : mIsValidatingTabGroup = true;
15326 : // We only need to do this check if we aren't in the chrome tab group
15327 27 : if (mIsChrome) {
15328 13 : MOZ_ASSERT(mTabGroup == TabGroup::GetChromeTabGroup());
15329 : } else {
15330 : // Sanity check that our tabgroup matches our opener or parent.
15331 28 : RefPtr<nsPIDOMWindowOuter> parent = GetScriptableParentOrNull();
15332 14 : MOZ_ASSERT_IF(parent, parent->TabGroup() == mTabGroup);
15333 28 : nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
15334 14 : nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
15335 14 : MOZ_ASSERT_IF(opener && Cast(opener) != this, opener->TabGroup() == mTabGroup);
15336 : }
15337 27 : mIsValidatingTabGroup = false;
15338 : }
15339 : #endif
15340 :
15341 27 : return mTabGroup;
15342 : }
15343 :
15344 : mozilla::dom::TabGroup*
15345 9 : nsGlobalWindow::TabGroupInner()
15346 : {
15347 9 : MOZ_RELEASE_ASSERT(IsInnerWindow());
15348 :
15349 : // If we don't have a TabGroup yet, try to get it from the outer window and
15350 : // cache it.
15351 9 : if (!mTabGroup) {
15352 7 : nsGlobalWindow* outer = GetOuterWindowInternal();
15353 : // This will never be called without either an outer window, or a cached tab group.
15354 : // This is because of the following:
15355 : // * This method is only called on inner windows
15356 : // * This method is called as a document is attached to it's script global
15357 : // by the document
15358 : // * Inner windows are created in nsGlobalWindow::SetNewDocument, which
15359 : // immediately sets a document, which will call this method, causing
15360 : // the TabGroup to be cached.
15361 7 : MOZ_RELEASE_ASSERT(outer, "Inner window without outer window has no cached tab group!");
15362 7 : mTabGroup = outer->TabGroup();
15363 : }
15364 9 : MOZ_ASSERT(mTabGroup);
15365 :
15366 : #ifdef DEBUG
15367 9 : nsGlobalWindow* outer = GetOuterWindowInternal();
15368 9 : MOZ_ASSERT_IF(outer, outer->TabGroup() == mTabGroup);
15369 : #endif
15370 :
15371 9 : return mTabGroup;
15372 : }
15373 :
15374 : template<typename T>
15375 : mozilla::dom::TabGroup*
15376 36 : nsPIDOMWindow<T>::TabGroup()
15377 : {
15378 : nsGlobalWindow* globalWindow =
15379 : static_cast<nsGlobalWindow*>(
15380 36 : reinterpret_cast<nsPIDOMWindow<nsISupports>*>(this));
15381 :
15382 36 : if (IsInnerWindow()) {
15383 9 : return globalWindow->TabGroupInner();
15384 : }
15385 27 : return globalWindow->TabGroupOuter();
15386 : }
15387 :
15388 : template<typename T>
15389 : mozilla::dom::DocGroup*
15390 686 : nsPIDOMWindow<T>::GetDocGroup() const
15391 : {
15392 686 : nsIDocument* doc = GetExtantDoc();
15393 686 : if (doc) {
15394 686 : return doc->GetDocGroup();
15395 : }
15396 0 : return nullptr;
15397 : }
15398 :
15399 : nsresult
15400 20 : nsGlobalWindow::Dispatch(const char* aName,
15401 : TaskCategory aCategory,
15402 : already_AddRefed<nsIRunnable>&& aRunnable)
15403 : {
15404 20 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
15405 20 : if (GetDocGroup()) {
15406 20 : return GetDocGroup()->Dispatch(aName, aCategory, Move(aRunnable));
15407 : }
15408 0 : return DispatcherTrait::Dispatch(aName, aCategory, Move(aRunnable));
15409 : }
15410 :
15411 : nsISerialEventTarget*
15412 16 : nsGlobalWindow::EventTargetFor(TaskCategory aCategory) const
15413 : {
15414 16 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
15415 16 : if (GetDocGroup()) {
15416 16 : return GetDocGroup()->EventTargetFor(aCategory);
15417 : }
15418 0 : return DispatcherTrait::EventTargetFor(aCategory);
15419 : }
15420 :
15421 : AbstractThread*
15422 0 : nsGlobalWindow::AbstractMainThreadFor(TaskCategory aCategory)
15423 : {
15424 0 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
15425 0 : if (GetDocGroup()) {
15426 0 : return GetDocGroup()->AbstractMainThreadFor(aCategory);
15427 : }
15428 0 : return DispatcherTrait::AbstractMainThreadFor(aCategory);
15429 : }
15430 :
15431 5 : nsGlobalWindow::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
15432 5 : nsGlobalWindow* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
15433 : {
15434 5 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
15435 :
15436 5 : MOZ_ASSERT(aWindow);
15437 5 : nsGlobalWindow* topWindow = aWindow->GetScriptableTopInternal();
15438 5 : if (!topWindow) {
15439 0 : NS_ERROR("nsGlobalWindow::TemporarilyDisableDialogs used without a top "
15440 : "window?");
15441 0 : return;
15442 : }
15443 :
15444 : // TODO: Warn if no top window?
15445 5 : topWindow = topWindow->GetCurrentInnerWindowInternal();
15446 5 : if (topWindow) {
15447 5 : mTopWindow = topWindow;
15448 5 : mSavedDialogsEnabled = mTopWindow->mAreDialogsEnabled;
15449 5 : mTopWindow->mAreDialogsEnabled = false;
15450 : }
15451 : }
15452 :
15453 10 : nsGlobalWindow::TemporarilyDisableDialogs::~TemporarilyDisableDialogs()
15454 : {
15455 5 : if (mTopWindow) {
15456 5 : mTopWindow->mAreDialogsEnabled = mSavedDialogsEnabled;
15457 : }
15458 5 : }
15459 :
15460 : Worklet*
15461 0 : nsGlobalWindow::GetAudioWorklet(ErrorResult& aRv)
15462 : {
15463 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
15464 :
15465 0 : if (!mAudioWorklet) {
15466 0 : nsIPrincipal* principal = GetPrincipal();
15467 0 : if (!principal) {
15468 0 : aRv.Throw(NS_ERROR_FAILURE);
15469 0 : return nullptr;
15470 : }
15471 :
15472 0 : mAudioWorklet = new Worklet(AsInner(), principal, Worklet::eAudioWorklet);
15473 : }
15474 :
15475 0 : return mAudioWorklet;
15476 : }
15477 :
15478 : Worklet*
15479 0 : nsGlobalWindow::GetPaintWorklet(ErrorResult& aRv)
15480 : {
15481 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
15482 :
15483 0 : if (!mPaintWorklet) {
15484 0 : nsIPrincipal* principal = GetPrincipal();
15485 0 : if (!principal) {
15486 0 : aRv.Throw(NS_ERROR_FAILURE);
15487 0 : return nullptr;
15488 : }
15489 :
15490 0 : mPaintWorklet = new Worklet(AsInner(), principal, Worklet::ePaintWorklet);
15491 : }
15492 :
15493 0 : return mPaintWorklet;
15494 : }
15495 :
15496 : void
15497 0 : nsGlobalWindow::GetAppLocalesAsBCP47(nsTArray<nsString>& aLocales)
15498 : {
15499 0 : nsTArray<nsCString> appLocales;
15500 0 : mozilla::intl::LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales);
15501 :
15502 0 : for (uint32_t i = 0; i < appLocales.Length(); i++) {
15503 0 : aLocales.AppendElement(NS_ConvertUTF8toUTF16(appLocales[i]));
15504 : }
15505 0 : }
15506 :
15507 : #ifdef ENABLE_INTL_API
15508 : IntlUtils*
15509 0 : nsGlobalWindow::GetIntlUtils(ErrorResult& aError)
15510 : {
15511 0 : MOZ_RELEASE_ASSERT(IsInnerWindow());
15512 :
15513 0 : if (!mIntlUtils) {
15514 0 : mIntlUtils = new IntlUtils(AsInner());
15515 : }
15516 :
15517 0 : return mIntlUtils;
15518 : }
15519 : #endif
15520 :
15521 : template class nsPIDOMWindow<mozIDOMWindowProxy>;
15522 : template class nsPIDOMWindow<mozIDOMWindow>;
15523 : template class nsPIDOMWindow<nsISupports>;
|