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 "nsGlobalWindowInner.h"
8 
9 #include <inttypes.h>
10 #include <math.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <cstdint>
15 #include <new>
16 #include <type_traits>
17 #include <utility>
18 #include "AudioChannelService.h"
19 #include "AutoplayPolicy.h"
20 #include "Crypto.h"
21 #include "GeckoProfiler.h"
22 #include "MainThreadUtils.h"
23 #include "Navigator.h"
24 #include "PaintWorkletImpl.h"
25 #include "SessionStorageCache.h"
26 #include "Units.h"
27 #include "VRManagerChild.h"
28 #include "WindowDestroyedEvent.h"
29 #include "WindowNamedPropertiesHandler.h"
30 #include "js/ComparisonOperators.h"
31 #include "js/CompileOptions.h"
32 #include "js/Id.h"
33 #include "js/PropertyDescriptor.h"
34 #include "js/RealmOptions.h"
35 #include "js/RootingAPI.h"
36 #include "js/TypeDecls.h"
37 #include "js/Value.h"
38 #include "js/Warnings.h"
39 #include "js/shadow/String.h"
40 #include "jsapi.h"
41 #include "jsfriendapi.h"
42 #include "mozIDOMWindow.h"
43 #include "moz_external_vr.h"
44 #include "mozilla/AlreadyAddRefed.h"
45 #include "mozilla/ArrayIterator.h"
46 #include "mozilla/ArrayUtils.h"
47 #include "mozilla/Attributes.h"
48 #include "mozilla/BaseProfilerMarkersPrerequisites.h"
49 #include "mozilla/BasicEvents.h"
50 #include "mozilla/CallState.h"
51 #include "mozilla/CycleCollectedJSContext.h"
52 #include "mozilla/DOMEventTargetHelper.h"
53 #include "mozilla/ErrorResult.h"
54 #include "mozilla/EventDispatcher.h"
55 #include "mozilla/EventListenerManager.h"
56 #include "mozilla/EventQueue.h"
57 #include "mozilla/ExtensionPolicyService.h"
58 #include "mozilla/FloatingPoint.h"
59 #include "mozilla/FlushType.h"
60 #include "mozilla/Likely.h"
61 #include "mozilla/LinkedList.h"
62 #include "mozilla/Logging.h"
63 #include "mozilla/MacroForEach.h"
64 #include "mozilla/Maybe.h"
65 #include "mozilla/OwningNonNull.h"
66 #include "mozilla/PermissionDelegateHandler.h"
67 #include "mozilla/Preferences.h"
68 #include "mozilla/PresShell.h"
69 #include "mozilla/ProcessHangMonitor.h"
70 #include "mozilla/RefPtr.h"
71 #include "mozilla/Result.h"
72 #include "mozilla/ScopeExit.h"
73 #include "mozilla/ScrollOrigin.h"
74 #include "mozilla/ScrollTypes.h"
75 #include "mozilla/Components.h"
76 #include "mozilla/SizeOfState.h"
77 #include "mozilla/Span.h"
78 #include "mozilla/SpinEventLoopUntil.h"
79 #include "mozilla/Sprintf.h"
80 #include "mozilla/StaticPrefs_browser.h"
81 #include "mozilla/StaticPrefs_dom.h"
82 #include "mozilla/StorageAccess.h"
83 #include "mozilla/TaskCategory.h"
84 #include "mozilla/Telemetry.h"
85 #include "mozilla/TelemetryHistogramEnums.h"
86 #include "mozilla/TimeStamp.h"
87 #include "mozilla/UniquePtr.h"
88 #include "mozilla/Unused.h"
89 #include "mozilla/dom/AudioContext.h"
90 #include "mozilla/dom/AutoEntryScript.h"
91 #include "mozilla/dom/BarProps.h"
92 #include "mozilla/dom/BindingDeclarations.h"
93 #include "mozilla/dom/BindingUtils.h"
94 #include "mozilla/dom/BrowserChild.h"
95 #include "mozilla/dom/BrowsingContext.h"
96 #include "mozilla/dom/CSPEvalChecker.h"
97 #include "mozilla/dom/CallbackDebuggerNotification.h"
98 #include "mozilla/dom/ChromeMessageBroadcaster.h"
99 #include "mozilla/dom/ClientInfo.h"
100 #include "mozilla/dom/ClientManager.h"
101 #include "mozilla/dom/ClientSource.h"
102 #include "mozilla/dom/ClientState.h"
103 #include "mozilla/dom/ClientsBinding.h"
104 #include "mozilla/dom/Console.h"
105 #include "mozilla/dom/ContentFrameMessageManager.h"
106 #include "mozilla/dom/ContentMediaController.h"
107 #include "mozilla/dom/CustomElementRegistry.h"
108 #include "mozilla/dom/DOMJSProxyHandler.h"
109 #include "mozilla/dom/DebuggerNotification.h"
110 #include "mozilla/dom/DebuggerNotificationBinding.h"
111 #include "mozilla/dom/DebuggerNotificationManager.h"
112 #include "mozilla/dom/DispatcherTrait.h"
113 #include "mozilla/dom/DocGroup.h"
114 #include "mozilla/dom/Document.h"
115 #include "mozilla/dom/DocumentInlines.h"
116 #include "mozilla/dom/Element.h"
117 #include "mozilla/dom/Event.h"
118 #include "mozilla/dom/EventTarget.h"
119 #include "mozilla/dom/External.h"
120 #include "mozilla/dom/Fetch.h"
121 #include "mozilla/dom/Gamepad.h"
122 #include "mozilla/dom/GamepadHandle.h"
123 #include "mozilla/dom/GamepadManager.h"
124 #include "mozilla/dom/HashChangeEvent.h"
125 #include "mozilla/dom/HashChangeEventBinding.h"
126 #include "mozilla/dom/IDBFactory.h"
127 #include "mozilla/dom/IdleRequest.h"
128 #include "mozilla/dom/ImageBitmap.h"
129 #include "mozilla/dom/ImageBitmapSource.h"
130 #include "mozilla/dom/InstallTriggerBinding.h"
131 #include "mozilla/dom/IntlUtils.h"
132 #include "mozilla/dom/JSExecutionContext.h"
133 #include "mozilla/dom/LSObject.h"
134 #include "mozilla/dom/LoadedScript.h"
135 #include "mozilla/dom/LocalStorage.h"
136 #include "mozilla/dom/LocalStorageCommon.h"
137 #include "mozilla/dom/Location.h"
138 #include "mozilla/dom/MediaKeys.h"
139 #include "mozilla/dom/NavigatorBinding.h"
140 #include "mozilla/dom/Nullable.h"
141 #include "mozilla/dom/PartitionedLocalStorage.h"
142 #include "mozilla/dom/Performance.h"
143 #include "mozilla/dom/PopStateEvent.h"
144 #include "mozilla/dom/PopStateEventBinding.h"
145 #include "mozilla/dom/PopupBlocker.h"
146 #include "mozilla/dom/PrimitiveConversions.h"
147 #include "mozilla/dom/Promise.h"
148 #include "mozilla/dom/RootedDictionary.h"
149 #include "mozilla/dom/ScriptLoader.h"
150 #include "mozilla/dom/ScriptSettings.h"
151 #include "mozilla/dom/ServiceWorker.h"
152 #include "mozilla/dom/ServiceWorkerDescriptor.h"
153 #include "mozilla/dom/ServiceWorkerRegistration.h"
154 #include "mozilla/dom/SessionStorageManager.h"
155 #include "mozilla/dom/SharedWorker.h"
156 #include "mozilla/dom/Storage.h"
157 #include "mozilla/dom/StorageEvent.h"
158 #include "mozilla/dom/StorageEventBinding.h"
159 #include "mozilla/dom/StorageNotifierService.h"
160 #include "mozilla/dom/StorageUtils.h"
161 #include "mozilla/dom/TabMessageTypes.h"
162 #include "mozilla/dom/Timeout.h"
163 #include "mozilla/dom/TimeoutHandler.h"
164 #include "mozilla/dom/TimeoutManager.h"
165 #include "mozilla/dom/ToJSValue.h"
166 #include "mozilla/dom/U2F.h"
167 #include "mozilla/dom/VRDisplay.h"
168 #include "mozilla/dom/VRDisplayEvent.h"
169 #include "mozilla/dom/VRDisplayEventBinding.h"
170 #include "mozilla/dom/VREventObserver.h"
171 #include "mozilla/dom/VisualViewport.h"
172 #include "mozilla/dom/WakeLock.h"
173 #include "mozilla/dom/WebIDLGlobalNameHash.h"
174 #include "mozilla/dom/WindowBinding.h"
175 #include "mozilla/dom/WindowContext.h"
176 #include "mozilla/dom/WindowGlobalChild.h"
177 #include "mozilla/dom/WindowProxyHolder.h"
178 #include "mozilla/dom/WorkerCommon.h"
179 #include "mozilla/dom/Worklet.h"
180 #include "mozilla/dom/XRPermissionRequest.h"
181 #include "mozilla/dom/cache/CacheStorage.h"
182 #include "mozilla/dom/cache/Types.h"
183 #include "mozilla/extensions/WebExtensionPolicy.h"
184 #include "mozilla/fallible.h"
185 #include "mozilla/gfx/BasePoint.h"
186 #include "mozilla/gfx/BaseRect.h"
187 #include "mozilla/gfx/BaseSize.h"
188 #include "mozilla/gfx/Rect.h"
189 #include "mozilla/gfx/Types.h"
190 #include "mozilla/intl/LocaleService.h"
191 #include "mozilla/net/CookieJarSettings.h"
192 #include "nsAtom.h"
193 #include "nsBaseHashtable.h"
194 #include "nsCCUncollectableMarker.h"
195 #include "nsCOMPtr.h"
196 #include "nsCRT.h"
197 #include "nsCRTGlue.h"
198 #include "nsCanvasFrame.h"
199 #include "nsCharTraits.h"
200 #include "nsCheapSets.h"
201 #include "nsContentUtils.h"
202 #include "nsCoord.h"
203 #include "nsCycleCollectionNoteChild.h"
204 #include "nsCycleCollectionTraversalCallback.h"
205 #include "nsDOMNavigationTiming.h"
206 #include "nsDOMOfflineResourceList.h"
207 #include "nsDebug.h"
208 #include "nsDocShell.h"
209 #include "nsFocusManager.h"
210 #include "nsFrameMessageManager.h"
211 #include "nsGkAtoms.h"
212 #include "nsGlobalWindowOuter.h"
213 #include "nsHashKeys.h"
214 #include "nsHistory.h"
215 #include "nsIAddonPolicyService.h"
216 #include "nsIArray.h"
217 #include "nsIBaseWindow.h"
218 #include "nsIBrowserChild.h"
219 #include "nsICancelableRunnable.h"
220 #include "nsIChannel.h"
221 #include "nsIContentSecurityPolicy.h"
222 #include "nsIControllers.h"
223 #include "nsICookieJarSettings.h"
224 #include "nsICookieService.h"
225 #include "nsID.h"
226 #include "nsIDOMStorageManager.h"
227 #include "nsIDeviceSensors.h"
228 #include "nsIDocShell.h"
229 #include "nsIDocShellTreeItem.h"
230 #include "nsIDocShellTreeOwner.h"
231 #include "nsIDocumentLoader.h"
232 #include "nsIDragService.h"
233 #include "nsIFocusManager.h"
234 #include "nsIFrame.h"
235 #include "nsIGlobalObject.h"
236 #include "nsIIOService.h"
237 #include "nsIIdleRunnable.h"
238 #include "nsIInterfaceRequestorUtils.h"
239 #include "nsILoadContext.h"
240 #include "nsILoadGroup.h"
241 #include "nsILoadInfo.h"
242 #include "nsINamed.h"
243 #include "nsINode.h"
244 #include "nsIObserver.h"
245 #include "nsIObserverService.h"
246 #include "nsIPermission.h"
247 #include "nsIPermissionManager.h"
248 #include "nsIPrefBranch.h"
249 #include "nsIPrincipal.h"
250 #include "nsIPrompt.h"
251 #include "nsIRunnable.h"
252 #include "nsIScreen.h"
253 #include "nsIScreenManager.h"
254 #include "nsIScriptContext.h"
255 #include "nsIScriptGlobalObject.h"
256 #include "nsIScriptObjectPrincipal.h"
257 #include "nsIScrollableFrame.h"
258 #include "nsISerialEventTarget.h"
259 #include "nsISimpleEnumerator.h"
260 #include "nsISizeOfEventTarget.h"
261 #include "nsISlowScriptDebug.h"
262 #include "nsISupportsUtils.h"
263 #include "nsIThread.h"
264 #include "nsITimedChannel.h"
265 #include "nsIURI.h"
266 #include "nsIVariant.h"
267 #include "nsIWeakReference.h"
268 #include "nsIWebBrowserChrome.h"
269 #include "nsIWebNavigation.h"
270 #include "nsIWebProgressListener.h"
271 #include "nsIWidget.h"
272 #include "nsIWidgetListener.h"
273 #include "nsIXULRuntime.h"
274 #include "nsJSPrincipals.h"
275 #include "nsJSUtils.h"
276 #include "nsLayoutStatics.h"
277 #include "nsLiteralString.h"
278 #include "nsNetUtil.h"
279 #include "nsPIDOMWindow.h"
280 #include "nsPIDOMWindowInlines.h"
281 #include "nsPIWindowRoot.h"
282 #include "nsPoint.h"
283 #include "nsPresContext.h"
284 #include "nsQueryObject.h"
285 #include "nsRefPtrHashtable.h"
286 #include "nsSandboxFlags.h"
287 #include "nsScreen.h"
288 #include "nsServiceManagerUtils.h"
289 #include "nsString.h"
290 #include "nsStringFlags.h"
291 #include "nsStringFwd.h"
292 #include "nsTArray.h"
293 #include "nsTLiteralString.h"
294 #include "nsTObserverArray.h"
295 #include "nsTStringRepr.h"
296 #include "nsThreadUtils.h"
297 #include "nsWeakReference.h"
298 #include "nsWindowMemoryReporter.h"
299 #include "nsWindowSizes.h"
300 #include "nsWrapperCache.h"
301 #include "nsWrapperCacheInlines.h"
302 #include "nsXULAppAPI.h"
303 #include "nsrootidl.h"
304 #include "prclist.h"
305 #include "prtypes.h"
306 #include "xpcprivate.h"
307 #include "xpcpublic.h"
308 
309 #ifdef MOZ_XUL
310 #  include "nsIDOMXULControlElement.h"
311 #  include "nsMenuPopupFrame.h"
312 #endif
313 
314 #ifdef NS_PRINTING
315 #  include "nsIPrintSettings.h"
316 #  include "nsIPrintSettingsService.h"
317 #  include "nsIWebBrowserPrint.h"
318 #endif
319 
320 #ifdef MOZ_WEBSPEECH
321 #  include "mozilla/dom/SpeechSynthesis.h"
322 #endif
323 
324 #ifdef ANDROID
325 #  include <android/log.h>
326 #endif
327 
328 #ifdef MOZ_WIDGET_ANDROID
329 #  include "mozilla/dom/WindowOrientationObserver.h"
330 #endif
331 
332 #ifdef XP_WIN
333 #  include "mozilla/Debug.h"
334 #  include <process.h>
335 #  define getpid _getpid
336 #else
337 #  include <unistd.h>  // for getpid()
338 #endif
339 
340 using namespace mozilla;
341 using namespace mozilla::dom;
342 using namespace mozilla::dom::ipc;
343 using mozilla::TimeDuration;
344 using mozilla::TimeStamp;
345 using mozilla::dom::GamepadHandle;
346 using mozilla::dom::cache::CacheStorage;
347 
348 #define FORWARD_TO_OUTER(method, args, err_rval)                     \
349   PR_BEGIN_MACRO                                                     \
350   nsGlobalWindowOuter* outer = GetOuterWindowInternal();             \
351   if (!HasActiveDocument()) {                                        \
352     NS_WARNING(outer ? "Inner window does not have active document." \
353                      : "No outer window available!");                \
354     return err_rval;                                                 \
355   }                                                                  \
356   return outer->method args;                                         \
357   PR_END_MACRO
358 
GetOuterWindowForForwarding(nsGlobalWindowInner * aInner,ErrorResult & aError)359 static nsGlobalWindowOuter* GetOuterWindowForForwarding(
360     nsGlobalWindowInner* aInner, ErrorResult& aError) {
361   nsGlobalWindowOuter* outer = aInner->GetOuterWindowInternal();
362   if (MOZ_LIKELY(aInner->HasActiveDocument())) {
363     return outer;
364   }
365   if (!outer) {
366     NS_WARNING("No outer window available!");
367     aError.Throw(NS_ERROR_NOT_INITIALIZED);
368   } else {
369     aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO);
370   }
371   return nullptr;
372 }
373 
374 #define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval)         \
375   PR_BEGIN_MACRO                                                               \
376   nsGlobalWindowOuter* outer = GetOuterWindowForForwarding(this, errorresult); \
377   if (MOZ_LIKELY(outer)) {                                                     \
378     return outer->method args;                                                 \
379   }                                                                            \
380   return err_rval;                                                             \
381   PR_END_MACRO
382 
383 #define FORWARD_TO_OUTER_VOID(method, args)                          \
384   PR_BEGIN_MACRO                                                     \
385   nsGlobalWindowOuter* outer = GetOuterWindowInternal();             \
386   if (!HasActiveDocument()) {                                        \
387     NS_WARNING(outer ? "Inner window does not have active document." \
388                      : "No outer window available!");                \
389     return;                                                          \
390   }                                                                  \
391   outer->method args;                                                \
392   return;                                                            \
393   PR_END_MACRO
394 
395 #define ENSURE_ACTIVE_DOCUMENT(errorresult, err_rval) \
396   PR_BEGIN_MACRO                                      \
397   if (MOZ_UNLIKELY(!HasActiveDocument())) {           \
398     aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \
399     return err_rval;                                  \
400   }                                                   \
401   PR_END_MACRO
402 
403 #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
404 #define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
405 #define PERMISSION_CHANGED_TOPIC "perm-changed"
406 
407 // Amount of time allowed between alert/prompt/confirm before enabling
408 // the stop dialog checkbox.
409 #define DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT 3  // 3 sec
410 
411 // Maximum number of successive dialogs before we prompt users to disable
412 // dialogs for this window.
413 #define MAX_SUCCESSIVE_DIALOG_COUNT 5
414 
415 static LazyLogModule gDOMLeakPRLogInner("DOMLeakInner");
416 extern mozilla::LazyLogModule gTimeoutLog;
417 
418 #ifdef DEBUG
419 static LazyLogModule gDocShellAndDOMWindowLeakLogging(
420     "DocShellAndDOMWindowLeak");
421 #endif
422 
423 static FILE* gDumpFile = nullptr;
424 
425 nsGlobalWindowInner::InnerWindowByIdTable*
426     nsGlobalWindowInner::sInnerWindowsById = nullptr;
427 
428 bool nsGlobalWindowInner::sDragServiceDisabled = false;
429 bool nsGlobalWindowInner::sMouseDown = false;
430 
431 /**
432  * An indirect observer object that means we don't have to implement nsIObserver
433  * on nsGlobalWindow, where any script could see it.
434  */
435 class nsGlobalWindowObserver final : public nsIObserver,
436                                      public nsIInterfaceRequestor,
437                                      public StorageNotificationObserver {
438  public:
nsGlobalWindowObserver(nsGlobalWindowInner * aWindow)439   explicit nsGlobalWindowObserver(nsGlobalWindowInner* aWindow)
440       : mWindow(aWindow) {}
441   NS_DECL_ISUPPORTS
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)442   NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
443                      const char16_t* aData) override {
444     if (!mWindow) return NS_OK;
445     return mWindow->Observe(aSubject, aTopic, aData);
446   }
Forget()447   void Forget() { mWindow = nullptr; }
GetInterface(const nsIID & aIID,void ** aResult)448   NS_IMETHOD GetInterface(const nsIID& aIID, void** aResult) override {
449     if (mWindow && aIID.Equals(NS_GET_IID(nsIDOMWindow)) && mWindow) {
450       return mWindow->QueryInterface(aIID, aResult);
451     }
452     return NS_NOINTERFACE;
453   }
454 
ObserveStorageNotification(StorageEvent * aEvent,const char16_t * aStorageType,bool aPrivateBrowsing)455   void ObserveStorageNotification(StorageEvent* aEvent,
456                                   const char16_t* aStorageType,
457                                   bool aPrivateBrowsing) override {
458     if (mWindow) {
459       mWindow->ObserveStorageNotification(aEvent, aStorageType,
460                                           aPrivateBrowsing);
461     }
462   }
463 
GetEffectiveStoragePrincipal() const464   nsIPrincipal* GetEffectiveStoragePrincipal() const override {
465     return mWindow ? mWindow->GetEffectiveStoragePrincipal() : nullptr;
466   }
467 
IsPrivateBrowsing() const468   bool IsPrivateBrowsing() const override {
469     return mWindow ? mWindow->IsPrivateBrowsing() : false;
470   }
471 
GetEventTarget() const472   nsIEventTarget* GetEventTarget() const override {
473     return mWindow ? mWindow->EventTargetFor(TaskCategory::Other) : nullptr;
474   }
475 
476  private:
477   ~nsGlobalWindowObserver() = default;
478 
479   // This reference is non-owning and safe because it's cleared by
480   // nsGlobalWindowInner::FreeInnerObjects().
481   nsGlobalWindowInner* MOZ_NON_OWNING_REF mWindow;
482 };
483 
484 NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)
485 
486 class IdleRequestExecutor;
487 
488 class IdleRequestExecutorTimeoutHandler final : public TimeoutHandler {
489  public:
IdleRequestExecutorTimeoutHandler(IdleRequestExecutor * aExecutor)490   explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor* aExecutor)
491       : mExecutor(aExecutor) {}
492 
493   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
494   NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestExecutorTimeoutHandler)
495 
496   bool Call(const char* /* unused */) override;
497 
498  private:
499   ~IdleRequestExecutorTimeoutHandler() override = default;
500   RefPtr<IdleRequestExecutor> mExecutor;
501 };
502 
503 NS_IMPL_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler, mExecutor)
504 
505 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutorTimeoutHandler)
506 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutorTimeoutHandler)
507 
508 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler)
509   NS_INTERFACE_MAP_ENTRY(nsISupports)
510 NS_INTERFACE_MAP_END
511 
512 class IdleRequestExecutor final : public nsIRunnable,
513                                   public nsICancelableRunnable,
514                                   public nsINamed,
515                                   public nsIIdleRunnable {
516  public:
IdleRequestExecutor(nsGlobalWindowInner * aWindow)517   explicit IdleRequestExecutor(nsGlobalWindowInner* aWindow)
518       : mDispatched(false), mDeadline(TimeStamp::Now()), mWindow(aWindow) {
519     MOZ_DIAGNOSTIC_ASSERT(mWindow);
520 
521     mIdlePeriodLimit = {mDeadline, mWindow->LastIdleRequestHandle()};
522     mDelayedExecutorDispatcher = new IdleRequestExecutorTimeoutHandler(this);
523   }
524 
525   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
526   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor, nsIRunnable)
527 
528   NS_DECL_NSIRUNNABLE
529   NS_DECL_NSINAMED
530   nsresult Cancel() override;
531   void SetDeadline(TimeStamp aDeadline) override;
532 
IsCancelled() const533   bool IsCancelled() const { return !mWindow || mWindow->IsDying(); }
534   // Checks if aRequest shouldn't execute in the current idle period
535   // since it has been queued from a chained call to
536   // requestIdleCallback from within a running idle callback.
IneligibleForCurrentIdlePeriod(IdleRequest * aRequest) const537   bool IneligibleForCurrentIdlePeriod(IdleRequest* aRequest) const {
538     return aRequest->Handle() >= mIdlePeriodLimit.mLastRequestIdInIdlePeriod &&
539            TimeStamp::Now() <= mIdlePeriodLimit.mEndOfIdlePeriod;
540   }
541 
542   void MaybeUpdateIdlePeriodLimit();
543 
544   // Maybe dispatch the IdleRequestExecutor. MabyeDispatch will
545   // schedule a delayed dispatch if the associated window is in the
546   // background or if given a time to wait until dispatching.
547   void MaybeDispatch(TimeStamp aDelayUntil = TimeStamp());
548   void ScheduleDispatch();
549 
550  private:
551   struct IdlePeriodLimit {
552     TimeStamp mEndOfIdlePeriod;
553     uint32_t mLastRequestIdInIdlePeriod;
554   };
555 
556   void DelayedDispatch(uint32_t aDelay);
557 
558   ~IdleRequestExecutor() override = default;
559 
560   bool mDispatched;
561   TimeStamp mDeadline;
562   IdlePeriodLimit mIdlePeriodLimit;
563   RefPtr<nsGlobalWindowInner> mWindow;
564   // The timeout handler responsible for dispatching this executor in
565   // the case of immediate dispatch to the idle queue isn't
566   // desirable. This is used if we've dispatched all idle callbacks
567   // that are allowed to run in the current idle period, or if the
568   // associated window is currently in the background.
569   RefPtr<TimeoutHandler> mDelayedExecutorDispatcher;
570   // If not Nothing() then this value is the handle to the currently
571   // scheduled delayed executor dispatcher. This is needed to be able
572   // to cancel the timeout handler in case of the executor being
573   // cancelled.
574   Maybe<int32_t> mDelayedExecutorHandle;
575 };
576 
577 NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequestExecutor)
578 
NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor)579 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor)
580 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor)
581 
582 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequestExecutor)
583   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
584   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDelayedExecutorDispatcher)
585 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
586 
587 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequestExecutor)
588   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
589   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDelayedExecutorDispatcher)
590 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
591 
592 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor)
593   NS_INTERFACE_MAP_ENTRY(nsIRunnable)
594   NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable)
595   NS_INTERFACE_MAP_ENTRY(nsINamed)
596   NS_INTERFACE_MAP_ENTRY(nsIIdleRunnable)
597   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable)
598 NS_INTERFACE_MAP_END
599 
600 NS_IMETHODIMP
601 IdleRequestExecutor::GetName(nsACString& aName) {
602   aName.AssignLiteral("IdleRequestExecutor");
603   return NS_OK;
604 }
605 
606 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until nsIRunnable::Run is MOZ_CAN_RUN_SCRIPT.
607 // See bug 1535398.
Run()608 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP IdleRequestExecutor::Run() {
609   MOZ_ASSERT(NS_IsMainThread());
610 
611   mDispatched = false;
612   if (mWindow) {
613     RefPtr<nsGlobalWindowInner> window(mWindow);
614     window->ExecuteIdleRequest(mDeadline);
615   }
616 
617   return NS_OK;
618 }
619 
Cancel()620 nsresult IdleRequestExecutor::Cancel() {
621   MOZ_ASSERT(NS_IsMainThread());
622 
623   if (mDelayedExecutorHandle && mWindow) {
624     mWindow->TimeoutManager().ClearTimeout(
625         mDelayedExecutorHandle.value(), Timeout::Reason::eIdleCallbackTimeout);
626   }
627 
628   mWindow = nullptr;
629   return NS_OK;
630 }
631 
SetDeadline(TimeStamp aDeadline)632 void IdleRequestExecutor::SetDeadline(TimeStamp aDeadline) {
633   MOZ_ASSERT(NS_IsMainThread());
634 
635   if (!mWindow) {
636     return;
637   }
638 
639   mDeadline = aDeadline;
640 }
641 
MaybeUpdateIdlePeriodLimit()642 void IdleRequestExecutor::MaybeUpdateIdlePeriodLimit() {
643   if (TimeStamp::Now() > mIdlePeriodLimit.mEndOfIdlePeriod) {
644     mIdlePeriodLimit = {mDeadline, mWindow->LastIdleRequestHandle()};
645   }
646 }
647 
MaybeDispatch(TimeStamp aDelayUntil)648 void IdleRequestExecutor::MaybeDispatch(TimeStamp aDelayUntil) {
649   // If we've already dispatched the executor we don't want to do it
650   // again. Also, if we've called IdleRequestExecutor::Cancel mWindow
651   // will be null, which indicates that we shouldn't dispatch this
652   // executor either.
653   if (mDispatched || IsCancelled()) {
654     return;
655   }
656 
657   mDispatched = true;
658 
659   nsPIDOMWindowOuter* outer = mWindow->GetOuterWindow();
660   if (outer && outer->IsBackground()) {
661     // Set a timeout handler with a timeout of 0 ms to throttle idle
662     // callback requests coming from a backround window using
663     // background timeout throttling.
664     DelayedDispatch(0);
665     return;
666   }
667 
668   TimeStamp now = TimeStamp::Now();
669   if (!aDelayUntil || aDelayUntil < now) {
670     ScheduleDispatch();
671     return;
672   }
673 
674   TimeDuration delay = aDelayUntil - now;
675   DelayedDispatch(static_cast<uint32_t>(delay.ToMilliseconds()));
676 }
677 
ScheduleDispatch()678 void IdleRequestExecutor::ScheduleDispatch() {
679   MOZ_ASSERT(mWindow);
680   mDelayedExecutorHandle = Nothing();
681   RefPtr<IdleRequestExecutor> request = this;
682   NS_DispatchToCurrentThreadQueue(request.forget(), EventQueuePriority::Idle);
683 }
684 
DelayedDispatch(uint32_t aDelay)685 void IdleRequestExecutor::DelayedDispatch(uint32_t aDelay) {
686   MOZ_ASSERT(mWindow);
687   MOZ_ASSERT(mDelayedExecutorHandle.isNothing());
688   int32_t handle;
689   mWindow->TimeoutManager().SetTimeout(
690       mDelayedExecutorDispatcher, aDelay, false,
691       Timeout::Reason::eIdleCallbackTimeout, &handle);
692   mDelayedExecutorHandle = Some(handle);
693 }
694 
Call(const char *)695 bool IdleRequestExecutorTimeoutHandler::Call(const char* /* unused */) {
696   if (!mExecutor->IsCancelled()) {
697     mExecutor->ScheduleDispatch();
698   }
699   return true;
700 }
701 
ScheduleIdleRequestDispatch()702 void nsGlobalWindowInner::ScheduleIdleRequestDispatch() {
703   AssertIsOnMainThread();
704 
705   if (!mIdleRequestExecutor) {
706     mIdleRequestExecutor = new IdleRequestExecutor(this);
707   }
708 
709   mIdleRequestExecutor->MaybeDispatch();
710 }
711 
SuspendIdleRequests()712 void nsGlobalWindowInner::SuspendIdleRequests() {
713   if (mIdleRequestExecutor) {
714     mIdleRequestExecutor->Cancel();
715     mIdleRequestExecutor = nullptr;
716   }
717 }
718 
ResumeIdleRequests()719 void nsGlobalWindowInner::ResumeIdleRequests() {
720   MOZ_ASSERT(!mIdleRequestExecutor);
721 
722   ScheduleIdleRequestDispatch();
723 }
724 
RemoveIdleCallback(mozilla::dom::IdleRequest * aRequest)725 void nsGlobalWindowInner::RemoveIdleCallback(
726     mozilla::dom::IdleRequest* aRequest) {
727   AssertIsOnMainThread();
728 
729   if (aRequest->HasTimeout()) {
730     mTimeoutManager->ClearTimeout(aRequest->GetTimeoutHandle(),
731                                   Timeout::Reason::eIdleCallbackTimeout);
732   }
733 
734   aRequest->removeFrom(mIdleRequestCallbacks);
735 }
736 
RunIdleRequest(IdleRequest * aRequest,DOMHighResTimeStamp aDeadline,bool aDidTimeout)737 void nsGlobalWindowInner::RunIdleRequest(IdleRequest* aRequest,
738                                          DOMHighResTimeStamp aDeadline,
739                                          bool aDidTimeout) {
740   AssertIsOnMainThread();
741   // XXXbz Do we still need this RefPtr?  MOZ_CAN_RUN_SCRIPT should
742   // guarantee that caller is holding a strong ref on the stack.
743   RefPtr<IdleRequest> request(aRequest);
744   RemoveIdleCallback(request);
745   request->IdleRun(this, aDeadline, aDidTimeout);
746 }
747 
ExecuteIdleRequest(TimeStamp aDeadline)748 void nsGlobalWindowInner::ExecuteIdleRequest(TimeStamp aDeadline) {
749   AssertIsOnMainThread();
750   RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
751 
752   if (!request) {
753     // There are no more idle requests, so stop scheduling idle
754     // request callbacks.
755     return;
756   }
757 
758   // If the request that we're trying to execute has been queued
759   // during the current idle period, then dispatch it again at the end
760   // of the idle period.
761   if (mIdleRequestExecutor->IneligibleForCurrentIdlePeriod(request)) {
762     mIdleRequestExecutor->MaybeDispatch(aDeadline);
763     return;
764   }
765 
766   DOMHighResTimeStamp deadline = 0.0;
767 
768   if (Performance* perf = GetPerformance()) {
769     deadline = perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline);
770   }
771 
772   mIdleRequestExecutor->MaybeUpdateIdlePeriodLimit();
773   RunIdleRequest(request, deadline, false);
774 
775   // Running the idle callback could've suspended the window, in which
776   // case mIdleRequestExecutor will be null.
777   if (mIdleRequestExecutor) {
778     mIdleRequestExecutor->MaybeDispatch();
779   }
780 }
781 
782 class IdleRequestTimeoutHandler final : public TimeoutHandler {
783  public:
IdleRequestTimeoutHandler(JSContext * aCx,IdleRequest * aIdleRequest,nsPIDOMWindowInner * aWindow)784   IdleRequestTimeoutHandler(JSContext* aCx, IdleRequest* aIdleRequest,
785                             nsPIDOMWindowInner* aWindow)
786       : TimeoutHandler(aCx), mIdleRequest(aIdleRequest), mWindow(aWindow) {}
787 
788   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestTimeoutHandler)789   NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestTimeoutHandler)
790 
791   MOZ_CAN_RUN_SCRIPT bool Call(const char* /* unused */) override {
792     RefPtr<nsGlobalWindowInner> window(nsGlobalWindowInner::Cast(mWindow));
793     RefPtr<IdleRequest> request(mIdleRequest);
794     window->RunIdleRequest(request, 0.0, true);
795     return true;
796   }
797 
798  private:
799   ~IdleRequestTimeoutHandler() override = default;
800 
801   RefPtr<IdleRequest> mIdleRequest;
802   nsCOMPtr<nsPIDOMWindowInner> mWindow;
803 };
804 
NS_IMPL_CYCLE_COLLECTION(IdleRequestTimeoutHandler,mIdleRequest,mWindow)805 NS_IMPL_CYCLE_COLLECTION(IdleRequestTimeoutHandler, mIdleRequest, mWindow)
806 
807 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestTimeoutHandler)
808 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestTimeoutHandler)
809 
810 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler)
811   NS_INTERFACE_MAP_ENTRY(nsISupports)
812 NS_INTERFACE_MAP_END
813 
814 uint32_t nsGlobalWindowInner::RequestIdleCallback(
815     JSContext* aCx, IdleRequestCallback& aCallback,
816     const IdleRequestOptions& aOptions, ErrorResult& aError) {
817   AssertIsOnMainThread();
818 
819   if (IsDying()) {
820     return 0;
821   }
822 
823   uint32_t handle = mIdleRequestCallbackCounter++;
824 
825   RefPtr<IdleRequest> request = new IdleRequest(&aCallback, handle);
826 
827   if (aOptions.mTimeout.WasPassed()) {
828     int32_t timeoutHandle;
829     RefPtr<TimeoutHandler> handler(
830         new IdleRequestTimeoutHandler(aCx, request, this));
831 
832     nsresult rv = mTimeoutManager->SetTimeout(
833         handler, aOptions.mTimeout.Value(), false,
834         Timeout::Reason::eIdleCallbackTimeout, &timeoutHandle);
835 
836     if (NS_WARN_IF(NS_FAILED(rv))) {
837       return 0;
838     }
839 
840     request->SetTimeoutHandle(timeoutHandle);
841   }
842 
843   mIdleRequestCallbacks.insertBack(request);
844 
845   if (!IsSuspended()) {
846     ScheduleIdleRequestDispatch();
847   }
848 
849   return handle;
850 }
851 
CancelIdleCallback(uint32_t aHandle)852 void nsGlobalWindowInner::CancelIdleCallback(uint32_t aHandle) {
853   for (IdleRequest* r : mIdleRequestCallbacks) {
854     if (r->Handle() == aHandle) {
855       RemoveIdleCallback(r);
856       break;
857     }
858   }
859 }
860 
DisableIdleCallbackRequests()861 void nsGlobalWindowInner::DisableIdleCallbackRequests() {
862   if (mIdleRequestExecutor) {
863     mIdleRequestExecutor->Cancel();
864     mIdleRequestExecutor = nullptr;
865   }
866 
867   while (!mIdleRequestCallbacks.isEmpty()) {
868     RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
869     RemoveIdleCallback(request);
870   }
871 }
872 
IsBackgroundInternal() const873 bool nsGlobalWindowInner::IsBackgroundInternal() const {
874   return !mOuterWindow || mOuterWindow->IsBackground();
875 }
876 
877 class PromiseDocumentFlushedResolver final {
878  public:
PromiseDocumentFlushedResolver(Promise * aPromise,PromiseDocumentFlushedCallback & aCallback)879   PromiseDocumentFlushedResolver(Promise* aPromise,
880                                  PromiseDocumentFlushedCallback& aCallback)
881       : mPromise(aPromise), mCallback(&aCallback) {}
882 
883   virtual ~PromiseDocumentFlushedResolver() = default;
884 
Call()885   void Call() {
886     nsMutationGuard guard;
887     ErrorResult error;
888     JS::Rooted<JS::Value> returnVal(RootingCx());
889     mCallback->Call(&returnVal, error);
890 
891     if (error.Failed()) {
892       mPromise->MaybeReject(std::move(error));
893     } else if (guard.Mutated(0)) {
894       // Something within the callback mutated the DOM.
895       mPromise->MaybeReject(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
896     } else {
897       mPromise->MaybeResolve(returnVal);
898     }
899   }
900 
901   RefPtr<Promise> mPromise;
902   RefPtr<PromiseDocumentFlushedCallback> mCallback;
903 };
904 
905 //*****************************************************************************
906 //***    nsGlobalWindowInner: Object Management
907 //*****************************************************************************
908 
nsGlobalWindowInner(nsGlobalWindowOuter * aOuterWindow,WindowGlobalChild * aActor)909 nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow,
910                                          WindowGlobalChild* aActor)
911     : nsPIDOMWindowInner(aOuterWindow, aActor),
912       mWasOffline(false),
913       mHasHadSlowScript(false),
914       mIsChrome(false),
915       mCleanMessageManager(false),
916       mNeedsFocus(true),
917       mHasFocus(false),
918       mFocusByKeyOccurred(false),
919       mDidFireDocElemInserted(false),
920       mHasGamepad(false),
921       mHasXRSession(false),
922       mHasVRDisplayActivateEvents(false),
923       mXRRuntimeDetectionInFlight(false),
924       mXRPermissionRequestInFlight(false),
925       mXRPermissionGranted(false),
926       mWasCurrentInnerWindow(false),
927       mHasSeenGamepadInput(false),
928       mHintedWasLoading(false),
929       mHasOpenedExternalProtocolFrame(false),
930       mSuspendDepth(0),
931       mFreezeDepth(0),
932 #ifdef DEBUG
933       mSerial(0),
934 #endif
935       mFocusMethod(0),
936       mIdleRequestCallbackCounter(1),
937       mIdleRequestExecutor(nullptr),
938       mDialogAbuseCount(0),
939       mAreDialogsEnabled(true),
940       mObservingRefresh(false),
941       mIteratingDocumentFlushedResolvers(false),
942       mCanSkipCCGeneration(0) {
943   mIsInnerWindow = true;
944 
945   AssertIsOnMainThread();
946   nsLayoutStatics::AddRef();
947 
948   // Initialize the PRCList (this).
949   PR_INIT_CLIST(this);
950 
951   // add this inner window to the outer window list of inners.
952   PR_INSERT_AFTER(this, aOuterWindow);
953 
954   mTimeoutManager = MakeUnique<dom::TimeoutManager>(
955       *this, StaticPrefs::dom_timeout_max_idle_defer_ms());
956 
957   mObserver = new nsGlobalWindowObserver(this);
958   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
959   if (os) {
960     // Watch for online/offline status changes so we can fire events. Use
961     // a strong reference.
962     os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, false);
963     os->AddObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC, false);
964     os->AddObserver(mObserver, PERMISSION_CHANGED_TOPIC, false);
965   }
966 
967   Preferences::AddStrongObserver(mObserver, "intl.accept_languages");
968 
969   // Watch for storage notifications so we can fire storage events.
970   RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
971   if (sns) {
972     sns->Register(mObserver);
973   }
974 
975   if (XRE_IsContentProcess()) {
976     nsCOMPtr<nsIDocShell> docShell = GetDocShell();
977     if (docShell) {
978       mBrowserChild = docShell->GetBrowserChild();
979     }
980   }
981 
982   if (gDumpFile == nullptr) {
983     nsAutoCString fname;
984     Preferences::GetCString("browser.dom.window.dump.file", fname);
985     if (!fname.IsEmpty()) {
986       // If this fails to open, Dump() knows to just go to stdout on null.
987       gDumpFile = fopen(fname.get(), "wb+");
988     } else {
989       gDumpFile = stdout;
990     }
991   }
992 
993 #ifdef DEBUG
994   mSerial = nsContentUtils::InnerOrOuterWindowCreated();
995 
996   MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
997           ("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
998            nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
999            static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
1000            static_cast<void*>(ToCanonicalSupports(aOuterWindow))));
1001 #endif
1002 
1003   MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
1004           ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
1005 
1006   // Add ourselves to the inner windows list.
1007   MOZ_ASSERT(sInnerWindowsById, "Inner Windows hash table must be created!");
1008   MOZ_ASSERT(!sInnerWindowsById->Contains(mWindowID),
1009              "This window shouldn't be in the hash table yet!");
1010   // We seem to see crashes in release builds because of null
1011   // |sInnerWindowsById|.
1012   if (sInnerWindowsById) {
1013     sInnerWindowsById->InsertOrUpdate(mWindowID, this);
1014   }
1015 }
1016 
1017 #ifdef DEBUG
1018 
1019 /* static */
AssertIsOnMainThread()1020 void nsGlobalWindowInner::AssertIsOnMainThread() {
1021   MOZ_ASSERT(NS_IsMainThread());
1022 }
1023 
1024 #endif  // DEBUG
1025 
1026 /* static */
Init()1027 void nsGlobalWindowInner::Init() {
1028   AssertIsOnMainThread();
1029 
1030   NS_ASSERTION(gDOMLeakPRLogInner,
1031                "gDOMLeakPRLogInner should have been initialized!");
1032 
1033   sInnerWindowsById = new InnerWindowByIdTable();
1034 }
1035 
~nsGlobalWindowInner()1036 nsGlobalWindowInner::~nsGlobalWindowInner() {
1037   AssertIsOnMainThread();
1038   MOZ_ASSERT(!mHintedWasLoading);
1039 
1040   if (IsChromeWindow()) {
1041     MOZ_ASSERT(mCleanMessageManager,
1042                "chrome windows may always disconnect the msg manager");
1043 
1044     DisconnectAndClearGroupMessageManagers();
1045 
1046     if (mChromeFields.mMessageManager) {
1047       static_cast<nsFrameMessageManager*>(mChromeFields.mMessageManager.get())
1048           ->Disconnect();
1049     }
1050 
1051     mCleanMessageManager = false;
1052   }
1053 
1054   // In most cases this should already have been called, but call it again
1055   // here to catch any corner cases.
1056   FreeInnerObjects();
1057 
1058   if (sInnerWindowsById) {
1059     sInnerWindowsById->Remove(mWindowID);
1060   }
1061 
1062   nsContentUtils::InnerOrOuterWindowDestroyed();
1063 
1064 #ifdef DEBUG
1065   if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)) {
1066     nsAutoCString url;
1067     if (mLastOpenedURI) {
1068       url = mLastOpenedURI->GetSpecOrDefault();
1069 
1070       // Data URLs can be very long, so truncate to avoid flooding the log.
1071       const uint32_t maxURLLength = 1000;
1072       if (url.Length() > maxURLLength) {
1073         url.Truncate(maxURLLength);
1074       }
1075     }
1076 
1077     nsGlobalWindowOuter* outer = nsGlobalWindowOuter::Cast(mOuterWindow);
1078     MOZ_LOG(
1079         gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
1080         ("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
1081          "%s]\n",
1082          nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
1083          static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
1084          static_cast<void*>(ToCanonicalSupports(outer)), url.get()));
1085   }
1086 #endif
1087   MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
1088           ("DOMWINDOW %p destroyed", this));
1089 
1090   Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
1091                         mMutationBits ? 1 : 0);
1092 
1093   // An inner window is destroyed, pull it out of the outer window's
1094   // list if inner windows.
1095 
1096   PR_REMOVE_LINK(this);
1097 
1098   // If our outer window's inner window is this window, null out the
1099   // outer window's reference to this window that's being deleted.
1100   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
1101   if (outer) {
1102     outer->MaybeClearInnerWindow(this);
1103   }
1104 
1105   // We don't have to leave the tab group if we are an inner window.
1106 
1107   nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
1108   if (ac) ac->RemoveWindowAsListener(this);
1109 
1110   nsLayoutStatics::Release();
1111 }
1112 
1113 // static
ShutDown()1114 void nsGlobalWindowInner::ShutDown() {
1115   AssertIsOnMainThread();
1116 
1117   if (gDumpFile && gDumpFile != stdout) {
1118     fclose(gDumpFile);
1119   }
1120   gDumpFile = nullptr;
1121 
1122   delete sInnerWindowsById;
1123   sInnerWindowsById = nullptr;
1124 }
1125 
FreeInnerObjects()1126 void nsGlobalWindowInner::FreeInnerObjects() {
1127   if (IsDying()) {
1128     return;
1129   }
1130   StartDying();
1131 
1132   if (mDoc && mDoc->GetWindowContext()) {
1133     // The document is about to lose its window, so this is a good time to send
1134     // our page use counters.
1135     //
1136     // (We also do this in Document::SetScriptGlobalObject(nullptr), which
1137     // catches most cases of documents losing their window, but not all.)
1138     mDoc->SendPageUseCounters();
1139   }
1140 
1141   // Make sure that this is called before we null out the document and
1142   // other members that the window destroyed observers could
1143   // re-create.
1144   NotifyDOMWindowDestroyed(this);
1145   if (auto* reporter = nsWindowMemoryReporter::Get()) {
1146     reporter->ObserveDOMWindowDetached(this);
1147   }
1148 
1149   // Kill all of the workers for this window.
1150   CancelWorkersForWindow(*this);
1151 
1152   for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
1153        mSharedWorkers.ForwardRange()) {
1154     pinnedWorker->Close();
1155   }
1156 
1157   if (mTimeoutManager) {
1158     mTimeoutManager->ClearAllTimeouts();
1159   }
1160 
1161   DisableIdleCallbackRequests();
1162 
1163   mChromeEventHandler = nullptr;
1164 
1165   if (mListenerManager) {
1166     mListenerManager->RemoveAllListeners();
1167     mListenerManager->Disconnect();
1168     mListenerManager = nullptr;
1169   }
1170 
1171   mHistory = nullptr;
1172 
1173   if (mNavigator) {
1174     mNavigator->OnNavigation();
1175     mNavigator->Invalidate();
1176     mNavigator = nullptr;
1177   }
1178 
1179   mScreen = nullptr;
1180 
1181 #if defined(MOZ_WIDGET_ANDROID)
1182   mOrientationChangeObserver = nullptr;
1183 #endif
1184 
1185   if (mDoc) {
1186     // Remember the document's principal, URI, and CSP.
1187     mDocumentPrincipal = mDoc->NodePrincipal();
1188     mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
1189     mDocumentPartitionedPrincipal = mDoc->PartitionedPrincipal();
1190     mDocumentURI = mDoc->GetDocumentURI();
1191     mDocBaseURI = mDoc->GetDocBaseURI();
1192     mDocumentCsp = mDoc->GetCsp();
1193 
1194     while (mDoc->EventHandlingSuppressed()) {
1195       mDoc->UnsuppressEventHandlingAndFireEvents(false);
1196     }
1197   }
1198 
1199   // Remove our reference to the document and the document principal.
1200   mFocusedElement = nullptr;
1201 
1202   if (mApplicationCache) {
1203     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())
1204         ->Disconnect();
1205     mApplicationCache = nullptr;
1206   }
1207 
1208   if (mIndexedDB) {
1209     mIndexedDB->DisconnectFromGlobal(this);
1210     mIndexedDB = nullptr;
1211   }
1212 
1213   nsIGlobalObject::UnlinkObjectsInGlobal();
1214 
1215   NotifyWindowIDDestroyed("inner-window-destroyed");
1216 
1217   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
1218     mAudioContexts[i]->OnWindowDestroy();
1219   }
1220   mAudioContexts.Clear();
1221 
1222   for (MediaKeys* mediaKeys : mMediaKeysInstances) {
1223     mediaKeys->OnInnerWindowDestroy();
1224   }
1225   mMediaKeysInstances.Clear();
1226 
1227   DisableGamepadUpdates();
1228   mHasGamepad = false;
1229   mGamepads.Clear();
1230   DisableVRUpdates();
1231   mHasXRSession = false;
1232   mHasVRDisplayActivateEvents = false;
1233   mXRRuntimeDetectionInFlight = false;
1234   mXRPermissionRequestInFlight = false;
1235   mXRPermissionGranted = false;
1236   mVRDisplays.Clear();
1237 
1238   // This breaks a cycle between the window and the ClientSource object.
1239   mClientSource.reset();
1240 
1241   if (mWindowGlobalChild) {
1242     // Remove any remaining listeners.
1243     int64_t nListeners = mWindowGlobalChild->BeforeUnloadListeners();
1244     for (int64_t i = 0; i < nListeners; ++i) {
1245       mWindowGlobalChild->BeforeUnloadRemoved();
1246     }
1247     MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() == 0);
1248   }
1249 
1250   // If we have any promiseDocumentFlushed callbacks, fire them now so
1251   // that the Promises can resolve.
1252   CallDocumentFlushedResolvers(/* aUntilExhaustion = */ true);
1253 
1254   DisconnectEventTargetObjects();
1255 
1256   if (mObserver) {
1257     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1258     if (os) {
1259       os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
1260       os->RemoveObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC);
1261       os->RemoveObserver(mObserver, PERMISSION_CHANGED_TOPIC);
1262     }
1263 
1264     RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
1265     if (sns) {
1266       sns->Unregister(mObserver);
1267     }
1268 
1269     Preferences::RemoveObserver(mObserver, "intl.accept_languages");
1270 
1271     // Drop its reference to this dying window, in case for some bogus reason
1272     // the object stays around.
1273     mObserver->Forget();
1274   }
1275 
1276   mMenubar = nullptr;
1277   mToolbar = nullptr;
1278   mLocationbar = nullptr;
1279   mPersonalbar = nullptr;
1280   mStatusbar = nullptr;
1281   mScrollbars = nullptr;
1282 
1283   mConsole = nullptr;
1284 
1285   mPaintWorklet = nullptr;
1286 
1287   mExternal = nullptr;
1288   mInstallTrigger = nullptr;
1289 
1290   if (mLocalStorage) {
1291     mLocalStorage->Disconnect();
1292     mLocalStorage = nullptr;
1293   }
1294   mSessionStorage = nullptr;
1295   mPerformance = nullptr;
1296 
1297   mContentMediaController = nullptr;
1298 
1299   mSharedWorkers.Clear();
1300 
1301 #ifdef MOZ_WEBSPEECH
1302   mSpeechSynthesis = nullptr;
1303 #endif
1304 
1305   mGlean = nullptr;
1306   mGleanPings = nullptr;
1307 
1308   mParentTarget = nullptr;
1309 
1310   if (mCleanMessageManager) {
1311     MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned");
1312     if (mChromeFields.mMessageManager) {
1313       mChromeFields.mMessageManager->Disconnect();
1314     }
1315   }
1316 
1317   if (mWindowGlobalChild && !mWindowGlobalChild->IsClosed()) {
1318     mWindowGlobalChild->Destroy();
1319   }
1320   mWindowGlobalChild = nullptr;
1321 
1322   mIntlUtils = nullptr;
1323 
1324   HintIsLoading(false);
1325 }
1326 
1327 //*****************************************************************************
1328 // nsGlobalWindowInner::nsISupports
1329 //*****************************************************************************
1330 
1331 // QueryInterface implementation for nsGlobalWindowInner
1332 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowInner)
1333   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1334   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
1335   NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
1336   NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
1337   NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
1338   NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
1339   NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
1340   NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowInner)
1341   NS_INTERFACE_MAP_ENTRY(mozIDOMWindow)
1342   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMChromeWindow, IsChromeWindow())
1343   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
1344   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
1345 NS_INTERFACE_MAP_END
1346 
1347 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowInner)
1348 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowInner)
1349 
1350 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowInner)
1351   if (tmp->IsBlackForCC(false)) {
1352     if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
1353       return true;
1354     }
1355     tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
1356     if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
1357       elm->MarkForCC();
1358     }
1359     if (tmp->mTimeoutManager) {
1360       tmp->mTimeoutManager->UnmarkGrayTimers();
1361     }
1362     return true;
1363   }
1364 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1365 
1366 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowInner)
1367   return tmp->IsBlackForCC(true);
1368 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1369 
1370 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowInner)
1371   return tmp->IsBlackForCC(false);
1372 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1373 
1374 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowInner)
1375 
1376 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
1377   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
1378     char name[512];
1379     nsAutoCString uri;
1380     if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
1381       uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
1382     }
1383     SprintfLiteral(name, "nsGlobalWindowInner # %" PRIu64 " inner %s",
1384                    tmp->mWindowID, uri.get());
1385     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
1386   } else {
1387     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowInner, tmp->mRefCnt.get())
1388   }
1389 
1390   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
1391 
1392   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
1393 
1394 #ifdef MOZ_WEBSPEECH
1395   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
1396 #endif
1397 
1398   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlean)
1399   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGleanPings)
1400 
1401   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)
1402 
1403   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopInnerWindow)
1404 
1405   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
1406 
1407   if (tmp->mTimeoutManager) {
__anonc51ae67b0102(Timeout* timeout) 1408     tmp->mTimeoutManager->ForEachUnorderedTimeout([&cb](Timeout* timeout) {
1409       cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout));
1410     });
1411   }
1412 
1413   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
1414   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
1415   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
1416   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorkers)
1417   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
1418   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
1419   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
1420   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
1421   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
1422   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)
1423   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal)
1424   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCsp)
1425   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild)
1426   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
1427 
1428   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
1429   for (IdleRequest* request : tmp->mIdleRequestCallbacks) {
1430     cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));
1431   }
1432 
1433   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClientSource)
1434 
1435   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
1436 
1437   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
1438   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays)
1439 
1440   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)
1441 
1442   // Traverse stuff from nsPIDOMWindow
1443   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
1444   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
1445   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedElement)
1446   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
1447   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobalChild)
1448 
1449   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
1450   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
1451   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
1452   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
1453   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
1454   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
1455   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
1456   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mU2F)
1457   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
1458   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet)
1459   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
1460   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInstallTrigger)
1461   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
1462 
1463   tmp->TraverseObjectsInGlobal(cb);
1464 
1465   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mMessageManager)
1466   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mGroupMessageManagers)
1467 
1468   for (size_t i = 0; i < tmp->mDocumentFlushedResolvers.Length(); i++) {
1469     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mPromise);
1470     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mCallback);
1471   }
1472 
1473 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1474 
1475 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
1476   NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
1477   if (sInnerWindowsById) {
1478     sInnerWindowsById->Remove(tmp->mWindowID);
1479   }
1480 
1481   JSObject* wrapper = tmp->GetWrapperPreserveColor();
1482   if (wrapper) {
1483     // Mark our realm as dead, so the JS engine won't hand out our
1484     // global after this point.
1485     JS::SetRealmNonLive(js::GetNonCCWObjectRealm(wrapper));
1486   }
1487 
1488   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
1489 
1490   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
1491 
1492 #ifdef MOZ_WEBSPEECH
1493   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
1494 #endif
1495 
1496   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlean)
1497   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGleanPings)
1498 
1499   if (tmp->mOuterWindow) {
1500     nsGlobalWindowOuter::Cast(tmp->mOuterWindow)->MaybeClearInnerWindow(tmp);
1501     NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
1502   }
1503 
1504   if (tmp->mListenerManager) {
1505     tmp->mListenerManager->Disconnect();
1506     NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
1507   }
1508 
1509   // Here the Timeouts list would've been unlinked, but we rely on
1510   // that Timeout objects have been traced and will remove themselves
1511   // while unlinking.
1512 
1513   tmp->UpdateTopInnerWindow();
1514   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow)
1515 
1516   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
1517   NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
1518   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)
1519   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharedWorkers)
1520   if (tmp->mLocalStorage) {
1521     tmp->mLocalStorage->Disconnect();
1522     NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
1523   }
1524   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
1525   if (tmp->mApplicationCache) {
1526     static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())
1527         ->Disconnect();
1528     NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
1529   }
1530   if (tmp->mIndexedDB) {
1531     tmp->mIndexedDB->DisconnectFromGlobal(tmp);
1532     NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
1533   }
1534   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
1535   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)
1536   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal)
1537   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCsp)
1538   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild)
1539   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
1540 
1541   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
1542 
1543   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
1544   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays)
1545 
1546   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)
1547 
1548   // Unlink stuff from nsPIDOMWindow
1549   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
1550   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
1551   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedElement)
1552   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
1553 
1554   MOZ_DIAGNOSTIC_ASSERT(
1555       !tmp->mWindowGlobalChild || tmp->mWindowGlobalChild->IsClosed(),
1556       "How are we unlinking a window before its actor has been destroyed?");
1557   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowGlobalChild)
1558 
1559   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
1560   NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
1561   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
1562   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
1563   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
1564   NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
1565   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
1566   NS_IMPL_CYCLE_COLLECTION_UNLINK(mU2F)
1567   NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
1568   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet)
1569   NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
1570   NS_IMPL_CYCLE_COLLECTION_UNLINK(mInstallTrigger)
1571   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
1572 
1573   tmp->UnlinkObjectsInGlobal();
1574 
1575   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)
1576 
1577   // Here the IdleRequest list would've been unlinked, but we rely on
1578   // that IdleRequest objects have been traced and will remove
1579   // themselves while unlinking.
1580 
1581   NS_IMPL_CYCLE_COLLECTION_UNLINK(mClientSource)
1582 
1583   if (tmp->IsChromeWindow()) {
1584     if (tmp->mChromeFields.mMessageManager) {
1585       static_cast<nsFrameMessageManager*>(
1586           tmp->mChromeFields.mMessageManager.get())
1587           ->Disconnect();
1588       NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mMessageManager)
1589     }
1590     tmp->DisconnectAndClearGroupMessageManagers();
1591     NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mGroupMessageManagers)
1592   }
1593 
1594   for (size_t i = 0; i < tmp->mDocumentFlushedResolvers.Length(); i++) {
1595     NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers[i]->mPromise);
1596     NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers[i]->mCallback);
1597   }
1598   tmp->mDocumentFlushedResolvers.Clear();
1599 
1600   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1601 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1602 
1603 #ifdef DEBUG
RiskyUnlink()1604 void nsGlobalWindowInner::RiskyUnlink() {
1605   NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);
1606 }
1607 #endif
1608 
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowInner)1609 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowInner)
1610   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
1611 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1612 
1613 bool nsGlobalWindowInner::IsBlackForCC(bool aTracingNeeded) {
1614   if (!nsCCUncollectableMarker::sGeneration) {
1615     return false;
1616   }
1617 
1618   return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
1619           HasKnownLiveWrapper()) &&
1620          (!aTracingNeeded || HasNothingToTrace(ToSupports(this)));
1621 }
1622 
1623 //*****************************************************************************
1624 // nsGlobalWindowInner::nsIScriptGlobalObject
1625 //*****************************************************************************
1626 
EnsureScriptEnvironment()1627 nsresult nsGlobalWindowInner::EnsureScriptEnvironment() {
1628   // NOTE: We can't use FORWARD_TO_OUTER here because we don't want to fail if
1629   // we're called on an inactive inner window.
1630   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
1631   if (!outer) {
1632     NS_WARNING("No outer window available!");
1633     return NS_ERROR_FAILURE;
1634   }
1635   return outer->EnsureScriptEnvironment();
1636 }
1637 
GetScriptContext()1638 nsIScriptContext* nsGlobalWindowInner::GetScriptContext() {
1639   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
1640   if (!outer) {
1641     return nullptr;
1642   }
1643   return outer->GetScriptContext();
1644 }
1645 
TraceGlobalJSObject(JSTracer * aTrc)1646 void nsGlobalWindowInner::TraceGlobalJSObject(JSTracer* aTrc) {
1647   TraceWrapper(aTrc, "active window global");
1648 }
1649 
UpdateAutoplayPermission()1650 void nsGlobalWindowInner::UpdateAutoplayPermission() {
1651   if (!GetWindowContext()) {
1652     return;
1653   }
1654   uint32_t perm = AutoplayPolicy::GetSiteAutoplayPermission(GetPrincipal());
1655   if (GetWindowContext()->GetAutoplayPermission() == perm) {
1656     return;
1657   }
1658 
1659   // Setting autoplay permission on a discarded context has no effect.
1660   Unused << GetWindowContext()->SetAutoplayPermission(perm);
1661 }
1662 
UpdateShortcutsPermission()1663 void nsGlobalWindowInner::UpdateShortcutsPermission() {
1664   if (!GetWindowContext() ||
1665       !GetWindowContext()->GetBrowsingContext()->IsTop()) {
1666     // We only cache the shortcuts permission on top-level WindowContexts
1667     // since we always check the top-level principal for the permission.
1668     return;
1669   }
1670 
1671   uint32_t perm = GetShortcutsPermission(GetPrincipal());
1672 
1673   if (GetWindowContext()->GetShortcutsPermission() == perm) {
1674     return;
1675   }
1676 
1677   // If the WindowContext is discarded this has no effect.
1678   Unused << GetWindowContext()->SetShortcutsPermission(perm);
1679 }
1680 
1681 /* static */
GetShortcutsPermission(nsIPrincipal * aPrincipal)1682 uint32_t nsGlobalWindowInner::GetShortcutsPermission(nsIPrincipal* aPrincipal) {
1683   uint32_t perm = nsIPermissionManager::DENY_ACTION;
1684   nsCOMPtr<nsIPermissionManager> permMgr =
1685       mozilla::components::PermissionManager::Service();
1686   if (aPrincipal && permMgr) {
1687     permMgr->TestExactPermissionFromPrincipal(aPrincipal, "shortcuts"_ns,
1688                                               &perm);
1689   }
1690   return perm;
1691 }
1692 
UpdatePopupPermission()1693 void nsGlobalWindowInner::UpdatePopupPermission() {
1694   if (!GetWindowContext()) {
1695     return;
1696   }
1697 
1698   uint32_t perm = PopupBlocker::GetPopupPermission(GetPrincipal());
1699   if (GetWindowContext()->GetPopupPermission() == perm) {
1700     return;
1701   }
1702 
1703   // If the WindowContext is discarded this has no effect.
1704   Unused << GetWindowContext()->SetPopupPermission(perm);
1705 }
1706 
UpdatePermissions()1707 void nsGlobalWindowInner::UpdatePermissions() {
1708   if (!GetWindowContext()) {
1709     return;
1710   }
1711 
1712   nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
1713   RefPtr<WindowContext> windowContext = GetWindowContext();
1714 
1715   WindowContext::Transaction txn;
1716   txn.SetAutoplayPermission(
1717       AutoplayPolicy::GetSiteAutoplayPermission(principal));
1718   txn.SetPopupPermission(PopupBlocker::GetPopupPermission(principal));
1719 
1720   if (windowContext->IsTop()) {
1721     txn.SetShortcutsPermission(GetShortcutsPermission(principal));
1722   }
1723 
1724   // Setting permissions on a discarded WindowContext has no effect
1725   Unused << txn.Commit(windowContext);
1726 }
1727 
InitDocumentDependentState(JSContext * aCx)1728 void nsGlobalWindowInner::InitDocumentDependentState(JSContext* aCx) {
1729   MOZ_ASSERT(mDoc);
1730 
1731   if (MOZ_LOG_TEST(gDOMLeakPRLogInner, LogLevel::Debug)) {
1732     nsIURI* uri = mDoc->GetDocumentURI();
1733     MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
1734             ("DOMWINDOW %p SetNewDocument %s", this,
1735              uri ? uri->GetSpecOrDefault().get() : ""));
1736   }
1737 
1738   mFocusedElement = nullptr;
1739   mLocalStorage = nullptr;
1740   mSessionStorage = nullptr;
1741   mPerformance = nullptr;
1742 
1743   // This must be called after nullifying the internal objects because here we
1744   // could recreate them, calling the getter methods, and store them into the JS
1745   // slots. If we nullify them after, the slot values and the objects will be
1746   // out of sync.
1747   ClearDocumentDependentSlots(aCx);
1748 
1749   if (!mWindowGlobalChild) {
1750     mWindowGlobalChild = WindowGlobalChild::Create(this);
1751   }
1752   MOZ_ASSERT(!GetWindowContext()->HasBeenUserGestureActivated(),
1753              "WindowContext should always not have user gesture activation at "
1754              "this point.");
1755 
1756   UpdatePermissions();
1757 
1758   RefPtr<PermissionDelegateHandler> permDelegateHandler =
1759       mDoc->GetPermissionDelegateHandler();
1760 
1761   if (permDelegateHandler) {
1762     permDelegateHandler->PopulateAllDelegatedPermissions();
1763   }
1764 
1765 #if defined(MOZ_WIDGET_ANDROID)
1766   // When we insert the new document to the window in the top-level browsing
1767   // context, we should reset the status of the request which is used for the
1768   // previous document.
1769   if (mWindowGlobalChild && GetBrowsingContext() &&
1770       !GetBrowsingContext()->GetParent()) {
1771     // Return value of setting synced field should be checked. See bug 1656492.
1772     Unused << GetBrowsingContext()->ResetGVAutoplayRequestStatus();
1773   }
1774 #endif
1775 
1776 #ifdef DEBUG
1777   mLastOpenedURI = mDoc->GetDocumentURI();
1778 #endif
1779 
1780   Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
1781                         mMutationBits ? 1 : 0);
1782 
1783   // Clear our mutation bitfield.
1784   mMutationBits = 0;
1785 }
1786 
EnsureClientSource()1787 nsresult nsGlobalWindowInner::EnsureClientSource() {
1788   MOZ_DIAGNOSTIC_ASSERT(mDoc);
1789 
1790   bool newClientSource = false;
1791 
1792   // Get the load info for the document if we performed a load.  Be careful not
1793   // to look at local URLs, though. Local URLs are those that have a scheme of:
1794   //  * about:
1795   //  * data:
1796   //  * blob:
1797   // We also do an additional check here so that we only treat about:blank
1798   // and about:srcdoc as local URLs.  Other internal firefox about: URLs should
1799   // not be treated this way.
1800   nsCOMPtr<nsILoadInfo> loadInfo;
1801   nsCOMPtr<nsIChannel> channel = mDoc->GetChannel();
1802   if (channel) {
1803     nsCOMPtr<nsIURI> uri;
1804     Unused << channel->GetURI(getter_AddRefs(uri));
1805 
1806     bool ignoreLoadInfo = false;
1807 
1808     // Note, this is mostly copied from NS_IsAboutBlank().  Its duplicated
1809     // here so we can efficiently check about:srcdoc as well.
1810     if (uri->SchemeIs("about")) {
1811       nsCString spec = uri->GetSpecOrDefault();
1812       ignoreLoadInfo = spec.EqualsLiteral("about:blank") ||
1813                        spec.EqualsLiteral("about:srcdoc");
1814     } else {
1815       // Its not an about: URL, so now check for our other URL types.
1816       ignoreLoadInfo = uri->SchemeIs("data") || uri->SchemeIs("blob");
1817     }
1818 
1819     if (!ignoreLoadInfo) {
1820       loadInfo = channel->LoadInfo();
1821     }
1822   }
1823 
1824   // Take the initial client source from the docshell immediately.  Even if we
1825   // don't end up using it here we should consume it.
1826   UniquePtr<ClientSource> initialClientSource;
1827   nsIDocShell* docshell = GetDocShell();
1828   if (docshell) {
1829     initialClientSource = docshell->TakeInitialClientSource();
1830   }
1831 
1832   // Try to get the reserved client from the LoadInfo.  A Client is
1833   // reserved at the start of the channel load if there is not an
1834   // initial about:blank document that will be reused.  It is also
1835   // created if the channel load encounters a cross-origin redirect.
1836   if (loadInfo) {
1837     UniquePtr<ClientSource> reservedClient =
1838         loadInfo->TakeReservedClientSource();
1839     if (reservedClient) {
1840       mClientSource.reset();
1841       mClientSource = std::move(reservedClient);
1842       newClientSource = true;
1843     }
1844   }
1845 
1846   // We don't have a LoadInfo reserved client, but maybe we should
1847   // be inheriting an initial one from the docshell.  This means
1848   // that the docshell started the channel load before creating the
1849   // initial about:blank document.  This is an optimization, though,
1850   // and it created an initial Client as a placeholder for the document.
1851   // In this case we want to inherit this placeholder Client here.
1852   if (!mClientSource) {
1853     mClientSource = std::move(initialClientSource);
1854     if (mClientSource) {
1855       newClientSource = true;
1856     }
1857   }
1858 
1859   // Verify the final ClientSource principal matches the final document
1860   // principal.  The ClientChannelHelper handles things like network
1861   // redirects, but there are other ways the document principal can change.
1862   // For example, if something sets the nsIChannel.owner property, then
1863   // the final channel principal can be anything.  Unfortunately there is
1864   // no good way to detect this until after the channel completes loading.
1865   //
1866   // For now we handle this just by reseting the ClientSource.  This will
1867   // result in a new ClientSource with the correct principal being created.
1868   // To APIs like ServiceWorker and Clients API it will look like there was
1869   // an initial content page created that was then immediately replaced.
1870   // This is pretty close to what we are actually doing.
1871   if (mClientSource) {
1872     auto principalOrErr = mClientSource->Info().GetPrincipal();
1873     nsCOMPtr<nsIPrincipal> clientPrincipal =
1874         principalOrErr.isOk() ? principalOrErr.unwrap() : nullptr;
1875     if (!clientPrincipal || !clientPrincipal->Equals(mDoc->NodePrincipal())) {
1876       mClientSource.reset();
1877     }
1878   }
1879 
1880   // If we don't have a reserved client or an initial client, then create
1881   // one now.  This can happen in certain cases where we avoid preallocating
1882   // the client in the docshell.  This mainly occurs in situations where
1883   // the principal is not clearly inherited from the parent; e.g. sandboxed
1884   // iframes, window.open(), etc.
1885   //
1886   // We also do this late ClientSource creation if the final document ended
1887   // up with a different principal.
1888   //
1889   // TODO: We may not be marking initial about:blank documents created
1890   //       this way as controlled by a service worker properly.  The
1891   //       controller should be coming from the same place as the inheritted
1892   //       principal.  We do this in docshell, but as mentioned we aren't
1893   //       smart enough to handle all cases yet.  For example, a
1894   //       window.open() with new URL should inherit the controller from
1895   //       the opener, but we probably don't handle that yet.
1896   if (!mClientSource) {
1897     mClientSource = ClientManager::CreateSource(
1898         ClientType::Window, EventTargetFor(TaskCategory::Other),
1899         mDoc->NodePrincipal());
1900     MOZ_DIAGNOSTIC_ASSERT(mClientSource);
1901     newClientSource = true;
1902 
1903     // Note, we don't apply the loadinfo controller below if we create
1904     // the ClientSource here.
1905   }
1906 
1907   // The load may have started controlling the Client as well.  If
1908   // so, mark it as controlled immediately here.  The actor may
1909   // or may not have been notified by the parent side about being
1910   // controlled yet.
1911   //
1912   // Note: We should be careful not to control a client that was created late.
1913   //       These clients were not seen by the ServiceWorkerManager when it
1914   //       marked the LoadInfo controlled and it won't know about them.  Its
1915   //       also possible we are creating the client late due to the final
1916   //       principal changing and these clients should definitely not be
1917   //       controlled by a service worker with a different principal.
1918   else if (loadInfo) {
1919     const Maybe<ServiceWorkerDescriptor> controller = loadInfo->GetController();
1920     if (controller.isSome()) {
1921       mClientSource->SetController(controller.ref());
1922     }
1923 
1924     // We also have to handle the case where te initial about:blank is
1925     // controlled due to inheritting the service worker from its parent,
1926     // but the actual nsIChannel load is not covered by any service worker.
1927     // In this case we want the final page to be uncontrolled.  There is
1928     // an open spec issue about how exactly this should be handled, but for
1929     // now we just force creation of a new ClientSource to clear the
1930     // controller.
1931     //
1932     //  https://github.com/w3c/ServiceWorker/issues/1232
1933     //
1934     else if (mClientSource->GetController().isSome()) {
1935       mClientSource.reset();
1936       mClientSource = ClientManager::CreateSource(
1937           ClientType::Window, EventTargetFor(TaskCategory::Other),
1938           mDoc->NodePrincipal());
1939       MOZ_DIAGNOSTIC_ASSERT(mClientSource);
1940       newClientSource = true;
1941     }
1942   }
1943 
1944   if (mClientSource) {
1945     // Generally the CSP is stored within the Client and cached on the document.
1946     // At the time of CSP parsing however, the Client has not been created yet,
1947     // hence we store the CSP on the document and propagate/sync the CSP with
1948     // Client here when we create the Client.
1949     mClientSource->SetCsp(mDoc->GetCsp());
1950 
1951     DocGroup* docGroup = GetDocGroup();
1952     MOZ_DIAGNOSTIC_ASSERT(docGroup);
1953     mClientSource->SetAgentClusterId(docGroup->AgentClusterId());
1954 
1955     if (mWindowGlobalChild) {
1956       mWindowGlobalChild->SendSetClientInfo(mClientSource->Info().ToIPC());
1957     }
1958   }
1959 
1960   // Its possible that we got a client just after being frozen in
1961   // the bfcache.  In that case freeze the client immediately.
1962   if (newClientSource && IsFrozen()) {
1963     mClientSource->Freeze();
1964   }
1965 
1966   return NS_OK;
1967 }
1968 
ExecutionReady()1969 nsresult nsGlobalWindowInner::ExecutionReady() {
1970   nsresult rv = EnsureClientSource();
1971   NS_ENSURE_SUCCESS(rv, rv);
1972 
1973   rv = mClientSource->WindowExecutionReady(this);
1974   NS_ENSURE_SUCCESS(rv, rv);
1975 
1976   return NS_OK;
1977 }
1978 
UpdateParentTarget()1979 void nsGlobalWindowInner::UpdateParentTarget() {
1980   // NOTE: This method is identical to
1981   // nsGlobalWindowOuter::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
1982   // UPDATE THE OTHER ONE TOO!
1983 
1984   // Try to get our frame element's tab child global (its in-process message
1985   // manager).  If that fails, fall back to the chrome event handler's tab
1986   // child global, and if it doesn't have one, just use the chrome event
1987   // handler itself.
1988 
1989   nsPIDOMWindowOuter* outer = GetOuterWindow();
1990   if (!outer) {
1991     return;
1992   }
1993   nsCOMPtr<Element> frameElement = outer->GetFrameElementInternal();
1994   nsCOMPtr<EventTarget> eventTarget =
1995       nsContentUtils::TryGetBrowserChildGlobal(frameElement);
1996 
1997   if (!eventTarget) {
1998     nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
1999     if (topWin) {
2000       frameElement = topWin->GetFrameElementInternal();
2001       eventTarget = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
2002     }
2003   }
2004 
2005   if (!eventTarget) {
2006     eventTarget = nsContentUtils::TryGetBrowserChildGlobal(mChromeEventHandler);
2007   }
2008 
2009   if (!eventTarget) {
2010     eventTarget = mChromeEventHandler;
2011   }
2012 
2013   mParentTarget = eventTarget;
2014 }
2015 
GetTargetForDOMEvent()2016 EventTarget* nsGlobalWindowInner::GetTargetForDOMEvent() {
2017   return GetOuterWindowInternal();
2018 }
2019 
GetEventTargetParent(EventChainPreVisitor & aVisitor)2020 void nsGlobalWindowInner::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
2021   EventMessage msg = aVisitor.mEvent->mMessage;
2022 
2023   aVisitor.mCanHandle = true;
2024   aVisitor.mForceContentDispatch = true;  // FIXME! Bug 329119
2025   if (msg == eResize && aVisitor.mEvent->IsTrusted()) {
2026     // QIing to window so that we can keep the old behavior also in case
2027     // a child window is handling resize.
2028     nsCOMPtr<nsPIDOMWindowInner> window =
2029         do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
2030     if (window) {
2031       mIsHandlingResizeEvent = true;
2032     }
2033   } else if (msg == eMouseDown && aVisitor.mEvent->IsTrusted()) {
2034     sMouseDown = true;
2035   } else if ((msg == eMouseUp || msg == eDragEnd) &&
2036              aVisitor.mEvent->IsTrusted()) {
2037     sMouseDown = false;
2038     if (sDragServiceDisabled) {
2039       nsCOMPtr<nsIDragService> ds =
2040           do_GetService("@mozilla.org/widget/dragservice;1");
2041       if (ds) {
2042         sDragServiceDisabled = false;
2043         ds->Unsuppress();
2044       }
2045     }
2046   }
2047 
2048   aVisitor.SetParentTarget(GetParentTarget(), true);
2049 }
2050 
DialogsAreBeingAbused()2051 bool nsGlobalWindowInner::DialogsAreBeingAbused() {
2052   NS_ASSERTION(GetInProcessScriptableTopInternal() &&
2053                    GetInProcessScriptableTopInternal()
2054                            ->GetCurrentInnerWindowInternal() == this,
2055                "DialogsAreBeingAbused called with invalid window");
2056 
2057   if (mLastDialogQuitTime.IsNull() || nsContentUtils::IsCallerChrome()) {
2058     return false;
2059   }
2060 
2061   TimeDuration dialogInterval(TimeStamp::Now() - mLastDialogQuitTime);
2062   if (dialogInterval.ToSeconds() <
2063       Preferences::GetInt("dom.successive_dialog_time_limit",
2064                           DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT)) {
2065     mDialogAbuseCount++;
2066 
2067     return PopupBlocker::GetPopupControlState() > PopupBlocker::openAllowed ||
2068            mDialogAbuseCount > MAX_SUCCESSIVE_DIALOG_COUNT;
2069   }
2070 
2071   // Reset the abuse counter
2072   mDialogAbuseCount = 0;
2073 
2074   return false;
2075 }
2076 
FireFrameLoadEvent()2077 void nsGlobalWindowInner::FireFrameLoadEvent() {
2078   // If we're not in a content frame, or are at a BrowsingContext tree boundary,
2079   // such as the content-chrome boundary, don't fire the "load" event.
2080   if (GetBrowsingContext()->IsTopContent() ||
2081       GetBrowsingContext()->IsChrome()) {
2082     return;
2083   }
2084 
2085   // If embedder is same-process, fire the event on our embedder element.
2086   //
2087   // XXX: Bug 1440212 is looking into potentially changing this behaviour to act
2088   // more like the remote case when in-process.
2089   RefPtr<Element> element = GetBrowsingContext()->GetEmbedderElement();
2090   if (element) {
2091     nsEventStatus status = nsEventStatus_eIgnore;
2092     WidgetEvent event(/* aIsTrusted = */ true, eLoad);
2093     event.mFlags.mBubbles = false;
2094     event.mFlags.mCancelable = false;
2095 
2096     if (mozilla::dom::DocGroup::TryToLoadIframesInBackground()) {
2097       nsDocShell* ds = nsDocShell::Cast(GetDocShell());
2098 
2099       if (ds && !ds->HasFakeOnLoadDispatched()) {
2100         EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status);
2101       }
2102     } else {
2103       // Most of the time we could get a pres context to pass in here,
2104       // but not always (i.e. if this window is not shown there won't
2105       // be a pres context available). Since we're not firing a GUI
2106       // event we don't need a pres context anyway so we just pass
2107       // null as the pres context all the time here.
2108       EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status);
2109     }
2110     return;
2111   }
2112 
2113   // We don't have an in-process embedder. Try to get our `BrowserChild` actor
2114   // to send a message to that embedder. We want to double-check that our outer
2115   // window is actually the one at the root of this browserChild though, just in
2116   // case.
2117   RefPtr<BrowserChild> browserChild =
2118       BrowserChild::GetFrom(static_cast<nsPIDOMWindowInner*>(this));
2119   if (browserChild) {
2120     // Double-check that our outer window is actually at the root of this
2121     // `BrowserChild`, in case we're in an odd maybe-unhosted situation like a
2122     // print preview dialog.
2123     nsCOMPtr<nsPIDOMWindowOuter> rootOuter =
2124         do_GetInterface(browserChild->WebNavigation());
2125     if (!rootOuter || rootOuter != GetOuterWindow()) {
2126       return;
2127     }
2128 
2129     mozilla::Unused << browserChild->SendMaybeFireEmbedderLoadEvents(
2130         EmbedderElementEventType::LoadEvent);
2131   }
2132 }
2133 
PostHandleEvent(EventChainPostVisitor & aVisitor)2134 nsresult nsGlobalWindowInner::PostHandleEvent(EventChainPostVisitor& aVisitor) {
2135   // Return early if there is nothing to do.
2136   switch (aVisitor.mEvent->mMessage) {
2137     case eResize:
2138     case eUnload:
2139     case eLoad:
2140       break;
2141     default:
2142       return NS_OK;
2143   }
2144 
2145   /* mChromeEventHandler and mContext go dangling in the middle of this
2146    function under some circumstances (events that destroy the window)
2147    without this addref. */
2148   RefPtr<EventTarget> kungFuDeathGrip1(mChromeEventHandler);
2149   mozilla::Unused
2150       << kungFuDeathGrip1;  // These aren't referred to through the function
2151   nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
2152   mozilla::Unused
2153       << kungFuDeathGrip2;  // These aren't referred to through the function
2154 
2155   if (aVisitor.mEvent->mMessage == eResize) {
2156     mIsHandlingResizeEvent = false;
2157   } else if (aVisitor.mEvent->mMessage == eUnload &&
2158              aVisitor.mEvent->IsTrusted()) {
2159     // If any VR display presentation is active at unload, the next page
2160     // will receive a vrdisplayactive event to indicate that it should
2161     // immediately begin vr presentation. This should occur when navigating
2162     // forwards, navigating backwards, and on page reload.
2163     for (const auto& display : mVRDisplays) {
2164       if (display->IsPresenting()) {
2165         display->StartVRNavigation();
2166         // Save this VR display ID to trigger vrdisplayactivate event
2167         // after the next load event.
2168         nsGlobalWindowOuter* outer = GetOuterWindowInternal();
2169         if (outer) {
2170           outer->SetAutoActivateVRDisplayID(display->DisplayId());
2171         }
2172 
2173         // XXX The WebVR 1.1 spec does not define which of multiple VR
2174         // presenting VR displays will be chosen during navigation.
2175         // As the underlying platform VR API's currently only allow a single
2176         // VR display, it is safe to choose the first VR display for now.
2177         break;
2178       }
2179     }
2180     mIsDocumentLoaded = false;
2181     // Tell the parent process that the document is not loaded.
2182     if (mWindowGlobalChild) {
2183       mWindowGlobalChild->SendUpdateDocumentHasLoaded(mIsDocumentLoaded);
2184     }
2185   } else if (aVisitor.mEvent->mMessage == eLoad &&
2186              aVisitor.mEvent->IsTrusted()) {
2187     // This is page load event since load events don't propagate to |window|.
2188     // @see Document::GetEventTargetParent.
2189     mIsDocumentLoaded = true;
2190     // Tell the parent process that the document is loaded.
2191     if (mWindowGlobalChild) {
2192       mWindowGlobalChild->SendUpdateDocumentHasLoaded(mIsDocumentLoaded);
2193     }
2194 
2195     mTimeoutManager->OnDocumentLoaded();
2196 
2197     MOZ_ASSERT(aVisitor.mEvent->IsTrusted());
2198     FireFrameLoadEvent();
2199 
2200     if (mVREventObserver) {
2201       mVREventObserver->NotifyAfterLoad();
2202     }
2203 
2204     uint32_t autoActivateVRDisplayID = 0;
2205     nsGlobalWindowOuter* outer = GetOuterWindowInternal();
2206     if (outer) {
2207       autoActivateVRDisplayID = outer->GetAutoActivateVRDisplayID();
2208     }
2209     if (autoActivateVRDisplayID) {
2210       DispatchVRDisplayActivate(autoActivateVRDisplayID,
2211                                 VRDisplayEventReason::Navigation);
2212     }
2213   }
2214 
2215   return NS_OK;
2216 }
2217 
DefineArgumentsProperty(nsIArray * aArguments)2218 nsresult nsGlobalWindowInner::DefineArgumentsProperty(nsIArray* aArguments) {
2219   nsIScriptContext* ctx = GetOuterWindowInternal()->mContext;
2220   NS_ENSURE_TRUE(aArguments && ctx, NS_ERROR_NOT_INITIALIZED);
2221 
2222   JS::Rooted<JSObject*> obj(RootingCx(), GetWrapperPreserveColor());
2223   return ctx->SetProperty(obj, "arguments", aArguments);
2224 }
2225 
2226 //*****************************************************************************
2227 // nsGlobalWindowInner::nsIScriptObjectPrincipal
2228 //*****************************************************************************
2229 
GetPrincipal()2230 nsIPrincipal* nsGlobalWindowInner::GetPrincipal() {
2231   if (mDoc) {
2232     // If we have a document, get the principal from the document
2233     return mDoc->NodePrincipal();
2234   }
2235 
2236   if (mDocumentPrincipal) {
2237     return mDocumentPrincipal;
2238   }
2239 
2240   // If we don't have a principal and we don't have a document we
2241   // ask the parent window for the principal. This can happen when
2242   // loading a frameset that has a <frame src="javascript:xxx">, in
2243   // that case the global window is used in JS before we've loaded
2244   // a document into the window.
2245 
2246   nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2247       do_QueryInterface(GetInProcessParentInternal());
2248 
2249   if (objPrincipal) {
2250     return objPrincipal->GetPrincipal();
2251   }
2252 
2253   return nullptr;
2254 }
2255 
GetEffectiveStoragePrincipal()2256 nsIPrincipal* nsGlobalWindowInner::GetEffectiveStoragePrincipal() {
2257   if (mDoc) {
2258     // If we have a document, get the principal from the document
2259     return mDoc->EffectiveStoragePrincipal();
2260   }
2261 
2262   if (mDocumentStoragePrincipal) {
2263     return mDocumentStoragePrincipal;
2264   }
2265 
2266   // If we don't have a storage principal and we don't have a document we ask
2267   // the parent window for the storage principal.
2268 
2269   nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2270       do_QueryInterface(GetInProcessParentInternal());
2271 
2272   if (objPrincipal) {
2273     return objPrincipal->GetEffectiveStoragePrincipal();
2274   }
2275 
2276   return nullptr;
2277 }
2278 
PartitionedPrincipal()2279 nsIPrincipal* nsGlobalWindowInner::PartitionedPrincipal() {
2280   if (mDoc) {
2281     // If we have a document, get the principal from the document
2282     return mDoc->PartitionedPrincipal();
2283   }
2284 
2285   if (mDocumentPartitionedPrincipal) {
2286     return mDocumentPartitionedPrincipal;
2287   }
2288 
2289   // If we don't have a partitioned principal and we don't have a document we
2290   // ask the parent window for the partitioned principal.
2291 
2292   nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2293       do_QueryInterface(GetInProcessParentInternal());
2294 
2295   if (objPrincipal) {
2296     return objPrincipal->PartitionedPrincipal();
2297   }
2298 
2299   return nullptr;
2300 }
2301 
2302 //*****************************************************************************
2303 // nsGlobalWindowInner::nsIDOMWindow
2304 //*****************************************************************************
2305 
AddAudioContext(AudioContext * aAudioContext)2306 bool nsPIDOMWindowInner::AddAudioContext(AudioContext* aAudioContext) {
2307   mAudioContexts.AppendElement(aAudioContext);
2308 
2309   // Return true if the context should be muted and false if not.
2310   nsIDocShell* docShell = GetDocShell();
2311   return docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline();
2312 }
2313 
RemoveAudioContext(AudioContext * aAudioContext)2314 void nsPIDOMWindowInner::RemoveAudioContext(AudioContext* aAudioContext) {
2315   mAudioContexts.RemoveElement(aAudioContext);
2316 }
2317 
MuteAudioContexts()2318 void nsPIDOMWindowInner::MuteAudioContexts() {
2319   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
2320     if (!mAudioContexts[i]->IsOffline()) {
2321       mAudioContexts[i]->Mute();
2322     }
2323   }
2324 }
2325 
UnmuteAudioContexts()2326 void nsPIDOMWindowInner::UnmuteAudioContexts() {
2327   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
2328     if (!mAudioContexts[i]->IsOffline()) {
2329       mAudioContexts[i]->Unmute();
2330     }
2331   }
2332 }
2333 
Window()2334 WindowProxyHolder nsGlobalWindowInner::Window() {
2335   return WindowProxyHolder(GetBrowsingContext());
2336 }
2337 
Navigator()2338 Navigator* nsPIDOMWindowInner::Navigator() {
2339   if (!mNavigator) {
2340     mNavigator = new mozilla::dom::Navigator(this);
2341   }
2342 
2343   return mNavigator;
2344 }
2345 
VisualViewport()2346 VisualViewport* nsGlobalWindowInner::VisualViewport() {
2347   if (!mVisualViewport) {
2348     mVisualViewport = new mozilla::dom::VisualViewport(this);
2349   }
2350 
2351   return mVisualViewport;
2352 }
2353 
GetScreen(ErrorResult & aError)2354 nsScreen* nsGlobalWindowInner::GetScreen(ErrorResult& aError) {
2355   if (!mScreen) {
2356     mScreen = nsScreen::Create(this);
2357     if (!mScreen) {
2358       aError.Throw(NS_ERROR_UNEXPECTED);
2359       return nullptr;
2360     }
2361   }
2362 
2363   return mScreen;
2364 }
2365 
GetHistory(ErrorResult & aError)2366 nsHistory* nsGlobalWindowInner::GetHistory(ErrorResult& aError) {
2367   if (!mHistory) {
2368     mHistory = new nsHistory(this);
2369   }
2370 
2371   return mHistory;
2372 }
2373 
CustomElements()2374 CustomElementRegistry* nsGlobalWindowInner::CustomElements() {
2375   if (!mCustomElements) {
2376     mCustomElements = new CustomElementRegistry(this);
2377   }
2378 
2379   return mCustomElements;
2380 }
2381 
GetExistingCustomElements()2382 CustomElementRegistry* nsGlobalWindowInner::GetExistingCustomElements() {
2383   return mCustomElements;
2384 }
2385 
GetPerformance()2386 Performance* nsPIDOMWindowInner::GetPerformance() {
2387   CreatePerformanceObjectIfNeeded();
2388   return mPerformance;
2389 }
2390 
QueuePerformanceNavigationTiming()2391 void nsPIDOMWindowInner::QueuePerformanceNavigationTiming() {
2392   CreatePerformanceObjectIfNeeded();
2393   if (mPerformance) {
2394     mPerformance->QueueNavigationTimingEntry();
2395   }
2396 }
2397 
CreatePerformanceObjectIfNeeded()2398 void nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded() {
2399   if (mPerformance || !mDoc) {
2400     return;
2401   }
2402   RefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
2403   nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
2404   bool timingEnabled = false;
2405   if (!timedChannel ||
2406       !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
2407       !timingEnabled) {
2408     timedChannel = nullptr;
2409   }
2410   if (timing) {
2411     mPerformance = Performance::CreateForMainThread(this, mDoc->NodePrincipal(),
2412                                                     timing, timedChannel);
2413   }
2414 }
2415 
IsSecureContext() const2416 bool nsPIDOMWindowInner::IsSecureContext() const {
2417   return nsGlobalWindowInner::Cast(this)->IsSecureContext();
2418 }
2419 
Suspend(bool aIncludeSubWindows)2420 void nsPIDOMWindowInner::Suspend(bool aIncludeSubWindows) {
2421   nsGlobalWindowInner::Cast(this)->Suspend(aIncludeSubWindows);
2422 }
2423 
Resume(bool aIncludeSubWindows)2424 void nsPIDOMWindowInner::Resume(bool aIncludeSubWindows) {
2425   nsGlobalWindowInner::Cast(this)->Resume(aIncludeSubWindows);
2426 }
2427 
SyncStateFromParentWindow()2428 void nsPIDOMWindowInner::SyncStateFromParentWindow() {
2429   nsGlobalWindowInner::Cast(this)->SyncStateFromParentWindow();
2430 }
2431 
GetClientInfo() const2432 Maybe<ClientInfo> nsPIDOMWindowInner::GetClientInfo() const {
2433   return nsGlobalWindowInner::Cast(this)->GetClientInfo();
2434 }
2435 
GetClientState() const2436 Maybe<ClientState> nsPIDOMWindowInner::GetClientState() const {
2437   return nsGlobalWindowInner::Cast(this)->GetClientState();
2438 }
2439 
GetController() const2440 Maybe<ServiceWorkerDescriptor> nsPIDOMWindowInner::GetController() const {
2441   return nsGlobalWindowInner::Cast(this)->GetController();
2442 }
2443 
SetCsp(nsIContentSecurityPolicy * aCsp)2444 void nsPIDOMWindowInner::SetCsp(nsIContentSecurityPolicy* aCsp) {
2445   return nsGlobalWindowInner::Cast(this)->SetCsp(aCsp);
2446 }
2447 
SetPreloadCsp(nsIContentSecurityPolicy * aPreloadCsp)2448 void nsPIDOMWindowInner::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCsp) {
2449   return nsGlobalWindowInner::Cast(this)->SetPreloadCsp(aPreloadCsp);
2450 }
2451 
GetCsp()2452 nsIContentSecurityPolicy* nsPIDOMWindowInner::GetCsp() {
2453   return nsGlobalWindowInner::Cast(this)->GetCsp();
2454 }
2455 
NoteCalledRegisterForServiceWorkerScope(const nsACString & aScope)2456 void nsPIDOMWindowInner::NoteCalledRegisterForServiceWorkerScope(
2457     const nsACString& aScope) {
2458   nsGlobalWindowInner::Cast(this)->NoteCalledRegisterForServiceWorkerScope(
2459       aScope);
2460 }
2461 
NoteDOMContentLoaded()2462 void nsPIDOMWindowInner::NoteDOMContentLoaded() {
2463   nsGlobalWindowInner::Cast(this)->NoteDOMContentLoaded();
2464 }
2465 
ShouldReportForServiceWorkerScope(const nsAString & aScope)2466 bool nsGlobalWindowInner::ShouldReportForServiceWorkerScope(
2467     const nsAString& aScope) {
2468   bool result = false;
2469 
2470   nsPIDOMWindowOuter* topOuter = GetInProcessScriptableTop();
2471   NS_ENSURE_TRUE(topOuter, false);
2472 
2473   nsGlobalWindowInner* topInner =
2474       nsGlobalWindowInner::Cast(topOuter->GetCurrentInnerWindow());
2475   NS_ENSURE_TRUE(topInner, false);
2476 
2477   topInner->ShouldReportForServiceWorkerScopeInternal(
2478       NS_ConvertUTF16toUTF8(aScope), &result);
2479   return result;
2480 }
2481 
GetInstallTrigger()2482 InstallTriggerImpl* nsGlobalWindowInner::GetInstallTrigger() {
2483   if (!mInstallTrigger) {
2484     ErrorResult rv;
2485     mInstallTrigger = ConstructJSImplementation<InstallTriggerImpl>(
2486         "@mozilla.org/addons/installtrigger;1", this, rv);
2487     if (rv.Failed()) {
2488       rv.SuppressException();
2489       return nullptr;
2490     }
2491   }
2492 
2493   return mInstallTrigger;
2494 }
2495 
GetWindowUtils(ErrorResult & aRv)2496 nsIDOMWindowUtils* nsGlobalWindowInner::GetWindowUtils(ErrorResult& aRv) {
2497   FORWARD_TO_OUTER_OR_THROW(WindowUtils, (), aRv, nullptr);
2498 }
2499 
ShouldReportForServiceWorkerScopeInternal(const nsACString & aScope,bool * aResultOut)2500 CallState nsGlobalWindowInner::ShouldReportForServiceWorkerScopeInternal(
2501     const nsACString& aScope, bool* aResultOut) {
2502   MOZ_DIAGNOSTIC_ASSERT(aResultOut);
2503 
2504   // First check to see if this window is controlled.  If so, then we have
2505   // found a match and are done.
2506   const Maybe<ServiceWorkerDescriptor> swd = GetController();
2507   if (swd.isSome() && swd.ref().Scope() == aScope) {
2508     *aResultOut = true;
2509     return CallState::Stop;
2510   }
2511 
2512   // Next, check to see if this window has called
2513   // navigator.serviceWorker.register() for this scope.  If so, then treat this
2514   // as a match so console reports appear in the devtools console.
2515   if (mClientSource &&
2516       mClientSource->CalledRegisterForServiceWorkerScope(aScope)) {
2517     *aResultOut = true;
2518     return CallState::Stop;
2519   }
2520 
2521   // Finally check the current docshell nsILoadGroup to see if there are any
2522   // outstanding navigation requests.  If so, match the scope against the
2523   // channel's URL.  We want to show console reports during the FetchEvent
2524   // intercepting the navigation itself.
2525   nsCOMPtr<nsIDocumentLoader> loader(do_QueryInterface(GetDocShell()));
2526   if (loader) {
2527     nsCOMPtr<nsILoadGroup> loadgroup;
2528     Unused << loader->GetLoadGroup(getter_AddRefs(loadgroup));
2529     if (loadgroup) {
2530       nsCOMPtr<nsISimpleEnumerator> iter;
2531       Unused << loadgroup->GetRequests(getter_AddRefs(iter));
2532       if (iter) {
2533         nsCOMPtr<nsISupports> tmp;
2534         bool hasMore = true;
2535         // Check each network request in the load group.
2536         while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
2537           iter->GetNext(getter_AddRefs(tmp));
2538           nsCOMPtr<nsIChannel> loadingChannel(do_QueryInterface(tmp));
2539           // Ignore subresource requests.  Logging for a subresource
2540           // FetchEvent should be handled above since the client is
2541           // already controlled.
2542           if (!loadingChannel ||
2543               !nsContentUtils::IsNonSubresourceRequest(loadingChannel)) {
2544             continue;
2545           }
2546           nsCOMPtr<nsIURI> loadingURL;
2547           Unused << loadingChannel->GetURI(getter_AddRefs(loadingURL));
2548           if (!loadingURL) {
2549             continue;
2550           }
2551           nsAutoCString loadingSpec;
2552           Unused << loadingURL->GetSpec(loadingSpec);
2553           // Perform a simple substring comparison to match the scope
2554           // against the channel URL.
2555           if (StringBeginsWith(loadingSpec, aScope)) {
2556             *aResultOut = true;
2557             return CallState::Stop;
2558           }
2559         }
2560       }
2561     }
2562   }
2563 
2564   // The current window doesn't care about this service worker, but maybe
2565   // one of our child frames does.
2566   return CallOnInProcessChildren(
2567       &nsGlobalWindowInner::ShouldReportForServiceWorkerScopeInternal, aScope,
2568       aResultOut);
2569 }
2570 
NoteCalledRegisterForServiceWorkerScope(const nsACString & aScope)2571 void nsGlobalWindowInner::NoteCalledRegisterForServiceWorkerScope(
2572     const nsACString& aScope) {
2573   if (!mClientSource) {
2574     return;
2575   }
2576 
2577   mClientSource->NoteCalledRegisterForServiceWorkerScope(aScope);
2578 }
2579 
NoteDOMContentLoaded()2580 void nsGlobalWindowInner::NoteDOMContentLoaded() {
2581   if (!mClientSource) {
2582     return;
2583   }
2584 
2585   mClientSource->NoteDOMContentLoaded();
2586 }
2587 
UpdateTopInnerWindow()2588 void nsGlobalWindowInner::UpdateTopInnerWindow() {
2589   if (IsTopInnerWindow() || !mTopInnerWindow) {
2590     return;
2591   }
2592 
2593   mTopInnerWindow->UpdateWebSocketCount(-(int32_t)mNumOfOpenWebSockets);
2594 }
2595 
IsInSyncOperation()2596 bool nsGlobalWindowInner::IsInSyncOperation() {
2597   return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
2598 }
2599 
IsSharedMemoryAllowedInternal(nsIPrincipal * aPrincipal) const2600 bool nsGlobalWindowInner::IsSharedMemoryAllowedInternal(
2601     nsIPrincipal* aPrincipal) const {
2602   MOZ_ASSERT(NS_IsMainThread());
2603 
2604   if (StaticPrefs::
2605           dom_postMessage_sharedArrayBuffer_bypassCOOP_COEP_insecure_enabled()) {
2606     return true;
2607   }
2608 
2609   if (ExtensionPolicyService::GetSingleton().IsExtensionProcess()) {
2610     if (auto* basePrincipal = BasePrincipal::Cast(aPrincipal)) {
2611       if (auto* policy = basePrincipal->AddonPolicy()) {
2612         return policy->IsPrivileged();
2613       }
2614     }
2615   }
2616 
2617   return CrossOriginIsolated();
2618 }
2619 
CrossOriginIsolated() const2620 bool nsGlobalWindowInner::CrossOriginIsolated() const {
2621   MOZ_ASSERT(NS_IsMainThread());
2622 
2623   RefPtr<BrowsingContext> bc = GetBrowsingContext();
2624   MOZ_DIAGNOSTIC_ASSERT(bc);
2625   return bc->CrossOriginIsolated();
2626 }
2627 
AddPeerConnection()2628 void nsPIDOMWindowInner::AddPeerConnection() {
2629   MOZ_ASSERT(NS_IsMainThread());
2630   mTopInnerWindow ? mTopInnerWindow->mTotalActivePeerConnections++
2631                   : mTotalActivePeerConnections++;
2632   ++mActivePeerConnections;
2633   if (mActivePeerConnections == 1 && mWindowGlobalChild) {
2634     mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::ACTIVE_PEER_CONNECTION);
2635   }
2636 }
2637 
RemovePeerConnection()2638 void nsPIDOMWindowInner::RemovePeerConnection() {
2639   MOZ_ASSERT(NS_IsMainThread());
2640   MOZ_ASSERT(mTopInnerWindow ? mTopInnerWindow->mTotalActivePeerConnections
2641                              : mTotalActivePeerConnections);
2642   MOZ_ASSERT(mActivePeerConnections > 0);
2643 
2644   mTopInnerWindow ? mTopInnerWindow->mTotalActivePeerConnections--
2645                   : mTotalActivePeerConnections--;
2646   --mActivePeerConnections;
2647   if (mActivePeerConnections == 0 && mWindowGlobalChild) {
2648     mWindowGlobalChild->UnblockBFCacheFor(
2649         BFCacheStatus::ACTIVE_PEER_CONNECTION);
2650   }
2651 }
2652 
HasActivePeerConnections()2653 bool nsPIDOMWindowInner::HasActivePeerConnections() {
2654   MOZ_ASSERT(NS_IsMainThread());
2655   return mTopInnerWindow ? mTopInnerWindow->mTotalActivePeerConnections
2656                          : mTotalActivePeerConnections;
2657 }
2658 
AddMediaKeysInstance(MediaKeys * aMediaKeys)2659 void nsPIDOMWindowInner::AddMediaKeysInstance(MediaKeys* aMediaKeys) {
2660   MOZ_ASSERT(NS_IsMainThread());
2661   mMediaKeysInstances.AppendElement(aMediaKeys);
2662   if (mWindowGlobalChild && mMediaKeysInstances.Length() == 1) {
2663     mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::CONTAINS_EME_CONTENT);
2664   }
2665 }
2666 
RemoveMediaKeysInstance(MediaKeys * aMediaKeys)2667 void nsPIDOMWindowInner::RemoveMediaKeysInstance(MediaKeys* aMediaKeys) {
2668   MOZ_ASSERT(NS_IsMainThread());
2669   mMediaKeysInstances.RemoveElement(aMediaKeys);
2670   if (mWindowGlobalChild && mMediaKeysInstances.IsEmpty()) {
2671     mWindowGlobalChild->UnblockBFCacheFor(BFCacheStatus::CONTAINS_EME_CONTENT);
2672   }
2673 }
2674 
HasActiveMediaKeysInstance()2675 bool nsPIDOMWindowInner::HasActiveMediaKeysInstance() {
2676   MOZ_ASSERT(NS_IsMainThread());
2677   return !mMediaKeysInstances.IsEmpty();
2678 }
2679 
IsPlayingAudio()2680 bool nsPIDOMWindowInner::IsPlayingAudio() {
2681   for (uint32_t i = 0; i < mAudioContexts.Length(); i++) {
2682     if (mAudioContexts[i]->IsRunning()) {
2683       return true;
2684     }
2685   }
2686   RefPtr<AudioChannelService> acs = AudioChannelService::Get();
2687   if (!acs) {
2688     return false;
2689   }
2690   auto outer = GetOuterWindow();
2691   if (!outer) {
2692     // We've been unlinked and are about to die.  Not a good time to pretend to
2693     // be playing audio.
2694     return false;
2695   }
2696   return acs->IsWindowActive(outer);
2697 }
2698 
IsDocumentLoaded() const2699 bool nsPIDOMWindowInner::IsDocumentLoaded() const { return mIsDocumentLoaded; }
2700 
TimeoutManager()2701 mozilla::dom::TimeoutManager& nsPIDOMWindowInner::TimeoutManager() {
2702   return *mTimeoutManager;
2703 }
2704 
IsRunningTimeout()2705 bool nsPIDOMWindowInner::IsRunningTimeout() {
2706   return TimeoutManager().IsRunningTimeout();
2707 }
2708 
TryToCacheTopInnerWindow()2709 void nsPIDOMWindowInner::TryToCacheTopInnerWindow() {
2710   if (mHasTriedToCacheTopInnerWindow) {
2711     return;
2712   }
2713 
2714   nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(this);
2715 
2716   MOZ_ASSERT(!window->IsDying());
2717 
2718   mHasTriedToCacheTopInnerWindow = true;
2719 
2720   MOZ_ASSERT(window);
2721 
2722   if (nsCOMPtr<nsPIDOMWindowOuter> topOutter =
2723           window->GetInProcessScriptableTop()) {
2724     mTopInnerWindow = topOutter->GetCurrentInnerWindow();
2725   }
2726 }
2727 
UpdateActiveIndexedDBDatabaseCount(int32_t aDelta)2728 void nsPIDOMWindowInner::UpdateActiveIndexedDBDatabaseCount(int32_t aDelta) {
2729   MOZ_ASSERT(NS_IsMainThread());
2730 
2731   if (aDelta == 0) {
2732     return;
2733   }
2734 
2735   // We count databases but not transactions because only active databases
2736   // could block throttling.
2737   uint32_t& counter = mTopInnerWindow
2738                           ? mTopInnerWindow->mNumOfIndexedDBDatabases
2739                           : mNumOfIndexedDBDatabases;
2740 
2741   counter += aDelta;
2742 }
2743 
HasActiveIndexedDBDatabases()2744 bool nsPIDOMWindowInner::HasActiveIndexedDBDatabases() {
2745   MOZ_ASSERT(NS_IsMainThread());
2746 
2747   return mTopInnerWindow ? mTopInnerWindow->mNumOfIndexedDBDatabases > 0
2748                          : mNumOfIndexedDBDatabases > 0;
2749 }
2750 
UpdateWebSocketCount(int32_t aDelta)2751 void nsPIDOMWindowInner::UpdateWebSocketCount(int32_t aDelta) {
2752   MOZ_ASSERT(NS_IsMainThread());
2753 
2754   if (aDelta == 0) {
2755     return;
2756   }
2757 
2758   if (mTopInnerWindow && !IsTopInnerWindow()) {
2759     mTopInnerWindow->UpdateWebSocketCount(aDelta);
2760   }
2761 
2762   MOZ_DIAGNOSTIC_ASSERT(
2763       aDelta > 0 || ((aDelta + mNumOfOpenWebSockets) < mNumOfOpenWebSockets));
2764 
2765   mNumOfOpenWebSockets += aDelta;
2766 }
2767 
HasOpenWebSockets() const2768 bool nsPIDOMWindowInner::HasOpenWebSockets() const {
2769   MOZ_ASSERT(NS_IsMainThread());
2770 
2771   return mNumOfOpenWebSockets ||
2772          (mTopInnerWindow && mTopInnerWindow->mNumOfOpenWebSockets);
2773 }
2774 
IsCurrentInnerWindow() const2775 bool nsPIDOMWindowInner::IsCurrentInnerWindow() const {
2776   if (mozilla::SessionHistoryInParent() && mBrowsingContext &&
2777       mBrowsingContext->IsInBFCache()) {
2778     return false;
2779   }
2780 
2781   if (!mBrowsingContext || mBrowsingContext->IsDiscarded()) {
2782     // If our BrowsingContext has been discarded, we consider ourselves
2783     // still-current if we were current at the time it was discarded.
2784     return mOuterWindow && WasCurrentInnerWindow();
2785   }
2786 
2787   nsPIDOMWindowOuter* outer = mBrowsingContext->GetDOMWindow();
2788   return outer && outer->GetCurrentInnerWindow() == this;
2789 }
2790 
IsFullyActive() const2791 bool nsPIDOMWindowInner::IsFullyActive() const {
2792   WindowContext* wc = GetWindowContext();
2793   if (!wc || wc->IsDiscarded() || wc->IsCached()) {
2794     return false;
2795   }
2796   return GetBrowsingContext()->AncestorsAreCurrent();
2797 }
2798 
SetAudioCapture(bool aCapture)2799 void nsPIDOMWindowInner::SetAudioCapture(bool aCapture) {
2800   RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
2801   if (service) {
2802     service->SetWindowAudioCaptured(GetOuterWindow(), mWindowID, aCapture);
2803   }
2804 }
2805 
SetActiveLoadingState(bool aIsLoading)2806 void nsGlobalWindowInner::SetActiveLoadingState(bool aIsLoading) {
2807   MOZ_LOG(
2808       gTimeoutLog, mozilla::LogLevel::Debug,
2809       ("SetActiveLoadingState innerwindow %p: %d", (void*)this, aIsLoading));
2810   if (GetBrowsingContext()) {
2811     // Setting loading on a discarded context has no effect.
2812     Unused << GetBrowsingContext()->SetLoading(aIsLoading);
2813   }
2814 
2815   if (!nsGlobalWindowInner::Cast(this)->IsChromeWindow()) {
2816     mTimeoutManager->SetLoading(aIsLoading);
2817   }
2818 
2819   HintIsLoading(aIsLoading);
2820 }
2821 
HintIsLoading(bool aIsLoading)2822 void nsGlobalWindowInner::HintIsLoading(bool aIsLoading) {
2823   // Hint to tell the JS GC to use modified triggers during pageload.
2824   if (mHintedWasLoading != aIsLoading) {
2825     using namespace js::gc;
2826     SetPerformanceHint(danger::GetJSContext(), aIsLoading
2827                                                    ? PerformanceHint::InPageLoad
2828                                                    : PerformanceHint::Normal);
2829     mHintedWasLoading = aIsLoading;
2830   }
2831 }
2832 
2833 // nsISpeechSynthesisGetter
2834 
2835 #ifdef MOZ_WEBSPEECH
GetSpeechSynthesis(ErrorResult & aError)2836 SpeechSynthesis* nsGlobalWindowInner::GetSpeechSynthesis(ErrorResult& aError) {
2837   if (!mSpeechSynthesis) {
2838     mSpeechSynthesis = new SpeechSynthesis(this);
2839   }
2840 
2841   return mSpeechSynthesis;
2842 }
2843 
HasActiveSpeechSynthesis()2844 bool nsGlobalWindowInner::HasActiveSpeechSynthesis() {
2845   if (mSpeechSynthesis) {
2846     return !mSpeechSynthesis->HasEmptyQueue();
2847   }
2848 
2849   return false;
2850 }
2851 
2852 #endif
2853 
Glean()2854 mozilla::glean::Glean* nsGlobalWindowInner::Glean() {
2855   if (!mGlean) {
2856     mGlean = new mozilla::glean::Glean();
2857   }
2858 
2859   return mGlean;
2860 }
2861 
GleanPings()2862 mozilla::glean::GleanPings* nsGlobalWindowInner::GleanPings() {
2863   if (!mGleanPings) {
2864     mGleanPings = new mozilla::glean::GleanPings();
2865   }
2866 
2867   return mGleanPings;
2868 }
2869 
GetParent(ErrorResult & aError)2870 Nullable<WindowProxyHolder> nsGlobalWindowInner::GetParent(
2871     ErrorResult& aError) {
2872   FORWARD_TO_OUTER_OR_THROW(GetParentOuter, (), aError, nullptr);
2873 }
2874 
2875 /**
2876  * GetInProcessScriptableParent used to be called when a script read
2877  * window.parent. Under Fission, that is now handled by
2878  * BrowsingContext::GetParent, and the result is a WindowProxyHolder rather than
2879  * an actual global window. This method still exists for legacy callers which
2880  * relied on the old logic, and require in-process windows. However, it only
2881  * works correctly when no out-of-process frames exist between this window and
2882  * the top-level window, so it should not be used in new code.
2883  *
2884  * In contrast to GetRealParent, GetInProcessScriptableParent respects <iframe
2885  * mozbrowser> boundaries, so if |this| is contained by an <iframe
2886  * mozbrowser>, we will return |this| as its own parent.
2887  */
GetInProcessScriptableParent()2888 nsPIDOMWindowOuter* nsGlobalWindowInner::GetInProcessScriptableParent() {
2889   FORWARD_TO_OUTER(GetInProcessScriptableParent, (), nullptr);
2890 }
2891 
2892 /**
2893  * GetInProcessScriptableTop used to be called when a script read window.top.
2894  * Under Fission, that is now handled by BrowsingContext::Top, and the result is
2895  * a WindowProxyHolder rather than an actual global window. This method still
2896  * exists for legacy callers which relied on the old logic, and require
2897  * in-process windows. However, it only works correctly when no out-of-process
2898  * frames exist between this window and the top-level window, so it should not
2899  * be used in new code.
2900  *
2901  * In contrast to GetRealTop, GetInProcessScriptableTop respects <iframe
2902  * mozbrowser> boundaries.  If we encounter a window owned by an <iframe
2903  * mozbrowser> while walking up the window hierarchy, we'll stop and return that
2904  * window.
2905  */
GetInProcessScriptableTop()2906 nsPIDOMWindowOuter* nsGlobalWindowInner::GetInProcessScriptableTop() {
2907   FORWARD_TO_OUTER(GetInProcessScriptableTop, (), nullptr);
2908 }
2909 
GetContent(JSContext * aCx,JS::MutableHandle<JSObject * > aRetval,CallerType aCallerType,ErrorResult & aError)2910 void nsGlobalWindowInner::GetContent(JSContext* aCx,
2911                                      JS::MutableHandle<JSObject*> aRetval,
2912                                      CallerType aCallerType,
2913                                      ErrorResult& aError) {
2914   FORWARD_TO_OUTER_OR_THROW(GetContentOuter,
2915                             (aCx, aRetval, aCallerType, aError), aError, );
2916 }
2917 
GetMenubar(ErrorResult & aError)2918 BarProp* nsGlobalWindowInner::GetMenubar(ErrorResult& aError) {
2919   if (!mMenubar) {
2920     mMenubar = new MenubarProp(this);
2921   }
2922 
2923   return mMenubar;
2924 }
2925 
GetToolbar(ErrorResult & aError)2926 BarProp* nsGlobalWindowInner::GetToolbar(ErrorResult& aError) {
2927   if (!mToolbar) {
2928     mToolbar = new ToolbarProp(this);
2929   }
2930 
2931   return mToolbar;
2932 }
2933 
GetLocationbar(ErrorResult & aError)2934 BarProp* nsGlobalWindowInner::GetLocationbar(ErrorResult& aError) {
2935   if (!mLocationbar) {
2936     mLocationbar = new LocationbarProp(this);
2937   }
2938   return mLocationbar;
2939 }
2940 
GetPersonalbar(ErrorResult & aError)2941 BarProp* nsGlobalWindowInner::GetPersonalbar(ErrorResult& aError) {
2942   if (!mPersonalbar) {
2943     mPersonalbar = new PersonalbarProp(this);
2944   }
2945   return mPersonalbar;
2946 }
2947 
GetStatusbar(ErrorResult & aError)2948 BarProp* nsGlobalWindowInner::GetStatusbar(ErrorResult& aError) {
2949   if (!mStatusbar) {
2950     mStatusbar = new StatusbarProp(this);
2951   }
2952   return mStatusbar;
2953 }
2954 
GetScrollbars(ErrorResult & aError)2955 BarProp* nsGlobalWindowInner::GetScrollbars(ErrorResult& aError) {
2956   if (!mScrollbars) {
2957     mScrollbars = new ScrollbarsProp(this);
2958   }
2959 
2960   return mScrollbars;
2961 }
2962 
GetClosed(ErrorResult & aError)2963 bool nsGlobalWindowInner::GetClosed(ErrorResult& aError) {
2964   // If we're called from JS (which is the only way we should be getting called
2965   // here) and we reach this point, that means our JS global is the current
2966   // target of the WindowProxy, which means that we are the "current inner"
2967   // of our outer. So if FORWARD_TO_OUTER fails to forward, that means the
2968   // outer is already torn down, which corresponds to the closed state.
2969   FORWARD_TO_OUTER(GetClosedOuter, (), true);
2970 }
2971 
IndexedGetter(uint32_t aIndex)2972 Nullable<WindowProxyHolder> nsGlobalWindowInner::IndexedGetter(
2973     uint32_t aIndex) {
2974   FORWARD_TO_OUTER(IndexedGetterOuter, (aIndex), nullptr);
2975 }
2976 
2977 namespace {
2978 
2979 struct InterfaceShimEntry {
2980   const char* geckoName;
2981   const char* domName;
2982 };
2983 
2984 }  // anonymous namespace
2985 
2986 // We add shims from Components.interfaces.nsIDOMFoo to window.Foo for each
2987 // interface that has interface constants that sites might be getting off
2988 // of Ci.
2989 const InterfaceShimEntry kInterfaceShimMap[] = {
2990     {"nsIXMLHttpRequest", "XMLHttpRequest"},
2991     {"nsIDOMDOMException", "DOMException"},
2992     {"nsIDOMNode", "Node"},
2993     {"nsIDOMCSSRule", "CSSRule"},
2994     {"nsIDOMEvent", "Event"},
2995     {"nsIDOMNSEvent", "Event"},
2996     {"nsIDOMKeyEvent", "KeyEvent"},
2997     {"nsIDOMMouseEvent", "MouseEvent"},
2998     {"nsIDOMMouseScrollEvent", "MouseScrollEvent"},
2999     {"nsIDOMMutationEvent", "MutationEvent"},
3000     {"nsIDOMUIEvent", "UIEvent"},
3001     {"nsIDOMHTMLMediaElement", "HTMLMediaElement"},
3002     {"nsIDOMRange", "Range"},
3003     // Think about whether Ci.nsINodeFilter can just go away for websites!
3004     {"nsIDOMNodeFilter", "NodeFilter"},
3005     {"nsIDOMXPathResult", "XPathResult"}};
3006 
ResolveComponentsShim(JSContext * aCx,JS::Handle<JSObject * > aGlobal,JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc)3007 bool nsGlobalWindowInner::ResolveComponentsShim(
3008     JSContext* aCx, JS::Handle<JSObject*> aGlobal,
3009     JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc) {
3010   // Keep track of how often this happens.
3011   Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true);
3012 
3013   // Warn once.
3014   nsCOMPtr<Document> doc = GetExtantDoc();
3015   if (doc) {
3016     doc->WarnOnceAbout(DeprecatedOperations::eComponents, /* asError = */ true);
3017   }
3018 
3019   // Create a fake Components object.
3020   AssertSameCompartment(aCx, aGlobal);
3021   JS::Rooted<JSObject*> components(aCx, JS_NewPlainObject(aCx));
3022   if (NS_WARN_IF(!components)) {
3023     return false;
3024   }
3025 
3026   // Create a fake interfaces object.
3027   JS::Rooted<JSObject*> interfaces(aCx, JS_NewPlainObject(aCx));
3028   if (NS_WARN_IF(!interfaces)) {
3029     return false;
3030   }
3031   bool ok =
3032       JS_DefineProperty(aCx, components, "interfaces", interfaces,
3033                         JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
3034   if (NS_WARN_IF(!ok)) {
3035     return false;
3036   }
3037 
3038   // Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM
3039   // interfaces with constants.
3040   for (uint32_t i = 0; i < ArrayLength(kInterfaceShimMap); ++i) {
3041     // Grab the names from the table.
3042     const char* geckoName = kInterfaceShimMap[i].geckoName;
3043     const char* domName = kInterfaceShimMap[i].domName;
3044 
3045     // Look up the appopriate interface object on the global.
3046     JS::Rooted<JS::Value> v(aCx, JS::UndefinedValue());
3047     ok = JS_GetProperty(aCx, aGlobal, domName, &v);
3048     if (NS_WARN_IF(!ok)) {
3049       return false;
3050     }
3051     if (!v.isObject()) {
3052       NS_WARNING("Unable to find interface object on global");
3053       continue;
3054     }
3055 
3056     // Define the shim on the interfaces object.
3057     ok = JS_DefineProperty(
3058         aCx, interfaces, geckoName, v,
3059         JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
3060     if (NS_WARN_IF(!ok)) {
3061       return false;
3062     }
3063   }
3064 
3065   aDesc.set(mozilla::Some(JS::PropertyDescriptor::Data(
3066       JS::ObjectValue(*components),
3067       {JS::PropertyAttribute::Configurable, JS::PropertyAttribute::Enumerable,
3068        JS::PropertyAttribute::Writable})));
3069   return true;
3070 }
3071 
3072 #ifdef RELEASE_OR_BETA
3073 #  define USE_CONTROLLERS_SHIM
3074 #endif
3075 
3076 #ifdef USE_CONTROLLERS_SHIM
3077 static const JSClass ControllersShimClass = {"Controllers", 0};
3078 static const JSClass XULControllersShimClass = {"XULControllers", 0};
3079 #endif
3080 
DoResolve(JSContext * aCx,JS::Handle<JSObject * > aObj,JS::Handle<jsid> aId,JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc)3081 bool nsGlobalWindowInner::DoResolve(
3082     JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId,
3083     JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc) {
3084   // Note: Keep this in sync with MayResolve.
3085 
3086   // Note: The infallibleInit call in GlobalResolve depends on this check.
3087   if (!JSID_IS_STRING(aId)) {
3088     return true;
3089   }
3090 
3091   bool found;
3092   if (!WebIDLGlobalNameHash::DefineIfEnabled(aCx, aObj, aId, aDesc, &found)) {
3093     return false;
3094   }
3095 
3096   if (found) {
3097     return true;
3098   }
3099 
3100   // We support a cut-down Components.interfaces in case websites are
3101   // using Components.interfaces.nsIFoo.CONSTANT_NAME for the ones
3102   // that have constants.
3103   if (StaticPrefs::dom_use_components_shim() &&
3104       aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) {
3105     return ResolveComponentsShim(aCx, aObj, aDesc);
3106   }
3107 
3108   // We also support a "window.controllers" thing; apparently some
3109   // sites use it for browser-sniffing.  See bug 1010577.
3110 #ifdef USE_CONTROLLERS_SHIM
3111   // Note: We use |aObj| rather than |this| to get the principal here, because
3112   // this is called during Window setup when the Document isn't necessarily
3113   // hooked up yet.
3114   if ((aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS) ||
3115        aId == XPCJSRuntime::Get()->GetStringID(
3116                   XPCJSContext::IDX_CONTROLLERS_CLASS)) &&
3117       !xpc::IsXrayWrapper(aObj) &&
3118       !nsContentUtils::ObjectPrincipal(aObj)->IsSystemPrincipal()) {
3119     if (GetExtantDoc()) {
3120       GetExtantDoc()->WarnOnceAbout(
3121           DeprecatedOperations::eWindow_Cc_ontrollers);
3122     }
3123     const JSClass* clazz;
3124     if (aId ==
3125         XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS)) {
3126       clazz = &XULControllersShimClass;
3127     } else {
3128       clazz = &ControllersShimClass;
3129     }
3130     MOZ_ASSERT(JS_IsGlobalObject(aObj));
3131     JS::Rooted<JSObject*> shim(aCx, JS_NewObject(aCx, clazz));
3132     if (NS_WARN_IF(!shim)) {
3133       return false;
3134     }
3135 
3136     aDesc.set(mozilla::Some(JS::PropertyDescriptor::Data(
3137         JS::ObjectValue(*shim),
3138         {JS::PropertyAttribute::Configurable, JS::PropertyAttribute::Enumerable,
3139          JS::PropertyAttribute::Writable})));
3140     return true;
3141   }
3142 #endif
3143 
3144   return true;
3145 }
3146 
3147 /* static */
MayResolve(jsid aId)3148 bool nsGlobalWindowInner::MayResolve(jsid aId) {
3149   // Note: This function does not fail and may not have any side-effects.
3150   // Note: Keep this in sync with DoResolve.
3151   if (!JSID_IS_STRING(aId)) {
3152     return false;
3153   }
3154 
3155   if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) {
3156     return true;
3157   }
3158 
3159   if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS) ||
3160       aId == XPCJSRuntime::Get()->GetStringID(
3161                  XPCJSContext::IDX_CONTROLLERS_CLASS)) {
3162     // We only resolve .controllers/.Controllers in release builds and on
3163     // non-chrome windows, but let's not worry about any of that stuff.
3164     return true;
3165   }
3166 
3167   return WebIDLGlobalNameHash::MayResolve(aId);
3168 }
3169 
GetOwnPropertyNames(JSContext * aCx,JS::MutableHandleVector<jsid> aNames,bool aEnumerableOnly,ErrorResult & aRv)3170 void nsGlobalWindowInner::GetOwnPropertyNames(
3171     JSContext* aCx, JS::MutableHandleVector<jsid> aNames, bool aEnumerableOnly,
3172     ErrorResult& aRv) {
3173   if (aEnumerableOnly) {
3174     // The names we would return from here get defined on the window via one of
3175     // two codepaths.  The ones coming from the WebIDLGlobalNameHash will end up
3176     // in the DefineConstructor function in BindingUtils, which always defines
3177     // things as non-enumerable.  The ones coming from the script namespace
3178     // manager get defined by our resolve hook using FillPropertyDescriptor with
3179     // 0 for the property attributes, so non-enumerable as well.
3180     //
3181     // So in the aEnumerableOnly case we have nothing to do.
3182     return;
3183   }
3184 
3185   // "Components" is marked as enumerable but only resolved on demand :-/.
3186   // aNames.AppendElement(u"Components"_ns);
3187 
3188   JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
3189 
3190   // There are actually two ways we can get called here: For normal
3191   // enumeration or for Xray enumeration.  In the latter case, we want to
3192   // return all possible WebIDL names, because we don't really support
3193   // deleting these names off our Xray; trying to resolve them will just make
3194   // them come back.  In the former case, we want to avoid returning deleted
3195   // names.  But the JS engine already knows about the non-deleted
3196   // already-resolved names, so we can just return the so-far-unresolved ones.
3197   //
3198   // We can tell which case we're in by whether aCx is in our wrapper's
3199   // compartment.  If not, we're in the Xray case.
3200   WebIDLGlobalNameHash::NameType nameType =
3201       js::IsObjectInContextCompartment(wrapper, aCx)
3202           ? WebIDLGlobalNameHash::UnresolvedNamesOnly
3203           : WebIDLGlobalNameHash::AllNames;
3204   if (!WebIDLGlobalNameHash::GetNames(aCx, wrapper, nameType, aNames)) {
3205     aRv.NoteJSContextException(aCx);
3206   }
3207 }
3208 
3209 /* static */
IsPrivilegedChromeWindow(JSContext *,JSObject * aObj)3210 bool nsGlobalWindowInner::IsPrivilegedChromeWindow(JSContext*, JSObject* aObj) {
3211   // For now, have to deal with XPConnect objects here.
3212   nsGlobalWindowInner* win = xpc::WindowOrNull(aObj);
3213   return win && win->IsChromeWindow() &&
3214          nsContentUtils::ObjectPrincipal(aObj) ==
3215              nsContentUtils::GetSystemPrincipal();
3216 }
3217 
3218 /* static */
IsRequestIdleCallbackEnabled(JSContext * aCx,JSObject *)3219 bool nsGlobalWindowInner::IsRequestIdleCallbackEnabled(JSContext* aCx,
3220                                                        JSObject*) {
3221   // The requestIdleCallback should always be enabled for system code.
3222   return StaticPrefs::dom_requestIdleCallback_enabled() ||
3223          nsContentUtils::IsSystemCaller(aCx);
3224 }
3225 
3226 /* static */
DeviceSensorsEnabled(JSContext *,JSObject *)3227 bool nsGlobalWindowInner::DeviceSensorsEnabled(JSContext*, JSObject*) {
3228   return Preferences::GetBool("device.sensors.enabled");
3229 }
3230 
3231 /* static */
ContentPropertyEnabled(JSContext * aCx,JSObject *)3232 bool nsGlobalWindowInner::ContentPropertyEnabled(JSContext* aCx, JSObject*) {
3233   return StaticPrefs::dom_window_content_untrusted_enabled() ||
3234          nsContentUtils::IsSystemCaller(aCx);
3235 }
3236 
GetApplicationCache(ErrorResult & aError)3237 nsDOMOfflineResourceList* nsGlobalWindowInner::GetApplicationCache(
3238     ErrorResult& aError) {
3239   if (!mApplicationCache) {
3240     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
3241     if (!webNav || !mDoc) {
3242       aError.Throw(NS_ERROR_FAILURE);
3243       return nullptr;
3244     }
3245 
3246     nsCOMPtr<nsIURI> uri;
3247     aError = webNav->GetCurrentURI(getter_AddRefs(uri));
3248     if (aError.Failed()) {
3249       return nullptr;
3250     }
3251 
3252     nsCOMPtr<nsIURI> manifestURI;
3253     nsContentUtils::GetOfflineAppManifest(mDoc, getter_AddRefs(manifestURI));
3254 
3255     RefPtr<nsDOMOfflineResourceList> applicationCache =
3256         new nsDOMOfflineResourceList(manifestURI, uri, mDoc->NodePrincipal(),
3257                                      this);
3258 
3259     mApplicationCache = applicationCache;
3260   }
3261 
3262   return mApplicationCache;
3263 }
3264 
GetApplicationCache()3265 nsDOMOfflineResourceList* nsGlobalWindowInner::GetApplicationCache() {
3266   return GetApplicationCache(IgnoreErrors());
3267 }
3268 
GetCrypto(ErrorResult & aError)3269 Crypto* nsGlobalWindowInner::GetCrypto(ErrorResult& aError) {
3270   if (!mCrypto) {
3271     mCrypto = new Crypto(this);
3272   }
3273   return mCrypto;
3274 }
3275 
GetU2f(ErrorResult & aError)3276 mozilla::dom::U2F* nsGlobalWindowInner::GetU2f(ErrorResult& aError) {
3277   if (!mU2F) {
3278     RefPtr<U2F> u2f = new U2F(this);
3279     u2f->Init(aError);
3280     if (NS_WARN_IF(aError.Failed())) {
3281       return nullptr;
3282     }
3283 
3284     mU2F = u2f;
3285   }
3286   return mU2F;
3287 }
3288 
GetControllers(ErrorResult & aError)3289 nsIControllers* nsGlobalWindowInner::GetControllers(ErrorResult& aError) {
3290   FORWARD_TO_OUTER_OR_THROW(GetControllersOuter, (aError), aError, nullptr);
3291 }
3292 
GetControllers(nsIControllers ** aResult)3293 nsresult nsGlobalWindowInner::GetControllers(nsIControllers** aResult) {
3294   ErrorResult rv;
3295   nsCOMPtr<nsIControllers> controllers = GetControllers(rv);
3296   controllers.forget(aResult);
3297 
3298   return rv.StealNSResult();
3299 }
3300 
GetOpenerWindow(ErrorResult & aError)3301 Nullable<WindowProxyHolder> nsGlobalWindowInner::GetOpenerWindow(
3302     ErrorResult& aError) {
3303   FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter, (), aError, nullptr);
3304 }
3305 
GetOpener(JSContext * aCx,JS::MutableHandle<JS::Value> aRetval,ErrorResult & aError)3306 void nsGlobalWindowInner::GetOpener(JSContext* aCx,
3307                                     JS::MutableHandle<JS::Value> aRetval,
3308                                     ErrorResult& aError) {
3309   Nullable<WindowProxyHolder> opener = GetOpenerWindow(aError);
3310   if (aError.Failed() || opener.IsNull()) {
3311     aRetval.setNull();
3312     return;
3313   }
3314 
3315   if (!ToJSValue(aCx, opener.Value(), aRetval)) {
3316     aError.NoteJSContextException(aCx);
3317   }
3318 }
3319 
SetOpener(JSContext * aCx,JS::Handle<JS::Value> aOpener,ErrorResult & aError)3320 void nsGlobalWindowInner::SetOpener(JSContext* aCx,
3321                                     JS::Handle<JS::Value> aOpener,
3322                                     ErrorResult& aError) {
3323   if (aOpener.isNull()) {
3324     RefPtr<BrowsingContext> bc(GetBrowsingContext());
3325     if (!bc->IsDiscarded()) {
3326       bc->SetOpener(nullptr);
3327     }
3328     return;
3329   }
3330 
3331   // If something other than null is passed, just define aOpener on our inner
3332   // window's JS object, wrapped into the current compartment so that for Xrays
3333   // we define on the Xray expando object, but don't set it on the outer window,
3334   // so that it'll get reset on navigation.  This is just like replaceable
3335   // properties, but we're not quite readonly.
3336   RedefineProperty(aCx, "opener", aOpener, aError);
3337 }
3338 
GetEvent(JSContext * aCx,JS::MutableHandle<JS::Value> aRetval)3339 void nsGlobalWindowInner::GetEvent(JSContext* aCx,
3340                                    JS::MutableHandle<JS::Value> aRetval) {
3341   if (mEvent) {
3342     Unused << nsContentUtils::WrapNative(aCx, mEvent, aRetval);
3343   } else {
3344     aRetval.setUndefined();
3345   }
3346 }
3347 
GetStatus(nsAString & aStatus,ErrorResult & aError)3348 void nsGlobalWindowInner::GetStatus(nsAString& aStatus, ErrorResult& aError) {
3349   FORWARD_TO_OUTER_OR_THROW(GetStatusOuter, (aStatus), aError, );
3350 }
3351 
SetStatus(const nsAString & aStatus,ErrorResult & aError)3352 void nsGlobalWindowInner::SetStatus(const nsAString& aStatus,
3353                                     ErrorResult& aError) {
3354   FORWARD_TO_OUTER_OR_THROW(SetStatusOuter, (aStatus), aError, );
3355 }
3356 
GetName(nsAString & aName,ErrorResult & aError)3357 void nsGlobalWindowInner::GetName(nsAString& aName, ErrorResult& aError) {
3358   FORWARD_TO_OUTER_OR_THROW(GetNameOuter, (aName), aError, );
3359 }
3360 
SetName(const nsAString & aName,mozilla::ErrorResult & aError)3361 void nsGlobalWindowInner::SetName(const nsAString& aName,
3362                                   mozilla::ErrorResult& aError) {
3363   FORWARD_TO_OUTER_OR_THROW(SetNameOuter, (aName, aError), aError, );
3364 }
3365 
GetInnerWidth(CallerType aCallerType,ErrorResult & aError)3366 double nsGlobalWindowInner::GetInnerWidth(CallerType aCallerType,
3367                                           ErrorResult& aError) {
3368   // We ignore aCallerType; we only have that argument because some other things
3369   // called by GetReplaceableWindowCoord need it.  If this ever changes, fix
3370   //   nsresult nsGlobalWindowInner::GetInnerWidth(double* aInnerWidth)
3371   // to actually take a useful CallerType and pass it in here.
3372   FORWARD_TO_OUTER_OR_THROW(GetInnerWidthOuter, (aError), aError, 0);
3373 }
3374 
GetInnerWidth(JSContext * aCx,JS::MutableHandle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3375 void nsGlobalWindowInner::GetInnerWidth(JSContext* aCx,
3376                                         JS::MutableHandle<JS::Value> aValue,
3377                                         CallerType aCallerType,
3378                                         ErrorResult& aError) {
3379   GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetInnerWidth, aValue,
3380                             aCallerType, aError);
3381 }
3382 
GetInnerWidth(double * aInnerWidth)3383 nsresult nsGlobalWindowInner::GetInnerWidth(double* aInnerWidth) {
3384   ErrorResult rv;
3385   // Callee doesn't care about the caller type, but play it safe.
3386   *aInnerWidth = GetInnerWidth(CallerType::NonSystem, rv);
3387 
3388   return rv.StealNSResult();
3389 }
3390 
SetInnerWidth(double aInnerWidth,CallerType aCallerType,ErrorResult & aError)3391 void nsGlobalWindowInner::SetInnerWidth(double aInnerWidth,
3392                                         CallerType aCallerType,
3393                                         ErrorResult& aError) {
3394   FORWARD_TO_OUTER_OR_THROW(SetInnerWidthOuter,
3395                             (aInnerWidth, aCallerType, aError), aError, );
3396 }
3397 
SetInnerWidth(JSContext * aCx,JS::Handle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3398 void nsGlobalWindowInner::SetInnerWidth(JSContext* aCx,
3399                                         JS::Handle<JS::Value> aValue,
3400                                         CallerType aCallerType,
3401                                         ErrorResult& aError) {
3402   SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetInnerWidth, aValue,
3403                             "innerWidth", aCallerType, aError);
3404 }
3405 
GetInnerHeight(CallerType aCallerType,ErrorResult & aError)3406 double nsGlobalWindowInner::GetInnerHeight(CallerType aCallerType,
3407                                            ErrorResult& aError) {
3408   // We ignore aCallerType; we only have that argument because some other things
3409   // called by GetReplaceableWindowCoord need it.  If this ever changes, fix
3410   //   nsresult nsGlobalWindowInner::GetInnerHeight(double* aInnerWidth)
3411   // to actually take a useful CallerType and pass it in here.
3412   FORWARD_TO_OUTER_OR_THROW(GetInnerHeightOuter, (aError), aError, 0);
3413 }
3414 
GetInnerHeight(JSContext * aCx,JS::MutableHandle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3415 void nsGlobalWindowInner::GetInnerHeight(JSContext* aCx,
3416                                          JS::MutableHandle<JS::Value> aValue,
3417                                          CallerType aCallerType,
3418                                          ErrorResult& aError) {
3419   GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetInnerHeight, aValue,
3420                             aCallerType, aError);
3421 }
3422 
GetInnerHeight(double * aInnerHeight)3423 nsresult nsGlobalWindowInner::GetInnerHeight(double* aInnerHeight) {
3424   ErrorResult rv;
3425   // Callee doesn't care about the caller type, but play it safe.
3426   *aInnerHeight = GetInnerHeight(CallerType::NonSystem, rv);
3427 
3428   return rv.StealNSResult();
3429 }
3430 
SetInnerHeight(double aInnerHeight,CallerType aCallerType,ErrorResult & aError)3431 void nsGlobalWindowInner::SetInnerHeight(double aInnerHeight,
3432                                          CallerType aCallerType,
3433                                          ErrorResult& aError) {
3434   FORWARD_TO_OUTER_OR_THROW(SetInnerHeightOuter,
3435                             (aInnerHeight, aCallerType, aError), aError, );
3436 }
3437 
SetInnerHeight(JSContext * aCx,JS::Handle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3438 void nsGlobalWindowInner::SetInnerHeight(JSContext* aCx,
3439                                          JS::Handle<JS::Value> aValue,
3440                                          CallerType aCallerType,
3441                                          ErrorResult& aError) {
3442   SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetInnerHeight, aValue,
3443                             "innerHeight", aCallerType, aError);
3444 }
3445 
GetOuterWidth(CallerType aCallerType,ErrorResult & aError)3446 int32_t nsGlobalWindowInner::GetOuterWidth(CallerType aCallerType,
3447                                            ErrorResult& aError) {
3448   FORWARD_TO_OUTER_OR_THROW(GetOuterWidthOuter, (aCallerType, aError), aError,
3449                             0);
3450 }
3451 
GetOuterWidth(JSContext * aCx,JS::MutableHandle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3452 void nsGlobalWindowInner::GetOuterWidth(JSContext* aCx,
3453                                         JS::MutableHandle<JS::Value> aValue,
3454                                         CallerType aCallerType,
3455                                         ErrorResult& aError) {
3456   GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetOuterWidth, aValue,
3457                             aCallerType, aError);
3458 }
3459 
GetOuterHeight(CallerType aCallerType,ErrorResult & aError)3460 int32_t nsGlobalWindowInner::GetOuterHeight(CallerType aCallerType,
3461                                             ErrorResult& aError) {
3462   FORWARD_TO_OUTER_OR_THROW(GetOuterHeightOuter, (aCallerType, aError), aError,
3463                             0);
3464 }
3465 
GetOuterHeight(JSContext * aCx,JS::MutableHandle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3466 void nsGlobalWindowInner::GetOuterHeight(JSContext* aCx,
3467                                          JS::MutableHandle<JS::Value> aValue,
3468                                          CallerType aCallerType,
3469                                          ErrorResult& aError) {
3470   GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetOuterHeight, aValue,
3471                             aCallerType, aError);
3472 }
3473 
SetOuterWidth(int32_t aOuterWidth,CallerType aCallerType,ErrorResult & aError)3474 void nsGlobalWindowInner::SetOuterWidth(int32_t aOuterWidth,
3475                                         CallerType aCallerType,
3476                                         ErrorResult& aError) {
3477   FORWARD_TO_OUTER_OR_THROW(SetOuterWidthOuter,
3478                             (aOuterWidth, aCallerType, aError), aError, );
3479 }
3480 
SetOuterWidth(JSContext * aCx,JS::Handle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3481 void nsGlobalWindowInner::SetOuterWidth(JSContext* aCx,
3482                                         JS::Handle<JS::Value> aValue,
3483                                         CallerType aCallerType,
3484                                         ErrorResult& aError) {
3485   SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetOuterWidth, aValue,
3486                             "outerWidth", aCallerType, aError);
3487 }
3488 
SetOuterHeight(int32_t aOuterHeight,CallerType aCallerType,ErrorResult & aError)3489 void nsGlobalWindowInner::SetOuterHeight(int32_t aOuterHeight,
3490                                          CallerType aCallerType,
3491                                          ErrorResult& aError) {
3492   FORWARD_TO_OUTER_OR_THROW(SetOuterHeightOuter,
3493                             (aOuterHeight, aCallerType, aError), aError, );
3494 }
3495 
SetOuterHeight(JSContext * aCx,JS::Handle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3496 void nsGlobalWindowInner::SetOuterHeight(JSContext* aCx,
3497                                          JS::Handle<JS::Value> aValue,
3498                                          CallerType aCallerType,
3499                                          ErrorResult& aError) {
3500   SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetOuterHeight, aValue,
3501                             "outerHeight", aCallerType, aError);
3502 }
3503 
GetScreenX(CallerType aCallerType,ErrorResult & aError)3504 int32_t nsGlobalWindowInner::GetScreenX(CallerType aCallerType,
3505                                         ErrorResult& aError) {
3506   FORWARD_TO_OUTER_OR_THROW(GetScreenXOuter, (aCallerType, aError), aError, 0);
3507 }
3508 
GetScreenX(JSContext * aCx,JS::MutableHandle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3509 void nsGlobalWindowInner::GetScreenX(JSContext* aCx,
3510                                      JS::MutableHandle<JS::Value> aValue,
3511                                      CallerType aCallerType,
3512                                      ErrorResult& aError) {
3513   GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetScreenX, aValue,
3514                             aCallerType, aError);
3515 }
3516 
GetMozInnerScreenX(CallerType aCallerType,ErrorResult & aError)3517 float nsGlobalWindowInner::GetMozInnerScreenX(CallerType aCallerType,
3518                                               ErrorResult& aError) {
3519   FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenXOuter, (aCallerType), aError, 0);
3520 }
3521 
GetMozInnerScreenY(CallerType aCallerType,ErrorResult & aError)3522 float nsGlobalWindowInner::GetMozInnerScreenY(CallerType aCallerType,
3523                                               ErrorResult& aError) {
3524   FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenYOuter, (aCallerType), aError, 0);
3525 }
3526 
GetDevicePixelRatio(CallerType aCallerType,ErrorResult & aError)3527 double nsGlobalWindowInner::GetDevicePixelRatio(CallerType aCallerType,
3528                                                 ErrorResult& aError) {
3529   FORWARD_TO_OUTER_OR_THROW(GetDevicePixelRatioOuter, (aCallerType), aError,
3530                             0.0);
3531 }
3532 
GetMozPaintCount(ErrorResult & aError)3533 uint64_t nsGlobalWindowInner::GetMozPaintCount(ErrorResult& aError) {
3534   FORWARD_TO_OUTER_OR_THROW(GetMozPaintCountOuter, (), aError, 0);
3535 }
3536 
RequestAnimationFrame(FrameRequestCallback & aCallback,ErrorResult & aError)3537 int32_t nsGlobalWindowInner::RequestAnimationFrame(
3538     FrameRequestCallback& aCallback, ErrorResult& aError) {
3539   if (!mDoc) {
3540     return 0;
3541   }
3542 
3543   if (GetWrapperPreserveColor()) {
3544     js::NotifyAnimationActivity(GetWrapperPreserveColor());
3545   }
3546 
3547   DebuggerNotificationDispatch(this,
3548                                DebuggerNotificationType::RequestAnimationFrame);
3549 
3550   int32_t handle;
3551   aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle);
3552   return handle;
3553 }
3554 
CancelAnimationFrame(int32_t aHandle,ErrorResult & aError)3555 void nsGlobalWindowInner::CancelAnimationFrame(int32_t aHandle,
3556                                                ErrorResult& aError) {
3557   if (!mDoc) {
3558     return;
3559   }
3560 
3561   DebuggerNotificationDispatch(this,
3562                                DebuggerNotificationType::CancelAnimationFrame);
3563 
3564   mDoc->CancelFrameRequestCallback(aHandle);
3565 }
3566 
MatchMedia(const nsACString & aMediaQueryList,CallerType aCallerType,ErrorResult & aError)3567 already_AddRefed<MediaQueryList> nsGlobalWindowInner::MatchMedia(
3568     const nsACString& aMediaQueryList, CallerType aCallerType,
3569     ErrorResult& aError) {
3570   ENSURE_ACTIVE_DOCUMENT(aError, nullptr);
3571   return mDoc->MatchMedia(aMediaQueryList, aCallerType);
3572 }
3573 
SetScreenX(int32_t aScreenX,CallerType aCallerType,ErrorResult & aError)3574 void nsGlobalWindowInner::SetScreenX(int32_t aScreenX, CallerType aCallerType,
3575                                      ErrorResult& aError) {
3576   FORWARD_TO_OUTER_OR_THROW(SetScreenXOuter, (aScreenX, aCallerType, aError),
3577                             aError, );
3578 }
3579 
SetScreenX(JSContext * aCx,JS::Handle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3580 void nsGlobalWindowInner::SetScreenX(JSContext* aCx,
3581                                      JS::Handle<JS::Value> aValue,
3582                                      CallerType aCallerType,
3583                                      ErrorResult& aError) {
3584   SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetScreenX, aValue,
3585                             "screenX", aCallerType, aError);
3586 }
3587 
GetScreenY(CallerType aCallerType,ErrorResult & aError)3588 int32_t nsGlobalWindowInner::GetScreenY(CallerType aCallerType,
3589                                         ErrorResult& aError) {
3590   FORWARD_TO_OUTER_OR_THROW(GetScreenYOuter, (aCallerType, aError), aError, 0);
3591 }
3592 
GetScreenY(JSContext * aCx,JS::MutableHandle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3593 void nsGlobalWindowInner::GetScreenY(JSContext* aCx,
3594                                      JS::MutableHandle<JS::Value> aValue,
3595                                      CallerType aCallerType,
3596                                      ErrorResult& aError) {
3597   GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetScreenY, aValue,
3598                             aCallerType, aError);
3599 }
3600 
SetScreenY(int32_t aScreenY,CallerType aCallerType,ErrorResult & aError)3601 void nsGlobalWindowInner::SetScreenY(int32_t aScreenY, CallerType aCallerType,
3602                                      ErrorResult& aError) {
3603   FORWARD_TO_OUTER_OR_THROW(SetScreenYOuter, (aScreenY, aCallerType, aError),
3604                             aError, );
3605 }
3606 
SetScreenY(JSContext * aCx,JS::Handle<JS::Value> aValue,CallerType aCallerType,ErrorResult & aError)3607 void nsGlobalWindowInner::SetScreenY(JSContext* aCx,
3608                                      JS::Handle<JS::Value> aValue,
3609                                      CallerType aCallerType,
3610                                      ErrorResult& aError) {
3611   SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetScreenY, aValue,
3612                             "screenY", aCallerType, aError);
3613 }
3614 
GetScrollMinX(ErrorResult & aError)3615 int32_t nsGlobalWindowInner::GetScrollMinX(ErrorResult& aError) {
3616   FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideLeft), aError, 0);
3617 }
3618 
GetScrollMinY(ErrorResult & aError)3619 int32_t nsGlobalWindowInner::GetScrollMinY(ErrorResult& aError) {
3620   FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideTop), aError, 0);
3621 }
3622 
GetScrollMaxX(ErrorResult & aError)3623 int32_t nsGlobalWindowInner::GetScrollMaxX(ErrorResult& aError) {
3624   FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideRight), aError, 0);
3625 }
3626 
GetScrollMaxY(ErrorResult & aError)3627 int32_t nsGlobalWindowInner::GetScrollMaxY(ErrorResult& aError) {
3628   FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideBottom), aError, 0);
3629 }
3630 
GetScrollX(ErrorResult & aError)3631 double nsGlobalWindowInner::GetScrollX(ErrorResult& aError) {
3632   FORWARD_TO_OUTER_OR_THROW(GetScrollXOuter, (), aError, 0);
3633 }
3634 
GetScrollY(ErrorResult & aError)3635 double nsGlobalWindowInner::GetScrollY(ErrorResult& aError) {
3636   FORWARD_TO_OUTER_OR_THROW(GetScrollYOuter, (), aError, 0);
3637 }
3638 
Length()3639 uint32_t nsGlobalWindowInner::Length() { FORWARD_TO_OUTER(Length, (), 0); }
3640 
GetTop(mozilla::ErrorResult & aError)3641 Nullable<WindowProxyHolder> nsGlobalWindowInner::GetTop(
3642     mozilla::ErrorResult& aError) {
3643   FORWARD_TO_OUTER_OR_THROW(GetTopOuter, (), aError, nullptr);
3644 }
3645 
GetChildWindow(const nsAString & aName)3646 already_AddRefed<BrowsingContext> nsGlobalWindowInner::GetChildWindow(
3647     const nsAString& aName) {
3648   if (GetOuterWindowInternal()) {
3649     return GetOuterWindowInternal()->GetChildWindow(aName);
3650   }
3651   return nullptr;
3652 }
3653 
RefreshRealmPrincipal()3654 void nsGlobalWindowInner::RefreshRealmPrincipal() {
3655   JS::SetRealmPrincipals(js::GetNonCCWObjectRealm(GetWrapperPreserveColor()),
3656                          nsJSPrincipals::get(mDoc->NodePrincipal()));
3657 }
3658 
GetMainWidget()3659 already_AddRefed<nsIWidget> nsGlobalWindowInner::GetMainWidget() {
3660   FORWARD_TO_OUTER(GetMainWidget, (), nullptr);
3661 }
3662 
GetNearestWidget() const3663 nsIWidget* nsGlobalWindowInner::GetNearestWidget() const {
3664   if (GetOuterWindowInternal()) {
3665     return GetOuterWindowInternal()->GetNearestWidget();
3666   }
3667   return nullptr;
3668 }
3669 
SetFullScreen(bool aFullscreen,mozilla::ErrorResult & aError)3670 void nsGlobalWindowInner::SetFullScreen(bool aFullscreen,
3671                                         mozilla::ErrorResult& aError) {
3672   FORWARD_TO_OUTER_OR_THROW(SetFullscreenOuter, (aFullscreen, aError), aError,
3673                             /* void */);
3674 }
3675 
GetFullScreen(ErrorResult & aError)3676 bool nsGlobalWindowInner::GetFullScreen(ErrorResult& aError) {
3677   FORWARD_TO_OUTER_OR_THROW(GetFullscreenOuter, (), aError, false);
3678 }
3679 
GetFullScreen()3680 bool nsGlobalWindowInner::GetFullScreen() {
3681   ErrorResult dummy;
3682   bool fullscreen = GetFullScreen(dummy);
3683   dummy.SuppressException();
3684   return fullscreen;
3685 }
3686 
Dump(const nsAString & aStr)3687 void nsGlobalWindowInner::Dump(const nsAString& aStr) {
3688   if (!nsJSUtils::DumpEnabled()) {
3689     return;
3690   }
3691 
3692   char* cstr = ToNewUTF8String(aStr);
3693 
3694 #if defined(XP_MACOSX)
3695   // have to convert \r to \n so that printing to the console works
3696   char *c = cstr, *cEnd = cstr + strlen(cstr);
3697   while (c < cEnd) {
3698     if (*c == '\r') *c = '\n';
3699     c++;
3700   }
3701 #endif
3702 
3703   if (cstr) {
3704     MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug,
3705             ("[Window.Dump] %s", cstr));
3706 #ifdef XP_WIN
3707     PrintToDebugger(cstr);
3708 #endif
3709 #ifdef ANDROID
3710     __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
3711 #endif
3712     FILE* fp = gDumpFile ? gDumpFile : stdout;
3713     fputs(cstr, fp);
3714     fflush(fp);
3715     free(cstr);
3716   }
3717 }
3718 
Alert(nsIPrincipal & aSubjectPrincipal,ErrorResult & aError)3719 void nsGlobalWindowInner::Alert(nsIPrincipal& aSubjectPrincipal,
3720                                 ErrorResult& aError) {
3721   Alert(u""_ns, aSubjectPrincipal, aError);
3722 }
3723 
Alert(const nsAString & aMessage,nsIPrincipal & aSubjectPrincipal,ErrorResult & aError)3724 void nsGlobalWindowInner::Alert(const nsAString& aMessage,
3725                                 nsIPrincipal& aSubjectPrincipal,
3726                                 ErrorResult& aError) {
3727   FORWARD_TO_OUTER_OR_THROW(AlertOuter, (aMessage, aSubjectPrincipal, aError),
3728                             aError, );
3729 }
3730 
Confirm(const nsAString & aMessage,nsIPrincipal & aSubjectPrincipal,ErrorResult & aError)3731 bool nsGlobalWindowInner::Confirm(const nsAString& aMessage,
3732                                   nsIPrincipal& aSubjectPrincipal,
3733                                   ErrorResult& aError) {
3734   FORWARD_TO_OUTER_OR_THROW(ConfirmOuter, (aMessage, aSubjectPrincipal, aError),
3735                             aError, false);
3736 }
3737 
Fetch(const RequestOrUSVString & aInput,const RequestInit & aInit,CallerType aCallerType,ErrorResult & aRv)3738 already_AddRefed<Promise> nsGlobalWindowInner::Fetch(
3739     const RequestOrUSVString& aInput, const RequestInit& aInit,
3740     CallerType aCallerType, ErrorResult& aRv) {
3741   return FetchRequest(this, aInput, aInit, aCallerType, aRv);
3742 }
3743 
Prompt(const nsAString & aMessage,const nsAString & aInitial,nsAString & aReturn,nsIPrincipal & aSubjectPrincipal,ErrorResult & aError)3744 void nsGlobalWindowInner::Prompt(const nsAString& aMessage,
3745                                  const nsAString& aInitial, nsAString& aReturn,
3746                                  nsIPrincipal& aSubjectPrincipal,
3747                                  ErrorResult& aError) {
3748   FORWARD_TO_OUTER_OR_THROW(
3749       PromptOuter, (aMessage, aInitial, aReturn, aSubjectPrincipal, aError),
3750       aError, );
3751 }
3752 
Focus(CallerType aCallerType,ErrorResult & aError)3753 void nsGlobalWindowInner::Focus(CallerType aCallerType, ErrorResult& aError) {
3754   FORWARD_TO_OUTER_OR_THROW(FocusOuter,
3755                             (aCallerType, /* aFromOtherProcess */ false,
3756                              nsFocusManager::GenerateFocusActionId()),
3757                             aError, );
3758 }
3759 
Focus(CallerType aCallerType)3760 nsresult nsGlobalWindowInner::Focus(CallerType aCallerType) {
3761   ErrorResult rv;
3762   Focus(aCallerType, rv);
3763 
3764   return rv.StealNSResult();
3765 }
3766 
Blur(CallerType aCallerType,ErrorResult & aError)3767 void nsGlobalWindowInner::Blur(CallerType aCallerType, ErrorResult& aError) {
3768   FORWARD_TO_OUTER_OR_THROW(BlurOuter, (aCallerType), aError, );
3769 }
3770 
Stop(ErrorResult & aError)3771 void nsGlobalWindowInner::Stop(ErrorResult& aError) {
3772   FORWARD_TO_OUTER_OR_THROW(StopOuter, (aError), aError, );
3773 }
3774 
Print(ErrorResult & aError)3775 void nsGlobalWindowInner::Print(ErrorResult& aError) {
3776   FORWARD_TO_OUTER_OR_THROW(PrintOuter, (aError), aError, );
3777 }
3778 
PrintPreview(nsIPrintSettings * aSettings,nsIWebProgressListener * aListener,nsIDocShell * aDocShellToCloneInto,ErrorResult & aError)3779 Nullable<WindowProxyHolder> nsGlobalWindowInner::PrintPreview(
3780     nsIPrintSettings* aSettings, nsIWebProgressListener* aListener,
3781     nsIDocShell* aDocShellToCloneInto, ErrorResult& aError) {
3782   FORWARD_TO_OUTER_OR_THROW(Print,
3783                             (aSettings, aListener, aDocShellToCloneInto,
3784                              nsGlobalWindowOuter::IsPreview::Yes,
3785                              nsGlobalWindowOuter::IsForWindowDotPrint::No,
3786                              /* aPrintPreviewCallback = */ nullptr, aError),
3787                             aError, nullptr);
3788 }
3789 
MoveTo(int32_t aXPos,int32_t aYPos,CallerType aCallerType,ErrorResult & aError)3790 void nsGlobalWindowInner::MoveTo(int32_t aXPos, int32_t aYPos,
3791                                  CallerType aCallerType, ErrorResult& aError) {
3792   FORWARD_TO_OUTER_OR_THROW(MoveToOuter, (aXPos, aYPos, aCallerType, aError),
3793                             aError, );
3794 }
3795 
MoveBy(int32_t aXDif,int32_t aYDif,CallerType aCallerType,ErrorResult & aError)3796 void nsGlobalWindowInner::MoveBy(int32_t aXDif, int32_t aYDif,
3797                                  CallerType aCallerType, ErrorResult& aError) {
3798   FORWARD_TO_OUTER_OR_THROW(MoveByOuter, (aXDif, aYDif, aCallerType, aError),
3799                             aError, );
3800 }
3801 
ResizeTo(int32_t aWidth,int32_t aHeight,CallerType aCallerType,ErrorResult & aError)3802 void nsGlobalWindowInner::ResizeTo(int32_t aWidth, int32_t aHeight,
3803                                    CallerType aCallerType,
3804                                    ErrorResult& aError) {
3805   FORWARD_TO_OUTER_OR_THROW(ResizeToOuter,
3806                             (aWidth, aHeight, aCallerType, aError), aError, );
3807 }
3808 
ResizeBy(int32_t aWidthDif,int32_t aHeightDif,CallerType aCallerType,ErrorResult & aError)3809 void nsGlobalWindowInner::ResizeBy(int32_t aWidthDif, int32_t aHeightDif,
3810                                    CallerType aCallerType,
3811                                    ErrorResult& aError) {
3812   FORWARD_TO_OUTER_OR_THROW(
3813       ResizeByOuter, (aWidthDif, aHeightDif, aCallerType, aError), aError, );
3814 }
3815 
SizeToContent(CallerType aCallerType,ErrorResult & aError)3816 void nsGlobalWindowInner::SizeToContent(CallerType aCallerType,
3817                                         ErrorResult& aError) {
3818   FORWARD_TO_OUTER_OR_THROW(SizeToContentOuter, (aCallerType, aError),
3819                             aError, );
3820 }
3821 
GetTopWindowRoot()3822 already_AddRefed<nsPIWindowRoot> nsGlobalWindowInner::GetTopWindowRoot() {
3823   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
3824   if (!outer) {
3825     return nullptr;
3826   }
3827   return outer->GetTopWindowRoot();
3828 }
3829 
Scroll(double aXScroll,double aYScroll)3830 void nsGlobalWindowInner::Scroll(double aXScroll, double aYScroll) {
3831   // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
3832   auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),
3833                                          mozilla::ToZeroIfNonfinite(aYScroll));
3834   ScrollTo(scrollPos, ScrollOptions());
3835 }
3836 
ScrollTo(double aXScroll,double aYScroll)3837 void nsGlobalWindowInner::ScrollTo(double aXScroll, double aYScroll) {
3838   // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
3839   auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),
3840                                          mozilla::ToZeroIfNonfinite(aYScroll));
3841   ScrollTo(scrollPos, ScrollOptions());
3842 }
3843 
ScrollTo(const ScrollToOptions & aOptions)3844 void nsGlobalWindowInner::ScrollTo(const ScrollToOptions& aOptions) {
3845   // When scrolling to a non-zero offset, we need to determine whether that
3846   // position is within our scrollable range, so we need updated layout
3847   // information which requires a layout flush, otherwise all we need is to
3848   // flush frames to be able to access our scrollable frame here.
3849   FlushType flushType =
3850       ((aOptions.mLeft.WasPassed() && aOptions.mLeft.Value() > 0) ||
3851        (aOptions.mTop.WasPassed() && aOptions.mTop.Value() > 0))
3852           ? FlushType::Layout
3853           : FlushType::Frames;
3854   FlushPendingNotifications(flushType);
3855   nsIScrollableFrame* sf = GetScrollFrame();
3856 
3857   if (sf) {
3858     CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
3859     if (aOptions.mLeft.WasPassed()) {
3860       scrollPos.x = mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
3861     }
3862     if (aOptions.mTop.WasPassed()) {
3863       scrollPos.y = mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
3864     }
3865 
3866     ScrollTo(scrollPos, aOptions);
3867   }
3868 }
3869 
Scroll(const ScrollToOptions & aOptions)3870 void nsGlobalWindowInner::Scroll(const ScrollToOptions& aOptions) {
3871   ScrollTo(aOptions);
3872 }
3873 
ScrollTo(const CSSIntPoint & aScroll,const ScrollOptions & aOptions)3874 void nsGlobalWindowInner::ScrollTo(const CSSIntPoint& aScroll,
3875                                    const ScrollOptions& aOptions) {
3876   // When scrolling to a non-zero offset, we need to determine whether that
3877   // position is within our scrollable range, so we need updated layout
3878   // information which requires a layout flush, otherwise all we need is to
3879   // flush frames to be able to access our scrollable frame here.
3880   FlushType flushType =
3881       (aScroll.x || aScroll.y) ? FlushType::Layout : FlushType::Frames;
3882   FlushPendingNotifications(flushType);
3883   nsIScrollableFrame* sf = GetScrollFrame();
3884 
3885   if (sf) {
3886     // Here we calculate what the max pixel value is that we can
3887     // scroll to, we do this by dividing maxint with the pixel to
3888     // twips conversion factor, and subtracting 4, the 4 comes from
3889     // experimenting with this value, anything less makes the view
3890     // code not scroll correctly, I have no idea why. -- jst
3891     const int32_t maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
3892 
3893     CSSIntPoint scroll(aScroll);
3894     if (scroll.x > maxpx) {
3895       scroll.x = maxpx;
3896     }
3897 
3898     if (scroll.y > maxpx) {
3899       scroll.y = maxpx;
3900     }
3901 
3902     ScrollMode scrollMode = sf->IsSmoothScroll(aOptions.mBehavior)
3903                                 ? ScrollMode::SmoothMsd
3904                                 : ScrollMode::Instant;
3905 
3906     sf->ScrollToCSSPixels(scroll, scrollMode);
3907   }
3908 }
3909 
ScrollBy(double aXScrollDif,double aYScrollDif)3910 void nsGlobalWindowInner::ScrollBy(double aXScrollDif, double aYScrollDif) {
3911   FlushPendingNotifications(FlushType::Layout);
3912   nsIScrollableFrame* sf = GetScrollFrame();
3913 
3914   if (sf) {
3915     // It seems like it would make more sense for ScrollBy to use
3916     // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
3917     // Perhaps Web content does too.
3918     ScrollToOptions options;
3919     options.mLeft.Construct(aXScrollDif);
3920     options.mTop.Construct(aYScrollDif);
3921     ScrollBy(options);
3922   }
3923 }
3924 
ScrollBy(const ScrollToOptions & aOptions)3925 void nsGlobalWindowInner::ScrollBy(const ScrollToOptions& aOptions) {
3926   FlushPendingNotifications(FlushType::Layout);
3927   nsIScrollableFrame* sf = GetScrollFrame();
3928 
3929   if (sf) {
3930     CSSIntPoint scrollDelta;
3931     if (aOptions.mLeft.WasPassed()) {
3932       scrollDelta.x = mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
3933     }
3934     if (aOptions.mTop.WasPassed()) {
3935       scrollDelta.y = mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
3936     }
3937 
3938     ScrollMode scrollMode = sf->IsSmoothScroll(aOptions.mBehavior)
3939                                 ? ScrollMode::SmoothMsd
3940                                 : ScrollMode::Instant;
3941 
3942     sf->ScrollByCSSPixels(scrollDelta, scrollMode,
3943                           mozilla::ScrollOrigin::Relative);
3944   }
3945 }
3946 
ScrollByLines(int32_t numLines,const ScrollOptions & aOptions)3947 void nsGlobalWindowInner::ScrollByLines(int32_t numLines,
3948                                         const ScrollOptions& aOptions) {
3949   FlushPendingNotifications(FlushType::Layout);
3950   nsIScrollableFrame* sf = GetScrollFrame();
3951   if (sf) {
3952     // It seems like it would make more sense for ScrollByLines to use
3953     // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
3954     // Perhaps Web content does too.
3955     ScrollMode scrollMode = sf->IsSmoothScroll(aOptions.mBehavior)
3956                                 ? ScrollMode::SmoothMsd
3957                                 : ScrollMode::Instant;
3958 
3959     sf->ScrollBy(nsIntPoint(0, numLines), ScrollUnit::LINES, scrollMode);
3960   }
3961 }
3962 
ScrollByPages(int32_t numPages,const ScrollOptions & aOptions)3963 void nsGlobalWindowInner::ScrollByPages(int32_t numPages,
3964                                         const ScrollOptions& aOptions) {
3965   FlushPendingNotifications(FlushType::Layout);
3966   nsIScrollableFrame* sf = GetScrollFrame();
3967   if (sf) {
3968     // It seems like it would make more sense for ScrollByPages to use
3969     // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
3970     // Perhaps Web content does too.
3971     ScrollMode scrollMode = sf->IsSmoothScroll(aOptions.mBehavior)
3972                                 ? ScrollMode::SmoothMsd
3973                                 : ScrollMode::Instant;
3974 
3975     sf->ScrollBy(nsIntPoint(0, numPages), ScrollUnit::PAGES, scrollMode);
3976   }
3977 }
3978 
MozScrollSnap()3979 void nsGlobalWindowInner::MozScrollSnap() {
3980   FlushPendingNotifications(FlushType::Layout);
3981   nsIScrollableFrame* sf = GetScrollFrame();
3982   if (sf) {
3983     sf->ScrollSnap();
3984   }
3985 }
3986 
ClearTimeout(int32_t aHandle)3987 void nsGlobalWindowInner::ClearTimeout(int32_t aHandle) {
3988   DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearTimeout);
3989 
3990   if (aHandle > 0) {
3991     mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
3992   }
3993 }
3994 
ClearInterval(int32_t aHandle)3995 void nsGlobalWindowInner::ClearInterval(int32_t aHandle) {
3996   DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearInterval);
3997 
3998   if (aHandle > 0) {
3999     mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
4000   }
4001 }
4002 
SetResizable(bool aResizable) const4003 void nsGlobalWindowInner::SetResizable(bool aResizable) const {
4004   // nop
4005 }
4006 
CaptureEvents()4007 void nsGlobalWindowInner::CaptureEvents() {
4008   if (mDoc) {
4009     mDoc->WarnOnceAbout(DeprecatedOperations::eUseOfCaptureEvents);
4010   }
4011 }
4012 
ReleaseEvents()4013 void nsGlobalWindowInner::ReleaseEvents() {
4014   if (mDoc) {
4015     mDoc->WarnOnceAbout(DeprecatedOperations::eUseOfReleaseEvents);
4016   }
4017 }
4018 
Open(const nsAString & aUrl,const nsAString & aName,const nsAString & aOptions,ErrorResult & aError)4019 Nullable<WindowProxyHolder> nsGlobalWindowInner::Open(const nsAString& aUrl,
4020                                                       const nsAString& aName,
4021                                                       const nsAString& aOptions,
4022                                                       ErrorResult& aError) {
4023   FORWARD_TO_OUTER_OR_THROW(OpenOuter, (aUrl, aName, aOptions, aError), aError,
4024                             nullptr);
4025 }
4026 
OpenDialog(JSContext * aCx,const nsAString & aUrl,const nsAString & aName,const nsAString & aOptions,const Sequence<JS::Value> & aExtraArgument,ErrorResult & aError)4027 Nullable<WindowProxyHolder> nsGlobalWindowInner::OpenDialog(
4028     JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
4029     const nsAString& aOptions, const Sequence<JS::Value>& aExtraArgument,
4030     ErrorResult& aError) {
4031   FORWARD_TO_OUTER_OR_THROW(
4032       OpenDialogOuter, (aCx, aUrl, aName, aOptions, aExtraArgument, aError),
4033       aError, nullptr);
4034 }
4035 
GetFrames(ErrorResult & aError)4036 WindowProxyHolder nsGlobalWindowInner::GetFrames(ErrorResult& aError) {
4037   FORWARD_TO_OUTER_OR_THROW(GetFramesOuter, (), aError, Window());
4038 }
4039 
PostMessageMoz(JSContext * aCx,JS::Handle<JS::Value> aMessage,const nsAString & aTargetOrigin,JS::Handle<JS::Value> aTransfer,nsIPrincipal & aSubjectPrincipal,ErrorResult & aError)4040 void nsGlobalWindowInner::PostMessageMoz(JSContext* aCx,
4041                                          JS::Handle<JS::Value> aMessage,
4042                                          const nsAString& aTargetOrigin,
4043                                          JS::Handle<JS::Value> aTransfer,
4044                                          nsIPrincipal& aSubjectPrincipal,
4045                                          ErrorResult& aError) {
4046   FORWARD_TO_OUTER_OR_THROW(
4047       PostMessageMozOuter,
4048       (aCx, aMessage, aTargetOrigin, aTransfer, aSubjectPrincipal, aError),
4049       aError, );
4050 }
4051 
PostMessageMoz(JSContext * aCx,JS::Handle<JS::Value> aMessage,const nsAString & aTargetOrigin,const Sequence<JSObject * > & aTransfer,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)4052 void nsGlobalWindowInner::PostMessageMoz(JSContext* aCx,
4053                                          JS::Handle<JS::Value> aMessage,
4054                                          const nsAString& aTargetOrigin,
4055                                          const Sequence<JSObject*>& aTransfer,
4056                                          nsIPrincipal& aSubjectPrincipal,
4057                                          ErrorResult& aRv) {
4058   JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
4059 
4060   aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransfer,
4061                                                           &transferArray);
4062   if (NS_WARN_IF(aRv.Failed())) {
4063     return;
4064   }
4065 
4066   PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray, aSubjectPrincipal,
4067                  aRv);
4068 }
4069 
PostMessageMoz(JSContext * aCx,JS::Handle<JS::Value> aMessage,const WindowPostMessageOptions & aOptions,nsIPrincipal & aSubjectPrincipal,ErrorResult & aRv)4070 void nsGlobalWindowInner::PostMessageMoz(
4071     JSContext* aCx, JS::Handle<JS::Value> aMessage,
4072     const WindowPostMessageOptions& aOptions, nsIPrincipal& aSubjectPrincipal,
4073     ErrorResult& aRv) {
4074   JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
4075 
4076   aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(
4077       aCx, aOptions.mTransfer, &transferArray);
4078   if (NS_WARN_IF(aRv.Failed())) {
4079     return;
4080   }
4081 
4082   PostMessageMoz(aCx, aMessage, aOptions.mTargetOrigin, transferArray,
4083                  aSubjectPrincipal, aRv);
4084 }
4085 
Close(CallerType aCallerType,ErrorResult & aError)4086 void nsGlobalWindowInner::Close(CallerType aCallerType, ErrorResult& aError) {
4087   FORWARD_TO_OUTER_OR_THROW(CloseOuter, (aCallerType == CallerType::System),
4088                             aError, );
4089 }
4090 
Close()4091 nsresult nsGlobalWindowInner::Close() {
4092   FORWARD_TO_OUTER(Close, (), NS_ERROR_UNEXPECTED);
4093 }
4094 
IsInModalState()4095 bool nsGlobalWindowInner::IsInModalState() {
4096   FORWARD_TO_OUTER(IsInModalState, (), false);
4097 }
4098 
4099 // static
NotifyDOMWindowDestroyed(nsGlobalWindowInner * aWindow)4100 void nsGlobalWindowInner::NotifyDOMWindowDestroyed(
4101     nsGlobalWindowInner* aWindow) {
4102   nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
4103   if (observerService) {
4104     observerService->NotifyObservers(ToSupports(aWindow),
4105                                      DOM_WINDOW_DESTROYED_TOPIC, nullptr);
4106   }
4107 }
4108 
NotifyWindowIDDestroyed(const char * aTopic)4109 void nsGlobalWindowInner::NotifyWindowIDDestroyed(const char* aTopic) {
4110   nsCOMPtr<nsIRunnable> runnable =
4111       new WindowDestroyedEvent(this, mWindowID, aTopic);
4112   Dispatch(TaskCategory::Other, runnable.forget());
4113 }
4114 
4115 // static
NotifyDOMWindowFrozen(nsGlobalWindowInner * aWindow)4116 void nsGlobalWindowInner::NotifyDOMWindowFrozen(nsGlobalWindowInner* aWindow) {
4117   if (aWindow) {
4118     nsCOMPtr<nsIObserverService> observerService =
4119         services::GetObserverService();
4120     if (observerService) {
4121       observerService->NotifyObservers(ToSupports(aWindow),
4122                                        DOM_WINDOW_FROZEN_TOPIC, nullptr);
4123     }
4124   }
4125 }
4126 
4127 // static
NotifyDOMWindowThawed(nsGlobalWindowInner * aWindow)4128 void nsGlobalWindowInner::NotifyDOMWindowThawed(nsGlobalWindowInner* aWindow) {
4129   if (aWindow) {
4130     nsCOMPtr<nsIObserverService> observerService =
4131         services::GetObserverService();
4132     if (observerService) {
4133       observerService->NotifyObservers(ToSupports(aWindow),
4134                                        DOM_WINDOW_THAWED_TOPIC, nullptr);
4135     }
4136   }
4137 }
4138 
GetFrameElement(nsIPrincipal & aSubjectPrincipal,ErrorResult & aError)4139 Element* nsGlobalWindowInner::GetFrameElement(nsIPrincipal& aSubjectPrincipal,
4140                                               ErrorResult& aError) {
4141   FORWARD_TO_OUTER_OR_THROW(GetFrameElement, (aSubjectPrincipal), aError,
4142                             nullptr);
4143 }
4144 
GetRealFrameElement(ErrorResult & aError)4145 Element* nsGlobalWindowInner::GetRealFrameElement(ErrorResult& aError) {
4146   FORWARD_TO_OUTER_OR_THROW(GetFrameElement, (), aError, nullptr);
4147 }
4148 
UpdateCommands(const nsAString & anAction,Selection * aSel,int16_t aReason)4149 void nsGlobalWindowInner::UpdateCommands(const nsAString& anAction,
4150                                          Selection* aSel, int16_t aReason) {
4151   if (GetOuterWindowInternal()) {
4152     GetOuterWindowInternal()->UpdateCommands(anAction, aSel, aReason);
4153   }
4154 }
4155 
GetSelection(ErrorResult & aError)4156 Selection* nsGlobalWindowInner::GetSelection(ErrorResult& aError) {
4157   FORWARD_TO_OUTER_OR_THROW(GetSelectionOuter, (), aError, nullptr);
4158 }
4159 
Find(const nsAString & aString,bool aCaseSensitive,bool aBackwards,bool aWrapAround,bool aWholeWord,bool aSearchInFrames,bool aShowDialog,ErrorResult & aError)4160 bool nsGlobalWindowInner::Find(const nsAString& aString, bool aCaseSensitive,
4161                                bool aBackwards, bool aWrapAround,
4162                                bool aWholeWord, bool aSearchInFrames,
4163                                bool aShowDialog, ErrorResult& aError) {
4164   FORWARD_TO_OUTER_OR_THROW(FindOuter,
4165                             (aString, aCaseSensitive, aBackwards, aWrapAround,
4166                              aWholeWord, aSearchInFrames, aShowDialog, aError),
4167                             aError, false);
4168 }
4169 
GetOrigin(nsAString & aOrigin)4170 void nsGlobalWindowInner::GetOrigin(nsAString& aOrigin) {
4171   nsContentUtils::GetUTFOrigin(GetPrincipal(), aOrigin);
4172 }
4173 
Atob(const nsAString & aAsciiBase64String,nsAString & aBinaryData,ErrorResult & aError)4174 void nsGlobalWindowInner::Atob(const nsAString& aAsciiBase64String,
4175                                nsAString& aBinaryData, ErrorResult& aError) {
4176   aError = nsContentUtils::Atob(aAsciiBase64String, aBinaryData);
4177 }
4178 
Btoa(const nsAString & aBinaryData,nsAString & aAsciiBase64String,ErrorResult & aError)4179 void nsGlobalWindowInner::Btoa(const nsAString& aBinaryData,
4180                                nsAString& aAsciiBase64String,
4181                                ErrorResult& aError) {
4182   aError = nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
4183 }
4184 
4185 //*****************************************************************************
4186 // EventTarget
4187 //*****************************************************************************
4188 
GetOwnerGlobalForBindingsInternal()4189 nsPIDOMWindowOuter* nsGlobalWindowInner::GetOwnerGlobalForBindingsInternal() {
4190   return nsPIDOMWindowOuter::GetFromCurrentInner(this);
4191 }
4192 
DispatchEvent(Event & aEvent,CallerType aCallerType,ErrorResult & aRv)4193 bool nsGlobalWindowInner::DispatchEvent(Event& aEvent, CallerType aCallerType,
4194                                         ErrorResult& aRv) {
4195   if (!IsCurrentInnerWindow()) {
4196     NS_WARNING(
4197         "DispatchEvent called on non-current inner window, dropping. "
4198         "Please check the window in the caller instead.");
4199     aRv.Throw(NS_ERROR_FAILURE);
4200     return false;
4201   }
4202 
4203   if (!mDoc) {
4204     aRv.Throw(NS_ERROR_FAILURE);
4205     return false;
4206   }
4207 
4208   // Obtain a presentation shell
4209   RefPtr<nsPresContext> presContext = mDoc->GetPresContext();
4210 
4211   nsEventStatus status = nsEventStatus_eIgnore;
4212   nsresult rv = EventDispatcher::DispatchDOMEvent(
4213       ToSupports(this), nullptr, &aEvent, presContext, &status);
4214   bool retval = !aEvent.DefaultPrevented(aCallerType);
4215   if (NS_FAILED(rv)) {
4216     aRv.Throw(rv);
4217   }
4218   return retval;
4219 }
4220 
4221 mozilla::Maybe<mozilla::dom::EventCallbackDebuggerNotificationType>
GetDebuggerNotificationType() const4222 nsGlobalWindowInner::GetDebuggerNotificationType() const {
4223   return mozilla::Some(
4224       mozilla::dom::EventCallbackDebuggerNotificationType::Global);
4225 }
4226 
ComputeDefaultWantsUntrusted(ErrorResult & aRv)4227 bool nsGlobalWindowInner::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
4228   return !nsContentUtils::IsChromeDoc(mDoc);
4229 }
4230 
GetOrCreateListenerManager()4231 EventListenerManager* nsGlobalWindowInner::GetOrCreateListenerManager() {
4232   if (!mListenerManager) {
4233     mListenerManager =
4234         new EventListenerManager(static_cast<EventTarget*>(this));
4235   }
4236 
4237   return mListenerManager;
4238 }
4239 
GetExistingListenerManager() const4240 EventListenerManager* nsGlobalWindowInner::GetExistingListenerManager() const {
4241   return mListenerManager;
4242 }
4243 
4244 mozilla::dom::DebuggerNotificationManager*
GetOrCreateDebuggerNotificationManager()4245 nsGlobalWindowInner::GetOrCreateDebuggerNotificationManager() {
4246   if (!mDebuggerNotificationManager) {
4247     mDebuggerNotificationManager = new DebuggerNotificationManager(this);
4248   }
4249 
4250   return mDebuggerNotificationManager;
4251 }
4252 
4253 mozilla::dom::DebuggerNotificationManager*
GetExistingDebuggerNotificationManager()4254 nsGlobalWindowInner::GetExistingDebuggerNotificationManager() {
4255   return mDebuggerNotificationManager;
4256 }
4257 
4258 //*****************************************************************************
4259 // nsGlobalWindowInner::nsPIDOMWindow
4260 //*****************************************************************************
4261 
Location()4262 Location* nsGlobalWindowInner::Location() {
4263   if (!mLocation) {
4264     mLocation = new dom::Location(this, GetBrowsingContext());
4265   }
4266 
4267   return mLocation;
4268 }
4269 
MaybeUpdateTouchState()4270 void nsGlobalWindowInner::MaybeUpdateTouchState() {
4271   if (mMayHaveTouchEventListener) {
4272     nsCOMPtr<nsIObserverService> observerService =
4273         services::GetObserverService();
4274 
4275     if (observerService) {
4276       observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
4277                                        DOM_TOUCH_LISTENER_ADDED, nullptr);
4278     }
4279   }
4280 }
4281 
EnableGamepadUpdates()4282 void nsGlobalWindowInner::EnableGamepadUpdates() {
4283   if (mHasGamepad) {
4284     RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
4285     if (gamepadManager) {
4286       gamepadManager->AddListener(this);
4287     }
4288   }
4289 }
4290 
DisableGamepadUpdates()4291 void nsGlobalWindowInner::DisableGamepadUpdates() {
4292   if (mHasGamepad) {
4293     RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
4294     if (gamepadManager) {
4295       gamepadManager->RemoveListener(this);
4296     }
4297   }
4298 }
4299 
EnableVRUpdates()4300 void nsGlobalWindowInner::EnableVRUpdates() {
4301   // We need to create a VREventObserver before we can either detect XR runtimes
4302   // or start an XR session
4303   if (!mVREventObserver && (mHasXRSession || mXRRuntimeDetectionInFlight)) {
4304     // Assert that we are not creating the observer while IsDying() as
4305     // that would result in a leak.  VREventObserver holds a RefPtr to
4306     // this nsGlobalWindowInner and would prevent it from being deallocated.
4307     MOZ_ASSERT(!IsDying(),
4308                "Creating a VREventObserver for an nsGlobalWindow that is "
4309                "dying would cause it to leak.");
4310     mVREventObserver = new VREventObserver(this);
4311   }
4312   // If the content has an XR session, then we need to tell
4313   // VREventObserver that there is VR activity.
4314   if (mHasXRSession) {
4315     nsPIDOMWindowOuter* outer = GetOuterWindow();
4316     if (outer && !outer->IsBackground()) {
4317       StartVRActivity();
4318     }
4319   }
4320 }
4321 
DisableVRUpdates()4322 void nsGlobalWindowInner::DisableVRUpdates() {
4323   if (mVREventObserver) {
4324     mVREventObserver->DisconnectFromOwner();
4325     mVREventObserver = nullptr;
4326   }
4327 }
4328 
ResetVRTelemetry(bool aUpdate)4329 void nsGlobalWindowInner::ResetVRTelemetry(bool aUpdate) {
4330   if (mVREventObserver) {
4331     mVREventObserver->UpdateSpentTimeIn2DTelemetry(aUpdate);
4332   }
4333 }
4334 
StartVRActivity()4335 void nsGlobalWindowInner::StartVRActivity() {
4336   /**
4337    * If the content has an XR session, tell
4338    * the VREventObserver that the window is accessing
4339    * VR devices.
4340    *
4341    * It's possible to have a VREventObserver without
4342    * and XR session, if we are using it to get updates
4343    * about XR runtime enumeration.  In this case,
4344    * we would not tell the VREventObserver that
4345    * we are accessing VR devices.
4346    */
4347   if (mVREventObserver && mHasXRSession) {
4348     mVREventObserver->StartActivity();
4349   }
4350 }
4351 
StopVRActivity()4352 void nsGlobalWindowInner::StopVRActivity() {
4353   /**
4354    * If the content has an XR session, tell
4355    * the VReventObserver that the window is no longer
4356    * accessing VR devices.  This does not stop the
4357    * XR session itself, which may be resumed with
4358    * EnableVRUpdates.
4359    * It's possible to have a VREventObserver without
4360    * and XR session, if we are using it to get updates
4361    * about XR runtime enumeration.  In this case,
4362    * we would not tell the VREventObserver that
4363    * we ending an activity that accesses VR devices.
4364    */
4365   if (mVREventObserver && mHasXRSession) {
4366     mVREventObserver->StopActivity();
4367   }
4368 }
4369 
SetFocusedElement(Element * aElement,uint32_t aFocusMethod,bool aNeedsFocus)4370 void nsGlobalWindowInner::SetFocusedElement(Element* aElement,
4371                                             uint32_t aFocusMethod,
4372                                             bool aNeedsFocus) {
4373   if (aElement && aElement->GetComposedDoc() != mDoc) {
4374     NS_WARNING("Trying to set focus to a node from a wrong document");
4375     return;
4376   }
4377 
4378   if (IsDying()) {
4379     NS_ASSERTION(!aElement, "Trying to focus cleaned up window!");
4380     aElement = nullptr;
4381     aNeedsFocus = false;
4382   }
4383   if (mFocusedElement != aElement) {
4384     UpdateCanvasFocus(false, aElement);
4385     mFocusedElement = aElement;
4386     // TODO: Maybe this should be set on refocus too?
4387     mFocusMethod = aFocusMethod & nsIFocusManager::METHOD_MASK;
4388   }
4389 
4390   if (mFocusedElement) {
4391     // if a node was focused by a keypress, turn on focus rings for the
4392     // window.
4393     if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
4394       mUnknownFocusMethodShouldShowOutline = true;
4395       mFocusByKeyOccurred = true;
4396     } else if (nsFocusManager::GetFocusMoveActionCause(mFocusMethod) !=
4397                widget::InputContextAction::CAUSE_UNKNOWN) {
4398       mUnknownFocusMethodShouldShowOutline = false;
4399     } else if (aFocusMethod & nsIFocusManager::FLAG_NOSHOWRING) {
4400       // If we get focused via script, and script has explicitly opted out of
4401       // outlines via FLAG_NOSHOWRING, we don't want to make a refocus start
4402       // showing outlines.
4403       mUnknownFocusMethodShouldShowOutline = false;
4404     }
4405   }
4406 
4407   if (aNeedsFocus) {
4408     mNeedsFocus = aNeedsFocus;
4409   }
4410 }
4411 
GetFocusMethod()4412 uint32_t nsGlobalWindowInner::GetFocusMethod() { return mFocusMethod; }
4413 
ShouldShowFocusRing()4414 bool nsGlobalWindowInner::ShouldShowFocusRing() {
4415   if (mFocusByKeyOccurred &&
4416       StaticPrefs::browser_display_always_show_rings_after_key_focus()) {
4417     return true;
4418   }
4419 
4420   nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
4421   return root && root->ShowFocusRings();
4422 }
4423 
TakeFocus(bool aFocus,uint32_t aFocusMethod)4424 bool nsGlobalWindowInner::TakeFocus(bool aFocus, uint32_t aFocusMethod) {
4425   if (IsDying()) {
4426     return false;
4427   }
4428 
4429   if (aFocus) {
4430     mFocusMethod = aFocusMethod & nsIFocusManager::METHOD_MASK;
4431   }
4432 
4433   if (mHasFocus != aFocus) {
4434     mHasFocus = aFocus;
4435     UpdateCanvasFocus(true, mFocusedElement);
4436   }
4437 
4438   // if mNeedsFocus is true, then the document has not yet received a
4439   // document-level focus event. If there is a root content node, then return
4440   // true to tell the calling focus manager that a focus event is expected. If
4441   // there is no root content node, the document hasn't loaded enough yet, or
4442   // there isn't one and there is no point in firing a focus event.
4443   if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nullptr) {
4444     mNeedsFocus = false;
4445     return true;
4446   }
4447 
4448   mNeedsFocus = false;
4449   return false;
4450 }
4451 
SetReadyForFocus()4452 void nsGlobalWindowInner::SetReadyForFocus() {
4453   bool oldNeedsFocus = mNeedsFocus;
4454   mNeedsFocus = false;
4455 
4456   nsFocusManager* fm = nsFocusManager::GetFocusManager();
4457   if (fm) {
4458     fm->WindowShown(GetOuterWindow(), oldNeedsFocus);
4459   }
4460 }
4461 
PageHidden()4462 void nsGlobalWindowInner::PageHidden() {
4463   // the window is being hidden, so tell the focus manager that the frame is
4464   // no longer valid. Use the persisted field to determine if the document
4465   // is being destroyed.
4466 
4467   nsFocusManager* fm = nsFocusManager::GetFocusManager();
4468   if (fm) {
4469     fm->WindowHidden(GetOuterWindow(), nsFocusManager::GenerateFocusActionId());
4470   }
4471 
4472   mNeedsFocus = true;
4473 }
4474 
4475 class HashchangeCallback : public Runnable {
4476  public:
HashchangeCallback(const nsAString & aOldURL,const nsAString & aNewURL,nsGlobalWindowInner * aWindow)4477   HashchangeCallback(const nsAString& aOldURL, const nsAString& aNewURL,
4478                      nsGlobalWindowInner* aWindow)
4479       : mozilla::Runnable("HashchangeCallback"), mWindow(aWindow) {
4480     MOZ_ASSERT(mWindow);
4481     mOldURL.Assign(aOldURL);
4482     mNewURL.Assign(aNewURL);
4483   }
4484 
Run()4485   NS_IMETHOD Run() override {
4486     MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread.");
4487     return mWindow->FireHashchange(mOldURL, mNewURL);
4488   }
4489 
4490  private:
4491   nsString mOldURL;
4492   nsString mNewURL;
4493   RefPtr<nsGlobalWindowInner> mWindow;
4494 };
4495 
DispatchAsyncHashchange(nsIURI * aOldURI,nsIURI * aNewURI)4496 nsresult nsGlobalWindowInner::DispatchAsyncHashchange(nsIURI* aOldURI,
4497                                                       nsIURI* aNewURI) {
4498   // Make sure that aOldURI and aNewURI are identical up to the '#', and that
4499   // their hashes are different.
4500   bool equal = false;
4501   NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->EqualsExceptRef(aNewURI, &equal)) &&
4502                   equal);
4503   nsAutoCString oldHash, newHash;
4504   bool oldHasHash, newHasHash;
4505   NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->GetRef(oldHash)) &&
4506                   NS_SUCCEEDED(aNewURI->GetRef(newHash)) &&
4507                   NS_SUCCEEDED(aOldURI->GetHasRef(&oldHasHash)) &&
4508                   NS_SUCCEEDED(aNewURI->GetHasRef(&newHasHash)) &&
4509                   (oldHasHash != newHasHash || !oldHash.Equals(newHash)));
4510 
4511   nsAutoCString oldSpec, newSpec;
4512   nsresult rv = aOldURI->GetSpec(oldSpec);
4513   NS_ENSURE_SUCCESS(rv, rv);
4514   rv = aNewURI->GetSpec(newSpec);
4515   NS_ENSURE_SUCCESS(rv, rv);
4516 
4517   NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
4518   NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
4519 
4520   nsCOMPtr<nsIRunnable> callback =
4521       new HashchangeCallback(oldWideSpec, newWideSpec, this);
4522   return Dispatch(TaskCategory::Other, callback.forget());
4523 }
4524 
FireHashchange(const nsAString & aOldURL,const nsAString & aNewURL)4525 nsresult nsGlobalWindowInner::FireHashchange(const nsAString& aOldURL,
4526                                              const nsAString& aNewURL) {
4527   // Don't do anything if the window is frozen.
4528   if (IsFrozen()) {
4529     return NS_OK;
4530   }
4531 
4532   // Get a presentation shell for use in creating the hashchange event.
4533   NS_ENSURE_STATE(IsCurrentInnerWindow());
4534 
4535   HashChangeEventInit init;
4536   init.mNewURL = aNewURL;
4537   init.mOldURL = aOldURL;
4538 
4539   RefPtr<HashChangeEvent> event =
4540       HashChangeEvent::Constructor(this, u"hashchange"_ns, init);
4541 
4542   event->SetTrusted(true);
4543 
4544   ErrorResult rv;
4545   DispatchEvent(*event, rv);
4546   return rv.StealNSResult();
4547 }
4548 
DispatchSyncPopState()4549 nsresult nsGlobalWindowInner::DispatchSyncPopState() {
4550   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
4551                "Must be safe to run script here.");
4552 
4553   // Bail if the window is frozen.
4554   if (IsFrozen()) {
4555     return NS_OK;
4556   }
4557 
4558   // Get the document's pending state object -- it contains the data we're
4559   // going to send along with the popstate event.  The object is serialized
4560   // using structured clone.
4561   nsCOMPtr<nsIVariant> stateObj;
4562   nsresult rv = mDoc->GetStateObject(getter_AddRefs(stateObj));
4563   NS_ENSURE_SUCCESS(rv, rv);
4564 
4565   AutoJSAPI jsapi;
4566   bool result = jsapi.Init(this);
4567   NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
4568 
4569   JSContext* cx = jsapi.cx();
4570   JS::Rooted<JS::Value> stateJSValue(cx, JS::NullValue());
4571   result = stateObj ? VariantToJsval(cx, stateObj, &stateJSValue) : true;
4572   NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
4573 
4574   RootedDictionary<PopStateEventInit> init(cx);
4575   init.mState = stateJSValue;
4576 
4577   RefPtr<PopStateEvent> event =
4578       PopStateEvent::Constructor(this, u"popstate"_ns, init);
4579   event->SetTrusted(true);
4580   event->SetTarget(this);
4581 
4582   ErrorResult err;
4583   DispatchEvent(*event, err);
4584   return err.StealNSResult();
4585 }
4586 
4587 //-------------------------------------------------------
4588 // Tells the HTMLFrame/CanvasFrame that is now has focus
UpdateCanvasFocus(bool aFocusChanged,nsIContent * aNewContent)4589 void nsGlobalWindowInner::UpdateCanvasFocus(bool aFocusChanged,
4590                                             nsIContent* aNewContent) {
4591   // this is called from the inner window so use GetDocShell
4592   nsIDocShell* docShell = GetDocShell();
4593   if (!docShell) return;
4594 
4595   bool editable;
4596   docShell->GetEditable(&editable);
4597   if (editable) return;
4598 
4599   PresShell* presShell = docShell->GetPresShell();
4600   if (!presShell || !mDoc) {
4601     return;
4602   }
4603 
4604   Element* rootElement = mDoc->GetRootElement();
4605   if (rootElement) {
4606     if ((mHasFocus || aFocusChanged) &&
4607         (mFocusedElement == rootElement || aNewContent == rootElement)) {
4608       nsCanvasFrame* canvasFrame = presShell->GetCanvasFrame();
4609       if (canvasFrame) {
4610         canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
4611       }
4612     }
4613   } else {
4614     // XXXbz I would expect that there is never a canvasFrame in this case...
4615     nsCanvasFrame* canvasFrame = presShell->GetCanvasFrame();
4616     if (canvasFrame) {
4617       canvasFrame->SetHasFocus(false);
4618     }
4619   }
4620 }
4621 
GetComputedStyle(Element & aElt,const nsAString & aPseudoElt,ErrorResult & aError)4622 already_AddRefed<nsICSSDeclaration> nsGlobalWindowInner::GetComputedStyle(
4623     Element& aElt, const nsAString& aPseudoElt, ErrorResult& aError) {
4624   return GetComputedStyleHelper(aElt, aPseudoElt, false, aError);
4625 }
4626 
4627 already_AddRefed<nsICSSDeclaration>
GetDefaultComputedStyle(Element & aElt,const nsAString & aPseudoElt,ErrorResult & aError)4628 nsGlobalWindowInner::GetDefaultComputedStyle(Element& aElt,
4629                                              const nsAString& aPseudoElt,
4630                                              ErrorResult& aError) {
4631   return GetComputedStyleHelper(aElt, aPseudoElt, true, aError);
4632 }
4633 
GetComputedStyleHelper(Element & aElt,const nsAString & aPseudoElt,bool aDefaultStylesOnly,ErrorResult & aError)4634 already_AddRefed<nsICSSDeclaration> nsGlobalWindowInner::GetComputedStyleHelper(
4635     Element& aElt, const nsAString& aPseudoElt, bool aDefaultStylesOnly,
4636     ErrorResult& aError) {
4637   FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelperOuter,
4638                             (aElt, aPseudoElt, aDefaultStylesOnly), aError,
4639                             nullptr);
4640 }
4641 
GetSessionStorage(ErrorResult & aError)4642 Storage* nsGlobalWindowInner::GetSessionStorage(ErrorResult& aError) {
4643   nsIPrincipal* principal = GetPrincipal();
4644   nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
4645   BrowsingContext* browsingContext = GetBrowsingContext();
4646 
4647   if (!principal || !storagePrincipal || !browsingContext ||
4648       !Storage::StoragePrefIsEnabled()) {
4649     return nullptr;
4650   }
4651 
4652   if (mSessionStorage) {
4653     MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
4654             ("nsGlobalWindowInner %p has %p sessionStorage", this,
4655              mSessionStorage.get()));
4656     bool canAccess =
4657         principal->Subsumes(mSessionStorage->Principal()) &&
4658         storagePrincipal->Subsumes(mSessionStorage->StoragePrincipal());
4659     if (!canAccess) {
4660       mSessionStorage = nullptr;
4661     }
4662   }
4663 
4664   if (!mSessionStorage) {
4665     nsString documentURI;
4666     if (mDoc) {
4667       aError = mDoc->GetDocumentURI(documentURI);
4668       if (NS_WARN_IF(aError.Failed())) {
4669         return nullptr;
4670       }
4671     }
4672 
4673     // If the document has the sandboxed origin flag set
4674     // don't allow access to sessionStorage.
4675     if (!mDoc) {
4676       aError.Throw(NS_ERROR_FAILURE);
4677       return nullptr;
4678     }
4679 
4680     if (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
4681       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
4682       return nullptr;
4683     }
4684 
4685     uint32_t rejectedReason = 0;
4686     StorageAccess access = StorageAllowedForWindow(this, &rejectedReason);
4687 
4688     // SessionStorage is an ephemeral per-tab per-origin storage that only lives
4689     // as long as the tab is open, although it may survive browser restarts
4690     // thanks to the session store. So we interpret storage access differently
4691     // than we would for persistent per-origin storage like LocalStorage and so
4692     // it may be okay to provide SessionStorage even when we receive a value of
4693     // eDeny.
4694     //
4695     // ContentBlocking::ShouldAllowAccessFor will return false for 3 main
4696     // reasons.
4697     //
4698     // 1. Cookies are entirely blocked due to a per-origin permission
4699     // (nsICookiePermission::ACCESS_DENY for the top-level principal or this
4700     // window's principal) or the very broad BEHAVIOR_REJECT. This will return
4701     // eDeny with a reason of STATE_COOKIES_BLOCKED_BY_PERMISSION or
4702     // STATE_COOKIES_BLOCKED_ALL.
4703     //
4704     // 2. Third-party cookies are limited via BEHAVIOR_REJECT_FOREIGN and
4705     // BEHAVIOR_LIMIT_FOREIGN and this is a third-party window. This will return
4706     // eDeny with a reason of STATE_COOKIES_BLOCKED_FOREIGN.
4707     //
4708     // 3. Tracking protection (BEHAVIOR_REJECT_TRACKER and
4709     // BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) is in effect and
4710     // IsThirdPartyTrackingResourceWindow() returned true and there wasn't a
4711     // permission that allows it. This will return ePartitionTrackersOrDeny with
4712     // a reason of STATE_COOKIES_BLOCKED_TRACKER or
4713     // STATE_COOKIES_BLOCKED_SOCIALTRACKER.
4714     //
4715     // In the 1st case, the user has explicitly indicated that they don't want
4716     // to allow any storage to the origin or all origins and so we throw an
4717     // error and deny access to SessionStorage. In the 2nd case, a legacy
4718     // decision reasoned that there's no harm in providing SessionStorage
4719     // because the information is not durable and cannot escape the current tab.
4720     // The rationale is similar for the 3rd case.
4721     if (access == StorageAccess::eDeny &&
4722         rejectedReason !=
4723             nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) {
4724       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
4725       return nullptr;
4726     }
4727 
4728     const RefPtr<SessionStorageManager> storageManager =
4729         browsingContext->GetSessionStorageManager();
4730     if (!storageManager) {
4731       aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
4732       return nullptr;
4733     }
4734 
4735     RefPtr<Storage> storage;
4736     aError = storageManager->CreateStorage(this, principal, storagePrincipal,
4737                                            documentURI, IsPrivateBrowsing(),
4738                                            getter_AddRefs(storage));
4739     if (aError.Failed()) {
4740       return nullptr;
4741     }
4742 
4743     mSessionStorage = storage;
4744     MOZ_ASSERT(mSessionStorage);
4745 
4746     MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
4747             ("nsGlobalWindowInner %p tried to get a new sessionStorage %p",
4748              this, mSessionStorage.get()));
4749 
4750     if (!mSessionStorage) {
4751       aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
4752       return nullptr;
4753     }
4754   }
4755 
4756   MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
4757           ("nsGlobalWindowInner %p returns %p sessionStorage", this,
4758            mSessionStorage.get()));
4759 
4760   return mSessionStorage;
4761 }
4762 
GetLocalStorage(ErrorResult & aError)4763 Storage* nsGlobalWindowInner::GetLocalStorage(ErrorResult& aError) {
4764   if (!Storage::StoragePrefIsEnabled()) {
4765     return nullptr;
4766   }
4767 
4768   // LocalStorage needs to be exposed in every context except for sandboxes and
4769   // NullPrincipals (data: URLs, for instance). But we need to keep data
4770   // separate in some scenarios: private-browsing and partitioned trackers.
4771   // In private-browsing, LocalStorage keeps data in memory, and it shares
4772   // StorageEvents just with other origins in the same private-browsing
4773   // environment.
4774   // For Partitioned Trackers, we expose a partitioned LocalStorage, which
4775   // doesn't share data with other contexts, and it's just in memory.
4776   // Partitioned localStorage is available only for trackers listed in the
4777   // privacy.restrict3rdpartystorage.partitionedHosts pref. See
4778   // nsContentUtils::IsURIInPrefList to know the syntax for the pref value.
4779   // This is a temporary web-compatibility hack.
4780 
4781   StorageAccess access = StorageAllowedForWindow(this);
4782 
4783   // We allow partitioned localStorage only to some hosts.
4784   bool isolated = false;
4785   if (ShouldPartitionStorage(access)) {
4786     if (!mDoc) {
4787       access = StorageAccess::eDeny;
4788     } else if (!StoragePartitioningEnabled(access, mDoc->CookieJarSettings())) {
4789       static const char* kPrefName =
4790           "privacy.restrict3rdpartystorage.partitionedHosts";
4791 
4792       bool isInList = false;
4793       mDoc->NodePrincipal()->IsURIInPrefList(kPrefName, &isInList);
4794       if (!isInList) {
4795         access = StorageAccess::eDeny;
4796       } else {
4797         isolated = true;
4798       }
4799     }
4800   }
4801 
4802   if (access == StorageAccess::eDeny) {
4803     aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
4804     return nullptr;
4805   }
4806 
4807   nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
4808   if (mDoc) {
4809     cookieJarSettings = mDoc->CookieJarSettings();
4810   } else {
4811     cookieJarSettings = net::CookieJarSettings::GetBlockingAll();
4812   }
4813 
4814   // Note that this behavior is observable: if we grant storage permission to a
4815   // tracker, we pass from the partitioned LocalStorage (or a partitioned cookie
4816   // jar) to the 'normal' one. The previous data is lost and the 2
4817   // window.localStorage objects, before and after the permission granted, will
4818   // be different.
4819   if (mLocalStorage) {
4820     if ((mLocalStorage->Type() == (isolated ? Storage::ePartitionedLocalStorage
4821                                             : Storage::eLocalStorage)) &&
4822         (mLocalStorage->StoragePrincipal() == GetEffectiveStoragePrincipal())) {
4823       return mLocalStorage;
4824     }
4825 
4826     // storage needs change
4827     mLocalStorage = nullptr;
4828   }
4829 
4830   MOZ_ASSERT(!mLocalStorage);
4831 
4832   if (!isolated) {
4833     RefPtr<Storage> storage;
4834 
4835     if (NextGenLocalStorageEnabled()) {
4836       aError = LSObject::CreateForWindow(this, getter_AddRefs(storage));
4837     } else {
4838       nsresult rv;
4839       nsCOMPtr<nsIDOMStorageManager> storageManager =
4840           do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
4841       if (NS_FAILED(rv)) {
4842         aError.Throw(rv);
4843         return nullptr;
4844       }
4845 
4846       nsString documentURI;
4847       if (mDoc) {
4848         aError = mDoc->GetDocumentURI(documentURI);
4849         if (NS_WARN_IF(aError.Failed())) {
4850           return nullptr;
4851         }
4852       }
4853 
4854       nsIPrincipal* principal = GetPrincipal();
4855       if (!principal) {
4856         aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
4857         return nullptr;
4858       }
4859 
4860       nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
4861       if (!storagePrincipal) {
4862         aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
4863         return nullptr;
4864       }
4865 
4866       aError = storageManager->CreateStorage(this, principal, storagePrincipal,
4867                                              documentURI, IsPrivateBrowsing(),
4868                                              getter_AddRefs(storage));
4869     }
4870 
4871     if (aError.Failed()) {
4872       return nullptr;
4873     }
4874 
4875     mLocalStorage = storage;
4876   } else {
4877     nsresult rv;
4878     nsCOMPtr<nsIDOMSessionStorageManager> storageManager =
4879         do_GetService("@mozilla.org/dom/sessionStorage-manager;1", &rv);
4880     if (NS_FAILED(rv)) {
4881       aError.Throw(rv);
4882       return nullptr;
4883     }
4884 
4885     nsIPrincipal* principal = GetPrincipal();
4886     if (!principal) {
4887       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
4888       return nullptr;
4889     }
4890 
4891     nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
4892     if (!storagePrincipal) {
4893       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
4894       return nullptr;
4895     }
4896 
4897     RefPtr<SessionStorageCache> cache;
4898     if (isolated) {
4899       cache = new SessionStorageCache();
4900     } else {
4901       // This will clone the session storage if it exists.
4902       rv = storageManager->GetSessionStorageCache(principal, storagePrincipal,
4903                                                   &cache);
4904       if (NS_FAILED(rv)) {
4905         aError.Throw(rv);
4906         return nullptr;
4907       }
4908     }
4909 
4910     mLocalStorage =
4911         new PartitionedLocalStorage(this, principal, storagePrincipal, cache);
4912   }
4913 
4914   MOZ_ASSERT(mLocalStorage);
4915   MOZ_ASSERT(
4916       mLocalStorage->Type() ==
4917       (isolated ? Storage::ePartitionedLocalStorage : Storage::eLocalStorage));
4918   return mLocalStorage;
4919 }
4920 
GetIndexedDB(ErrorResult & aError)4921 IDBFactory* nsGlobalWindowInner::GetIndexedDB(ErrorResult& aError) {
4922   if (!mIndexedDB) {
4923     // This may keep mIndexedDB null without setting an error.
4924     auto res = IDBFactory::CreateForWindow(this);
4925     if (res.isErr()) {
4926       aError = res.unwrapErr();
4927     } else {
4928       mIndexedDB = res.unwrap();
4929     }
4930   }
4931 
4932   return mIndexedDB;
4933 }
4934 
4935 //*****************************************************************************
4936 // nsGlobalWindowInner::nsIInterfaceRequestor
4937 //*****************************************************************************
4938 
4939 NS_IMETHODIMP
GetInterface(const nsIID & aIID,void ** aSink)4940 nsGlobalWindowInner::GetInterface(const nsIID& aIID, void** aSink) {
4941   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
4942   NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
4943 
4944   nsresult rv = outer->GetInterfaceInternal(aIID, aSink);
4945   if (rv == NS_ERROR_NO_INTERFACE) {
4946     return QueryInterface(aIID, aSink);
4947   }
4948   return rv;
4949 }
4950 
GetInterface(JSContext * aCx,JS::Handle<JS::Value> aIID,JS::MutableHandle<JS::Value> aRetval,ErrorResult & aError)4951 void nsGlobalWindowInner::GetInterface(JSContext* aCx,
4952                                        JS::Handle<JS::Value> aIID,
4953                                        JS::MutableHandle<JS::Value> aRetval,
4954                                        ErrorResult& aError) {
4955   dom::GetInterface(aCx, this, aIID, aRetval, aError);
4956 }
4957 
GetCaches(ErrorResult & aRv)4958 already_AddRefed<CacheStorage> nsGlobalWindowInner::GetCaches(
4959     ErrorResult& aRv) {
4960   if (!mCacheStorage) {
4961     bool forceTrustedOrigin =
4962         GetBrowsingContext() &&
4963         GetBrowsingContext()->Top()->GetServiceWorkersTestingEnabled();
4964     mCacheStorage = CacheStorage::CreateOnMainThread(
4965         cache::DEFAULT_NAMESPACE, this, GetEffectiveStoragePrincipal(),
4966         forceTrustedOrigin, aRv);
4967   }
4968 
4969   RefPtr<CacheStorage> ref = mCacheStorage;
4970   return ref.forget();
4971 }
4972 
FireOfflineStatusEventIfChanged()4973 void nsGlobalWindowInner::FireOfflineStatusEventIfChanged() {
4974   if (!IsCurrentInnerWindow()) return;
4975 
4976   // Don't fire an event if the status hasn't changed
4977   if (mWasOffline == NS_IsOffline()) {
4978     return;
4979   }
4980 
4981   mWasOffline = !mWasOffline;
4982 
4983   nsAutoString name;
4984   if (mWasOffline) {
4985     name.AssignLiteral("offline");
4986   } else {
4987     name.AssignLiteral("online");
4988   }
4989   nsContentUtils::DispatchTrustedEvent(mDoc, static_cast<EventTarget*>(this),
4990                                        name, CanBubble::eNo, Cancelable::eNo);
4991 }
4992 
4993 nsGlobalWindowInner::SlowScriptResponse
ShowSlowScriptDialog(JSContext * aCx,const nsString & aAddonId,const double aDuration)4994 nsGlobalWindowInner::ShowSlowScriptDialog(JSContext* aCx,
4995                                           const nsString& aAddonId,
4996                                           const double aDuration) {
4997   nsresult rv;
4998 
4999   if (Preferences::GetBool("dom.always_stop_slow_scripts")) {
5000     return KillSlowScript;
5001   }
5002 
5003   // If it isn't safe to run script, then it isn't safe to bring up the prompt
5004   // (since that spins the event loop). In that (rare) case, we just kill the
5005   // script and report a warning.
5006   if (!nsContentUtils::IsSafeToRunScript()) {
5007     JS::WarnASCII(aCx, "A long running script was terminated");
5008     return KillSlowScript;
5009   }
5010 
5011   // If our document is not active, just kill the script: we've been unloaded
5012   if (!HasActiveDocument()) {
5013     return KillSlowScript;
5014   }
5015 
5016   // Check if we should offer the option to debug
5017   JS::AutoFilename filename;
5018   unsigned lineno;
5019   // Computing the line number can be very expensive (see bug 1330231 for
5020   // example), and we don't use the line number anywhere except than in the
5021   // parent process, so we avoid computing it elsewhere.  This gives us most of
5022   // the wins we are interested in, since the source of the slowness here is
5023   // minified scripts which is more common in Web content that is loaded in the
5024   // content process.
5025   unsigned* linenop = XRE_IsParentProcess() ? &lineno : nullptr;
5026   bool hasFrame = JS::DescribeScriptedCaller(aCx, &filename, linenop);
5027 
5028   // Record the slow script event if we haven't done so already for this inner
5029   // window (which represents a particular page to the user).
5030   if (!mHasHadSlowScript) {
5031     Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT, 1);
5032   }
5033   mHasHadSlowScript = true;
5034 
5035   // Override the cursor to something that we're sure the user can see.
5036   SetCursor("auto"_ns, IgnoreErrors());
5037 
5038   if (XRE_IsContentProcess() && ProcessHangMonitor::Get()) {
5039     ProcessHangMonitor::SlowScriptAction action;
5040     RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
5041     nsIDocShell* docShell = GetDocShell();
5042     nsCOMPtr<nsIBrowserChild> child =
5043         docShell ? docShell->GetBrowserChild() : nullptr;
5044     action =
5045         monitor->NotifySlowScript(child, filename.get(), aAddonId, aDuration);
5046     if (action == ProcessHangMonitor::Terminate) {
5047       return KillSlowScript;
5048     }
5049 
5050     if (action == ProcessHangMonitor::StartDebugger) {
5051       // Spin a nested event loop so that the debugger in the parent can fetch
5052       // any information it needs. Once the debugger has started, return to the
5053       // script.
5054       RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal();
5055       outer->EnterModalState();
5056       SpinEventLoopUntil(
5057           [&]() { return monitor->IsDebuggerStartupComplete(); });
5058       outer->LeaveModalState();
5059       return ContinueSlowScript;
5060     }
5061 
5062     return ContinueSlowScriptAndKeepNotifying;
5063   }
5064 
5065   // Reached only on non-e10s - once per slow script dialog.
5066   // On e10s - we probe once at ProcessHangsMonitor.jsm
5067   Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTICE_COUNT, 1);
5068 
5069   // Get the nsIPrompt interface from the docshell
5070   nsCOMPtr<nsIDocShell> ds = GetDocShell();
5071   NS_ENSURE_TRUE(ds, KillSlowScript);
5072   nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
5073   NS_ENSURE_TRUE(prompt, KillSlowScript);
5074 
5075   // Prioritize the SlowScriptDebug interface over JSD1.
5076   nsCOMPtr<nsISlowScriptDebugCallback> debugCallback;
5077 
5078   if (hasFrame) {
5079     const char* debugCID = "@mozilla.org/dom/slow-script-debug;1";
5080     nsCOMPtr<nsISlowScriptDebug> debugService = do_GetService(debugCID, &rv);
5081     if (NS_SUCCEEDED(rv)) {
5082       debugService->GetActivationHandler(getter_AddRefs(debugCallback));
5083     }
5084   }
5085 
5086   bool failed = false;
5087   auto getString = [&](const char* name,
5088                        nsContentUtils::PropertiesFile propFile =
5089                            nsContentUtils::eDOM_PROPERTIES) {
5090     nsAutoString result;
5091     nsresult rv = nsContentUtils::GetLocalizedString(propFile, name, result);
5092 
5093     // GetStringFromName can return NS_OK and still give nullptr string
5094     failed = failed || NS_FAILED(rv) || result.IsEmpty();
5095     return result;
5096   };
5097 
5098   bool isAddonScript = !aAddonId.IsEmpty();
5099   bool showDebugButton = debugCallback && !isAddonScript;
5100 
5101   // Get localizable strings
5102 
5103   nsAutoString title, checkboxMsg, debugButton, msg;
5104   if (isAddonScript) {
5105     title = getString("KillAddonScriptTitle");
5106     checkboxMsg = getString("KillAddonScriptGlobalMessage");
5107 
5108     auto appName =
5109         getString("brandShortName", nsContentUtils::eBRAND_PROPERTIES);
5110 
5111     nsCOMPtr<nsIAddonPolicyService> aps =
5112         do_GetService("@mozilla.org/addons/policy-service;1");
5113     nsString addonName;
5114     if (!aps || NS_FAILED(aps->GetExtensionName(aAddonId, addonName))) {
5115       addonName = aAddonId;
5116     }
5117 
5118     rv = nsContentUtils::FormatLocalizedString(
5119         msg, nsContentUtils::eDOM_PROPERTIES, "KillAddonScriptMessage",
5120         addonName, appName);
5121 
5122     failed = failed || NS_FAILED(rv);
5123   } else {
5124     title = getString("KillScriptTitle");
5125     checkboxMsg = getString("DontAskAgain");
5126 
5127     if (showDebugButton) {
5128       debugButton = getString("DebugScriptButton");
5129       msg = getString("KillScriptWithDebugMessage");
5130     } else {
5131       msg = getString("KillScriptMessage");
5132     }
5133   }
5134 
5135   auto stopButton = getString("StopScriptButton");
5136   auto waitButton = getString("WaitForScriptButton");
5137 
5138   if (failed) {
5139     NS_ERROR("Failed to get localized strings.");
5140     return ContinueSlowScript;
5141   }
5142 
5143   // Append file and line number information, if available
5144   if (filename.get()) {
5145     nsAutoString scriptLocation;
5146     // We want to drop the middle part of too-long locations.  We'll
5147     // define "too-long" as longer than 60 UTF-16 code units.  Just
5148     // have to be a bit careful about unpaired surrogates.
5149     NS_ConvertUTF8toUTF16 filenameUTF16(filename.get());
5150     if (filenameUTF16.Length() > 60) {
5151       // XXXbz Do we need to insert any bidi overrides here?
5152       size_t cutStart = 30;
5153       size_t cutLength = filenameUTF16.Length() - 60;
5154       MOZ_ASSERT(cutLength > 0);
5155       if (NS_IS_LOW_SURROGATE(filenameUTF16[cutStart])) {
5156         // Don't truncate before the low surrogate, in case it's preceded by a
5157         // high surrogate and forms a single Unicode character.  Instead, just
5158         // include the low surrogate.
5159         ++cutStart;
5160         --cutLength;
5161       }
5162       if (NS_IS_LOW_SURROGATE(filenameUTF16[cutStart + cutLength])) {
5163         // Likewise, don't drop a trailing low surrogate here.  We want to
5164         // increase cutLength, since it might be 0 already so we can't very well
5165         // decrease it.
5166         ++cutLength;
5167       }
5168 
5169       // Insert U+2026 HORIZONTAL ELLIPSIS
5170       filenameUTF16.ReplaceLiteral(cutStart, cutLength, u"\x2026");
5171     }
5172     rv = nsContentUtils::FormatLocalizedString(
5173         scriptLocation, nsContentUtils::eDOM_PROPERTIES, "KillScriptLocation",
5174         filenameUTF16);
5175 
5176     if (NS_SUCCEEDED(rv)) {
5177       msg.AppendLiteral("\n\n");
5178       msg.Append(scriptLocation);
5179       msg.Append(':');
5180       msg.AppendInt(lineno);
5181     }
5182   }
5183 
5184   uint32_t buttonFlags = nsIPrompt::BUTTON_POS_1_DEFAULT +
5185                          (nsIPrompt::BUTTON_TITLE_IS_STRING *
5186                           (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
5187 
5188   // Add a third button if necessary.
5189   if (showDebugButton)
5190     buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
5191 
5192   bool checkboxValue = false;
5193   int32_t buttonPressed = 0;  // In case the user exits dialog by clicking X.
5194   {
5195     // Null out the operation callback while we're re-entering JS here.
5196     AutoDisableJSInterruptCallback disabler(aCx);
5197 
5198     // Open the dialog.
5199     rv = prompt->ConfirmEx(
5200         title.get(), msg.get(), buttonFlags, waitButton.get(), stopButton.get(),
5201         debugButton.get(), checkboxMsg.get(), &checkboxValue, &buttonPressed);
5202   }
5203 
5204   if (buttonPressed == 0) {
5205     if (checkboxValue && !isAddonScript && NS_SUCCEEDED(rv))
5206       return AlwaysContinueSlowScript;
5207     return ContinueSlowScript;
5208   }
5209 
5210   if (buttonPressed == 2) {
5211     MOZ_RELEASE_ASSERT(debugCallback);
5212 
5213     rv = debugCallback->HandleSlowScriptDebug(this);
5214     return NS_SUCCEEDED(rv) ? ContinueSlowScript : KillSlowScript;
5215   }
5216 
5217   JS_ClearPendingException(aCx);
5218 
5219   return KillSlowScript;
5220 }
5221 
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)5222 nsresult nsGlobalWindowInner::Observe(nsISupports* aSubject, const char* aTopic,
5223                                       const char16_t* aData) {
5224   if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
5225     if (!IsFrozen()) {
5226       // Fires an offline status event if the offline status has changed
5227       FireOfflineStatusEventIfChanged();
5228     }
5229     return NS_OK;
5230   }
5231 
5232   if (!nsCRT::strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) {
5233     if (mPerformance) {
5234       mPerformance->MemoryPressure();
5235     }
5236     RemoveReportRecords();
5237     return NS_OK;
5238   }
5239 
5240   if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) {
5241     if (mApplicationCache) return NS_OK;
5242 
5243     // Instantiate the application object now. It observes update belonging to
5244     // this window's document and correctly updates the applicationCache object
5245     // state.
5246     nsCOMPtr<nsIObserver> observer = GetApplicationCache();
5247     if (observer) observer->Observe(aSubject, aTopic, aData);
5248 
5249     return NS_OK;
5250   }
5251 
5252   if (!nsCRT::strcmp(aTopic, PERMISSION_CHANGED_TOPIC)) {
5253     nsCOMPtr<nsIPermission> perm(do_QueryInterface(aSubject));
5254     if (!perm) {
5255       // A null permission indicates that the entire permission list
5256       // was cleared.
5257       MOZ_ASSERT(!nsCRT::strcmp(aData, u"cleared"));
5258       UpdatePermissions();
5259       return NS_OK;
5260     }
5261 
5262     nsAutoCString type;
5263     perm->GetType(type);
5264     if (type == "autoplay-media"_ns) {
5265       UpdateAutoplayPermission();
5266     } else if (type == "shortcuts"_ns) {
5267       UpdateShortcutsPermission();
5268     } else if (type == "popup"_ns) {
5269       UpdatePopupPermission();
5270     }
5271 
5272     if (!mDoc) {
5273       return NS_OK;
5274     }
5275 
5276     RefPtr<PermissionDelegateHandler> permDelegateHandler =
5277         mDoc->GetPermissionDelegateHandler();
5278 
5279     if (permDelegateHandler) {
5280       permDelegateHandler->UpdateDelegatedPermission(type);
5281     }
5282 
5283     return NS_OK;
5284   }
5285 
5286   if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
5287     MOZ_ASSERT(!NS_strcmp(aData, u"intl.accept_languages"));
5288 
5289     // The user preferred languages have changed, we need to fire an event on
5290     // Window object and invalidate the cache for navigator.languages. It is
5291     // done for every change which can be a waste of cycles but those should be
5292     // fairly rare.
5293     // We MUST invalidate navigator.languages before sending the event in the
5294     // very likely situation where an event handler will try to read its value.
5295 
5296     if (mNavigator) {
5297       Navigator_Binding::ClearCachedLanguageValue(mNavigator);
5298       Navigator_Binding::ClearCachedLanguagesValue(mNavigator);
5299     }
5300 
5301     // The event has to be dispatched only to the current inner window.
5302     if (!IsCurrentInnerWindow()) {
5303       return NS_OK;
5304     }
5305 
5306     RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
5307     event->InitEvent(u"languagechange"_ns, false, false);
5308     event->SetTrusted(true);
5309 
5310     ErrorResult rv;
5311     DispatchEvent(*event, rv);
5312     return rv.StealNSResult();
5313   }
5314 
5315   NS_WARNING("unrecognized topic in nsGlobalWindowInner::Observe");
5316   return NS_ERROR_FAILURE;
5317 }
5318 
ObserveStorageNotification(StorageEvent * aEvent,const char16_t * aStorageType,bool aPrivateBrowsing)5319 void nsGlobalWindowInner::ObserveStorageNotification(
5320     StorageEvent* aEvent, const char16_t* aStorageType, bool aPrivateBrowsing) {
5321   MOZ_ASSERT(aEvent);
5322 
5323   // The private browsing check must be done here again because this window
5324   // could have changed its state before the notification check and now. This
5325   // happens in case this window did have a docShell at that time.
5326   if (aPrivateBrowsing != IsPrivateBrowsing()) {
5327     return;
5328   }
5329 
5330   // LocalStorage can only exist on an inner window, and we don't want to
5331   // generate events on frozen or otherwise-navigated-away from windows.
5332   // (Actually, this code used to try and buffer events for frozen windows,
5333   // but it never worked, so we've removed it.  See bug 1285898.)
5334   if (!IsCurrentInnerWindow() || IsFrozen()) {
5335     return;
5336   }
5337 
5338   nsIPrincipal* principal = GetPrincipal();
5339   if (!principal) {
5340     return;
5341   }
5342 
5343   bool fireMozStorageChanged = false;
5344   nsAutoString eventType;
5345   eventType.AssignLiteral("storage");
5346 
5347   if (!NS_strcmp(aStorageType, u"sessionStorage")) {
5348     RefPtr<Storage> changingStorage = aEvent->GetStorageArea();
5349     MOZ_ASSERT(changingStorage);
5350 
5351     bool check = false;
5352 
5353     if (const RefPtr<SessionStorageManager> storageManager =
5354             GetBrowsingContext()->GetSessionStorageManager()) {
5355       nsresult rv = storageManager->CheckStorage(GetEffectiveStoragePrincipal(),
5356                                                  changingStorage, &check);
5357       if (NS_FAILED(rv)) {
5358         return;
5359       }
5360     }
5361 
5362     if (!check) {
5363       // This storage event is not coming from our storage or is coming
5364       // from a different docshell, i.e. it is a clone, ignore this event.
5365       return;
5366     }
5367 
5368     MOZ_LOG(
5369         gDOMLeakPRLogInner, LogLevel::Debug,
5370         ("nsGlobalWindowInner %p with sessionStorage %p passing event from %p",
5371          this, mSessionStorage.get(), changingStorage.get()));
5372 
5373     fireMozStorageChanged = mSessionStorage == changingStorage;
5374     if (fireMozStorageChanged) {
5375       eventType.AssignLiteral("MozSessionStorageChanged");
5376     }
5377   }
5378 
5379   else {
5380     MOZ_ASSERT(!NS_strcmp(aStorageType, u"localStorage"));
5381 
5382     nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
5383     if (!storagePrincipal) {
5384       return;
5385     }
5386 
5387     MOZ_DIAGNOSTIC_ASSERT(StorageUtils::PrincipalsEqual(aEvent->GetPrincipal(),
5388                                                         storagePrincipal));
5389 
5390     fireMozStorageChanged =
5391         mLocalStorage && mLocalStorage == aEvent->GetStorageArea();
5392 
5393     if (fireMozStorageChanged) {
5394       eventType.AssignLiteral("MozLocalStorageChanged");
5395     }
5396   }
5397 
5398   // Clone the storage event included in the observer notification. We want
5399   // to dispatch clones rather than the original event.
5400   IgnoredErrorResult error;
5401   RefPtr<StorageEvent> clonedEvent =
5402       CloneStorageEvent(eventType, aEvent, error);
5403   if (error.Failed() || !clonedEvent) {
5404     return;
5405   }
5406 
5407   clonedEvent->SetTrusted(true);
5408 
5409   if (fireMozStorageChanged) {
5410     WidgetEvent* internalEvent = clonedEvent->WidgetEventPtr();
5411     internalEvent->mFlags.mOnlyChromeDispatch = true;
5412   }
5413 
5414   DispatchEvent(*clonedEvent);
5415 }
5416 
CloneStorageEvent(const nsAString & aType,const RefPtr<StorageEvent> & aEvent,ErrorResult & aRv)5417 already_AddRefed<StorageEvent> nsGlobalWindowInner::CloneStorageEvent(
5418     const nsAString& aType, const RefPtr<StorageEvent>& aEvent,
5419     ErrorResult& aRv) {
5420   StorageEventInit dict;
5421 
5422   dict.mBubbles = aEvent->Bubbles();
5423   dict.mCancelable = aEvent->Cancelable();
5424   aEvent->GetKey(dict.mKey);
5425   aEvent->GetOldValue(dict.mOldValue);
5426   aEvent->GetNewValue(dict.mNewValue);
5427   aEvent->GetUrl(dict.mUrl);
5428 
5429   RefPtr<Storage> storageArea = aEvent->GetStorageArea();
5430 
5431   RefPtr<Storage> storage;
5432 
5433   // If null, this is a localStorage event received by IPC.
5434   if (!storageArea) {
5435     storage = GetLocalStorage(aRv);
5436     if (!NextGenLocalStorageEnabled()) {
5437       if (aRv.Failed() || !storage) {
5438         return nullptr;
5439       }
5440 
5441       if (storage->Type() == Storage::eLocalStorage) {
5442         RefPtr<LocalStorage> localStorage =
5443             static_cast<LocalStorage*>(storage.get());
5444 
5445         // We must apply the current change to the 'local' localStorage.
5446         localStorage->ApplyEvent(aEvent);
5447       }
5448     }
5449   } else if (storageArea->Type() == Storage::eSessionStorage) {
5450     storage = GetSessionStorage(aRv);
5451   } else {
5452     MOZ_ASSERT(storageArea->Type() == Storage::eLocalStorage);
5453     storage = GetLocalStorage(aRv);
5454   }
5455 
5456   if (aRv.Failed() || !storage) {
5457     return nullptr;
5458   }
5459 
5460   if (storage->Type() == Storage::ePartitionedLocalStorage) {
5461     // This error message is not exposed.
5462     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
5463     return nullptr;
5464   }
5465 
5466   MOZ_ASSERT(storage);
5467   MOZ_ASSERT_IF(storageArea, storage->IsForkOf(storageArea));
5468 
5469   dict.mStorageArea = storage;
5470 
5471   RefPtr<StorageEvent> event = StorageEvent::Constructor(this, aType, dict);
5472   return event.forget();
5473 }
5474 
Suspend(bool aIncludeSubWindows)5475 void nsGlobalWindowInner::Suspend(bool aIncludeSubWindows) {
5476   MOZ_ASSERT(NS_IsMainThread());
5477 
5478   // We can only safely suspend windows that are the current inner window.  If
5479   // its not the current inner, then we are in one of two different cases.
5480   // Either we are in the bfcache or we are doomed window that is going away.
5481   // When a window becomes inactive we purposely avoid placing already suspended
5482   // windows into the bfcache.  It only expects windows suspended due to the
5483   // Freeze() method which occurs while the window is still the current inner.
5484   // So we must not call Suspend() on bfcache windows at this point or this
5485   // invariant will be broken.  If the window is doomed there is no point in
5486   // suspending it since it will soon be gone.
5487   if (!IsCurrentInnerWindow()) {
5488     return;
5489   }
5490 
5491   // All in-process descendants are also suspended.  This ensure mSuspendDepth
5492   // is set properly and the timers are properly canceled for each in-process
5493   // descendant.
5494   if (aIncludeSubWindows) {
5495     CallOnInProcessDescendants(&nsGlobalWindowInner::Suspend, false);
5496   }
5497 
5498   mSuspendDepth += 1;
5499   if (mSuspendDepth != 1) {
5500     return;
5501   }
5502 
5503   if (mWindowGlobalChild) {
5504     mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::SUSPENDED);
5505   }
5506 
5507   nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
5508   if (ac) {
5509     for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
5510       ac->RemoveWindowListener(mEnabledSensors[i], this);
5511   }
5512   DisableGamepadUpdates();
5513   DisableVRUpdates();
5514 
5515   SuspendWorkersForWindow(*this);
5516 
5517   for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
5518        mSharedWorkers.ForwardRange()) {
5519     pinnedWorker->Suspend();
5520   }
5521 
5522   SuspendIdleRequests();
5523 
5524   mTimeoutManager->Suspend();
5525 
5526   // Suspend all of the AudioContexts for this window
5527   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
5528     mAudioContexts[i]->SuspendFromChrome();
5529   }
5530 }
5531 
Resume(bool aIncludeSubWindows)5532 void nsGlobalWindowInner::Resume(bool aIncludeSubWindows) {
5533   MOZ_ASSERT(NS_IsMainThread());
5534 
5535   // We can only safely resume a window if its the current inner window.  If
5536   // its not the current inner, then we are in one of two different cases.
5537   // Either we are in the bfcache or we are doomed window that is going away.
5538   // If a window is suspended when it becomes inactive we purposely do not
5539   // put it in the bfcache, so Resume should never be needed in that case.
5540   // If the window is doomed then there is no point in resuming it.
5541   if (!IsCurrentInnerWindow()) {
5542     return;
5543   }
5544 
5545   // Resume all in-process descendants.  This restores timers recursively
5546   // canceled in Suspend() and ensures all in-process descendants have the
5547   // correct mSuspendDepth.
5548   if (aIncludeSubWindows) {
5549     CallOnInProcessDescendants(&nsGlobalWindowInner::Resume, false);
5550   }
5551 
5552   if (mSuspendDepth == 0) {
5553     // Ignore if the window is not suspended.
5554     return;
5555   }
5556 
5557   mSuspendDepth -= 1;
5558 
5559   if (mSuspendDepth != 0) {
5560     return;
5561   }
5562 
5563   // We should not be able to resume a frozen window.  It must be Thaw()'d
5564   // first.
5565   MOZ_ASSERT(mFreezeDepth == 0);
5566 
5567   nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
5568   if (ac) {
5569     for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
5570       ac->AddWindowListener(mEnabledSensors[i], this);
5571   }
5572   EnableGamepadUpdates();
5573   EnableVRUpdates();
5574 
5575   // Resume all of the AudioContexts for this window
5576   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
5577     mAudioContexts[i]->ResumeFromChrome();
5578   }
5579 
5580   mTimeoutManager->Resume();
5581 
5582   ResumeIdleRequests();
5583 
5584   // Resume all of the workers for this window.  We must do this
5585   // after timeouts since workers may have queued events that can trigger
5586   // a setTimeout().
5587   ResumeWorkersForWindow(*this);
5588 
5589   for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
5590        mSharedWorkers.ForwardRange()) {
5591     pinnedWorker->Resume();
5592   }
5593 
5594   if (mWindowGlobalChild) {
5595     mWindowGlobalChild->UnblockBFCacheFor(BFCacheStatus::SUSPENDED);
5596   }
5597 }
5598 
IsSuspended() const5599 bool nsGlobalWindowInner::IsSuspended() const {
5600   MOZ_ASSERT(NS_IsMainThread());
5601   return mSuspendDepth != 0;
5602 }
5603 
Freeze(bool aIncludeSubWindows)5604 void nsGlobalWindowInner::Freeze(bool aIncludeSubWindows) {
5605   MOZ_ASSERT(NS_IsMainThread());
5606   Suspend(aIncludeSubWindows);
5607   FreezeInternal(aIncludeSubWindows);
5608 }
5609 
FreezeInternal(bool aIncludeSubWindows)5610 void nsGlobalWindowInner::FreezeInternal(bool aIncludeSubWindows) {
5611   MOZ_ASSERT(NS_IsMainThread());
5612   MOZ_DIAGNOSTIC_ASSERT(IsCurrentInnerWindow());
5613   MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
5614 
5615   HintIsLoading(false);
5616 
5617   if (aIncludeSubWindows) {
5618     CallOnInProcessChildren(&nsGlobalWindowInner::FreezeInternal,
5619                             aIncludeSubWindows);
5620   }
5621 
5622   mFreezeDepth += 1;
5623   MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
5624   if (mFreezeDepth != 1) {
5625     return;
5626   }
5627 
5628   FreezeWorkersForWindow(*this);
5629 
5630   for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
5631        mSharedWorkers.ForwardRange()) {
5632     pinnedWorker->Freeze();
5633   }
5634 
5635   mTimeoutManager->Freeze();
5636   if (mClientSource) {
5637     mClientSource->Freeze();
5638   }
5639 
5640   NotifyDOMWindowFrozen(this);
5641 }
5642 
Thaw(bool aIncludeSubWindows)5643 void nsGlobalWindowInner::Thaw(bool aIncludeSubWindows) {
5644   MOZ_ASSERT(NS_IsMainThread());
5645   ThawInternal(aIncludeSubWindows);
5646   Resume(aIncludeSubWindows);
5647 }
5648 
ThawInternal(bool aIncludeSubWindows)5649 void nsGlobalWindowInner::ThawInternal(bool aIncludeSubWindows) {
5650   MOZ_ASSERT(NS_IsMainThread());
5651   MOZ_DIAGNOSTIC_ASSERT(IsCurrentInnerWindow());
5652   MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
5653 
5654   if (aIncludeSubWindows) {
5655     CallOnInProcessChildren(&nsGlobalWindowInner::ThawInternal,
5656                             aIncludeSubWindows);
5657   }
5658 
5659   MOZ_ASSERT(mFreezeDepth != 0);
5660   mFreezeDepth -= 1;
5661   MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
5662   if (mFreezeDepth != 0) {
5663     return;
5664   }
5665 
5666   if (mClientSource) {
5667     mClientSource->Thaw();
5668   }
5669   mTimeoutManager->Thaw();
5670 
5671   ThawWorkersForWindow(*this);
5672 
5673   for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
5674        mSharedWorkers.ForwardRange()) {
5675     pinnedWorker->Thaw();
5676   }
5677 
5678   NotifyDOMWindowThawed(this);
5679 }
5680 
IsFrozen() const5681 bool nsGlobalWindowInner::IsFrozen() const {
5682   MOZ_ASSERT(NS_IsMainThread());
5683   bool frozen = mFreezeDepth != 0;
5684   MOZ_ASSERT_IF(frozen, IsSuspended());
5685   return frozen;
5686 }
5687 
SyncStateFromParentWindow()5688 void nsGlobalWindowInner::SyncStateFromParentWindow() {
5689   // This method should only be called on an inner window that has been
5690   // assigned to an outer window already.
5691   MOZ_ASSERT(IsCurrentInnerWindow());
5692   nsPIDOMWindowOuter* outer = GetOuterWindow();
5693   MOZ_ASSERT(outer);
5694 
5695   // Attempt to find our parent windows.
5696   nsCOMPtr<Element> frame = outer->GetFrameElementInternal();
5697   nsPIDOMWindowOuter* parentOuter =
5698       frame ? frame->OwnerDoc()->GetWindow() : nullptr;
5699   nsGlobalWindowInner* parentInner =
5700       parentOuter
5701           ? nsGlobalWindowInner::Cast(parentOuter->GetCurrentInnerWindow())
5702           : nullptr;
5703 
5704   // If our outer is in a modal state, but our parent is not in a modal
5705   // state, then we must apply the suspend directly.  If our parent is
5706   // in a modal state then we should get the suspend automatically
5707   // via the parentSuspendDepth application below.
5708   if ((!parentInner || !parentInner->IsInModalState()) && IsInModalState()) {
5709     Suspend();
5710   }
5711 
5712   uint32_t parentFreezeDepth = parentInner ? parentInner->mFreezeDepth : 0;
5713   uint32_t parentSuspendDepth = parentInner ? parentInner->mSuspendDepth : 0;
5714 
5715   // Since every Freeze() calls Suspend(), the suspend count must
5716   // be equal or greater to the freeze count.
5717   MOZ_ASSERT(parentFreezeDepth <= parentSuspendDepth);
5718 
5719   // First apply the Freeze() calls.
5720   for (uint32_t i = 0; i < parentFreezeDepth; ++i) {
5721     Freeze();
5722   }
5723 
5724   // Now apply only the number of Suspend() calls to reach the target
5725   // suspend count after applying the Freeze() calls.
5726   for (uint32_t i = 0; i < (parentSuspendDepth - parentFreezeDepth); ++i) {
5727     Suspend();
5728   }
5729 }
5730 
5731 template <typename Method, typename... Args>
CallOnInProcessDescendantsInternal(BrowsingContext * aBrowsingContext,bool aChildOnly,Method aMethod,Args &&...aArgs)5732 CallState nsGlobalWindowInner::CallOnInProcessDescendantsInternal(
5733     BrowsingContext* aBrowsingContext, bool aChildOnly, Method aMethod,
5734     Args&&... aArgs) {
5735   MOZ_ASSERT(NS_IsMainThread());
5736   MOZ_ASSERT(aBrowsingContext);
5737 
5738   CallState state = CallState::Continue;
5739   for (const RefPtr<BrowsingContext>& bc : aBrowsingContext->Children()) {
5740     if (nsCOMPtr<nsPIDOMWindowOuter> pWin = bc->GetDOMWindow()) {
5741       auto* win = nsGlobalWindowOuter::Cast(pWin);
5742       if (nsGlobalWindowInner* inner = win->GetCurrentInnerWindowInternal()) {
5743         // Call the descendant method using our helper CallDescendant() template
5744         // method. This allows us to handle both void returning methods and
5745         // methods that return CallState explicitly.  For void returning methods
5746         // we assume CallState::Continue.
5747         typedef decltype((inner->*aMethod)(aArgs...)) returnType;
5748         state = CallDescendant<returnType>(inner, aMethod, aArgs...);
5749 
5750         if (state == CallState::Stop) {
5751           return state;
5752         }
5753       }
5754     }
5755 
5756     if (!aChildOnly) {
5757       state = CallOnInProcessDescendantsInternal(bc.get(), aChildOnly, aMethod,
5758                                                  aArgs...);
5759       if (state == CallState::Stop) {
5760         return state;
5761       }
5762     }
5763   }
5764 
5765   return state;
5766 }
5767 
GetClientInfo() const5768 Maybe<ClientInfo> nsGlobalWindowInner::GetClientInfo() const {
5769   MOZ_ASSERT(NS_IsMainThread());
5770   if (mDoc && mDoc->IsStaticDocument()) {
5771     if (Maybe<ClientInfo> info = mDoc->GetOriginalDocument()->GetClientInfo()) {
5772       return info;
5773     }
5774   }
5775 
5776   Maybe<ClientInfo> clientInfo;
5777   if (mClientSource) {
5778     clientInfo.emplace(mClientSource->Info());
5779   }
5780   return clientInfo;
5781 }
5782 
GetClientState() const5783 Maybe<ClientState> nsGlobalWindowInner::GetClientState() const {
5784   MOZ_ASSERT(NS_IsMainThread());
5785   if (mDoc && mDoc->IsStaticDocument()) {
5786     if (Maybe<ClientState> state =
5787             mDoc->GetOriginalDocument()->GetClientState()) {
5788       return state;
5789     }
5790   }
5791 
5792   Maybe<ClientState> clientState;
5793   if (mClientSource) {
5794     Result<ClientState, ErrorResult> res = mClientSource->SnapshotState();
5795     if (res.isOk()) {
5796       clientState.emplace(res.unwrap());
5797     } else {
5798       res.unwrapErr().SuppressException();
5799     }
5800   }
5801   return clientState;
5802 }
5803 
GetController() const5804 Maybe<ServiceWorkerDescriptor> nsGlobalWindowInner::GetController() const {
5805   MOZ_ASSERT(NS_IsMainThread());
5806   if (mDoc && mDoc->IsStaticDocument()) {
5807     if (Maybe<ServiceWorkerDescriptor> controller =
5808             mDoc->GetOriginalDocument()->GetController()) {
5809       return controller;
5810     }
5811   }
5812 
5813   Maybe<ServiceWorkerDescriptor> controller;
5814   if (mClientSource) {
5815     controller = mClientSource->GetController();
5816   }
5817   return controller;
5818 }
5819 
SetCsp(nsIContentSecurityPolicy * aCsp)5820 void nsGlobalWindowInner::SetCsp(nsIContentSecurityPolicy* aCsp) {
5821   if (!mClientSource) {
5822     return;
5823   }
5824   mClientSource->SetCsp(aCsp);
5825   // Also cache the CSP within the document
5826   mDoc->SetCsp(aCsp);
5827 
5828   if (mWindowGlobalChild) {
5829     mWindowGlobalChild->SendSetClientInfo(mClientSource->Info().ToIPC());
5830   }
5831 }
5832 
SetPreloadCsp(nsIContentSecurityPolicy * aPreloadCsp)5833 void nsGlobalWindowInner::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCsp) {
5834   if (!mClientSource) {
5835     return;
5836   }
5837   mClientSource->SetPreloadCsp(aPreloadCsp);
5838   // Also cache the preload CSP within the document
5839   mDoc->SetPreloadCsp(aPreloadCsp);
5840 
5841   if (mWindowGlobalChild) {
5842     mWindowGlobalChild->SendSetClientInfo(mClientSource->Info().ToIPC());
5843   }
5844 }
5845 
GetCsp()5846 nsIContentSecurityPolicy* nsGlobalWindowInner::GetCsp() {
5847   if (mDoc) {
5848     return mDoc->GetCsp();
5849   }
5850 
5851   // If the window is partially torn down and has its document nulled out,
5852   // we query the CSP we snapshot in FreeInnerObjects.
5853   if (mDocumentCsp) {
5854     return mDocumentCsp;
5855   }
5856   return nullptr;
5857 }
5858 
GetOrCreateServiceWorker(const ServiceWorkerDescriptor & aDescriptor)5859 RefPtr<ServiceWorker> nsGlobalWindowInner::GetOrCreateServiceWorker(
5860     const ServiceWorkerDescriptor& aDescriptor) {
5861   MOZ_ASSERT(NS_IsMainThread());
5862   RefPtr<ServiceWorker> ref;
5863   ForEachEventTargetObject([&](DOMEventTargetHelper* aTarget, bool* aDoneOut) {
5864     RefPtr<ServiceWorker> sw = do_QueryObject(aTarget);
5865     if (!sw || !sw->Descriptor().Matches(aDescriptor)) {
5866       return;
5867     }
5868 
5869     ref = std::move(sw);
5870     *aDoneOut = true;
5871   });
5872 
5873   if (!ref) {
5874     ref = ServiceWorker::Create(this, aDescriptor);
5875   }
5876 
5877   return ref;
5878 }
5879 
5880 RefPtr<mozilla::dom::ServiceWorkerRegistration>
GetServiceWorkerRegistration(const mozilla::dom::ServiceWorkerRegistrationDescriptor & aDescriptor) const5881 nsGlobalWindowInner::GetServiceWorkerRegistration(
5882     const mozilla::dom::ServiceWorkerRegistrationDescriptor& aDescriptor)
5883     const {
5884   MOZ_ASSERT(NS_IsMainThread());
5885   RefPtr<ServiceWorkerRegistration> ref;
5886   ForEachEventTargetObject([&](DOMEventTargetHelper* aTarget, bool* aDoneOut) {
5887     RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aTarget);
5888     if (!swr || !swr->MatchesDescriptor(aDescriptor)) {
5889       return;
5890     }
5891 
5892     ref = std::move(swr);
5893     *aDoneOut = true;
5894   });
5895   return ref;
5896 }
5897 
5898 RefPtr<ServiceWorkerRegistration>
GetOrCreateServiceWorkerRegistration(const ServiceWorkerRegistrationDescriptor & aDescriptor)5899 nsGlobalWindowInner::GetOrCreateServiceWorkerRegistration(
5900     const ServiceWorkerRegistrationDescriptor& aDescriptor) {
5901   MOZ_ASSERT(NS_IsMainThread());
5902   RefPtr<ServiceWorkerRegistration> ref =
5903       GetServiceWorkerRegistration(aDescriptor);
5904   if (!ref) {
5905     ref = ServiceWorkerRegistration::CreateForMainThread(this, aDescriptor);
5906   }
5907   return ref;
5908 }
5909 
FireDelayedDOMEvents(bool aIncludeSubWindows)5910 nsresult nsGlobalWindowInner::FireDelayedDOMEvents(bool aIncludeSubWindows) {
5911   if (mApplicationCache) {
5912     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())
5913         ->FirePendingEvents();
5914   }
5915 
5916   // Fires an offline status event if the offline status has changed
5917   FireOfflineStatusEventIfChanged();
5918 
5919   if (!aIncludeSubWindows) {
5920     return NS_OK;
5921   }
5922 
5923   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
5924   if (docShell) {
5925     int32_t childCount = 0;
5926     docShell->GetInProcessChildCount(&childCount);
5927 
5928     // Take a copy of the current children so that modifications to
5929     // the child list don't affect to the iteration.
5930     AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> children;
5931     for (int32_t i = 0; i < childCount; ++i) {
5932       nsCOMPtr<nsIDocShellTreeItem> childShell;
5933       docShell->GetInProcessChildAt(i, getter_AddRefs(childShell));
5934       if (childShell) {
5935         children.AppendElement(childShell);
5936       }
5937     }
5938 
5939     for (nsCOMPtr<nsIDocShellTreeItem> childShell : children) {
5940       if (nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow()) {
5941         auto* win = nsGlobalWindowOuter::Cast(pWin);
5942         win->FireDelayedDOMEvents(true);
5943       }
5944     }
5945   }
5946 
5947   return NS_OK;
5948 }
5949 
5950 //*****************************************************************************
5951 // nsGlobalWindowInner: Window Control Functions
5952 //*****************************************************************************
5953 
GetInProcessParentInternal()5954 nsPIDOMWindowOuter* nsGlobalWindowInner::GetInProcessParentInternal() {
5955   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
5956   if (!outer) {
5957     // No outer window available!
5958     return nullptr;
5959   }
5960   return outer->GetInProcessParentInternal();
5961 }
5962 
GetTopLevelAntiTrackingPrincipal()5963 nsIPrincipal* nsGlobalWindowInner::GetTopLevelAntiTrackingPrincipal() {
5964   nsPIDOMWindowOuter* outerWindow = GetOuterWindowInternal();
5965   if (!outerWindow) {
5966     return nullptr;
5967   }
5968 
5969   nsPIDOMWindowOuter* topLevelOuterWindow =
5970       GetBrowsingContext()->Top()->GetDOMWindow();
5971   if (!topLevelOuterWindow) {
5972     return nullptr;
5973   }
5974 
5975   bool stopAtOurLevel =
5976       mDoc && mDoc->CookieJarSettings()->GetCookieBehavior() ==
5977                   nsICookieService::BEHAVIOR_REJECT_TRACKER;
5978 
5979   if (stopAtOurLevel && topLevelOuterWindow == outerWindow) {
5980     return nullptr;
5981   }
5982 
5983   nsPIDOMWindowInner* topLevelInnerWindow =
5984       topLevelOuterWindow->GetCurrentInnerWindow();
5985   if (NS_WARN_IF(!topLevelInnerWindow)) {
5986     return nullptr;
5987   }
5988 
5989   nsIPrincipal* topLevelPrincipal =
5990       nsGlobalWindowInner::Cast(topLevelInnerWindow)->GetPrincipal();
5991   if (NS_WARN_IF(!topLevelPrincipal)) {
5992     return nullptr;
5993   }
5994 
5995   return topLevelPrincipal;
5996 }
5997 
GetTopLevelStorageAreaPrincipal()5998 nsIPrincipal* nsGlobalWindowInner::GetTopLevelStorageAreaPrincipal() {
5999   if (mDoc && (mDoc->StorageAccessSandboxed())) {
6000     // Storage access is disabled
6001     return nullptr;
6002   }
6003 
6004   BrowsingContext* parent = GetBrowsingContext()->GetParent();
6005   nsPIDOMWindowOuter* outerWindow = parent ? parent->GetDOMWindow() : nullptr;
6006   if (!outerWindow) {
6007     // No outer window available!
6008     return nullptr;
6009   }
6010 
6011   if (!outerWindow->GetBrowsingContext()->IsTop()) {
6012     return nullptr;
6013   }
6014 
6015   nsPIDOMWindowInner* innerWindow = outerWindow->GetCurrentInnerWindow();
6016   if (NS_WARN_IF(!innerWindow)) {
6017     return nullptr;
6018   }
6019 
6020   nsIPrincipal* parentPrincipal =
6021       nsGlobalWindowInner::Cast(innerWindow)->GetPrincipal();
6022   if (NS_WARN_IF(!parentPrincipal)) {
6023     return nullptr;
6024   }
6025 
6026   return parentPrincipal;
6027 }
6028 
6029 //*****************************************************************************
6030 // nsGlobalWindowInner: Timeout Functions
6031 //*****************************************************************************
6032 
6033 class WindowScriptTimeoutHandler final : public ScriptTimeoutHandler {
6034  public:
6035   NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WindowScriptTimeoutHandler,ScriptTimeoutHandler)6036   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WindowScriptTimeoutHandler,
6037                                            ScriptTimeoutHandler)
6038 
6039   WindowScriptTimeoutHandler(JSContext* aCx, nsIGlobalObject* aGlobal,
6040                              const nsAString& aExpression)
6041       : ScriptTimeoutHandler(aCx, aGlobal, aExpression),
6042         mInitiatingScript(ScriptLoader::GetActiveScript(aCx)) {}
6043 
6044   MOZ_CAN_RUN_SCRIPT virtual bool Call(const char* aExecutionReason) override;
6045 
6046  private:
6047   virtual ~WindowScriptTimeoutHandler() = default;
6048 
6049   // Initiating script for use when evaluating mExpr on the main thread.
6050   RefPtr<LoadedScript> mInitiatingScript;
6051 };
6052 
NS_IMPL_CYCLE_COLLECTION_INHERITED(WindowScriptTimeoutHandler,ScriptTimeoutHandler,mInitiatingScript)6053 NS_IMPL_CYCLE_COLLECTION_INHERITED(WindowScriptTimeoutHandler,
6054                                    ScriptTimeoutHandler, mInitiatingScript)
6055 
6056 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowScriptTimeoutHandler)
6057 NS_INTERFACE_MAP_END_INHERITING(ScriptTimeoutHandler)
6058 
6059 NS_IMPL_ADDREF_INHERITED(WindowScriptTimeoutHandler, ScriptTimeoutHandler)
6060 NS_IMPL_RELEASE_INHERITED(WindowScriptTimeoutHandler, ScriptTimeoutHandler)
6061 
6062 bool WindowScriptTimeoutHandler::Call(const char* aExecutionReason) {
6063   // New script entry point required, due to the "Create a script" sub-step
6064   // of
6065   // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
6066   nsAutoMicroTask mt;
6067   AutoEntryScript aes(mGlobal, aExecutionReason, true);
6068   JS::CompileOptions options(aes.cx());
6069   options.setFileAndLine(mFileName.get(), mLineNo);
6070   options.setNoScriptRval(true);
6071   options.setIntroductionType("domTimer");
6072   JS::Rooted<JSObject*> global(aes.cx(), mGlobal->GetGlobalJSObject());
6073   {
6074     JSExecutionContext exec(aes.cx(), global, options);
6075     nsresult rv = exec.Compile(mExpr);
6076 
6077     JS::Rooted<JSScript*> script(aes.cx(), exec.MaybeGetScript());
6078     if (script) {
6079       if (mInitiatingScript) {
6080         mInitiatingScript->AssociateWithScript(script);
6081       }
6082 
6083       rv = exec.ExecScript();
6084     }
6085 
6086     if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
6087       return false;
6088     }
6089   }
6090 
6091   return true;
6092 };
6093 
InnerForSetTimeoutOrInterval(ErrorResult & aError)6094 nsGlobalWindowInner* nsGlobalWindowInner::InnerForSetTimeoutOrInterval(
6095     ErrorResult& aError) {
6096   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
6097   nsGlobalWindowInner* currentInner =
6098       outer ? outer->GetCurrentInnerWindowInternal() : this;
6099 
6100   // If forwardTo is not the window with an active document then we want the
6101   // call to setTimeout/Interval to be a noop, so return null but don't set an
6102   // error.
6103   return HasActiveDocument() ? currentInner : nullptr;
6104 }
6105 
SetTimeout(JSContext * aCx,Function & aFunction,int32_t aTimeout,const Sequence<JS::Value> & aArguments,ErrorResult & aError)6106 int32_t nsGlobalWindowInner::SetTimeout(JSContext* aCx, Function& aFunction,
6107                                         int32_t aTimeout,
6108                                         const Sequence<JS::Value>& aArguments,
6109                                         ErrorResult& aError) {
6110   return SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments, false,
6111                               aError);
6112 }
6113 
SetTimeout(JSContext * aCx,const nsAString & aHandler,int32_t aTimeout,const Sequence<JS::Value> &,ErrorResult & aError)6114 int32_t nsGlobalWindowInner::SetTimeout(JSContext* aCx,
6115                                         const nsAString& aHandler,
6116                                         int32_t aTimeout,
6117                                         const Sequence<JS::Value>& /* unused */,
6118                                         ErrorResult& aError) {
6119   return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError);
6120 }
6121 
SetInterval(JSContext * aCx,Function & aFunction,const int32_t aTimeout,const Sequence<JS::Value> & aArguments,ErrorResult & aError)6122 int32_t nsGlobalWindowInner::SetInterval(JSContext* aCx, Function& aFunction,
6123                                          const int32_t aTimeout,
6124                                          const Sequence<JS::Value>& aArguments,
6125                                          ErrorResult& aError) {
6126   return SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments, true,
6127                               aError);
6128 }
6129 
SetInterval(JSContext * aCx,const nsAString & aHandler,const int32_t aTimeout,const Sequence<JS::Value> &,ErrorResult & aError)6130 int32_t nsGlobalWindowInner::SetInterval(
6131     JSContext* aCx, const nsAString& aHandler, const int32_t aTimeout,
6132     const Sequence<JS::Value>& /* unused */, ErrorResult& aError) {
6133   return SetTimeoutOrInterval(aCx, aHandler, aTimeout, true, aError);
6134 }
6135 
SetTimeoutOrInterval(JSContext * aCx,Function & aFunction,int32_t aTimeout,const Sequence<JS::Value> & aArguments,bool aIsInterval,ErrorResult & aError)6136 int32_t nsGlobalWindowInner::SetTimeoutOrInterval(
6137     JSContext* aCx, Function& aFunction, int32_t aTimeout,
6138     const Sequence<JS::Value>& aArguments, bool aIsInterval,
6139     ErrorResult& aError) {
6140   nsGlobalWindowInner* inner = InnerForSetTimeoutOrInterval(aError);
6141   if (!inner) {
6142     return -1;
6143   }
6144 
6145   if (inner != this) {
6146     RefPtr<nsGlobalWindowInner> innerRef(inner);
6147     return innerRef->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
6148                                           aIsInterval, aError);
6149   }
6150 
6151   DebuggerNotificationDispatch(
6152       this, aIsInterval ? DebuggerNotificationType::SetInterval
6153                         : DebuggerNotificationType::SetTimeout);
6154 
6155   if (!GetContextInternal() || !HasJSGlobal()) {
6156     // This window was already closed, or never properly initialized,
6157     // don't let a timer be scheduled on such a window.
6158     aError.Throw(NS_ERROR_NOT_INITIALIZED);
6159     return 0;
6160   }
6161 
6162   nsTArray<JS::Heap<JS::Value>> args;
6163   if (!args.AppendElements(aArguments, fallible)) {
6164     aError.Throw(NS_ERROR_OUT_OF_MEMORY);
6165     return 0;
6166   }
6167 
6168   RefPtr<TimeoutHandler> handler =
6169       new CallbackTimeoutHandler(aCx, this, &aFunction, std::move(args));
6170 
6171   int32_t result;
6172   aError =
6173       mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval,
6174                                   Timeout::Reason::eTimeoutOrInterval, &result);
6175   return result;
6176 }
6177 
SetTimeoutOrInterval(JSContext * aCx,const nsAString & aHandler,int32_t aTimeout,bool aIsInterval,ErrorResult & aError)6178 int32_t nsGlobalWindowInner::SetTimeoutOrInterval(JSContext* aCx,
6179                                                   const nsAString& aHandler,
6180                                                   int32_t aTimeout,
6181                                                   bool aIsInterval,
6182                                                   ErrorResult& aError) {
6183   nsGlobalWindowInner* inner = InnerForSetTimeoutOrInterval(aError);
6184   if (!inner) {
6185     return -1;
6186   }
6187 
6188   if (inner != this) {
6189     RefPtr<nsGlobalWindowInner> innerRef(inner);
6190     return innerRef->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
6191                                           aError);
6192   }
6193 
6194   DebuggerNotificationDispatch(
6195       this, aIsInterval ? DebuggerNotificationType::SetInterval
6196                         : DebuggerNotificationType::SetTimeout);
6197 
6198   if (!GetContextInternal() || !HasJSGlobal()) {
6199     // This window was already closed, or never properly initialized,
6200     // don't let a timer be scheduled on such a window.
6201     aError.Throw(NS_ERROR_NOT_INITIALIZED);
6202     return 0;
6203   }
6204 
6205   bool allowEval = false;
6206   aError = CSPEvalChecker::CheckForWindow(aCx, this, aHandler, &allowEval);
6207   if (NS_WARN_IF(aError.Failed()) || !allowEval) {
6208     return 0;
6209   }
6210 
6211   RefPtr<TimeoutHandler> handler =
6212       new WindowScriptTimeoutHandler(aCx, this, aHandler);
6213 
6214   int32_t result;
6215   aError =
6216       mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval,
6217                                   Timeout::Reason::eTimeoutOrInterval, &result);
6218   return result;
6219 }
6220 
GetTimeoutReasonString(Timeout * aTimeout)6221 static const char* GetTimeoutReasonString(Timeout* aTimeout) {
6222   switch (aTimeout->mReason) {
6223     case Timeout::Reason::eTimeoutOrInterval:
6224       if (aTimeout->mIsInterval) {
6225         return "setInterval handler";
6226       }
6227       return "setTimeout handler";
6228     case Timeout::Reason::eIdleCallbackTimeout:
6229       return "setIdleCallback handler (timed out)";
6230     default:
6231       MOZ_CRASH("Unexpected enum value");
6232       return "";
6233   }
6234 }
6235 
RunTimeoutHandler(Timeout * aTimeout,nsIScriptContext * aScx)6236 bool nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout,
6237                                             nsIScriptContext* aScx) {
6238   // Hold on to the timeout in case mExpr or mFunObj releases its
6239   // doc.
6240   // XXXbz Our caller guarantees it'll hold on to the timeout (because
6241   // we're MOZ_CAN_RUN_SCRIPT), so we can probably stop doing that...
6242   RefPtr<Timeout> timeout = aTimeout;
6243   Timeout* last_running_timeout = mTimeoutManager->BeginRunningTimeout(timeout);
6244   timeout->mRunning = true;
6245 
6246   // Push this timeout's popup control state, which should only be
6247   // enabled the first time a timeout fires that was created while
6248   // popups were enabled and with a delay less than
6249   // "dom.disable_open_click_delay".
6250   AutoPopupStatePusher popupStatePusher(timeout->mPopupState);
6251 
6252   // Clear the timeout's popup state, if any, to prevent interval
6253   // timeouts from repeatedly opening poups.
6254   timeout->mPopupState = PopupBlocker::openAbused;
6255 
6256   uint32_t nestingLevel = TimeoutManager::GetNestingLevel();
6257   TimeoutManager::SetNestingLevel(timeout->mNestingLevel);
6258 
6259   const char* reason = GetTimeoutReasonString(timeout);
6260 
6261   nsCString str;
6262   if (profiler_can_accept_markers()) {
6263     TimeDuration originalInterval = timeout->When() - timeout->SubmitTime();
6264     str.Append(reason);
6265     str.Append(" with interval ");
6266     str.AppendInt(int(originalInterval.ToMilliseconds()));
6267     str.Append("ms: ");
6268     nsCString handlerDescription;
6269     timeout->mScriptHandler->GetDescription(handlerDescription);
6270     str.Append(handlerDescription);
6271   }
6272   AUTO_PROFILER_MARKER_TEXT("setTimeout callback", DOM,
6273                             MarkerOptions(MarkerStack::TakeBacktrace(
6274                                               timeout->TakeProfilerBacktrace()),
6275                                           MarkerInnerWindowId(mWindowID)),
6276                             str);
6277 
6278   bool abortIntervalHandler;
6279   {
6280     RefPtr<TimeoutHandler> handler(timeout->mScriptHandler);
6281 
6282     CallbackDebuggerNotificationGuard guard(
6283         this, timeout->mIsInterval
6284                   ? DebuggerNotificationType::SetIntervalCallback
6285                   : DebuggerNotificationType::SetTimeoutCallback);
6286     abortIntervalHandler = !handler->Call(reason);
6287   }
6288 
6289   // If we received an uncatchable exception, do not schedule the timeout again.
6290   // This allows the slow script dialog to break easy DoS attacks like
6291   // setInterval(function() { while(1); }, 100);
6292   if (abortIntervalHandler) {
6293     // If it wasn't an interval timer to begin with, this does nothing.  If it
6294     // was, we'll treat it as a timeout that we just ran and discard it when
6295     // we return.
6296     timeout->mIsInterval = false;
6297   }
6298 
6299   // We ignore any failures from calling EvaluateString() on the context or
6300   // Call() on a Function here since we're in a loop
6301   // where we're likely to be running timeouts whose OS timers
6302   // didn't fire in time and we don't want to not fire those timers
6303   // now just because execution of one timer failed. We can't
6304   // propagate the error to anyone who cares about it from this
6305   // point anyway, and the script context should have already reported
6306   // the script error in the usual way - so we just drop it.
6307 
6308   TimeoutManager::SetNestingLevel(nestingLevel);
6309 
6310   mTimeoutManager->EndRunningTimeout(last_running_timeout);
6311   timeout->mRunning = false;
6312 
6313   return timeout->mCleared;
6314 }
6315 
6316 //*****************************************************************************
6317 // nsGlobalWindowInner: Helper Functions
6318 //*****************************************************************************
6319 
GetTreeOwner()6320 already_AddRefed<nsIDocShellTreeOwner> nsGlobalWindowInner::GetTreeOwner() {
6321   FORWARD_TO_OUTER(GetTreeOwner, (), nullptr);
6322 }
6323 
6324 already_AddRefed<nsIWebBrowserChrome>
GetWebBrowserChrome()6325 nsGlobalWindowInner::GetWebBrowserChrome() {
6326   nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
6327 
6328   nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
6329   return browserChrome.forget();
6330 }
6331 
GetScrollFrame()6332 nsIScrollableFrame* nsGlobalWindowInner::GetScrollFrame() {
6333   FORWARD_TO_OUTER(GetScrollFrame, (), nullptr);
6334 }
6335 
IsPrivateBrowsing()6336 bool nsGlobalWindowInner::IsPrivateBrowsing() {
6337   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell());
6338   return loadContext && loadContext->UsePrivateBrowsing();
6339 }
6340 
FlushPendingNotifications(FlushType aType)6341 void nsGlobalWindowInner::FlushPendingNotifications(FlushType aType) {
6342   if (mDoc) {
6343     mDoc->FlushPendingNotifications(aType);
6344   }
6345 }
6346 
EnableDeviceSensor(uint32_t aType)6347 void nsGlobalWindowInner::EnableDeviceSensor(uint32_t aType) {
6348   bool alreadyEnabled = false;
6349   for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
6350     if (mEnabledSensors[i] == aType) {
6351       alreadyEnabled = true;
6352       break;
6353     }
6354   }
6355 
6356   mEnabledSensors.AppendElement(aType);
6357 
6358   if (alreadyEnabled) {
6359     return;
6360   }
6361 
6362   nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
6363   if (ac) {
6364     ac->AddWindowListener(aType, this);
6365   }
6366 }
6367 
DisableDeviceSensor(uint32_t aType)6368 void nsGlobalWindowInner::DisableDeviceSensor(uint32_t aType) {
6369   int32_t doomedElement = -1;
6370   int32_t listenerCount = 0;
6371   for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
6372     if (mEnabledSensors[i] == aType) {
6373       doomedElement = i;
6374       listenerCount++;
6375     }
6376   }
6377 
6378   if (doomedElement == -1) {
6379     return;
6380   }
6381 
6382   mEnabledSensors.RemoveElementAt(doomedElement);
6383 
6384   if (listenerCount > 1) {
6385     return;
6386   }
6387 
6388   nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
6389   if (ac) {
6390     ac->RemoveWindowListener(aType, this);
6391   }
6392 }
6393 
6394 #if defined(MOZ_WIDGET_ANDROID)
EnableOrientationChangeListener()6395 void nsGlobalWindowInner::EnableOrientationChangeListener() {
6396   if (!nsContentUtils::ShouldResistFingerprinting(GetDocShell()) &&
6397       !mOrientationChangeObserver) {
6398     mOrientationChangeObserver = MakeUnique<WindowOrientationObserver>(this);
6399   }
6400 }
6401 
DisableOrientationChangeListener()6402 void nsGlobalWindowInner::DisableOrientationChangeListener() {
6403   mOrientationChangeObserver = nullptr;
6404 }
6405 #endif
6406 
SetHasGamepadEventListener(bool aHasGamepad)6407 void nsGlobalWindowInner::SetHasGamepadEventListener(
6408     bool aHasGamepad /* = true*/) {
6409   mHasGamepad = aHasGamepad;
6410   if (aHasGamepad) {
6411     EnableGamepadUpdates();
6412   }
6413 }
6414 
NotifyDetectXRRuntimesCompleted()6415 void nsGlobalWindowInner::NotifyDetectXRRuntimesCompleted() {
6416   if (!mXRRuntimeDetectionInFlight) {
6417     return;
6418   }
6419   mXRRuntimeDetectionInFlight = false;
6420   if (mXRPermissionRequestInFlight) {
6421     return;
6422   }
6423   gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
6424   bool supported = vm->RuntimeSupportsVR();
6425   if (!supported) {
6426     // A VR runtime was not installed; we can suppress
6427     // the permission prompt
6428     OnXRPermissionRequestCancel();
6429     return;
6430   }
6431   // A VR runtime was found.  Display a permission prompt before
6432   // allowing it to be accessed.
6433   // Connect to the VRManager in order to receive the runtime
6434   // detection results.
6435   mXRPermissionRequestInFlight = true;
6436   RefPtr<XRPermissionRequest> request =
6437       new XRPermissionRequest(this, WindowID());
6438   Unused << NS_WARN_IF(NS_FAILED(request->Start()));
6439 }
6440 
RequestXRPermission()6441 void nsGlobalWindowInner::RequestXRPermission() {
6442   if (IsDying()) {
6443     // Do not proceed if the window is dying, as that will result
6444     // in leaks of objects that get re-allocated after FreeInnerObjects
6445     // has been called, including mVREventObserver.
6446     return;
6447   }
6448   if (mXRPermissionGranted) {
6449     // Don't prompt redundantly once permission to
6450     // access XR devices has been granted.
6451     OnXRPermissionRequestAllow();
6452     return;
6453   }
6454   if (mXRRuntimeDetectionInFlight || mXRPermissionRequestInFlight) {
6455     // Don't allow multiple simultaneous permissions requests;
6456     return;
6457   }
6458   // Before displaying a permission prompt, detect
6459   // if there is any VR runtime installed.
6460   gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
6461   mXRRuntimeDetectionInFlight = true;
6462   EnableVRUpdates();
6463   vm->DetectRuntimes();
6464 }
6465 
OnXRPermissionRequestAllow()6466 void nsGlobalWindowInner::OnXRPermissionRequestAllow() {
6467   mXRPermissionRequestInFlight = false;
6468   if (IsDying()) {
6469     // The window may have started dying while the permission request
6470     // is in flight.
6471     // Do not proceed if the window is dying, as that will result
6472     // in leaks of objects that get re-allocated after FreeInnerObjects
6473     // has been called, including mNavigator.
6474     return;
6475   }
6476   mXRPermissionGranted = true;
6477 
6478   NotifyHasXRSession();
6479 
6480   dom::Navigator* nav = Navigator();
6481   MOZ_ASSERT(nav != nullptr);
6482   nav->OnXRPermissionRequestAllow();
6483 }
6484 
OnXRPermissionRequestCancel()6485 void nsGlobalWindowInner::OnXRPermissionRequestCancel() {
6486   mXRPermissionRequestInFlight = false;
6487   if (IsDying()) {
6488     // The window may have started dying while the permission request
6489     // is in flight.
6490     // Do not proceed if the window is dying, as that will result
6491     // in leaks of objects that get re-allocated after FreeInnerObjects
6492     // has been called, including mNavigator.
6493     return;
6494   }
6495   dom::Navigator* nav = Navigator();
6496   MOZ_ASSERT(nav != nullptr);
6497   nav->OnXRPermissionRequestCancel();
6498 }
6499 
EventListenerAdded(nsAtom * aType)6500 void nsGlobalWindowInner::EventListenerAdded(nsAtom* aType) {
6501   if (aType == nsGkAtoms::onvrdisplayactivate ||
6502       aType == nsGkAtoms::onvrdisplayconnect ||
6503       aType == nsGkAtoms::onvrdisplaydeactivate ||
6504       aType == nsGkAtoms::onvrdisplaydisconnect ||
6505       aType == nsGkAtoms::onvrdisplaypresentchange) {
6506     RequestXRPermission();
6507   }
6508 
6509   if (aType == nsGkAtoms::onvrdisplayactivate) {
6510     mHasVRDisplayActivateEvents = true;
6511   }
6512 
6513   if ((aType == nsGkAtoms::onunload || aType == nsGkAtoms::onbeforeunload) &&
6514       mWindowGlobalChild) {
6515     if (++mUnloadOrBeforeUnloadListenerCount == 1) {
6516       mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::UNLOAD_LISTENER);
6517     }
6518     if (aType == nsGkAtoms::onbeforeunload &&
6519         (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
6520       mWindowGlobalChild->BeforeUnloadAdded();
6521       MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() > 0);
6522     }
6523   }
6524 
6525   // We need to initialize localStorage in order to receive notifications.
6526   if (aType == nsGkAtoms::onstorage) {
6527     ErrorResult rv;
6528     GetLocalStorage(rv);
6529     rv.SuppressException();
6530 
6531     if (NextGenLocalStorageEnabled() && mLocalStorage &&
6532         mLocalStorage->Type() == Storage::eLocalStorage) {
6533       auto object = static_cast<LSObject*>(mLocalStorage.get());
6534 
6535       Unused << NS_WARN_IF(NS_FAILED(object->EnsureObserver()));
6536     }
6537   }
6538 }
6539 
EventListenerRemoved(nsAtom * aType)6540 void nsGlobalWindowInner::EventListenerRemoved(nsAtom* aType) {
6541   if ((aType == nsGkAtoms::onunload || aType == nsGkAtoms::onbeforeunload) &&
6542       mWindowGlobalChild) {
6543     MOZ_ASSERT(mUnloadOrBeforeUnloadListenerCount > 0);
6544     if (--mUnloadOrBeforeUnloadListenerCount == 0) {
6545       mWindowGlobalChild->UnblockBFCacheFor(BFCacheStatus::UNLOAD_LISTENER);
6546     }
6547     if (aType == nsGkAtoms::onbeforeunload &&
6548         (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
6549       mWindowGlobalChild->BeforeUnloadRemoved();
6550       MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() >= 0);
6551     }
6552   }
6553 
6554   if (aType == nsGkAtoms::onstorage) {
6555     if (NextGenLocalStorageEnabled() && mLocalStorage &&
6556         mLocalStorage->Type() == Storage::eLocalStorage &&
6557         // The remove event is fired even if this isn't the last listener, so
6558         // only remove if there are no other listeners left.
6559         mListenerManager &&
6560         !mListenerManager->HasListenersFor(nsGkAtoms::onstorage)) {
6561       auto object = static_cast<LSObject*>(mLocalStorage.get());
6562 
6563       object->DropObserver();
6564     }
6565   }
6566 }
6567 
NotifyHasXRSession()6568 void nsGlobalWindowInner::NotifyHasXRSession() {
6569   if (IsDying()) {
6570     // Do not proceed if the window is dying, as that will result
6571     // in leaks of objects that get re-allocated after FreeInnerObjects
6572     // has been called, including mVREventObserver.
6573     return;
6574   }
6575   if (mWindowGlobalChild && !mHasXRSession) {
6576     mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::HAS_USED_VR);
6577   }
6578   mHasXRSession = true;
6579   EnableVRUpdates();
6580 }
6581 
HasUsedVR() const6582 bool nsGlobalWindowInner::HasUsedVR() const {
6583   // Returns true only if content has enumerated and activated
6584   // XR devices.  Detection of XR runtimes without activation
6585   // will not cause true to be returned.
6586   return mHasXRSession;
6587 }
6588 
IsVRContentDetected() const6589 bool nsGlobalWindowInner::IsVRContentDetected() const {
6590   // Returns true only if the content will respond to
6591   // the VRDisplayActivate event.
6592   return mHasVRDisplayActivateEvents;
6593 }
6594 
IsVRContentPresenting() const6595 bool nsGlobalWindowInner::IsVRContentPresenting() const {
6596   for (const auto& display : mVRDisplays) {
6597     if (display->IsAnyPresenting(gfx::kVRGroupAll)) {
6598       return true;
6599     }
6600   }
6601   return false;
6602 }
6603 
AddSizeOfIncludingThis(nsWindowSizes & aWindowSizes) const6604 void nsGlobalWindowInner::AddSizeOfIncludingThis(
6605     nsWindowSizes& aWindowSizes) const {
6606   aWindowSizes.mDOMSizes.mDOMOtherSize +=
6607       aWindowSizes.mState.mMallocSizeOf(this);
6608   aWindowSizes.mDOMSizes.mDOMOtherSize +=
6609       nsIGlobalObject::ShallowSizeOfExcludingThis(
6610           aWindowSizes.mState.mMallocSizeOf);
6611 
6612   EventListenerManager* elm = GetExistingListenerManager();
6613   if (elm) {
6614     aWindowSizes.mDOMSizes.mDOMOtherSize +=
6615         elm->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf);
6616     aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
6617   }
6618   if (mDoc) {
6619     // Multiple global windows can share a document. So only measure the
6620     // document if it (a) doesn't have a global window, or (b) it's the
6621     // primary document for the window.
6622     if (!mDoc->GetInnerWindow() || mDoc->GetInnerWindow() == this) {
6623       mDoc->DocAddSizeOfIncludingThis(aWindowSizes);
6624     }
6625   }
6626 
6627   if (mNavigator) {
6628     aWindowSizes.mDOMSizes.mDOMOtherSize +=
6629         mNavigator->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf);
6630   }
6631 
6632   ForEachEventTargetObject([&](DOMEventTargetHelper* et, bool* aDoneOut) {
6633     if (nsCOMPtr<nsISizeOfEventTarget> iSizeOf = do_QueryObject(et)) {
6634       aWindowSizes.mDOMSizes.mDOMEventTargetsSize +=
6635           iSizeOf->SizeOfEventTargetIncludingThis(
6636               aWindowSizes.mState.mMallocSizeOf);
6637     }
6638     if (EventListenerManager* elm = et->GetExistingListenerManager()) {
6639       aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
6640     }
6641     ++aWindowSizes.mDOMEventTargetsCount;
6642   });
6643 
6644   if (mPerformance) {
6645     aWindowSizes.mDOMSizes.mDOMPerformanceUserEntries =
6646         mPerformance->SizeOfUserEntries(aWindowSizes.mState.mMallocSizeOf);
6647     aWindowSizes.mDOMSizes.mDOMPerformanceResourceEntries =
6648         mPerformance->SizeOfResourceEntries(aWindowSizes.mState.mMallocSizeOf);
6649     aWindowSizes.mDOMSizes.mDOMPerformanceEventEntries =
6650         mPerformance->SizeOfEventEntries(aWindowSizes.mState.mMallocSizeOf);
6651   }
6652 }
6653 
RegisterDataDocumentForMemoryReporting(Document * aDocument)6654 void nsGlobalWindowInner::RegisterDataDocumentForMemoryReporting(
6655     Document* aDocument) {
6656   aDocument->SetAddedToMemoryReportAsDataDocument();
6657   mDataDocumentsForMemoryReporting.AppendElement(
6658       do_GetWeakReference(aDocument));
6659 }
6660 
UnregisterDataDocumentForMemoryReporting(Document * aDocument)6661 void nsGlobalWindowInner::UnregisterDataDocumentForMemoryReporting(
6662     Document* aDocument) {
6663   nsWeakPtr doc = do_GetWeakReference(aDocument);
6664   MOZ_ASSERT(mDataDocumentsForMemoryReporting.Contains(doc));
6665   mDataDocumentsForMemoryReporting.RemoveElement(doc);
6666 }
6667 
CollectDOMSizesForDataDocuments(nsWindowSizes & aSize) const6668 void nsGlobalWindowInner::CollectDOMSizesForDataDocuments(
6669     nsWindowSizes& aSize) const {
6670   for (const nsWeakPtr& ptr : mDataDocumentsForMemoryReporting) {
6671     if (nsCOMPtr<Document> doc = do_QueryReferent(ptr)) {
6672       doc->DocAddSizeOfIncludingThis(aSize);
6673     }
6674   }
6675 }
6676 
AddGamepad(GamepadHandle aHandle,Gamepad * aGamepad)6677 void nsGlobalWindowInner::AddGamepad(GamepadHandle aHandle, Gamepad* aGamepad) {
6678   // Create the index we will present to content based on which indices are
6679   // already taken, as required by the spec.
6680   // https://w3c.github.io/gamepad/gamepad.html#widl-Gamepad-index
6681   int index = 0;
6682   while (mGamepadIndexSet.Contains(index)) {
6683     ++index;
6684   }
6685   mGamepadIndexSet.Put(index);
6686   aGamepad->SetIndex(index);
6687   mGamepads.InsertOrUpdate(aHandle, RefPtr{aGamepad});
6688 }
6689 
RemoveGamepad(GamepadHandle aHandle)6690 void nsGlobalWindowInner::RemoveGamepad(GamepadHandle aHandle) {
6691   RefPtr<Gamepad> gamepad;
6692   if (!mGamepads.Get(aHandle, getter_AddRefs(gamepad))) {
6693     return;
6694   }
6695   // Free up the index we were using so it can be reused
6696   mGamepadIndexSet.Remove(gamepad->Index());
6697   mGamepads.Remove(aHandle);
6698 }
6699 
GetGamepads(nsTArray<RefPtr<Gamepad>> & aGamepads)6700 void nsGlobalWindowInner::GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads) {
6701   aGamepads.Clear();
6702 
6703   // navigator.getGamepads() always returns an empty array when
6704   // privacy.resistFingerprinting is true.
6705   if (nsContentUtils::ShouldResistFingerprinting(GetDocShell())) {
6706     return;
6707   }
6708 
6709   // mGamepads.Count() may not be sufficient, but it's not harmful.
6710   aGamepads.SetCapacity(mGamepads.Count());
6711   for (const auto& entry : mGamepads) {
6712     Gamepad* gamepad = entry.GetWeak();
6713     aGamepads.EnsureLengthAtLeast(gamepad->Index() + 1);
6714     aGamepads[gamepad->Index()] = gamepad;
6715   }
6716 }
6717 
GetGamepad(GamepadHandle aHandle)6718 already_AddRefed<Gamepad> nsGlobalWindowInner::GetGamepad(
6719     GamepadHandle aHandle) {
6720   RefPtr<Gamepad> gamepad;
6721 
6722   if (mGamepads.Get(aHandle, getter_AddRefs(gamepad))) {
6723     return gamepad.forget();
6724   }
6725 
6726   return nullptr;
6727 }
6728 
SetHasSeenGamepadInput(bool aHasSeen)6729 void nsGlobalWindowInner::SetHasSeenGamepadInput(bool aHasSeen) {
6730   mHasSeenGamepadInput = aHasSeen;
6731 }
6732 
HasSeenGamepadInput()6733 bool nsGlobalWindowInner::HasSeenGamepadInput() { return mHasSeenGamepadInput; }
6734 
SyncGamepadState()6735 void nsGlobalWindowInner::SyncGamepadState() {
6736   if (mHasSeenGamepadInput) {
6737     RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
6738     for (const auto& entry : mGamepads) {
6739       gamepadManager->SyncGamepadState(entry.GetKey(), this, entry.GetWeak());
6740     }
6741   }
6742 }
6743 
StopGamepadHaptics()6744 void nsGlobalWindowInner::StopGamepadHaptics() {
6745   if (mHasSeenGamepadInput) {
6746     RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
6747     gamepadManager->StopHaptics();
6748   }
6749 }
6750 
UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>> & aDevices)6751 bool nsGlobalWindowInner::UpdateVRDisplays(
6752     nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDevices) {
6753   VRDisplay::UpdateVRDisplays(mVRDisplays, this);
6754   aDevices = mVRDisplays.Clone();
6755   return true;
6756 }
6757 
NotifyActiveVRDisplaysChanged()6758 void nsGlobalWindowInner::NotifyActiveVRDisplaysChanged() {
6759   if (mNavigator) {
6760     mNavigator->NotifyActiveVRDisplaysChanged();
6761   }
6762 }
6763 
NotifyPresentationGenerationChanged(uint32_t aDisplayID)6764 void nsGlobalWindowInner::NotifyPresentationGenerationChanged(
6765     uint32_t aDisplayID) {
6766   for (const auto& display : mVRDisplays) {
6767     if (display->DisplayId() == aDisplayID) {
6768       display->OnPresentationGenerationChanged();
6769     }
6770   }
6771 }
6772 
DispatchVRDisplayActivate(uint32_t aDisplayID,mozilla::dom::VRDisplayEventReason aReason)6773 void nsGlobalWindowInner::DispatchVRDisplayActivate(
6774     uint32_t aDisplayID, mozilla::dom::VRDisplayEventReason aReason) {
6775   // Ensure that our list of displays is up to date
6776   VRDisplay::UpdateVRDisplays(mVRDisplays, this);
6777 
6778   // Search for the display identified with aDisplayID and fire the
6779   // event if found.
6780   for (const auto& display : mVRDisplays) {
6781     if (display->DisplayId() == aDisplayID) {
6782       if (aReason != VRDisplayEventReason::Navigation &&
6783           display->IsAnyPresenting(gfx::kVRGroupContent)) {
6784         // We only want to trigger this event if nobody is presenting to the
6785         // display already or when a page is loaded by navigating away
6786         // from a page with an active VR Presentation.
6787         continue;
6788       }
6789 
6790       VRDisplayEventInit init;
6791       init.mBubbles = false;
6792       init.mCancelable = false;
6793       init.mDisplay = display;
6794       init.mReason.Construct(aReason);
6795 
6796       RefPtr<VRDisplayEvent> event =
6797           VRDisplayEvent::Constructor(this, u"vrdisplayactivate"_ns, init);
6798       // vrdisplayactivate is a trusted event, allowing VRDisplay.requestPresent
6799       // to be used in response to link traversal, user request (chrome UX), and
6800       // HMD mounting detection sensors.
6801       event->SetTrusted(true);
6802       // VRDisplay.requestPresent normally requires a user gesture; however, an
6803       // exception is made to allow it to be called in response to
6804       // vrdisplayactivate during VR link traversal.
6805       display->StartHandlingVRNavigationEvent();
6806       DispatchEvent(*event);
6807       display->StopHandlingVRNavigationEvent();
6808       // Once we dispatch the event, we must not access any members as an event
6809       // listener can do anything, including closing windows.
6810       return;
6811     }
6812   }
6813 }
6814 
DispatchVRDisplayDeactivate(uint32_t aDisplayID,mozilla::dom::VRDisplayEventReason aReason)6815 void nsGlobalWindowInner::DispatchVRDisplayDeactivate(
6816     uint32_t aDisplayID, mozilla::dom::VRDisplayEventReason aReason) {
6817   // Ensure that our list of displays is up to date
6818   VRDisplay::UpdateVRDisplays(mVRDisplays, this);
6819 
6820   // Search for the display identified with aDisplayID and fire the
6821   // event if found.
6822   for (const auto& display : mVRDisplays) {
6823     if (display->DisplayId() == aDisplayID && display->IsPresenting()) {
6824       // We only want to trigger this event to content that is presenting to
6825       // the display already.
6826 
6827       VRDisplayEventInit init;
6828       init.mBubbles = false;
6829       init.mCancelable = false;
6830       init.mDisplay = display;
6831       init.mReason.Construct(aReason);
6832 
6833       RefPtr<VRDisplayEvent> event =
6834           VRDisplayEvent::Constructor(this, u"vrdisplaydeactivate"_ns, init);
6835       event->SetTrusted(true);
6836       DispatchEvent(*event);
6837       // Once we dispatch the event, we must not access any members as an event
6838       // listener can do anything, including closing windows.
6839       return;
6840     }
6841   }
6842 }
6843 
DispatchVRDisplayConnect(uint32_t aDisplayID)6844 void nsGlobalWindowInner::DispatchVRDisplayConnect(uint32_t aDisplayID) {
6845   // Ensure that our list of displays is up to date
6846   VRDisplay::UpdateVRDisplays(mVRDisplays, this);
6847 
6848   // Search for the display identified with aDisplayID and fire the
6849   // event if found.
6850   for (const auto& display : mVRDisplays) {
6851     if (display->DisplayId() == aDisplayID) {
6852       // Fire event even if not presenting to the display.
6853       VRDisplayEventInit init;
6854       init.mBubbles = false;
6855       init.mCancelable = false;
6856       init.mDisplay = display;
6857       // VRDisplayEvent.reason is not set for vrdisplayconnect
6858 
6859       RefPtr<VRDisplayEvent> event =
6860           VRDisplayEvent::Constructor(this, u"vrdisplayconnect"_ns, init);
6861       event->SetTrusted(true);
6862       DispatchEvent(*event);
6863       // Once we dispatch the event, we must not access any members as an event
6864       // listener can do anything, including closing windows.
6865       return;
6866     }
6867   }
6868 }
6869 
DispatchVRDisplayDisconnect(uint32_t aDisplayID)6870 void nsGlobalWindowInner::DispatchVRDisplayDisconnect(uint32_t aDisplayID) {
6871   // Ensure that our list of displays is up to date
6872   VRDisplay::UpdateVRDisplays(mVRDisplays, this);
6873 
6874   // Search for the display identified with aDisplayID and fire the
6875   // event if found.
6876   for (const auto& display : mVRDisplays) {
6877     if (display->DisplayId() == aDisplayID) {
6878       // Fire event even if not presenting to the display.
6879       VRDisplayEventInit init;
6880       init.mBubbles = false;
6881       init.mCancelable = false;
6882       init.mDisplay = display;
6883       // VRDisplayEvent.reason is not set for vrdisplaydisconnect
6884 
6885       RefPtr<VRDisplayEvent> event =
6886           VRDisplayEvent::Constructor(this, u"vrdisplaydisconnect"_ns, init);
6887       event->SetTrusted(true);
6888       DispatchEvent(*event);
6889       // Once we dispatch the event, we must not access any members as an event
6890       // listener can do anything, including closing windows.
6891       return;
6892     }
6893   }
6894 }
6895 
DispatchVRDisplayPresentChange(uint32_t aDisplayID)6896 void nsGlobalWindowInner::DispatchVRDisplayPresentChange(uint32_t aDisplayID) {
6897   // Ensure that our list of displays is up to date
6898   VRDisplay::UpdateVRDisplays(mVRDisplays, this);
6899 
6900   // Search for the display identified with aDisplayID and fire the
6901   // event if found.
6902   for (const auto& display : mVRDisplays) {
6903     if (display->DisplayId() == aDisplayID) {
6904       // Fire event even if not presenting to the display.
6905       VRDisplayEventInit init;
6906       init.mBubbles = false;
6907       init.mCancelable = false;
6908       init.mDisplay = display;
6909       // VRDisplayEvent.reason is not set for vrdisplaypresentchange
6910       RefPtr<VRDisplayEvent> event =
6911           VRDisplayEvent::Constructor(this, u"vrdisplaypresentchange"_ns, init);
6912       event->SetTrusted(true);
6913       DispatchEvent(*event);
6914       // Once we dispatch the event, we must not access any members as an event
6915       // listener can do anything, including closing windows.
6916       return;
6917     }
6918   }
6919 }
6920 
6921 enum WindowState {
6922   // These constants need to match the constants in Window.webidl
6923   STATE_MAXIMIZED = 1,
6924   STATE_MINIMIZED = 2,
6925   STATE_NORMAL = 3,
6926   STATE_FULLSCREEN = 4
6927 };
6928 
WindowState()6929 uint16_t nsGlobalWindowInner::WindowState() {
6930   nsCOMPtr<nsIWidget> widget = GetMainWidget();
6931 
6932   int32_t mode = widget ? widget->SizeMode() : 0;
6933 
6934   switch (mode) {
6935     case nsSizeMode_Minimized:
6936       return STATE_MINIMIZED;
6937     case nsSizeMode_Maximized:
6938       return STATE_MAXIMIZED;
6939     case nsSizeMode_Fullscreen:
6940       return STATE_FULLSCREEN;
6941     case nsSizeMode_Normal:
6942       return STATE_NORMAL;
6943     default:
6944       NS_WARNING("Illegal window state for this chrome window");
6945       break;
6946   }
6947 
6948   return STATE_NORMAL;
6949 }
6950 
IsFullyOccluded()6951 bool nsGlobalWindowInner::IsFullyOccluded() {
6952   nsCOMPtr<nsIWidget> widget = GetMainWidget();
6953   return widget && widget->IsFullyOccluded();
6954 }
6955 
Maximize()6956 void nsGlobalWindowInner::Maximize() {
6957   nsCOMPtr<nsIWidget> widget = GetMainWidget();
6958 
6959   if (widget) {
6960     widget->SetSizeMode(nsSizeMode_Maximized);
6961   }
6962 }
6963 
Minimize()6964 void nsGlobalWindowInner::Minimize() {
6965   nsCOMPtr<nsIWidget> widget = GetMainWidget();
6966 
6967   if (widget) {
6968     widget->SetSizeMode(nsSizeMode_Minimized);
6969   }
6970 }
6971 
Restore()6972 void nsGlobalWindowInner::Restore() {
6973   nsCOMPtr<nsIWidget> widget = GetMainWidget();
6974 
6975   if (widget) {
6976     widget->SetSizeMode(nsSizeMode_Normal);
6977   }
6978 }
6979 
GetWorkspaceID(nsAString & workspaceID)6980 void nsGlobalWindowInner::GetWorkspaceID(nsAString& workspaceID) {
6981   nsCOMPtr<nsIWidget> widget = GetMainWidget();
6982 
6983   workspaceID.Truncate();
6984   if (widget) {
6985     return widget->GetWorkspaceID(workspaceID);
6986   }
6987 }
6988 
MoveToWorkspace(const nsAString & workspaceID)6989 void nsGlobalWindowInner::MoveToWorkspace(const nsAString& workspaceID) {
6990   nsCOMPtr<nsIWidget> widget = GetMainWidget();
6991 
6992   if (widget) {
6993     widget->MoveToWorkspace(workspaceID);
6994   }
6995 }
6996 
GetAttention(ErrorResult & aResult)6997 void nsGlobalWindowInner::GetAttention(ErrorResult& aResult) {
6998   return GetAttentionWithCycleCount(-1, aResult);
6999 }
7000 
GetAttentionWithCycleCount(int32_t aCycleCount,ErrorResult & aError)7001 void nsGlobalWindowInner::GetAttentionWithCycleCount(int32_t aCycleCount,
7002                                                      ErrorResult& aError) {
7003   nsCOMPtr<nsIWidget> widget = GetMainWidget();
7004 
7005   if (widget) {
7006     aError = widget->GetAttention(aCycleCount);
7007   }
7008 }
7009 
PromiseDocumentFlushed(PromiseDocumentFlushedCallback & aCallback,ErrorResult & aError)7010 already_AddRefed<Promise> nsGlobalWindowInner::PromiseDocumentFlushed(
7011     PromiseDocumentFlushedCallback& aCallback, ErrorResult& aError) {
7012   MOZ_RELEASE_ASSERT(IsChromeWindow());
7013 
7014   if (!IsCurrentInnerWindow()) {
7015     aError.Throw(NS_ERROR_FAILURE);
7016     return nullptr;
7017   }
7018 
7019   if (!mDoc || mIteratingDocumentFlushedResolvers) {
7020     aError.Throw(NS_ERROR_FAILURE);
7021     return nullptr;
7022   }
7023 
7024   PresShell* presShell = mDoc->GetPresShell();
7025   if (!presShell) {
7026     aError.Throw(NS_ERROR_FAILURE);
7027     return nullptr;
7028   }
7029 
7030   // We need to associate the lifetime of the Promise to the lifetime
7031   // of the caller's global. That way, if the window we're observing
7032   // refresh driver ticks on goes away before our observer is fired,
7033   // we can still resolve the Promise.
7034   nsIGlobalObject* global = GetIncumbentGlobal();
7035   if (!global) {
7036     aError.Throw(NS_ERROR_FAILURE);
7037     return nullptr;
7038   }
7039 
7040   RefPtr<Promise> resultPromise = Promise::Create(global, aError);
7041   if (aError.Failed()) {
7042     return nullptr;
7043   }
7044 
7045   UniquePtr<PromiseDocumentFlushedResolver> flushResolver(
7046       new PromiseDocumentFlushedResolver(resultPromise, aCallback));
7047 
7048   if (!presShell->NeedStyleFlush() && !presShell->NeedLayoutFlush()) {
7049     flushResolver->Call();
7050     return resultPromise.forget();
7051   }
7052 
7053   if (!TryToObserveRefresh()) {
7054     aError.Throw(NS_ERROR_FAILURE);
7055     return nullptr;
7056   }
7057 
7058   mDocumentFlushedResolvers.AppendElement(std::move(flushResolver));
7059   return resultPromise.forget();
7060 }
7061 
TryToObserveRefresh()7062 bool nsGlobalWindowInner::TryToObserveRefresh() {
7063   if (mObservingRefresh) {
7064     return true;
7065   }
7066 
7067   if (!mDoc) {
7068     return false;
7069   }
7070 
7071   nsPresContext* pc = mDoc->GetPresContext();
7072   if (!pc) {
7073     return false;
7074   }
7075 
7076   mObservingRefresh = true;
7077   auto observer = MakeRefPtr<ManagedPostRefreshObserver>(
7078       pc, [win = RefPtr{this}](bool aWasCanceled) {
7079         if (win->MaybeCallDocumentFlushedResolvers(
7080                 /* aUntilExhaustion = */ aWasCanceled)) {
7081           return ManagedPostRefreshObserver::Unregister::No;
7082         }
7083         win->mObservingRefresh = false;
7084         return ManagedPostRefreshObserver::Unregister::Yes;
7085       });
7086   pc->RegisterManagedPostRefreshObserver(observer.get());
7087   return mObservingRefresh;
7088 }
7089 
CallDocumentFlushedResolvers(bool aUntilExhaustion)7090 void nsGlobalWindowInner::CallDocumentFlushedResolvers(bool aUntilExhaustion) {
7091   while (true) {
7092     {
7093       // To coalesce MicroTask checkpoints inside callback call, enclose the
7094       // inner loop with nsAutoMicroTask, and perform a MicroTask checkpoint
7095       // after the loop.
7096       nsAutoMicroTask mt;
7097 
7098       mIteratingDocumentFlushedResolvers = true;
7099 
7100       auto resolvers = std::move(mDocumentFlushedResolvers);
7101       for (const auto& resolver : resolvers) {
7102         resolver->Call();
7103       }
7104 
7105       mIteratingDocumentFlushedResolvers = false;
7106     }
7107 
7108     // Leaving nsAutoMicroTask above will perform MicroTask checkpoint, and
7109     // Promise callbacks there may create mDocumentFlushedResolvers items.
7110 
7111     // If there's no new resolvers, or we're not exhausting the queue, there's
7112     // nothing to do (we'll keep observing if there's any new observer).
7113     //
7114     // Otherwise, keep looping to call all promises. This case can happen while
7115     // destroying the window.  This violates the constraint that the
7116     // promiseDocumentFlushed callback only ever run when no flush is needed,
7117     // but it's necessary to resolve the Promise returned by that.
7118     if (!aUntilExhaustion || mDocumentFlushedResolvers.IsEmpty()) {
7119       break;
7120     }
7121   }
7122 }
7123 
MaybeCallDocumentFlushedResolvers(bool aUntilExhaustion)7124 bool nsGlobalWindowInner::MaybeCallDocumentFlushedResolvers(
7125     bool aUntilExhaustion) {
7126   MOZ_ASSERT(mDoc);
7127 
7128   PresShell* presShell = mDoc->GetPresShell();
7129   if (!presShell || aUntilExhaustion) {
7130     CallDocumentFlushedResolvers(/* aUntilExhaustion = */ true);
7131     return false;
7132   }
7133 
7134   if (presShell->NeedStyleFlush() || presShell->NeedLayoutFlush()) {
7135     // By the time our observer fired, something has already invalidated
7136     // style or layout - or perhaps we're still in the middle of a flush that
7137     // was interrupted. In either case, we'll wait until the next refresh driver
7138     // tick instead and try again.
7139     return true;
7140   }
7141 
7142   CallDocumentFlushedResolvers(/* aUntilExhaustion = */ false);
7143   return !mDocumentFlushedResolvers.IsEmpty();
7144 }
7145 
GetWindowRoot(mozilla::ErrorResult & aError)7146 already_AddRefed<nsWindowRoot> nsGlobalWindowInner::GetWindowRoot(
7147     mozilla::ErrorResult& aError) {
7148   FORWARD_TO_OUTER_OR_THROW(GetWindowRootOuter, (), aError, nullptr);
7149 }
7150 
SetCursor(const nsACString & aCursor,ErrorResult & aError)7151 void nsGlobalWindowInner::SetCursor(const nsACString& aCursor,
7152                                     ErrorResult& aError) {
7153   FORWARD_TO_OUTER_OR_THROW(SetCursorOuter, (aCursor, aError), aError, );
7154 }
7155 
7156 NS_IMETHODIMP
GetBrowserDOMWindow(nsIBrowserDOMWindow ** aBrowserWindow)7157 nsGlobalWindowInner::GetBrowserDOMWindow(nsIBrowserDOMWindow** aBrowserWindow) {
7158   MOZ_RELEASE_ASSERT(IsChromeWindow());
7159 
7160   ErrorResult rv;
7161   NS_IF_ADDREF(*aBrowserWindow = GetBrowserDOMWindow(rv));
7162   return rv.StealNSResult();
7163 }
7164 
GetBrowserDOMWindow(ErrorResult & aError)7165 nsIBrowserDOMWindow* nsGlobalWindowInner::GetBrowserDOMWindow(
7166     ErrorResult& aError) {
7167   FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindowOuter, (), aError, nullptr);
7168 }
7169 
SetBrowserDOMWindow(nsIBrowserDOMWindow * aBrowserWindow,ErrorResult & aError)7170 void nsGlobalWindowInner::SetBrowserDOMWindow(
7171     nsIBrowserDOMWindow* aBrowserWindow, ErrorResult& aError) {
7172   FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindowOuter, (aBrowserWindow),
7173                             aError, );
7174 }
7175 
NotifyDefaultButtonLoaded(Element & aDefaultButton,ErrorResult & aError)7176 void nsGlobalWindowInner::NotifyDefaultButtonLoaded(Element& aDefaultButton,
7177                                                     ErrorResult& aError) {
7178 #ifdef MOZ_XUL
7179   // Don't snap to a disabled button.
7180   nsCOMPtr<nsIDOMXULControlElement> xulControl = aDefaultButton.AsXULControl();
7181   if (!xulControl) {
7182     aError.Throw(NS_ERROR_FAILURE);
7183     return;
7184   }
7185   bool disabled;
7186   aError = xulControl->GetDisabled(&disabled);
7187   if (aError.Failed() || disabled) {
7188     return;
7189   }
7190 
7191   // Get the button rect in screen coordinates.
7192   nsIFrame* frame = aDefaultButton.GetPrimaryFrame();
7193   if (!frame) {
7194     aError.Throw(NS_ERROR_FAILURE);
7195     return;
7196   }
7197   LayoutDeviceIntRect buttonRect = LayoutDeviceIntRect::FromAppUnitsToNearest(
7198       frame->GetScreenRectInAppUnits(),
7199       frame->PresContext()->AppUnitsPerDevPixel());
7200 
7201   // Get the widget rect in screen coordinates.
7202   nsIWidget* widget = GetNearestWidget();
7203   if (!widget) {
7204     aError.Throw(NS_ERROR_FAILURE);
7205     return;
7206   }
7207   LayoutDeviceIntRect widgetRect = widget->GetScreenBounds();
7208 
7209   // Convert the buttonRect coordinates from screen to the widget.
7210   buttonRect -= widgetRect.TopLeft();
7211   nsresult rv = widget->OnDefaultButtonLoaded(buttonRect);
7212   if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
7213     aError.Throw(rv);
7214   }
7215 #else
7216   aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
7217 #endif
7218 }
7219 
MessageManager()7220 ChromeMessageBroadcaster* nsGlobalWindowInner::MessageManager() {
7221   MOZ_ASSERT(IsChromeWindow());
7222   if (!mChromeFields.mMessageManager) {
7223     RefPtr<ChromeMessageBroadcaster> globalMM =
7224         nsFrameMessageManager::GetGlobalMessageManager();
7225     mChromeFields.mMessageManager = new ChromeMessageBroadcaster(globalMM);
7226   }
7227   return mChromeFields.mMessageManager;
7228 }
7229 
GetGroupMessageManager(const nsAString & aGroup)7230 ChromeMessageBroadcaster* nsGlobalWindowInner::GetGroupMessageManager(
7231     const nsAString& aGroup) {
7232   MOZ_ASSERT(IsChromeWindow());
7233 
7234   return mChromeFields.mGroupMessageManagers
7235       .LookupOrInsertWith(
7236           aGroup,
7237           [&] {
7238             return MakeAndAddRef<ChromeMessageBroadcaster>(MessageManager());
7239           })
7240       .get();
7241 }
7242 
InitWasOffline()7243 void nsGlobalWindowInner::InitWasOffline() { mWasOffline = NS_IsOffline(); }
7244 
7245 #if defined(MOZ_WIDGET_ANDROID)
Orientation(CallerType aCallerType) const7246 int16_t nsGlobalWindowInner::Orientation(CallerType aCallerType) const {
7247   return nsContentUtils::ResistFingerprinting(aCallerType)
7248              ? 0
7249              : WindowOrientationObserver::OrientationAngle();
7250 }
7251 #endif
7252 
GetConsole(JSContext * aCx,ErrorResult & aRv)7253 already_AddRefed<Console> nsGlobalWindowInner::GetConsole(JSContext* aCx,
7254                                                           ErrorResult& aRv) {
7255   if (!mConsole) {
7256     mConsole = Console::Create(aCx, this, aRv);
7257     if (NS_WARN_IF(aRv.Failed())) {
7258       return nullptr;
7259     }
7260   }
7261 
7262   RefPtr<Console> console = mConsole;
7263   return console.forget();
7264 }
7265 
IsSecureContext() const7266 bool nsGlobalWindowInner::IsSecureContext() const {
7267   JS::Realm* realm = js::GetNonCCWObjectRealm(GetWrapperPreserveColor());
7268   return JS::GetIsSecureContext(realm);
7269 }
7270 
GetExternal(ErrorResult & aRv)7271 External* nsGlobalWindowInner::GetExternal(ErrorResult& aRv) {
7272   if (!mExternal) {
7273     mExternal = new dom::External(ToSupports(this));
7274   }
7275 
7276   return mExternal;
7277 }
7278 
GetSidebar(OwningExternalOrWindowProxy & aResult,ErrorResult & aRv)7279 void nsGlobalWindowInner::GetSidebar(OwningExternalOrWindowProxy& aResult,
7280                                      ErrorResult& aRv) {
7281   // First check for a named frame named "sidebar"
7282   RefPtr<BrowsingContext> domWindow = GetChildWindow(u"sidebar"_ns);
7283   if (domWindow) {
7284     aResult.SetAsWindowProxy() = std::move(domWindow);
7285     return;
7286   }
7287 
7288   RefPtr<External> external = GetExternal(aRv);
7289   if (external) {
7290     aResult.SetAsExternal() = external;
7291   }
7292 }
7293 
ClearDocumentDependentSlots(JSContext * aCx)7294 void nsGlobalWindowInner::ClearDocumentDependentSlots(JSContext* aCx) {
7295   // If JSAPI OOMs here, there is basically nothing we can do to recover safely.
7296   if (!Window_Binding::ClearCachedDocumentValue(aCx, this) ||
7297       !Window_Binding::ClearCachedPerformanceValue(aCx, this)) {
7298     MOZ_CRASH("Unhandlable OOM while clearing document dependent slots.");
7299   }
7300 }
7301 
7302 /* static */
CreateNamedPropertiesObject(JSContext * aCx,JS::Handle<JSObject * > aProto)7303 JSObject* nsGlobalWindowInner::CreateNamedPropertiesObject(
7304     JSContext* aCx, JS::Handle<JSObject*> aProto) {
7305   return WindowNamedPropertiesHandler::Create(aCx, aProto);
7306 }
7307 
RedefineProperty(JSContext * aCx,const char * aPropName,JS::Handle<JS::Value> aValue,ErrorResult & aError)7308 void nsGlobalWindowInner::RedefineProperty(JSContext* aCx,
7309                                            const char* aPropName,
7310                                            JS::Handle<JS::Value> aValue,
7311                                            ErrorResult& aError) {
7312   JS::Rooted<JSObject*> thisObj(aCx, GetWrapperPreserveColor());
7313   if (!thisObj) {
7314     aError.Throw(NS_ERROR_UNEXPECTED);
7315     return;
7316   }
7317 
7318   if (!JS_WrapObject(aCx, &thisObj) ||
7319       !JS_DefineProperty(aCx, thisObj, aPropName, aValue, JSPROP_ENUMERATE)) {
7320     aError.Throw(NS_ERROR_FAILURE);
7321   }
7322 }
7323 
7324 template <typename T>
GetReplaceableWindowCoord(JSContext * aCx,nsGlobalWindowInner::WindowCoordGetter<T> aGetter,JS::MutableHandle<JS::Value> aRetval,CallerType aCallerType,ErrorResult & aError)7325 void nsGlobalWindowInner::GetReplaceableWindowCoord(
7326     JSContext* aCx, nsGlobalWindowInner::WindowCoordGetter<T> aGetter,
7327     JS::MutableHandle<JS::Value> aRetval, CallerType aCallerType,
7328     ErrorResult& aError) {
7329   T coord = (this->*aGetter)(aCallerType, aError);
7330   if (!aError.Failed() && !ToJSValue(aCx, coord, aRetval)) {
7331     aError.Throw(NS_ERROR_FAILURE);
7332   }
7333 }
7334 
7335 template <typename T>
SetReplaceableWindowCoord(JSContext * aCx,nsGlobalWindowInner::WindowCoordSetter<T> aSetter,JS::Handle<JS::Value> aValue,const char * aPropName,CallerType aCallerType,ErrorResult & aError)7336 void nsGlobalWindowInner::SetReplaceableWindowCoord(
7337     JSContext* aCx, nsGlobalWindowInner::WindowCoordSetter<T> aSetter,
7338     JS::Handle<JS::Value> aValue, const char* aPropName, CallerType aCallerType,
7339     ErrorResult& aError) {
7340   /*
7341    * If caller is not chrome and the user has not explicitly exempted the site,
7342    * just treat this the way we would an IDL replaceable property.
7343    */
7344   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
7345   if (!outer || !outer->CanMoveResizeWindows(aCallerType) ||
7346       mBrowsingContext->IsFrame()) {
7347     RedefineProperty(aCx, aPropName, aValue, aError);
7348     return;
7349   }
7350 
7351   T value;
7352   if (!ValueToPrimitive<T, eDefault>(aCx, aValue, aPropName, &value)) {
7353     aError.Throw(NS_ERROR_UNEXPECTED);
7354     return;
7355   }
7356 
7357   if (nsContentUtils::ShouldResistFingerprinting(GetDocShell())) {
7358     bool innerWidthSpecified = false;
7359     bool innerHeightSpecified = false;
7360     bool outerWidthSpecified = false;
7361     bool outerHeightSpecified = false;
7362 
7363     if (strcmp(aPropName, "innerWidth") == 0) {
7364       innerWidthSpecified = true;
7365     } else if (strcmp(aPropName, "innerHeight") == 0) {
7366       innerHeightSpecified = true;
7367     } else if (strcmp(aPropName, "outerWidth") == 0) {
7368       outerWidthSpecified = true;
7369     } else if (strcmp(aPropName, "outerHeight") == 0) {
7370       outerHeightSpecified = true;
7371     }
7372 
7373     if (innerWidthSpecified || innerHeightSpecified || outerWidthSpecified ||
7374         outerHeightSpecified) {
7375       nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = outer->GetTreeOwnerWindow();
7376       nsCOMPtr<nsIScreen> screen;
7377       nsCOMPtr<nsIScreenManager> screenMgr(
7378           do_GetService("@mozilla.org/gfx/screenmanager;1"));
7379       int32_t winLeft = 0;
7380       int32_t winTop = 0;
7381       int32_t winWidth = 0;
7382       int32_t winHeight = 0;
7383       double scale = 1.0;
7384 
7385       if (treeOwnerAsWin && screenMgr) {
7386         // Acquire current window size.
7387         treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);
7388         treeOwnerAsWin->GetPositionAndSize(&winLeft, &winTop, &winWidth,
7389                                            &winHeight);
7390         winLeft = NSToIntRound(winHeight / scale);
7391         winTop = NSToIntRound(winWidth / scale);
7392         winWidth = NSToIntRound(winWidth / scale);
7393         winHeight = NSToIntRound(winHeight / scale);
7394 
7395         // Acquire content window size.
7396         CSSSize contentSize;
7397         outer->GetInnerSize(contentSize);
7398 
7399         screenMgr->ScreenForRect(winLeft, winTop, winWidth, winHeight,
7400                                  getter_AddRefs(screen));
7401 
7402         if (screen) {
7403           int32_t roundedValue = std::round(value);
7404           int32_t* targetContentWidth = nullptr;
7405           int32_t* targetContentHeight = nullptr;
7406           int32_t screenWidth = 0;
7407           int32_t screenHeight = 0;
7408           int32_t chromeWidth = 0;
7409           int32_t chromeHeight = 0;
7410           int32_t inputWidth = 0;
7411           int32_t inputHeight = 0;
7412           int32_t unused = 0;
7413 
7414           // Get screen dimensions (in device pixels)
7415           screen->GetAvailRect(&unused, &unused, &screenWidth, &screenHeight);
7416           // Convert them to CSS pixels
7417           screenWidth = NSToIntRound(screenWidth / scale);
7418           screenHeight = NSToIntRound(screenHeight / scale);
7419 
7420           // Calculate the chrome UI size.
7421           chromeWidth = winWidth - contentSize.width;
7422           chromeHeight = winHeight - contentSize.height;
7423 
7424           if (innerWidthSpecified || outerWidthSpecified) {
7425             inputWidth = value;
7426             targetContentWidth = &roundedValue;
7427             targetContentHeight = &unused;
7428           } else if (innerHeightSpecified || outerHeightSpecified) {
7429             inputHeight = value;
7430             targetContentWidth = &unused;
7431             targetContentHeight = &roundedValue;
7432           }
7433 
7434           nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
7435               chromeWidth, chromeHeight, screenWidth, screenHeight, inputWidth,
7436               inputHeight, outerWidthSpecified, outerHeightSpecified,
7437               targetContentWidth, targetContentHeight);
7438           value = T(roundedValue);
7439         }
7440       }
7441     }
7442   }
7443 
7444   (this->*aSetter)(value, aCallerType, aError);
7445 }
7446 
FireOnNewGlobalObject()7447 void nsGlobalWindowInner::FireOnNewGlobalObject() {
7448   // AutoEntryScript required to invoke debugger hook, which is a
7449   // Gecko-specific concept at present.
7450   AutoEntryScript aes(this, "nsGlobalWindowInner report new global");
7451   JS::Rooted<JSObject*> global(aes.cx(), GetWrapper());
7452   JS_FireOnNewGlobalObject(aes.cx(), global);
7453 }
7454 
7455 #if defined(_WINDOWS_) && !defined(MOZ_WRAPPED_WINDOWS_H)
7456 #  pragma message( \
7457       "wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)
7458 #  error "Never include unwrapped windows.h in this file!"
7459 #endif
7460 
CreateImageBitmap(const ImageBitmapSource & aImage,ErrorResult & aRv)7461 already_AddRefed<Promise> nsGlobalWindowInner::CreateImageBitmap(
7462     const ImageBitmapSource& aImage, ErrorResult& aRv) {
7463   return ImageBitmap::Create(this, aImage, Nothing(), aRv);
7464 }
7465 
CreateImageBitmap(const ImageBitmapSource & aImage,int32_t aSx,int32_t aSy,int32_t aSw,int32_t aSh,ErrorResult & aRv)7466 already_AddRefed<Promise> nsGlobalWindowInner::CreateImageBitmap(
7467     const ImageBitmapSource& aImage, int32_t aSx, int32_t aSy, int32_t aSw,
7468     int32_t aSh, ErrorResult& aRv) {
7469   return ImageBitmap::Create(this, aImage,
7470                              Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aRv);
7471 }
7472 
Dispatch(TaskCategory aCategory,already_AddRefed<nsIRunnable> && aRunnable)7473 nsresult nsGlobalWindowInner::Dispatch(
7474     TaskCategory aCategory, already_AddRefed<nsIRunnable>&& aRunnable) {
7475   MOZ_RELEASE_ASSERT(NS_IsMainThread());
7476   if (GetDocGroup()) {
7477     return GetDocGroup()->Dispatch(aCategory, std::move(aRunnable));
7478   }
7479   return DispatcherTrait::Dispatch(aCategory, std::move(aRunnable));
7480 }
7481 
EventTargetFor(TaskCategory aCategory) const7482 nsISerialEventTarget* nsGlobalWindowInner::EventTargetFor(
7483     TaskCategory aCategory) const {
7484   MOZ_RELEASE_ASSERT(NS_IsMainThread());
7485   if (GetDocGroup()) {
7486     return GetDocGroup()->EventTargetFor(aCategory);
7487   }
7488   return DispatcherTrait::EventTargetFor(aCategory);
7489 }
7490 
AbstractMainThreadFor(TaskCategory aCategory)7491 AbstractThread* nsGlobalWindowInner::AbstractMainThreadFor(
7492     TaskCategory aCategory) {
7493   MOZ_RELEASE_ASSERT(NS_IsMainThread());
7494   if (GetDocGroup()) {
7495     return GetDocGroup()->AbstractMainThreadFor(aCategory);
7496   }
7497   return DispatcherTrait::AbstractMainThreadFor(aCategory);
7498 }
7499 
GetPaintWorklet(ErrorResult & aRv)7500 Worklet* nsGlobalWindowInner::GetPaintWorklet(ErrorResult& aRv) {
7501   if (!mPaintWorklet) {
7502     nsIPrincipal* principal = GetPrincipal();
7503     if (!principal) {
7504       aRv.Throw(NS_ERROR_FAILURE);
7505       return nullptr;
7506     }
7507 
7508     mPaintWorklet = PaintWorkletImpl::CreateWorklet(this, principal);
7509   }
7510 
7511   return mPaintWorklet;
7512 }
7513 
GetRegionalPrefsLocales(nsTArray<nsString> & aLocales)7514 void nsGlobalWindowInner::GetRegionalPrefsLocales(
7515     nsTArray<nsString>& aLocales) {
7516   MOZ_ASSERT(mozilla::intl::LocaleService::GetInstance());
7517 
7518   AutoTArray<nsCString, 10> rpLocales;
7519   mozilla::intl::LocaleService::GetInstance()->GetRegionalPrefsLocales(
7520       rpLocales);
7521 
7522   for (const auto& loc : rpLocales) {
7523     aLocales.AppendElement(NS_ConvertUTF8toUTF16(loc));
7524   }
7525 }
7526 
GetWebExposedLocales(nsTArray<nsString> & aLocales)7527 void nsGlobalWindowInner::GetWebExposedLocales(nsTArray<nsString>& aLocales) {
7528   MOZ_ASSERT(mozilla::intl::LocaleService::GetInstance());
7529 
7530   AutoTArray<nsCString, 10> rpLocales;
7531   mozilla::intl::LocaleService::GetInstance()->GetWebExposedLocales(rpLocales);
7532 
7533   for (const auto& loc : rpLocales) {
7534     aLocales.AppendElement(NS_ConvertUTF8toUTF16(loc));
7535   }
7536 }
7537 
GetIntlUtils(ErrorResult & aError)7538 IntlUtils* nsGlobalWindowInner::GetIntlUtils(ErrorResult& aError) {
7539   if (!mIntlUtils) {
7540     mIntlUtils = new IntlUtils(this);
7541   }
7542 
7543   return mIntlUtils;
7544 }
7545 
StoreSharedWorker(SharedWorker * aSharedWorker)7546 void nsGlobalWindowInner::StoreSharedWorker(SharedWorker* aSharedWorker) {
7547   MOZ_ASSERT(aSharedWorker);
7548   MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
7549 
7550   mSharedWorkers.AppendElement(aSharedWorker);
7551 }
7552 
ForgetSharedWorker(SharedWorker * aSharedWorker)7553 void nsGlobalWindowInner::ForgetSharedWorker(SharedWorker* aSharedWorker) {
7554   MOZ_ASSERT(aSharedWorker);
7555   MOZ_ASSERT(mSharedWorkers.Contains(aSharedWorker));
7556 
7557   mSharedWorkers.RemoveElement(aSharedWorker);
7558 }
7559 
StorageAccessPermissionGranted()7560 void nsGlobalWindowInner::StorageAccessPermissionGranted() {
7561   PropagateStorageAccessPermissionGrantedToWorkers(*this);
7562 
7563   // If we have a partitioned localStorage, it's time to replace it with a real
7564   // one in order to receive notifications.
7565 
7566   if (mLocalStorage) {
7567     IgnoredErrorResult error;
7568     GetLocalStorage(error);
7569     if (NS_WARN_IF(error.Failed())) {
7570       return;
7571     }
7572 
7573     MOZ_ASSERT(mLocalStorage &&
7574                mLocalStorage->Type() == Storage::eLocalStorage);
7575 
7576     if (NextGenLocalStorageEnabled() && mListenerManager &&
7577         mListenerManager->HasListenersFor(nsGkAtoms::onstorage)) {
7578       auto object = static_cast<LSObject*>(mLocalStorage.get());
7579 
7580       object->EnsureObserver();
7581     }
7582   }
7583 
7584   // Reset the IndexedDB factory.
7585   mIndexedDB = nullptr;
7586 
7587   // Reset DOM Cache
7588   mCacheStorage = nullptr;
7589 
7590   // Reset the active storage principal
7591   if (mDoc) {
7592     mDoc->ClearActiveStoragePrincipal();
7593     if (mWindowGlobalChild) {
7594       // XXX(farre): This is a bit backwards, but clearing the storage
7595       // principal might make us end up with a new effective storage
7596       // principal on the child side than on the parent side, which
7597       // means that we need to sync it. See bug 1705359.
7598       mWindowGlobalChild->SetDocumentPrincipal(
7599           mDoc->NodePrincipal(), mDoc->EffectiveStoragePrincipal());
7600     }
7601   }
7602 }
7603 
GetContentMediaController()7604 ContentMediaController* nsGlobalWindowInner::GetContentMediaController() {
7605   if (mContentMediaController) {
7606     return mContentMediaController;
7607   }
7608   if (!mBrowsingContext) {
7609     return nullptr;
7610   }
7611 
7612   mContentMediaController = new ContentMediaController(mBrowsingContext->Id());
7613   return mContentMediaController;
7614 }
7615 
SetScrollMarks(const nsTArray<uint32_t> & aScrollMarks)7616 void nsGlobalWindowInner::SetScrollMarks(
7617     const nsTArray<uint32_t>& aScrollMarks) {
7618   mScrollMarks.Assign(aScrollMarks);
7619 
7620   // Mark the scrollbar for repainting.
7621   if (mDoc) {
7622     PresShell* presShell = mDoc->GetPresShell();
7623     if (presShell) {
7624       nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
7625       if (sf) {
7626         sf->InvalidateVerticalScrollbar();
7627       }
7628     }
7629   }
7630 }
7631 
7632 /* static */
Create(nsGlobalWindowOuter * aOuterWindow,bool aIsChrome,WindowGlobalChild * aActor)7633 already_AddRefed<nsGlobalWindowInner> nsGlobalWindowInner::Create(
7634     nsGlobalWindowOuter* aOuterWindow, bool aIsChrome,
7635     WindowGlobalChild* aActor) {
7636   RefPtr<nsGlobalWindowInner> window =
7637       new nsGlobalWindowInner(aOuterWindow, aActor);
7638   if (aIsChrome) {
7639     window->mIsChrome = true;
7640     window->mCleanMessageManager = true;
7641   }
7642 
7643   if (aActor) {
7644     aActor->InitWindowGlobal(window);
7645   }
7646 
7647   window->InitWasOffline();
7648   return window.forget();
7649 }
7650 
GetDocumentURI() const7651 nsIURI* nsPIDOMWindowInner::GetDocumentURI() const {
7652   return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
7653 }
7654 
GetDocBaseURI() const7655 nsIURI* nsPIDOMWindowInner::GetDocBaseURI() const {
7656   return mDoc ? mDoc->GetDocBaseURI() : mDocBaseURI.get();
7657 }
7658 
GetWindowContext() const7659 mozilla::dom::WindowContext* nsPIDOMWindowInner::GetWindowContext() const {
7660   return mWindowGlobalChild ? mWindowGlobalChild->WindowContext() : nullptr;
7661 }
7662 
RemoveFromBFCacheSync()7663 bool nsPIDOMWindowInner::RemoveFromBFCacheSync() {
7664   if (Document* doc = GetExtantDoc()) {
7665     return doc->RemoveFromBFCacheSync();
7666   }
7667   return false;
7668 }
7669 
MaybeCreateDoc()7670 void nsPIDOMWindowInner::MaybeCreateDoc() {
7671   // XXX: Forward to outer?
7672   MOZ_ASSERT(!mDoc);
7673   if (nsIDocShell* docShell = GetDocShell()) {
7674     // Note that |document| here is the same thing as our mDoc, but we
7675     // don't have to explicitly set the member variable because the docshell
7676     // has already called SetNewDocument().
7677     nsCOMPtr<Document> document = docShell->GetDocument();
7678     Unused << document;
7679   }
7680 }
7681 
GetDocGroup() const7682 mozilla::dom::DocGroup* nsPIDOMWindowInner::GetDocGroup() const {
7683   Document* doc = GetExtantDoc();
7684   if (doc) {
7685     return doc->GetDocGroup();
7686   }
7687   return nullptr;
7688 }
7689 
7690 mozilla::dom::BrowsingContextGroup*
GetBrowsingContextGroup() const7691 nsPIDOMWindowInner::GetBrowsingContextGroup() const {
7692   return mBrowsingContext ? mBrowsingContext->Group() : nullptr;
7693 }
7694 
AsGlobal()7695 nsIGlobalObject* nsPIDOMWindowInner::AsGlobal() {
7696   return nsGlobalWindowInner::Cast(this);
7697 }
7698 
AsGlobal() const7699 const nsIGlobalObject* nsPIDOMWindowInner::AsGlobal() const {
7700   return nsGlobalWindowInner::Cast(this);
7701 }
7702 
SaveStorageAccessPermissionGranted()7703 void nsPIDOMWindowInner::SaveStorageAccessPermissionGranted() {
7704   mStorageAccessPermissionGranted = true;
7705 
7706   nsGlobalWindowInner::Cast(this)->StorageAccessPermissionGranted();
7707 }
7708 
HasStorageAccessPermissionGranted()7709 bool nsPIDOMWindowInner::HasStorageAccessPermissionGranted() {
7710   return mStorageAccessPermissionGranted;
7711 }
7712 
nsPIDOMWindowInner(nsPIDOMWindowOuter * aOuterWindow,WindowGlobalChild * aActor)7713 nsPIDOMWindowInner::nsPIDOMWindowInner(nsPIDOMWindowOuter* aOuterWindow,
7714                                        WindowGlobalChild* aActor)
7715     : mMutationBits(0),
7716       mIsDocumentLoaded(false),
7717       mIsHandlingResizeEvent(false),
7718       mMayHavePaintEventListener(false),
7719       mMayHaveTouchEventListener(false),
7720       mMayHaveSelectionChangeEventListener(false),
7721       mMayHaveMouseEnterLeaveEventListener(false),
7722       mMayHavePointerEnterLeaveEventListener(false),
7723       mMayHaveBeforeInputEventListenerForTelemetry(false),
7724       mMutationObserverHasObservedNodeForTelemetry(false),
7725       mOuterWindow(aOuterWindow),
7726       mWindowID(0),
7727       mHasNotifiedGlobalCreated(false),
7728       mMarkedCCGeneration(0),
7729       mHasTriedToCacheTopInnerWindow(false),
7730       mNumOfIndexedDBDatabases(0),
7731       mNumOfOpenWebSockets(0),
7732       mEvent(nullptr),
7733       mStorageAccessPermissionGranted(false),
7734       mWindowGlobalChild(aActor),
7735       mWasSuspendedByGroup(false) {
7736   MOZ_ASSERT(aOuterWindow);
7737   mBrowsingContext = aOuterWindow->GetBrowsingContext();
7738 
7739   if (mWindowGlobalChild) {
7740     mWindowID = aActor->InnerWindowId();
7741 
7742     MOZ_ASSERT(mWindowGlobalChild->BrowsingContext() == mBrowsingContext);
7743   } else {
7744     mWindowID = nsContentUtils::GenerateWindowId();
7745   }
7746 }
7747 
7748 nsPIDOMWindowInner::~nsPIDOMWindowInner() = default;
7749 
7750 #undef FORWARD_TO_OUTER
7751 #undef FORWARD_TO_OUTER_OR_THROW
7752 #undef FORWARD_TO_OUTER_VOID
7753