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/. */
7 #include "nsGlobalWindowInner.h"
15 #include <type_traits>
17 #include "AudioChannelService.h"
18 #include "AutoplayPolicy.h"
20 #include "MainThreadUtils.h"
21 #include "Navigator.h"
22 #include "PaintWorkletImpl.h"
23 #include "SessionStorageCache.h"
25 #include "VRManagerChild.h"
26 #include "WindowDestroyedEvent.h"
27 #include "WindowNamedPropertiesHandler.h"
28 #include "js/ComparisonOperators.h"
29 #include "js/CompileOptions.h"
30 #include "js/friend/PerformanceHint.h"
32 #include "js/loader/LoadedScript.h"
33 #include "js/PropertyAndElement.h" // JS_DefineProperty, JS_GetProperty
34 #include "js/PropertyDescriptor.h"
35 #include "js/RealmOptions.h"
36 #include "js/RootingAPI.h"
37 #include "js/TypeDecls.h"
39 #include "js/Warnings.h"
40 #include "js/shadow/String.h"
42 #include "jsfriendapi.h"
43 #include "mozIDOMWindow.h"
44 #include "moz_external_vr.h"
45 #include "mozilla/AlreadyAddRefed.h"
46 #include "mozilla/ArrayIterator.h"
47 #include "mozilla/ArrayUtils.h"
48 #include "mozilla/Attributes.h"
49 #include "mozilla/BaseProfilerMarkersPrerequisites.h"
50 #include "mozilla/BasicEvents.h"
51 #include "mozilla/BounceTrackingStorageObserver.h"
52 #include "mozilla/CallState.h"
53 #include "mozilla/CycleCollectedJSContext.h"
54 #include "mozilla/DOMEventTargetHelper.h"
55 #include "mozilla/ErrorResult.h"
56 #include "mozilla/EventDispatcher.h"
57 #include "mozilla/EventListenerManager.h"
58 #include "mozilla/EventQueue.h"
59 #include "mozilla/ExtensionPolicyService.h"
60 #include "mozilla/FloatingPoint.h"
61 #include "mozilla/FlushType.h"
62 #include "mozilla/Likely.h"
63 #include "mozilla/LinkedList.h"
64 #include "mozilla/LookAndFeel.h"
65 #include "mozilla/Logging.h"
66 #include "mozilla/MacroForEach.h"
67 #include "mozilla/Maybe.h"
68 #include "mozilla/OwningNonNull.h"
69 #include "mozilla/PermissionDelegateHandler.h"
70 #include "mozilla/Preferences.h"
71 #include "mozilla/PresShell.h"
72 #include "mozilla/ProcessHangMonitor.h"
73 #include "mozilla/RefPtr.h"
74 #include "mozilla/Result.h"
75 #include "mozilla/ScrollTypes.h"
76 #include "mozilla/Components.h"
77 #include "mozilla/SizeOfState.h"
78 #include "mozilla/Span.h"
79 #include "mozilla/SpinEventLoopUntil.h"
80 #include "mozilla/Sprintf.h"
81 #include "mozilla/StaticPrefs_browser.h"
82 #include "mozilla/StaticPrefs_docshell.h"
83 #include "mozilla/StaticPrefs_dom.h"
84 #include "mozilla/StaticPrefs_extensions.h"
85 #include "mozilla/StaticPrefs_privacy.h"
86 #include "mozilla/StorageAccess.h"
87 #include "mozilla/StoragePrincipalHelper.h"
88 #include "mozilla/Telemetry.h"
89 #include "mozilla/TelemetryHistogramEnums.h"
90 #include "mozilla/TimeStamp.h"
91 #include "mozilla/UniquePtr.h"
92 #include "mozilla/Unused.h"
93 #include "mozilla/dom/AudioContext.h"
94 #include "mozilla/dom/AutoEntryScript.h"
95 #include "mozilla/dom/BarProps.h"
96 #include "mozilla/dom/BindingDeclarations.h"
97 #include "mozilla/dom/BindingUtils.h"
98 #include "mozilla/dom/BrowserChild.h"
99 #include "mozilla/dom/BrowsingContext.h"
100 #include "mozilla/dom/CSPEvalChecker.h"
101 #include "mozilla/dom/CallbackDebuggerNotification.h"
102 #include "mozilla/dom/ChromeMessageBroadcaster.h"
103 #include "mozilla/dom/ClientInfo.h"
104 #include "mozilla/dom/ClientManager.h"
105 #include "mozilla/dom/ClientSource.h"
106 #include "mozilla/dom/ClientState.h"
107 #include "mozilla/dom/ClientsBinding.h"
108 #include "mozilla/dom/Console.h"
109 #include "mozilla/dom/ContentChild.h"
110 #include "mozilla/dom/ContentFrameMessageManager.h"
111 #include "mozilla/dom/ContentMediaController.h"
112 #include "mozilla/dom/CustomElementRegistry.h"
113 #include "mozilla/dom/DebuggerNotification.h"
114 #include "mozilla/dom/DebuggerNotificationBinding.h"
115 #include "mozilla/dom/DebuggerNotificationManager.h"
116 #include "mozilla/dom/DocGroup.h"
117 #include "mozilla/dom/Document.h"
118 #include "mozilla/dom/DocumentInlines.h"
119 #include "mozilla/dom/Element.h"
120 #include "mozilla/dom/Event.h"
121 #include "mozilla/dom/EventTarget.h"
122 #include "mozilla/dom/External.h"
123 #include "mozilla/dom/Fetch.h"
124 #include "mozilla/dom/Gamepad.h"
125 #include "mozilla/dom/GamepadHandle.h"
126 #include "mozilla/dom/GamepadManager.h"
127 #include "mozilla/dom/HashChangeEvent.h"
128 #include "mozilla/dom/HashChangeEventBinding.h"
129 #include "mozilla/dom/IDBFactory.h"
130 #include "mozilla/dom/IdleRequest.h"
131 #include "mozilla/dom/ImageBitmap.h"
132 #include "mozilla/dom/ImageBitmapSource.h"
133 #include "mozilla/dom/InstallTriggerBinding.h"
134 #include "mozilla/dom/IntlUtils.h"
135 #include "mozilla/dom/JSExecutionContext.h"
136 #include "mozilla/dom/LSObject.h"
137 #include "mozilla/dom/LocalStorage.h"
138 #include "mozilla/dom/LocalStorageCommon.h"
139 #include "mozilla/dom/Location.h"
140 #include "mozilla/dom/MediaDevices.h"
141 #include "mozilla/dom/MediaKeys.h"
142 #include "mozilla/dom/NavigatorBinding.h"
143 #include "mozilla/dom/Nullable.h"
144 #include "mozilla/dom/PartitionedLocalStorage.h"
145 #include "mozilla/dom/Performance.h"
146 #include "mozilla/dom/PerformanceMainThread.h"
147 #include "mozilla/dom/PopStateEvent.h"
148 #include "mozilla/dom/PopStateEventBinding.h"
149 #include "mozilla/dom/PopupBlocker.h"
150 #include "mozilla/dom/PrimitiveConversions.h"
151 #include "mozilla/dom/Promise.h"
152 #include "mozilla/dom/RootedDictionary.h"
153 #include "mozilla/dom/WebTaskSchedulerMainThread.h"
154 #include "mozilla/dom/ScriptLoader.h"
155 #include "mozilla/dom/ScriptSettings.h"
156 #include "mozilla/dom/ServiceWorker.h"
157 #include "mozilla/dom/ServiceWorkerDescriptor.h"
158 #include "mozilla/dom/ServiceWorkerRegistration.h"
159 #include "mozilla/dom/SessionStorageManager.h"
160 #include "mozilla/dom/SharedWorker.h"
161 #include "mozilla/dom/Storage.h"
162 #include "mozilla/dom/StorageEvent.h"
163 #include "mozilla/dom/StorageEventBinding.h"
164 #include "mozilla/dom/StorageNotifierService.h"
165 #include "mozilla/dom/StorageUtils.h"
166 #include "mozilla/dom/TabMessageTypes.h"
167 #include "mozilla/dom/Timeout.h"
168 #include "mozilla/dom/TimeoutHandler.h"
169 #include "mozilla/dom/TimeoutManager.h"
170 #include "mozilla/dom/ToJSValue.h"
171 #include "mozilla/dom/TrustedTypePolicyFactory.h"
172 #include "mozilla/dom/VRDisplay.h"
173 #include "mozilla/dom/VRDisplayEvent.h"
174 #include "mozilla/dom/VRDisplayEventBinding.h"
175 #include "mozilla/dom/VREventObserver.h"
176 #include "mozilla/dom/VisualViewport.h"
177 #include "mozilla/dom/WebIDLGlobalNameHash.h"
178 #include "mozilla/dom/WindowBinding.h"
179 #include "mozilla/dom/WindowContext.h"
180 #include "mozilla/dom/WindowGlobalChild.h"
181 #include "mozilla/dom/WindowProxyHolder.h"
182 #include "mozilla/dom/WorkerCommon.h"
183 #include "mozilla/dom/Worklet.h"
184 #include "mozilla/dom/XRPermissionRequest.h"
185 #include "mozilla/dom/cache/CacheStorage.h"
186 #include "mozilla/dom/cache/Types.h"
187 #include "mozilla/glean/bindings/Glean.h"
188 #include "mozilla/glean/bindings/GleanPings.h"
189 #include "mozilla/extensions/WebExtensionPolicy.h"
190 #include "mozilla/fallible.h"
191 #include "mozilla/gfx/BasePoint.h"
192 #include "mozilla/gfx/BaseRect.h"
193 #include "mozilla/gfx/BaseSize.h"
194 #include "mozilla/gfx/Rect.h"
195 #include "mozilla/gfx/Types.h"
196 #include "mozilla/intl/LocaleService.h"
197 #include "mozilla/ipc/BackgroundUtils.h"
198 #include "mozilla/ipc/PBackgroundSharedTypes.h"
199 #include "mozilla/net/CookieJarSettings.h"
201 #include "nsBaseHashtable.h"
202 #include "nsCCUncollectableMarker.h"
203 #include "nsCOMPtr.h"
205 #include "nsCRTGlue.h"
206 #include "nsCanvasFrame.h"
207 #include "nsCharTraits.h"
208 #include "nsCheapSets.h"
209 #include "nsContentUtils.h"
211 #include "nsCycleCollectionNoteChild.h"
212 #include "nsCycleCollectionTraversalCallback.h"
213 #include "nsDOMNavigationTiming.h"
215 #include "nsDeviceContext.h"
216 #include "nsDocShell.h"
217 #include "nsFocusManager.h"
218 #include "nsFrameMessageManager.h"
219 #include "nsGkAtoms.h"
220 #include "nsGlobalWindowOuter.h"
221 #include "nsHashKeys.h"
222 #include "nsHistory.h"
223 #include "nsIAddonPolicyService.h"
224 #include "nsIArray.h"
225 #include "nsIBaseWindow.h"
226 #include "nsIBrowserChild.h"
227 #include "nsICancelableRunnable.h"
228 #include "nsIChannel.h"
229 #include "nsIClipboard.h"
230 #include "nsIContentSecurityPolicy.h"
231 #include "nsIControllers.h"
232 #include "nsICookieJarSettings.h"
233 #include "nsICookieService.h"
235 #include "nsIDOMStorageManager.h"
236 #include "nsIDeviceSensors.h"
237 #include "nsIDocShell.h"
238 #include "nsIDocShellTreeItem.h"
239 #include "nsIDocShellTreeOwner.h"
240 #include "nsIDocumentLoader.h"
241 #include "nsIDragService.h"
242 #include "nsIFocusManager.h"
243 #include "nsIFrame.h"
244 #include "nsIGlobalObject.h"
245 #include "nsIIOService.h"
246 #include "nsIIdleRunnable.h"
247 #include "nsIInterfaceRequestorUtils.h"
248 #include "nsILoadContext.h"
249 #include "nsILoadGroup.h"
250 #include "nsILoadInfo.h"
251 #include "nsINamed.h"
253 #include "nsIObserver.h"
254 #include "nsIObserverService.h"
255 #include "nsIPermission.h"
256 #include "nsIPermissionManager.h"
257 #include "nsIPrefBranch.h"
258 #include "nsIPrincipal.h"
259 #include "nsIPrompt.h"
260 #include "nsIRunnable.h"
261 #include "nsIScreen.h"
262 #include "nsIScreenManager.h"
263 #include "nsIScriptContext.h"
264 #include "nsIScriptGlobalObject.h"
265 #include "nsIScriptObjectPrincipal.h"
266 #include "nsIScrollableFrame.h"
267 #include "nsISerialEventTarget.h"
268 #include "nsISimpleEnumerator.h"
269 #include "nsISizeOfEventTarget.h"
270 #include "nsISlowScriptDebug.h"
271 #include "nsISupportsUtils.h"
272 #include "nsIThread.h"
273 #include "nsITimedChannel.h"
275 #include "nsIWeakReference.h"
276 #include "nsIWebBrowserChrome.h"
277 #include "nsIWebNavigation.h"
278 #include "nsIWebProgressListener.h"
279 #include "nsIWidget.h"
280 #include "nsIWidgetListener.h"
281 #include "nsIXULRuntime.h"
282 #include "nsJSPrincipals.h"
283 #include "nsJSUtils.h"
284 #include "nsLayoutStatics.h"
285 #include "nsLiteralString.h"
286 #include "nsNetUtil.h"
287 #include "nsPIDOMWindow.h"
288 #include "nsPIDOMWindowInlines.h"
289 #include "nsPIWindowRoot.h"
291 #include "nsPresContext.h"
292 #include "nsQueryObject.h"
293 #include "nsSandboxFlags.h"
294 #include "nsScreen.h"
295 #include "nsServiceManagerUtils.h"
296 #include "nsString.h"
297 #include "nsStringFlags.h"
298 #include "nsStringFwd.h"
299 #include "nsTArray.h"
300 #include "nsTLiteralString.h"
301 #include "nsTObserverArray.h"
302 #include "nsTStringRepr.h"
303 #include "nsThreadUtils.h"
304 #include "nsWeakReference.h"
305 #include "nsWindowMemoryReporter.h"
306 #include "nsWindowSizes.h"
307 #include "nsWrapperCache.h"
308 #include "nsWrapperCacheInlines.h"
309 #include "nsXULAppAPI.h"
310 #include "nsrootidl.h"
313 #include "xpcprivate.h"
314 #include "xpcpublic.h"
316 #include "nsIDOMXULControlElement.h"
319 # include "nsIPrintSettings.h"
323 # include "mozilla/dom/SpeechSynthesis.h"
327 # include <android/log.h>
331 # include "mozilla/Debug.h"
332 # include <process.h>
333 # define getpid _getpid
335 # include <unistd.h> // for getpid()
338 using namespace mozilla
;
339 using namespace mozilla::dom
;
340 using namespace mozilla::dom::ipc
;
341 using mozilla::TimeDuration
;
342 using mozilla::TimeStamp
;
343 using mozilla::dom::GamepadHandle
;
344 using mozilla::dom::cache::CacheStorage
;
346 #define FORWARD_TO_OUTER(method, args, err_rval) \
348 RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal(); \
349 if (!HasActiveDocument()) { \
350 NS_WARNING(outer ? "Inner window does not have active document." \
351 : "No outer window available!"); \
354 return outer->method args; \
357 static nsGlobalWindowOuter
* GetOuterWindowForForwarding(
358 nsGlobalWindowInner
* aInner
, ErrorResult
& aError
) {
359 nsGlobalWindowOuter
* outer
= aInner
->GetOuterWindowInternal();
360 if (MOZ_LIKELY(aInner
->HasActiveDocument())) {
364 NS_WARNING("No outer window available!");
365 aError
.Throw(NS_ERROR_NOT_INITIALIZED
);
367 aError
.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO
);
372 #define FORWARD_TO_OUTER_OR_THROW(method, args, rv, err_rval) \
374 RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowForForwarding(this, rv); \
375 if (MOZ_LIKELY(outer)) { \
376 return outer->method args; \
381 #define FORWARD_TO_OUTER_VOID(method, args) \
383 RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal(); \
384 if (!HasActiveDocument()) { \
385 NS_WARNING(outer ? "Inner window does not have active document." \
386 : "No outer window available!"); \
389 outer->method args; \
393 #define ENSURE_ACTIVE_DOCUMENT(errorresult, err_rval) \
395 if (MOZ_UNLIKELY(!HasActiveDocument())) { \
396 aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \
401 #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
402 #define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
403 #define PERMISSION_CHANGED_TOPIC "perm-changed"
405 static LazyLogModule
gDOMLeakPRLogInner("DOMLeakInner");
406 extern mozilla::LazyLogModule gTimeoutLog
;
409 static LazyLogModule
gDocShellAndDOMWindowLeakLogging(
410 "DocShellAndDOMWindowLeak");
413 static FILE* gDumpFile
= nullptr;
415 nsGlobalWindowInner::InnerWindowByIdTable
*
416 nsGlobalWindowInner::sInnerWindowsById
= nullptr;
418 bool nsGlobalWindowInner::sDragServiceDisabled
= false;
419 bool nsGlobalWindowInner::sMouseDown
= false;
422 * An indirect observer object that means we don't have to implement nsIObserver
423 * on nsGlobalWindow, where any script could see it.
425 class nsGlobalWindowObserver final
: public nsIObserver
,
426 public nsIInterfaceRequestor
,
427 public StorageNotificationObserver
{
429 explicit nsGlobalWindowObserver(nsGlobalWindowInner
* aWindow
)
430 : mWindow(aWindow
) {}
432 NS_IMETHOD
Observe(nsISupports
* aSubject
, const char* aTopic
,
433 const char16_t
* aData
) override
{
434 if (!mWindow
) return NS_OK
;
435 return mWindow
->Observe(aSubject
, aTopic
, aData
);
437 void Forget() { mWindow
= nullptr; }
438 NS_IMETHOD
GetInterface(const nsIID
& aIID
, void** aResult
) override
{
439 if (mWindow
&& aIID
.Equals(NS_GET_IID(nsIDOMWindow
)) && mWindow
) {
440 return mWindow
->QueryInterface(aIID
, aResult
);
442 return NS_NOINTERFACE
;
445 void ObserveStorageNotification(StorageEvent
* aEvent
,
446 const char16_t
* aStorageType
,
447 bool aPrivateBrowsing
) override
{
449 mWindow
->ObserveStorageNotification(aEvent
, aStorageType
,
454 nsIPrincipal
* GetEffectiveCookiePrincipal() const override
{
455 return mWindow
? mWindow
->GetEffectiveCookiePrincipal() : nullptr;
458 nsIPrincipal
* GetEffectiveStoragePrincipal() const override
{
459 return mWindow
? mWindow
->GetEffectiveStoragePrincipal() : nullptr;
462 bool IsPrivateBrowsing() const override
{
463 return mWindow
? mWindow
->IsPrivateBrowsing() : false;
466 nsIEventTarget
* GetEventTarget() const override
{
467 return mWindow
? mWindow
->SerialEventTarget() : nullptr;
471 ~nsGlobalWindowObserver() = default;
473 // This reference is non-owning and safe because it's cleared by
474 // nsGlobalWindowInner::FreeInnerObjects().
475 nsGlobalWindowInner
* MOZ_NON_OWNING_REF mWindow
;
478 NS_IMPL_ISUPPORTS(nsGlobalWindowObserver
, nsIObserver
, nsIInterfaceRequestor
)
480 class IdleRequestExecutor
;
482 class IdleRequestExecutorTimeoutHandler final
: public TimeoutHandler
{
484 explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor
* aExecutor
)
485 : mExecutor(aExecutor
) {}
487 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
488 NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestExecutorTimeoutHandler
)
490 bool Call(const char* /* unused */) override
;
493 ~IdleRequestExecutorTimeoutHandler() override
= default;
494 RefPtr
<IdleRequestExecutor
> mExecutor
;
497 NS_IMPL_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler
, mExecutor
)
499 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutorTimeoutHandler
)
500 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutorTimeoutHandler
)
502 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler
)
503 NS_INTERFACE_MAP_ENTRY(nsISupports
)
506 class IdleRequestExecutor final
: public nsIRunnable
,
507 public nsICancelableRunnable
,
509 public nsIIdleRunnable
{
511 explicit IdleRequestExecutor(nsGlobalWindowInner
* aWindow
)
512 : mDispatched(false), mDeadline(TimeStamp::Now()), mWindow(aWindow
) {
513 MOZ_DIAGNOSTIC_ASSERT(mWindow
);
515 mIdlePeriodLimit
= {mDeadline
, mWindow
->LastIdleRequestHandle()};
516 mDelayedExecutorDispatcher
= new IdleRequestExecutorTimeoutHandler(this);
519 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
520 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor
, nsIRunnable
)
524 nsresult
Cancel() override
;
525 void SetDeadline(TimeStamp aDeadline
) override
;
527 bool IsCancelled() const { return !mWindow
|| mWindow
->IsDying(); }
528 // Checks if aRequest shouldn't execute in the current idle period
529 // since it has been queued from a chained call to
530 // requestIdleCallback from within a running idle callback.
531 bool IneligibleForCurrentIdlePeriod(IdleRequest
* aRequest
) const {
532 return aRequest
->Handle() >= mIdlePeriodLimit
.mLastRequestIdInIdlePeriod
&&
533 TimeStamp::Now() <= mIdlePeriodLimit
.mEndOfIdlePeriod
;
536 void MaybeUpdateIdlePeriodLimit();
538 // Maybe dispatch the IdleRequestExecutor. MabyeDispatch will
539 // schedule a delayed dispatch if the associated window is in the
540 // background or if given a time to wait until dispatching.
541 void MaybeDispatch(TimeStamp aDelayUntil
= TimeStamp());
542 void ScheduleDispatch();
545 struct IdlePeriodLimit
{
546 TimeStamp mEndOfIdlePeriod
;
547 uint32_t mLastRequestIdInIdlePeriod
;
550 void DelayedDispatch(uint32_t aDelay
);
552 ~IdleRequestExecutor() override
= default;
556 IdlePeriodLimit mIdlePeriodLimit
;
557 RefPtr
<nsGlobalWindowInner
> mWindow
;
558 // The timeout handler responsible for dispatching this executor in
559 // the case of immediate dispatch to the idle queue isn't
560 // desirable. This is used if we've dispatched all idle callbacks
561 // that are allowed to run in the current idle period, or if the
562 // associated window is currently in the background.
563 RefPtr
<TimeoutHandler
> mDelayedExecutorDispatcher
;
564 // If not Nothing() then this value is the handle to the currently
565 // scheduled delayed executor dispatcher. This is needed to be able
566 // to cancel the timeout handler in case of the executor being
568 Maybe
<int32_t> mDelayedExecutorHandle
;
571 NS_IMPL_CYCLE_COLLECTION(IdleRequestExecutor
, mWindow
,
572 mDelayedExecutorDispatcher
)
574 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor
)
575 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor
)
577 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor
)
578 NS_INTERFACE_MAP_ENTRY(nsIRunnable
)
579 NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable
)
580 NS_INTERFACE_MAP_ENTRY(nsINamed
)
581 NS_INTERFACE_MAP_ENTRY(nsIIdleRunnable
)
582 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIRunnable
)
586 IdleRequestExecutor::GetName(nsACString
& aName
) {
587 aName
.AssignLiteral("IdleRequestExecutor");
591 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until nsIRunnable::Run is MOZ_CAN_RUN_SCRIPT.
593 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
IdleRequestExecutor::Run() {
594 MOZ_ASSERT(NS_IsMainThread());
598 RefPtr
<nsGlobalWindowInner
> window(mWindow
);
599 window
->ExecuteIdleRequest(mDeadline
);
605 nsresult
IdleRequestExecutor::Cancel() {
606 MOZ_ASSERT(NS_IsMainThread());
608 if (mDelayedExecutorHandle
&& mWindow
) {
609 mWindow
->TimeoutManager().ClearTimeout(
610 mDelayedExecutorHandle
.value(), Timeout::Reason::eIdleCallbackTimeout
);
617 void IdleRequestExecutor::SetDeadline(TimeStamp aDeadline
) {
618 MOZ_ASSERT(NS_IsMainThread());
624 mDeadline
= aDeadline
;
627 void IdleRequestExecutor::MaybeUpdateIdlePeriodLimit() {
628 if (TimeStamp::Now() > mIdlePeriodLimit
.mEndOfIdlePeriod
) {
629 mIdlePeriodLimit
= {mDeadline
, mWindow
->LastIdleRequestHandle()};
633 void IdleRequestExecutor::MaybeDispatch(TimeStamp aDelayUntil
) {
634 // If we've already dispatched the executor we don't want to do it
635 // again. Also, if we've called IdleRequestExecutor::Cancel mWindow
636 // will be null, which indicates that we shouldn't dispatch this
638 if (mDispatched
|| IsCancelled()) {
644 nsPIDOMWindowOuter
* outer
= mWindow
->GetOuterWindow();
645 if (outer
&& outer
->IsBackground()) {
646 // Set a timeout handler with a timeout of 0 ms to throttle idle
647 // callback requests coming from a backround window using
648 // background timeout throttling.
653 TimeStamp now
= TimeStamp::Now();
654 if (!aDelayUntil
|| aDelayUntil
< now
) {
659 TimeDuration delay
= aDelayUntil
- now
;
660 DelayedDispatch(static_cast<uint32_t>(delay
.ToMilliseconds()));
663 void IdleRequestExecutor::ScheduleDispatch() {
665 mDelayedExecutorHandle
= Nothing();
666 RefPtr
<IdleRequestExecutor
> request
= this;
667 NS_DispatchToCurrentThreadQueue(request
.forget(), EventQueuePriority::Idle
);
670 void IdleRequestExecutor::DelayedDispatch(uint32_t aDelay
) {
672 MOZ_ASSERT(mDelayedExecutorHandle
.isNothing());
674 mWindow
->TimeoutManager().SetTimeout(
675 mDelayedExecutorDispatcher
, aDelay
, false,
676 Timeout::Reason::eIdleCallbackTimeout
, &handle
);
677 mDelayedExecutorHandle
= Some(handle
);
680 bool IdleRequestExecutorTimeoutHandler::Call(const char* /* unused */) {
681 if (!mExecutor
->IsCancelled()) {
682 mExecutor
->ScheduleDispatch();
687 void nsGlobalWindowInner::ScheduleIdleRequestDispatch() {
688 AssertIsOnMainThread();
690 if (!mIdleRequestExecutor
) {
691 mIdleRequestExecutor
= new IdleRequestExecutor(this);
694 mIdleRequestExecutor
->MaybeDispatch();
697 void nsGlobalWindowInner::SuspendIdleRequests() {
698 if (mIdleRequestExecutor
) {
699 mIdleRequestExecutor
->Cancel();
700 mIdleRequestExecutor
= nullptr;
704 void nsGlobalWindowInner::ResumeIdleRequests() {
705 MOZ_ASSERT(!mIdleRequestExecutor
);
707 ScheduleIdleRequestDispatch();
710 void nsGlobalWindowInner::RemoveIdleCallback(
711 mozilla::dom::IdleRequest
* aRequest
) {
712 AssertIsOnMainThread();
714 if (aRequest
->HasTimeout()) {
715 mTimeoutManager
->ClearTimeout(aRequest
->GetTimeoutHandle(),
716 Timeout::Reason::eIdleCallbackTimeout
);
719 aRequest
->removeFrom(mIdleRequestCallbacks
);
722 void nsGlobalWindowInner::RunIdleRequest(IdleRequest
* aRequest
,
723 DOMHighResTimeStamp aDeadline
,
725 AssertIsOnMainThread();
726 // XXXbz Do we still need this RefPtr? MOZ_CAN_RUN_SCRIPT should
727 // guarantee that caller is holding a strong ref on the stack.
728 RefPtr
<IdleRequest
> request(aRequest
);
729 RemoveIdleCallback(request
);
730 request
->IdleRun(this, aDeadline
, aDidTimeout
);
733 void nsGlobalWindowInner::ExecuteIdleRequest(TimeStamp aDeadline
) {
734 AssertIsOnMainThread();
735 RefPtr
<IdleRequest
> request
= mIdleRequestCallbacks
.getFirst();
738 // There are no more idle requests, so stop scheduling idle
739 // request callbacks.
743 // If the request that we're trying to execute has been queued
744 // during the current idle period, then dispatch it again at the end
745 // of the idle period.
746 if (mIdleRequestExecutor
->IneligibleForCurrentIdlePeriod(request
)) {
747 mIdleRequestExecutor
->MaybeDispatch(aDeadline
);
751 DOMHighResTimeStamp deadline
= 0.0;
753 if (Performance
* perf
= GetPerformance()) {
754 deadline
= perf
->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline
);
757 mIdleRequestExecutor
->MaybeUpdateIdlePeriodLimit();
758 RunIdleRequest(request
, deadline
, false);
760 // Running the idle callback could've suspended the window, in which
761 // case mIdleRequestExecutor will be null.
762 if (mIdleRequestExecutor
) {
763 mIdleRequestExecutor
->MaybeDispatch();
767 class IdleRequestTimeoutHandler final
: public TimeoutHandler
{
769 IdleRequestTimeoutHandler(JSContext
* aCx
, IdleRequest
* aIdleRequest
,
770 nsPIDOMWindowInner
* aWindow
)
771 : TimeoutHandler(aCx
), mIdleRequest(aIdleRequest
), mWindow(aWindow
) {}
773 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
774 NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestTimeoutHandler
)
776 MOZ_CAN_RUN_SCRIPT
bool Call(const char* /* unused */) override
{
777 RefPtr
<nsGlobalWindowInner
> window(nsGlobalWindowInner::Cast(mWindow
));
778 RefPtr
<IdleRequest
> request(mIdleRequest
);
779 window
->RunIdleRequest(request
, 0.0, true);
784 ~IdleRequestTimeoutHandler() override
= default;
786 RefPtr
<IdleRequest
> mIdleRequest
;
787 nsCOMPtr
<nsPIDOMWindowInner
> mWindow
;
790 NS_IMPL_CYCLE_COLLECTION(IdleRequestTimeoutHandler
, mIdleRequest
, mWindow
)
792 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestTimeoutHandler
)
793 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestTimeoutHandler
)
795 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler
)
796 NS_INTERFACE_MAP_ENTRY(nsISupports
)
799 uint32_t nsGlobalWindowInner::RequestIdleCallback(
800 JSContext
* aCx
, IdleRequestCallback
& aCallback
,
801 const IdleRequestOptions
& aOptions
, ErrorResult
& aError
) {
802 AssertIsOnMainThread();
808 uint32_t handle
= mIdleRequestCallbackCounter
++;
810 RefPtr
<IdleRequest
> request
= new IdleRequest(&aCallback
, handle
);
812 if (aOptions
.mTimeout
.WasPassed()) {
813 int32_t timeoutHandle
;
814 RefPtr
<TimeoutHandler
> handler(
815 new IdleRequestTimeoutHandler(aCx
, request
, this));
817 nsresult rv
= mTimeoutManager
->SetTimeout(
818 handler
, aOptions
.mTimeout
.Value(), false,
819 Timeout::Reason::eIdleCallbackTimeout
, &timeoutHandle
);
821 if (NS_WARN_IF(NS_FAILED(rv
))) {
825 request
->SetTimeoutHandle(timeoutHandle
);
828 mIdleRequestCallbacks
.insertBack(request
);
830 if (!IsSuspended()) {
831 ScheduleIdleRequestDispatch();
837 void nsGlobalWindowInner::CancelIdleCallback(uint32_t aHandle
) {
838 for (IdleRequest
* r
: mIdleRequestCallbacks
) {
839 if (r
->Handle() == aHandle
) {
840 RemoveIdleCallback(r
);
846 void nsGlobalWindowInner::DisableIdleCallbackRequests() {
847 if (mIdleRequestExecutor
) {
848 mIdleRequestExecutor
->Cancel();
849 mIdleRequestExecutor
= nullptr;
852 while (!mIdleRequestCallbacks
.isEmpty()) {
853 RefPtr
<IdleRequest
> request
= mIdleRequestCallbacks
.getFirst();
854 RemoveIdleCallback(request
);
858 bool nsGlobalWindowInner::IsBackgroundInternal() const {
859 return !mOuterWindow
|| mOuterWindow
->IsBackground();
862 class PromiseDocumentFlushedResolver final
{
864 PromiseDocumentFlushedResolver(Promise
* aPromise
,
865 PromiseDocumentFlushedCallback
& aCallback
)
866 : mPromise(aPromise
), mCallback(&aCallback
) {}
868 virtual ~PromiseDocumentFlushedResolver() = default;
871 nsMutationGuard guard
;
873 JS::Rooted
<JS::Value
> returnVal(RootingCx());
874 mCallback
->Call(&returnVal
, error
);
876 if (error
.Failed()) {
877 mPromise
->MaybeReject(std::move(error
));
878 } else if (guard
.Mutated(0)) {
879 // Something within the callback mutated the DOM.
880 mPromise
->MaybeRejectWithNoModificationAllowedError(
881 "DOM mutated from promiseDocumentFlushed callbacks");
883 mPromise
->MaybeResolve(returnVal
);
887 RefPtr
<Promise
> mPromise
;
888 RefPtr
<PromiseDocumentFlushedCallback
> mCallback
;
891 //*****************************************************************************
892 //*** nsGlobalWindowInner: Object Management
893 //*****************************************************************************
895 nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter
* aOuterWindow
,
896 WindowGlobalChild
* aActor
)
897 : nsPIDOMWindowInner(aOuterWindow
, aActor
),
898 mHasOrientationChangeListeners(false),
900 mHasHadSlowScript(false),
902 mCleanMessageManager(false),
905 mFocusByKeyOccurred(false),
906 mDidFireDocElemInserted(false),
908 mHasXRSession(false),
909 mHasVRDisplayActivateEvents(false),
910 mXRRuntimeDetectionInFlight(false),
911 mXRPermissionRequestInFlight(false),
912 mXRPermissionGranted(false),
913 mWasCurrentInnerWindow(false),
914 mHasSeenGamepadInput(false),
915 mHintedWasLoading(false),
916 mHasOpenedExternalProtocolFrame(false),
917 mScrollMarksOnHScrollbar(false),
918 mStorageAllowedReasonCache(0),
925 mIdleRequestCallbackCounter(1),
926 mIdleRequestExecutor(nullptr),
927 mObservingRefresh(false),
928 mIteratingDocumentFlushedResolvers(false),
929 mCanSkipCCGeneration(0) {
930 mIsInnerWindow
= true;
932 AssertIsOnMainThread();
934 nsLayoutStatics::AddRef();
936 // Initialize the PRCList (this).
939 // add this inner window to the outer window list of inners.
940 PR_INSERT_AFTER(this, aOuterWindow
);
942 mTimeoutManager
= MakeUnique
<dom::TimeoutManager
>(
943 *this, StaticPrefs::dom_timeout_max_idle_defer_ms());
945 mObserver
= new nsGlobalWindowObserver(this);
946 if (nsCOMPtr
<nsIObserverService
> os
= services::GetObserverService()) {
947 // Watch for online/offline status changes so we can fire events. Use
948 // a strong reference.
949 os
->AddObserver(mObserver
, NS_IOSERVICE_OFFLINE_STATUS_TOPIC
, false);
950 os
->AddObserver(mObserver
, MEMORY_PRESSURE_OBSERVER_TOPIC
, false);
951 os
->AddObserver(mObserver
, PERMISSION_CHANGED_TOPIC
, false);
952 os
->AddObserver(mObserver
, "screen-information-changed", false);
955 Preferences::AddStrongObserver(mObserver
, "intl.accept_languages");
957 // Watch for storage notifications so we can fire storage events.
958 RefPtr
<StorageNotifierService
> sns
= StorageNotifierService::GetOrCreate();
960 sns
->Register(mObserver
);
963 if (XRE_IsContentProcess()) {
964 nsCOMPtr
<nsIDocShell
> docShell
= GetDocShell();
966 mBrowserChild
= docShell
->GetBrowserChild();
970 if (gDumpFile
== nullptr) {
972 Preferences::GetCString("browser.dom.window.dump.file", fname
);
973 if (!fname
.IsEmpty()) {
974 // If this fails to open, Dump() knows to just go to stdout on null.
975 gDumpFile
= fopen(fname
.get(), "wb+");
982 mSerial
= nsContentUtils::InnerOrOuterWindowCreated();
984 MOZ_LOG(gDocShellAndDOMWindowLeakLogging
, LogLevel::Info
,
985 ("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
986 nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
987 static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial
,
988 static_cast<void*>(ToCanonicalSupports(aOuterWindow
))));
991 MOZ_LOG(gDOMLeakPRLogInner
, LogLevel::Debug
,
992 ("DOMWINDOW %p created outer=%p", this, aOuterWindow
));
994 // Add ourselves to the inner windows list.
995 MOZ_ASSERT(sInnerWindowsById
, "Inner Windows hash table must be created!");
996 MOZ_ASSERT(!sInnerWindowsById
->Contains(mWindowID
),
997 "This window shouldn't be in the hash table yet!");
998 // We seem to see crashes in release builds because of null
999 // |sInnerWindowsById|.
1000 if (sInnerWindowsById
) {
1001 sInnerWindowsById
->InsertOrUpdate(mWindowID
, this);
1008 void nsGlobalWindowInner::AssertIsOnMainThread() {
1009 MOZ_ASSERT(NS_IsMainThread());
1015 void nsGlobalWindowInner::Init() {
1016 AssertIsOnMainThread();
1018 NS_ASSERTION(gDOMLeakPRLogInner
,
1019 "gDOMLeakPRLogInner should have been initialized!");
1021 sInnerWindowsById
= new InnerWindowByIdTable();
1024 nsGlobalWindowInner::~nsGlobalWindowInner() {
1025 AssertIsOnMainThread();
1026 MOZ_ASSERT(!mHintedWasLoading
);
1028 if (IsChromeWindow()) {
1029 MOZ_ASSERT(mCleanMessageManager
,
1030 "chrome windows may always disconnect the msg manager");
1032 DisconnectAndClearGroupMessageManagers();
1034 if (mChromeFields
.mMessageManager
) {
1035 static_cast<nsFrameMessageManager
*>(mChromeFields
.mMessageManager
.get())
1039 mCleanMessageManager
= false;
1042 // In most cases this should already have been called, but call it again
1043 // here to catch any corner cases.
1046 if (sInnerWindowsById
) {
1047 sInnerWindowsById
->Remove(mWindowID
);
1050 nsContentUtils::InnerOrOuterWindowDestroyed();
1053 if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging
, LogLevel::Info
)) {
1055 if (mLastOpenedURI
) {
1056 url
= mLastOpenedURI
->GetSpecOrDefault();
1058 // Data URLs can be very long, so truncate to avoid flooding the log.
1059 const uint32_t maxURLLength
= 1000;
1060 if (url
.Length() > maxURLLength
) {
1061 url
.Truncate(maxURLLength
);
1065 nsGlobalWindowOuter
* outer
= nsGlobalWindowOuter::Cast(mOuterWindow
);
1067 gDocShellAndDOMWindowLeakLogging
, LogLevel::Info
,
1068 ("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
1070 nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
1071 static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial
,
1072 static_cast<void*>(ToCanonicalSupports(outer
)), url
.get()));
1075 MOZ_LOG(gDOMLeakPRLogInner
, LogLevel::Debug
,
1076 ("DOMWINDOW %p destroyed", this));
1078 Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS
,
1079 mMutationBits
? 1 : 0);
1081 // An inner window is destroyed, pull it out of the outer window's
1082 // list if inner windows.
1084 PR_REMOVE_LINK(this);
1086 // If our outer window's inner window is this window, null out the
1087 // outer window's reference to this window that's being deleted.
1088 nsGlobalWindowOuter
* outer
= GetOuterWindowInternal();
1090 outer
->MaybeClearInnerWindow(this);
1093 // We don't have to leave the tab group if we are an inner window.
1095 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
1096 if (ac
) ac
->RemoveWindowAsListener(this);
1098 nsLayoutStatics::Release();
1102 void nsGlobalWindowInner::ShutDown() {
1103 AssertIsOnMainThread();
1105 if (gDumpFile
&& gDumpFile
!= stdout
) {
1108 gDumpFile
= nullptr;
1110 delete sInnerWindowsById
;
1111 sInnerWindowsById
= nullptr;
1114 void nsGlobalWindowInner::FreeInnerObjects() {
1120 if (mDoc
&& mDoc
->GetWindowContext()) {
1121 // The document is about to lose its window, so this is a good time to send
1122 // our page use counters.
1124 // (We also do this in Document::SetScriptGlobalObject(nullptr), which
1125 // catches most cases of documents losing their window, but not all.)
1126 mDoc
->SendPageUseCounters();
1129 // Make sure that this is called before we null out the document and
1130 // other members that the window destroyed observers could
1132 NotifyDOMWindowDestroyed(this);
1133 if (auto* reporter
= nsWindowMemoryReporter::Get()) {
1134 reporter
->ObserveDOMWindowDetached(this);
1137 // Kill all of the workers for this window.
1138 CancelWorkersForWindow(*this);
1140 for (RefPtr
<mozilla::dom::SharedWorker
> pinnedWorker
:
1141 mSharedWorkers
.ForwardRange()) {
1142 pinnedWorker
->Close();
1145 if (mTimeoutManager
) {
1146 mTimeoutManager
->ClearAllTimeouts();
1149 DisableIdleCallbackRequests();
1151 mChromeEventHandler
= nullptr;
1153 if (mListenerManager
) {
1154 mListenerManager
->RemoveAllListeners();
1155 mListenerManager
->Disconnect();
1156 mListenerManager
= nullptr;
1162 mNavigator
->OnNavigation();
1163 mNavigator
->Invalidate();
1164 mNavigator
= nullptr;
1170 // Remember the document's principal, URI, and CSP.
1171 mDocumentPrincipal
= mDoc
->NodePrincipal();
1172 mDocumentCookiePrincipal
= mDoc
->EffectiveCookiePrincipal();
1173 mDocumentStoragePrincipal
= mDoc
->EffectiveStoragePrincipal();
1174 mDocumentPartitionedPrincipal
= mDoc
->PartitionedPrincipal();
1175 mDocumentURI
= mDoc
->GetDocumentURI();
1176 mDocBaseURI
= mDoc
->GetDocBaseURI();
1177 mDocumentCsp
= mDoc
->GetCsp();
1179 while (mDoc
->EventHandlingSuppressed()) {
1180 mDoc
->UnsuppressEventHandlingAndFireEvents(false);
1184 // Remove our reference to the document and the document principal.
1185 mFocusedElement
= nullptr;
1187 nsIGlobalObject::UnlinkObjectsInGlobal();
1189 NotifyWindowIDDestroyed("inner-window-destroyed");
1191 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
1192 mAudioContexts
[i
]->OnWindowDestroy();
1194 mAudioContexts
.Clear();
1196 for (MediaKeys
* mediaKeys
: mMediaKeysInstances
) {
1197 mediaKeys
->OnInnerWindowDestroy();
1199 mMediaKeysInstances
.Clear();
1201 DisableGamepadUpdates();
1202 mHasGamepad
= false;
1205 mHasXRSession
= false;
1206 mHasVRDisplayActivateEvents
= false;
1207 mXRRuntimeDetectionInFlight
= false;
1208 mXRPermissionRequestInFlight
= false;
1209 mXRPermissionGranted
= false;
1210 mVRDisplays
.Clear();
1212 // This breaks a cycle between the window and the ClientSource object.
1213 mClientSource
.reset();
1215 if (mWindowGlobalChild
) {
1216 // Remove any remaining listeners.
1217 int64_t nListeners
= mWindowGlobalChild
->BeforeUnloadListeners();
1218 for (int64_t i
= 0; i
< nListeners
; ++i
) {
1219 mWindowGlobalChild
->BeforeUnloadRemoved();
1221 MOZ_ASSERT(mWindowGlobalChild
->BeforeUnloadListeners() == 0);
1224 // If we have any promiseDocumentFlushed callbacks, fire them now so
1225 // that the Promises can resolve.
1226 CallDocumentFlushedResolvers(/* aUntilExhaustion = */ true);
1228 DisconnectGlobalTeardownObservers();
1230 #ifdef MOZ_WIDGET_ANDROID
1231 DisableOrientationChangeListener();
1235 if (nsCOMPtr
<nsIObserverService
> os
= services::GetObserverService()) {
1236 os
->RemoveObserver(mObserver
, NS_IOSERVICE_OFFLINE_STATUS_TOPIC
);
1237 os
->RemoveObserver(mObserver
, MEMORY_PRESSURE_OBSERVER_TOPIC
);
1238 os
->RemoveObserver(mObserver
, PERMISSION_CHANGED_TOPIC
);
1239 os
->RemoveObserver(mObserver
, "screen-information-changed");
1242 RefPtr
<StorageNotifierService
> sns
= StorageNotifierService::GetOrCreate();
1244 sns
->Unregister(mObserver
);
1247 Preferences::RemoveObserver(mObserver
, "intl.accept_languages");
1249 // Drop its reference to this dying window, in case for some bogus reason
1250 // the object stays around.
1251 mObserver
->Forget();
1256 mLocationbar
= nullptr;
1257 mPersonalbar
= nullptr;
1258 mStatusbar
= nullptr;
1259 mScrollbars
= nullptr;
1263 mPaintWorklet
= nullptr;
1265 mExternal
= nullptr;
1266 mInstallTrigger
= nullptr;
1268 if (mLocalStorage
) {
1269 mLocalStorage
->Disconnect();
1270 mLocalStorage
= nullptr;
1272 mSessionStorage
= nullptr;
1274 // Since window is dying, nothing is going to be painted
1275 // with meaningful sizes, so these temp data for LCP is
1276 // no longer needed.
1277 static_cast<PerformanceMainThread
*>(mPerformance
.get())
1278 ->ClearGeneratedTempDataForLCP();
1280 mPerformance
= nullptr;
1282 mContentMediaController
= nullptr;
1284 if (mWebTaskScheduler
) {
1285 mWebTaskScheduler
->Disconnect();
1286 mWebTaskScheduler
= nullptr;
1289 mTrustedTypePolicyFactory
= nullptr;
1291 mSharedWorkers
.Clear();
1293 #ifdef MOZ_WEBSPEECH
1294 mSpeechSynthesis
= nullptr;
1298 mGleanPings
= nullptr;
1300 mParentTarget
= nullptr;
1302 if (mCleanMessageManager
) {
1303 MOZ_ASSERT(mIsChrome
, "only chrome should have msg manager cleaned");
1304 if (mChromeFields
.mMessageManager
) {
1305 mChromeFields
.mMessageManager
->Disconnect();
1309 if (mWindowGlobalChild
&& !mWindowGlobalChild
->IsClosed()) {
1310 mWindowGlobalChild
->Destroy();
1313 mIntlUtils
= nullptr;
1315 HintIsLoading(false);
1318 //*****************************************************************************
1319 // nsGlobalWindowInner::nsISupports
1320 //*****************************************************************************
1322 // QueryInterface implementation for nsGlobalWindowInner
1323 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowInner
)
1324 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1325 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, EventTarget
)
1326 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow
)
1327 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject
)
1328 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject
)
1329 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal
)
1330 NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget
)
1331 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowInner
)
1332 NS_INTERFACE_MAP_ENTRY(mozIDOMWindow
)
1333 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
1334 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
1335 NS_INTERFACE_MAP_END
1337 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowInner
)
1338 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowInner
)
1340 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowInner
)
1341 if (tmp
->IsBlackForCC(false)) {
1342 if (nsCCUncollectableMarker::InGeneration(tmp
->mCanSkipCCGeneration
)) {
1345 tmp
->mCanSkipCCGeneration
= nsCCUncollectableMarker::sGeneration
;
1346 if (EventListenerManager
* elm
= tmp
->GetExistingListenerManager()) {
1349 if (tmp
->mTimeoutManager
) {
1350 tmp
->mTimeoutManager
->UnmarkGrayTimers();
1354 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1356 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowInner
)
1357 return tmp
->IsBlackForCC(true);
1358 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1360 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowInner
)
1361 return tmp
->IsBlackForCC(false);
1362 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1364 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowInner
)
1366 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner
)
1367 if (MOZ_UNLIKELY(cb
.WantDebugInfo())) {
1370 if (tmp
->mDoc
&& tmp
->mDoc
->GetDocumentURI()) {
1371 uri
= tmp
->mDoc
->GetDocumentURI()->GetSpecOrDefault();
1373 SprintfLiteral(name
, "nsGlobalWindowInner # %" PRIu64
" inner %s",
1374 tmp
->mWindowID
, uri
.get());
1375 cb
.DescribeRefCountedNode(tmp
->mRefCnt
.get(), name
);
1377 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowInner
, tmp
->mRefCnt
.get())
1380 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator
)
1382 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance
)
1384 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler
)
1386 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrustedTypePolicyFactory
)
1388 #ifdef MOZ_WEBSPEECH
1389 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis
)
1392 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlean
)
1393 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGleanPings
)
1395 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow
)
1397 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopInnerWindow
)
1399 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager
)
1401 if (tmp
->mTimeoutManager
) {
1402 tmp
->mTimeoutManager
->ForEachUnorderedTimeout([&cb
](Timeout
* timeout
) {
1403 cb
.NoteNativeChild(timeout
, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout
));
1407 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation
)
1408 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory
)
1409 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements
)
1410 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorkers
)
1411 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage
)
1412 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage
)
1413 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB
)
1414 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal
)
1415 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCookiePrincipal
)
1416 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal
)
1417 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal
)
1418 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCsp
)
1419 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild
)
1420 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc
)
1422 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor
)
1423 for (IdleRequest
* request
: tmp
->mIdleRequestCallbacks
) {
1424 cb
.NoteNativeChild(request
, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest
));
1427 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClientSource
)
1429 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads
)
1431 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage
)
1432 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays
)
1434 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager
)
1436 // Traverse stuff from nsPIDOMWindow
1437 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler
)
1438 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget
)
1439 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedElement
)
1440 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext
)
1441 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobalChild
)
1443 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar
)
1444 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar
)
1445 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar
)
1446 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar
)
1447 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar
)
1448 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars
)
1449 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto
)
1450 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole
)
1451 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet
)
1452 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal
)
1453 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInstallTrigger
)
1454 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils
)
1455 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVisualViewport
)
1456 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPasteDataTransfer
)
1458 tmp
->TraverseObjectsInGlobal(cb
);
1460 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields
.mMessageManager
)
1461 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields
.mGroupMessageManagers
)
1463 for (size_t i
= 0; i
< tmp
->mDocumentFlushedResolvers
.Length(); i
++) {
1464 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers
[i
]->mPromise
);
1465 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers
[i
]->mCallback
);
1468 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1470 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner
)
1471 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
1472 if (sInnerWindowsById
) {
1473 sInnerWindowsById
->Remove(tmp
->mWindowID
);
1476 JSObject
* wrapper
= tmp
->GetWrapperPreserveColor();
1478 // Mark our realm as dead, so the JS engine won't hand out our
1479 // global after this point.
1480 JS::SetRealmNonLive(js::GetNonCCWObjectRealm(wrapper
));
1483 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator
)
1485 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance
)
1487 if (tmp
->mWebTaskScheduler
) {
1488 tmp
->mWebTaskScheduler
->Disconnect();
1489 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler
)
1492 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrustedTypePolicyFactory
)
1494 #ifdef MOZ_WEBSPEECH
1495 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis
)
1498 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlean
)
1499 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGleanPings
)
1501 if (tmp
->mOuterWindow
) {
1502 nsGlobalWindowOuter::Cast(tmp
->mOuterWindow
)->MaybeClearInnerWindow(tmp
);
1503 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow
)
1506 if (tmp
->mListenerManager
) {
1507 tmp
->mListenerManager
->Disconnect();
1508 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager
)
1511 // Here the Timeouts list would've been unlinked, but we rely on
1512 // that Timeout objects have been traced and will remove themselves
1515 tmp
->UpdateTopInnerWindow();
1516 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow
)
1518 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation
)
1519 NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory
)
1520 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements
)
1521 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharedWorkers
)
1522 if (tmp
->mLocalStorage
) {
1523 tmp
->mLocalStorage
->Disconnect();
1524 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage
)
1526 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage
)
1527 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB
)
1528 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal
)
1529 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCookiePrincipal
)
1530 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal
)
1531 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal
)
1532 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCsp
)
1533 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild
)
1534 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc
)
1536 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads
)
1538 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage
)
1539 NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays
)
1541 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager
)
1543 // Unlink stuff from nsPIDOMWindow
1544 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler
)
1545 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget
)
1546 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedElement
)
1547 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext
)
1549 MOZ_DIAGNOSTIC_ASSERT(
1550 !tmp
->mWindowGlobalChild
|| tmp
->mWindowGlobalChild
->IsClosed(),
1551 "How are we unlinking a window before its actor has been destroyed?");
1552 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowGlobalChild
)
1554 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar
)
1555 NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar
)
1556 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar
)
1557 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar
)
1558 NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar
)
1559 NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars
)
1560 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto
)
1561 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole
)
1562 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet
)
1563 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal
)
1564 NS_IMPL_CYCLE_COLLECTION_UNLINK(mInstallTrigger
)
1565 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils
)
1566 NS_IMPL_CYCLE_COLLECTION_UNLINK(mVisualViewport
)
1567 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCurrentPasteDataTransfer
)
1569 tmp
->UnlinkObjectsInGlobal();
1571 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor
)
1573 // Here the IdleRequest list would've been unlinked, but we rely on
1574 // that IdleRequest objects have been traced and will remove
1575 // themselves while unlinking.
1577 NS_IMPL_CYCLE_COLLECTION_UNLINK(mClientSource
)
1579 if (tmp
->IsChromeWindow()) {
1580 if (tmp
->mChromeFields
.mMessageManager
) {
1581 static_cast<nsFrameMessageManager
*>(
1582 tmp
->mChromeFields
.mMessageManager
.get())
1584 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields
.mMessageManager
)
1586 tmp
->DisconnectAndClearGroupMessageManagers();
1587 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields
.mGroupMessageManagers
)
1590 for (size_t i
= 0; i
< tmp
->mDocumentFlushedResolvers
.Length(); i
++) {
1591 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers
[i
]->mPromise
);
1592 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers
[i
]->mCallback
);
1594 tmp
->mDocumentFlushedResolvers
.Clear();
1596 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1597 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1600 void nsGlobalWindowInner::RiskyUnlink() {
1601 NS_CYCLE_COLLECTION_INNERNAME
.Unlink(this);
1605 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowInner
)
1606 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
1607 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1609 bool nsGlobalWindowInner::IsBlackForCC(bool aTracingNeeded
) {
1610 if (!nsCCUncollectableMarker::sGeneration
) {
1614 return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
1615 HasKnownLiveWrapper()) &&
1616 (!aTracingNeeded
|| HasNothingToTrace(ToSupports(this)));
1619 //*****************************************************************************
1620 // nsGlobalWindowInner::nsIScriptGlobalObject
1621 //*****************************************************************************
1623 bool nsGlobalWindowInner::ShouldResistFingerprinting(RFPTarget aTarget
) const {
1625 return mDoc
->ShouldResistFingerprinting(aTarget
);
1627 return nsContentUtils::ShouldResistFingerprinting(
1628 "If we do not have a document then we do not have any context"
1629 "to make an informed RFP choice, so we fall back to the global pref",
1633 OriginTrials
nsGlobalWindowInner::Trials() const {
1634 return OriginTrials::FromWindow(this);
1637 FontFaceSet
* nsGlobalWindowInner::GetFonts() {
1639 return mDoc
->Fonts();
1644 mozilla::Result
<mozilla::ipc::PrincipalInfo
, nsresult
>
1645 nsGlobalWindowInner::GetStorageKey() {
1646 MOZ_ASSERT(NS_IsMainThread());
1648 nsIPrincipal
* principal
= GetEffectiveStoragePrincipal();
1650 return mozilla::Err(NS_ERROR_FAILURE
);
1653 mozilla::ipc::PrincipalInfo principalInfo
;
1654 nsresult rv
= PrincipalToPrincipalInfo(principal
, &principalInfo
);
1655 if (NS_FAILED(rv
)) {
1656 return mozilla::Err(rv
);
1659 // Block expanded and null principals, let content and system through.
1660 if (principalInfo
.type() !=
1661 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo
&&
1662 principalInfo
.type() !=
1663 mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo
) {
1664 return Err(NS_ERROR_DOM_SECURITY_ERR
);
1667 return std::move(principalInfo
);
1670 mozilla::dom::StorageManager
* nsGlobalWindowInner::GetStorageManager() {
1671 return Navigator()->Storage();
1674 // https://html.spec.whatwg.org/multipage/web-messaging.html#eligible-for-messaging
1675 // * a Window object whose associated Document is fully active
1676 bool nsGlobalWindowInner::IsEligibleForMessaging() { return IsFullyActive(); }
1678 nsresult
nsGlobalWindowInner::EnsureScriptEnvironment() {
1679 // NOTE: We can't use FORWARD_TO_OUTER here because we don't want to fail if
1680 // we're called on an inactive inner window.
1681 nsGlobalWindowOuter
* outer
= GetOuterWindowInternal();
1683 NS_WARNING("No outer window available!");
1684 return NS_ERROR_FAILURE
;
1686 return outer
->EnsureScriptEnvironment();
1689 nsIScriptContext
* nsGlobalWindowInner::GetScriptContext() {
1690 nsGlobalWindowOuter
* outer
= GetOuterWindowInternal();
1694 return outer
->GetScriptContext();
1697 void nsGlobalWindowInner::TraceGlobalJSObject(JSTracer
* aTrc
) {
1698 TraceWrapper(aTrc
, "active window global");
1701 void nsGlobalWindowInner::UpdateAutoplayPermission() {
1702 if (!GetWindowContext()) {
1706 media::AutoplayPolicy::GetSiteAutoplayPermission(GetPrincipal());
1707 if (GetWindowContext()->GetAutoplayPermission() == perm
) {
1711 // Setting autoplay permission on a discarded context has no effect.
1712 Unused
<< GetWindowContext()->SetAutoplayPermission(perm
);
1715 void nsGlobalWindowInner::UpdateShortcutsPermission() {
1716 if (!GetWindowContext() ||
1717 !GetWindowContext()->GetBrowsingContext()->IsTop()) {
1718 // We only cache the shortcuts permission on top-level WindowContexts
1719 // since we always check the top-level principal for the permission.
1723 uint32_t perm
= GetShortcutsPermission(GetPrincipal());
1725 if (GetWindowContext()->GetShortcutsPermission() == perm
) {
1729 // If the WindowContext is discarded this has no effect.
1730 Unused
<< GetWindowContext()->SetShortcutsPermission(perm
);
1734 uint32_t nsGlobalWindowInner::GetShortcutsPermission(nsIPrincipal
* aPrincipal
) {
1735 uint32_t perm
= nsIPermissionManager::DENY_ACTION
;
1736 nsCOMPtr
<nsIPermissionManager
> permMgr
=
1737 mozilla::components::PermissionManager::Service();
1738 if (aPrincipal
&& permMgr
) {
1739 permMgr
->TestExactPermissionFromPrincipal(aPrincipal
, "shortcuts"_ns
,
1745 void nsGlobalWindowInner::UpdatePopupPermission() {
1746 if (!GetWindowContext()) {
1750 uint32_t perm
= PopupBlocker::GetPopupPermission(GetPrincipal());
1751 if (GetWindowContext()->GetPopupPermission() == perm
) {
1755 // If the WindowContext is discarded this has no effect.
1756 Unused
<< GetWindowContext()->SetPopupPermission(perm
);
1759 void nsGlobalWindowInner::UpdatePermissions() {
1760 if (!GetWindowContext()) {
1764 nsCOMPtr
<nsIPrincipal
> principal
= GetPrincipal();
1765 RefPtr
<WindowContext
> windowContext
= GetWindowContext();
1767 WindowContext::Transaction txn
;
1768 txn
.SetAutoplayPermission(
1769 media::AutoplayPolicy::GetSiteAutoplayPermission(principal
));
1770 txn
.SetPopupPermission(PopupBlocker::GetPopupPermission(principal
));
1772 if (windowContext
->IsTop()) {
1773 txn
.SetShortcutsPermission(GetShortcutsPermission(principal
));
1776 // Setting permissions on a discarded WindowContext has no effect
1777 Unused
<< txn
.Commit(windowContext
);
1780 void nsGlobalWindowInner::InitDocumentDependentState(JSContext
* aCx
) {
1783 if (MOZ_LOG_TEST(gDOMLeakPRLogInner
, LogLevel::Debug
)) {
1784 nsIURI
* uri
= mDoc
->GetDocumentURI();
1785 MOZ_LOG(gDOMLeakPRLogInner
, LogLevel::Debug
,
1786 ("DOMWINDOW %p SetNewDocument %s", this,
1787 uri
? uri
->GetSpecOrDefault().get() : ""));
1790 mFocusedElement
= nullptr;
1791 mLocalStorage
= nullptr;
1792 mSessionStorage
= nullptr;
1793 mPerformance
= nullptr;
1794 if (mWebTaskScheduler
) {
1795 mWebTaskScheduler
->Disconnect();
1796 mWebTaskScheduler
= nullptr;
1799 // This must be called after nullifying the internal objects because here we
1800 // could recreate them, calling the getter methods, and store them into the JS
1801 // slots. If we nullify them after, the slot values and the objects will be
1803 ClearDocumentDependentSlots(aCx
);
1805 if (!mWindowGlobalChild
) {
1806 mWindowGlobalChild
= WindowGlobalChild::Create(this);
1808 MOZ_ASSERT(!GetWindowContext()->HasBeenUserGestureActivated(),
1809 "WindowContext should always not have user gesture activation at "
1812 UpdatePermissions();
1814 RefPtr
<PermissionDelegateHandler
> permDelegateHandler
=
1815 mDoc
->GetPermissionDelegateHandler();
1817 if (permDelegateHandler
) {
1818 permDelegateHandler
->PopulateAllDelegatedPermissions();
1821 #if defined(MOZ_WIDGET_ANDROID)
1822 // When we insert the new document to the window in the top-level browsing
1823 // context, we should reset the status of the request which is used for the
1824 // previous document.
1825 if (mWindowGlobalChild
&& GetBrowsingContext() &&
1826 !GetBrowsingContext()->GetParent()) {
1827 // Return value of setting synced field should be checked. See bug 1656492.
1828 Unused
<< GetBrowsingContext()->ResetGVAutoplayRequestStatus();
1833 mLastOpenedURI
= mDoc
->GetDocumentURI();
1836 Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS
,
1837 mMutationBits
? 1 : 0);
1839 // Clear our mutation bitfield.
1843 nsresult
nsGlobalWindowInner::EnsureClientSource() {
1844 MOZ_DIAGNOSTIC_ASSERT(mDoc
);
1846 bool newClientSource
= false;
1848 // Get the load info for the document if we performed a load. Be careful not
1849 // to look at local URLs, though. Local URLs are those that have a scheme of:
1853 // We also do an additional check here so that we only treat about:blank
1854 // and about:srcdoc as local URLs. Other internal firefox about: URLs should
1855 // not be treated this way.
1856 nsCOMPtr
<nsILoadInfo
> loadInfo
;
1857 nsCOMPtr
<nsIChannel
> channel
= mDoc
->GetChannel();
1859 nsCOMPtr
<nsIURI
> uri
;
1860 Unused
<< channel
->GetURI(getter_AddRefs(uri
));
1862 bool ignoreLoadInfo
= false;
1864 // Note, this is mostly copied from NS_IsAboutBlank(). Its duplicated
1865 // here so we can efficiently check about:srcdoc as well.
1866 if (uri
->SchemeIs("about")) {
1867 nsCString spec
= uri
->GetSpecOrDefault();
1868 ignoreLoadInfo
= spec
.EqualsLiteral("about:blank") ||
1869 spec
.EqualsLiteral("about:srcdoc");
1871 // Its not an about: URL, so now check for our other URL types.
1872 ignoreLoadInfo
= uri
->SchemeIs("data") || uri
->SchemeIs("blob");
1875 if (!ignoreLoadInfo
) {
1876 loadInfo
= channel
->LoadInfo();
1880 // Take the initial client source from the docshell immediately. Even if we
1881 // don't end up using it here we should consume it.
1882 UniquePtr
<ClientSource
> initialClientSource
;
1883 nsIDocShell
* docshell
= GetDocShell();
1885 initialClientSource
= docshell
->TakeInitialClientSource();
1888 // Try to get the reserved client from the LoadInfo. A Client is
1889 // reserved at the start of the channel load if there is not an
1890 // initial about:blank document that will be reused. It is also
1891 // created if the channel load encounters a cross-origin redirect.
1893 UniquePtr
<ClientSource
> reservedClient
=
1894 loadInfo
->TakeReservedClientSource();
1895 if (reservedClient
) {
1896 mClientSource
.reset();
1897 mClientSource
= std::move(reservedClient
);
1898 newClientSource
= true;
1902 // We don't have a LoadInfo reserved client, but maybe we should
1903 // be inheriting an initial one from the docshell. This means
1904 // that the docshell started the channel load before creating the
1905 // initial about:blank document. This is an optimization, though,
1906 // and it created an initial Client as a placeholder for the document.
1907 // In this case we want to inherit this placeholder Client here.
1908 if (!mClientSource
) {
1909 mClientSource
= std::move(initialClientSource
);
1910 if (mClientSource
) {
1911 newClientSource
= true;
1915 nsCOMPtr
<nsIPrincipal
> foreignPartitionedPrincipal
;
1917 nsresult rv
= StoragePrincipalHelper::GetPrincipal(
1919 StaticPrefs::privacy_partition_serviceWorkers()
1920 ? StoragePrincipalHelper::eForeignPartitionedPrincipal
1921 : StoragePrincipalHelper::eRegularPrincipal
,
1922 getter_AddRefs(foreignPartitionedPrincipal
));
1923 NS_ENSURE_SUCCESS(rv
, rv
);
1925 // Verify the final ClientSource principal matches the final document
1926 // principal. The ClientChannelHelper handles things like network
1927 // redirects, but there are other ways the document principal can change.
1928 // For example, if something sets the nsIChannel.owner property, then
1929 // the final channel principal can be anything. Unfortunately there is
1930 // no good way to detect this until after the channel completes loading.
1932 // For now we handle this just by reseting the ClientSource. This will
1933 // result in a new ClientSource with the correct principal being created.
1934 // To APIs like ServiceWorker and Clients API it will look like there was
1935 // an initial content page created that was then immediately replaced.
1936 // This is pretty close to what we are actually doing.
1937 if (mClientSource
) {
1938 auto principalOrErr
= mClientSource
->Info().GetPrincipal();
1939 nsCOMPtr
<nsIPrincipal
> clientPrincipal
=
1940 principalOrErr
.isOk() ? principalOrErr
.unwrap() : nullptr;
1941 if (!clientPrincipal
||
1942 !clientPrincipal
->Equals(foreignPartitionedPrincipal
)) {
1943 mClientSource
.reset();
1947 // If we don't have a reserved client or an initial client, then create
1948 // one now. This can happen in certain cases where we avoid preallocating
1949 // the client in the docshell. This mainly occurs in situations where
1950 // the principal is not clearly inherited from the parent; e.g. sandboxed
1951 // iframes, window.open(), etc.
1953 // We also do this late ClientSource creation if the final document ended
1954 // up with a different principal.
1956 // TODO: We may not be marking initial about:blank documents created
1957 // this way as controlled by a service worker properly. The
1958 // controller should be coming from the same place as the inheritted
1959 // principal. We do this in docshell, but as mentioned we aren't
1960 // smart enough to handle all cases yet. For example, a
1961 // window.open() with new URL should inherit the controller from
1962 // the opener, but we probably don't handle that yet.
1963 if (!mClientSource
) {
1964 mClientSource
= ClientManager::CreateSource(
1965 ClientType::Window
, SerialEventTarget(), foreignPartitionedPrincipal
);
1966 MOZ_DIAGNOSTIC_ASSERT(mClientSource
);
1967 newClientSource
= true;
1969 // Note, we don't apply the loadinfo controller below if we create
1970 // the ClientSource here.
1973 // The load may have started controlling the Client as well. If
1974 // so, mark it as controlled immediately here. The actor may
1975 // or may not have been notified by the parent side about being
1978 // Note: We should be careful not to control a client that was created late.
1979 // These clients were not seen by the ServiceWorkerManager when it
1980 // marked the LoadInfo controlled and it won't know about them. Its
1981 // also possible we are creating the client late due to the final
1982 // principal changing and these clients should definitely not be
1983 // controlled by a service worker with a different principal.
1984 else if (loadInfo
) {
1985 const Maybe
<ServiceWorkerDescriptor
> controller
= loadInfo
->GetController();
1986 if (controller
.isSome()) {
1987 mClientSource
->SetController(controller
.ref());
1990 // We also have to handle the case where te initial about:blank is
1991 // controlled due to inheritting the service worker from its parent,
1992 // but the actual nsIChannel load is not covered by any service worker.
1993 // In this case we want the final page to be uncontrolled. There is
1994 // an open spec issue about how exactly this should be handled, but for
1995 // now we just force creation of a new ClientSource to clear the
1998 // https://github.com/w3c/ServiceWorker/issues/1232
2000 else if (mClientSource
->GetController().isSome()) {
2001 mClientSource
.reset();
2002 mClientSource
= ClientManager::CreateSource(
2003 ClientType::Window
, SerialEventTarget(), foreignPartitionedPrincipal
);
2004 MOZ_DIAGNOSTIC_ASSERT(mClientSource
);
2005 newClientSource
= true;
2009 if (mClientSource
) {
2010 // Generally the CSP is stored within the Client and cached on the document.
2011 // At the time of CSP parsing however, the Client has not been created yet,
2012 // hence we store the CSP on the document and propagate/sync the CSP with
2013 // Client here when we create the Client.
2014 mClientSource
->SetCsp(mDoc
->GetCsp());
2016 DocGroup
* docGroup
= GetDocGroup();
2017 MOZ_DIAGNOSTIC_ASSERT(docGroup
);
2018 mClientSource
->SetAgentClusterId(docGroup
->AgentClusterId());
2020 if (mWindowGlobalChild
) {
2021 mWindowGlobalChild
->SendSetClientInfo(mClientSource
->Info().ToIPC());
2025 // Its possible that we got a client just after being frozen in
2026 // the bfcache. In that case freeze the client immediately.
2027 if (newClientSource
&& IsFrozen()) {
2028 mClientSource
->Freeze();
2034 nsresult
nsGlobalWindowInner::ExecutionReady() {
2035 nsresult rv
= EnsureClientSource();
2036 NS_ENSURE_SUCCESS(rv
, rv
);
2038 rv
= mClientSource
->WindowExecutionReady(this);
2039 NS_ENSURE_SUCCESS(rv
, rv
);
2044 void nsGlobalWindowInner::UpdateParentTarget() {
2045 // NOTE: This method is identical to
2046 // nsGlobalWindowOuter::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
2047 // UPDATE THE OTHER ONE TOO!
2049 // Try to get our frame element's tab child global (its in-process message
2050 // manager). If that fails, fall back to the chrome event handler's tab
2051 // child global, and if it doesn't have one, just use the chrome event
2054 nsPIDOMWindowOuter
* outer
= GetOuterWindow();
2058 nsCOMPtr
<Element
> frameElement
= outer
->GetFrameElementInternal();
2059 nsCOMPtr
<EventTarget
> eventTarget
=
2060 nsContentUtils::TryGetBrowserChildGlobal(frameElement
);
2063 nsGlobalWindowOuter
* topWin
= GetInProcessScriptableTopInternal();
2065 frameElement
= topWin
->GetFrameElementInternal();
2066 eventTarget
= nsContentUtils::TryGetBrowserChildGlobal(frameElement
);
2071 eventTarget
= nsContentUtils::TryGetBrowserChildGlobal(mChromeEventHandler
);
2075 eventTarget
= mChromeEventHandler
;
2078 mParentTarget
= eventTarget
;
2081 EventTarget
* nsGlobalWindowInner::GetTargetForDOMEvent() {
2082 return GetOuterWindowInternal();
2085 void nsGlobalWindowInner::GetEventTargetParent(EventChainPreVisitor
& aVisitor
) {
2086 EventMessage msg
= aVisitor
.mEvent
->mMessage
;
2088 aVisitor
.mCanHandle
= true;
2089 aVisitor
.mForceContentDispatch
= true; // FIXME! Bug 329119
2090 if (msg
== eResize
&& aVisitor
.mEvent
->IsTrusted()) {
2091 // Checking whether the event target is an inner window or not, so we can
2092 // keep the old behavior also in case a child window is handling resize.
2093 if (aVisitor
.mEvent
->mOriginalTarget
&&
2094 aVisitor
.mEvent
->mOriginalTarget
->IsInnerWindow()) {
2095 mIsHandlingResizeEvent
= true;
2097 } else if (msg
== eMouseDown
&& aVisitor
.mEvent
->IsTrusted()) {
2099 } else if ((msg
== eMouseUp
|| msg
== eDragEnd
) &&
2100 aVisitor
.mEvent
->IsTrusted()) {
2102 if (sDragServiceDisabled
) {
2103 nsCOMPtr
<nsIDragService
> ds
=
2104 do_GetService("@mozilla.org/widget/dragservice;1");
2106 sDragServiceDisabled
= false;
2112 aVisitor
.SetParentTarget(GetParentTarget(), true);
2115 void nsGlobalWindowInner::FireFrameLoadEvent() {
2116 // If we're not in a content frame, or are at a BrowsingContext tree boundary,
2117 // such as the content-chrome boundary, don't fire the "load" event.
2118 if (GetBrowsingContext()->IsTopContent() ||
2119 GetBrowsingContext()->IsChrome()) {
2123 // If embedder is same-process, fire the event on our embedder element.
2125 // XXX: Bug 1440212 is looking into potentially changing this behaviour to act
2126 // more like the remote case when in-process.
2127 RefPtr
<Element
> element
= GetBrowsingContext()->GetEmbedderElement();
2129 nsEventStatus status
= nsEventStatus_eIgnore
;
2130 WidgetEvent
event(/* aIsTrusted = */ true, eLoad
);
2131 event
.mFlags
.mBubbles
= false;
2132 event
.mFlags
.mCancelable
= false;
2134 // Most of the time we could get a pres context to pass in here, but not
2135 // always (i.e. if this window is not shown there won't be a pres context
2136 // available). Since we're not firing a GUI event we don't need a pres
2137 // context anyway so we just pass null as the pres context all the time.
2138 EventDispatcher::Dispatch(element
, nullptr, &event
, nullptr, &status
);
2142 // We don't have an in-process embedder. Try to get our `BrowserChild` actor
2143 // to send a message to that embedder. We want to double-check that our outer
2144 // window is actually the one at the root of this browserChild though, just in
2146 RefPtr
<BrowserChild
> browserChild
=
2147 BrowserChild::GetFrom(static_cast<nsPIDOMWindowInner
*>(this));
2149 !GetBrowsingContext()->GetParentWindowContext()->IsInProcess()) {
2150 // Double-check that our outer window is actually at the root of this
2151 // `BrowserChild`, in case we're in an odd maybe-unhosted situation like a
2152 // print preview dialog.
2153 nsCOMPtr
<nsPIDOMWindowOuter
> rootOuter
=
2154 do_GetInterface(browserChild
->WebNavigation());
2155 if (!rootOuter
|| rootOuter
!= GetOuterWindow()) {
2159 mozilla::Unused
<< browserChild
->SendMaybeFireEmbedderLoadEvents(
2160 EmbedderElementEventType::LoadEvent
);
2164 nsresult
nsGlobalWindowInner::PostHandleEvent(EventChainPostVisitor
& aVisitor
) {
2165 // Return early if there is nothing to do.
2166 switch (aVisitor
.mEvent
->mMessage
) {
2175 /* mChromeEventHandler and mContext go dangling in the middle of this
2176 function under some circumstances (events that destroy the window)
2177 without this addref. */
2178 RefPtr
<EventTarget
> kungFuDeathGrip1(mChromeEventHandler
);
2180 << kungFuDeathGrip1
; // These aren't referred to through the function
2181 nsCOMPtr
<nsIScriptContext
> kungFuDeathGrip2(GetContextInternal());
2183 << kungFuDeathGrip2
; // These aren't referred to through the function
2185 if (aVisitor
.mEvent
->mMessage
== eResize
) {
2186 mIsHandlingResizeEvent
= false;
2187 } else if (aVisitor
.mEvent
->mMessage
== eUnload
&&
2188 aVisitor
.mEvent
->IsTrusted()) {
2189 // If any VR display presentation is active at unload, the next page
2190 // will receive a vrdisplayactive event to indicate that it should
2191 // immediately begin vr presentation. This should occur when navigating
2192 // forwards, navigating backwards, and on page reload.
2193 for (const auto& display
: mVRDisplays
) {
2194 if (display
->IsPresenting()) {
2195 display
->StartVRNavigation();
2196 // Save this VR display ID to trigger vrdisplayactivate event
2197 // after the next load event.
2198 nsGlobalWindowOuter
* outer
= GetOuterWindowInternal();
2200 outer
->SetAutoActivateVRDisplayID(display
->DisplayId());
2203 // XXX The WebVR 1.1 spec does not define which of multiple VR
2204 // presenting VR displays will be chosen during navigation.
2205 // As the underlying platform VR API's currently only allow a single
2206 // VR display, it is safe to choose the first VR display for now.
2210 mIsDocumentLoaded
= false;
2211 // Tell the parent process that the document is not loaded.
2212 if (mWindowGlobalChild
) {
2213 mWindowGlobalChild
->SendUpdateDocumentHasLoaded(mIsDocumentLoaded
);
2215 } else if (aVisitor
.mEvent
->mMessage
== eLoad
&&
2216 aVisitor
.mEvent
->IsTrusted()) {
2217 // This is page load event since load events don't propagate to |window|.
2218 // @see Document::GetEventTargetParent.
2219 mIsDocumentLoaded
= true;
2220 // Tell the parent process that the document is loaded.
2221 if (mWindowGlobalChild
) {
2222 mWindowGlobalChild
->SendUpdateDocumentHasLoaded(mIsDocumentLoaded
);
2225 mTimeoutManager
->OnDocumentLoaded();
2227 MOZ_ASSERT(aVisitor
.mEvent
->IsTrusted());
2228 FireFrameLoadEvent();
2230 if (mVREventObserver
) {
2231 mVREventObserver
->NotifyAfterLoad();
2234 uint32_t autoActivateVRDisplayID
= 0;
2235 nsGlobalWindowOuter
* outer
= GetOuterWindowInternal();
2237 autoActivateVRDisplayID
= outer
->GetAutoActivateVRDisplayID();
2239 if (autoActivateVRDisplayID
) {
2240 DispatchVRDisplayActivate(autoActivateVRDisplayID
,
2241 VRDisplayEventReason::Navigation
);
2248 nsresult
nsGlobalWindowInner::DefineArgumentsProperty(nsIArray
* aArguments
) {
2249 nsIScriptContext
* ctx
= GetOuterWindowInternal()->mContext
;
2250 NS_ENSURE_TRUE(aArguments
&& ctx
, NS_ERROR_NOT_INITIALIZED
);
2252 JS::Rooted
<JSObject
*> obj(RootingCx(), GetWrapperPreserveColor());
2253 return ctx
->SetProperty(obj
, "arguments", aArguments
);
2256 //*****************************************************************************
2257 // nsGlobalWindowInner::nsIScriptObjectPrincipal
2258 //*****************************************************************************
2260 nsIPrincipal
* nsGlobalWindowInner::GetPrincipal() {
2262 // If we have a document, get the principal from the document
2263 return mDoc
->NodePrincipal();
2266 if (mDocumentPrincipal
) {
2267 return mDocumentPrincipal
;
2270 // If we don't have a principal and we don't have a document we
2271 // ask the parent window for the principal. This can happen when
2272 // loading a frameset that has a <frame src="javascript:xxx">, in
2273 // that case the global window is used in JS before we've loaded
2274 // a document into the window.
2276 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
2277 do_QueryInterface(GetInProcessParentInternal());
2280 return objPrincipal
->GetPrincipal();
2286 nsIPrincipal
* nsGlobalWindowInner::GetEffectiveCookiePrincipal() {
2288 // If we have a document, get the principal from the document
2289 return mDoc
->EffectiveCookiePrincipal();
2292 if (mDocumentCookiePrincipal
) {
2293 return mDocumentCookiePrincipal
;
2296 // If we don't have a cookie principal and we don't have a document we ask
2297 // the parent window for the cookie principal.
2299 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
2300 do_QueryInterface(GetInProcessParentInternal());
2303 return objPrincipal
->GetEffectiveCookiePrincipal();
2309 nsIPrincipal
* nsGlobalWindowInner::GetEffectiveStoragePrincipal() {
2311 // If we have a document, get the principal from the document
2312 return mDoc
->EffectiveStoragePrincipal();
2315 if (mDocumentStoragePrincipal
) {
2316 return mDocumentStoragePrincipal
;
2319 // If we don't have a cookie principal and we don't have a document we ask
2320 // the parent window for the cookie principal.
2322 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
2323 do_QueryInterface(GetInProcessParentInternal());
2326 return objPrincipal
->GetEffectiveStoragePrincipal();
2332 nsIPrincipal
* nsGlobalWindowInner::PartitionedPrincipal() {
2334 // If we have a document, get the principal from the document
2335 return mDoc
->PartitionedPrincipal();
2338 if (mDocumentPartitionedPrincipal
) {
2339 return mDocumentPartitionedPrincipal
;
2342 // If we don't have a partitioned principal and we don't have a document we
2343 // ask the parent window for the partitioned principal.
2345 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
2346 do_QueryInterface(GetInProcessParentInternal());
2349 return objPrincipal
->PartitionedPrincipal();
2355 //*****************************************************************************
2356 // nsGlobalWindowInner::nsIDOMWindow
2357 //*****************************************************************************
2359 bool nsPIDOMWindowInner::AddAudioContext(AudioContext
* aAudioContext
) {
2360 mAudioContexts
.AppendElement(aAudioContext
);
2362 // Return true if the context should be muted and false if not.
2363 nsIDocShell
* docShell
= GetDocShell();
2364 return docShell
&& !docShell
->GetAllowMedia() && !aAudioContext
->IsOffline();
2367 void nsPIDOMWindowInner::RemoveAudioContext(AudioContext
* aAudioContext
) {
2368 mAudioContexts
.RemoveElement(aAudioContext
);
2371 void nsPIDOMWindowInner::MuteAudioContexts() {
2372 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
2373 if (!mAudioContexts
[i
]->IsOffline()) {
2374 mAudioContexts
[i
]->Mute();
2379 void nsPIDOMWindowInner::UnmuteAudioContexts() {
2380 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
2381 if (!mAudioContexts
[i
]->IsOffline()) {
2382 mAudioContexts
[i
]->Unmute();
2387 WindowProxyHolder
nsGlobalWindowInner::Window() {
2388 return WindowProxyHolder(GetBrowsingContext());
2391 Navigator
* nsPIDOMWindowInner::Navigator() {
2393 mNavigator
= new mozilla::dom::Navigator(this);
2399 MediaDevices
* nsPIDOMWindowInner::GetExtantMediaDevices() const {
2400 return mNavigator
? mNavigator
->GetExtantMediaDevices() : nullptr;
2403 VisualViewport
* nsGlobalWindowInner::VisualViewport() {
2404 if (!mVisualViewport
) {
2405 mVisualViewport
= new mozilla::dom::VisualViewport(this);
2407 return mVisualViewport
;
2410 nsScreen
* nsGlobalWindowInner::Screen() {
2412 mScreen
= new nsScreen(this);
2417 nsHistory
* nsGlobalWindowInner::GetHistory(ErrorResult
& aError
) {
2419 mHistory
= new nsHistory(this);
2424 CustomElementRegistry
* nsGlobalWindowInner::CustomElements() {
2425 if (!mCustomElements
) {
2426 mCustomElements
= new CustomElementRegistry(this);
2429 return mCustomElements
;
2432 CustomElementRegistry
* nsGlobalWindowInner::GetExistingCustomElements() {
2433 return mCustomElements
;
2436 Performance
* nsPIDOMWindowInner::GetPerformance() {
2437 CreatePerformanceObjectIfNeeded();
2438 return mPerformance
;
2441 void nsPIDOMWindowInner::QueuePerformanceNavigationTiming() {
2442 CreatePerformanceObjectIfNeeded();
2444 mPerformance
->QueueNavigationTimingEntry();
2448 void nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded() {
2449 if (mPerformance
|| !mDoc
) {
2452 RefPtr
<nsDOMNavigationTiming
> timing
= mDoc
->GetNavigationTiming();
2453 nsCOMPtr
<nsITimedChannel
> timedChannel(do_QueryInterface(mDoc
->GetChannel()));
2454 bool timingEnabled
= false;
2455 if (!timedChannel
||
2456 !NS_SUCCEEDED(timedChannel
->GetTimingEnabled(&timingEnabled
)) ||
2458 timedChannel
= nullptr;
2461 mPerformance
= Performance::CreateForMainThread(this, mDoc
->NodePrincipal(),
2462 timing
, timedChannel
);
2466 bool nsPIDOMWindowInner::IsSecureContext() const {
2467 return nsGlobalWindowInner::Cast(this)->IsSecureContext();
2470 void nsPIDOMWindowInner::Suspend(bool aIncludeSubWindows
) {
2471 nsGlobalWindowInner::Cast(this)->Suspend(aIncludeSubWindows
);
2474 void nsPIDOMWindowInner::Resume(bool aIncludeSubWindows
) {
2475 nsGlobalWindowInner::Cast(this)->Resume(aIncludeSubWindows
);
2478 void nsPIDOMWindowInner::SyncStateFromParentWindow() {
2479 nsGlobalWindowInner::Cast(this)->SyncStateFromParentWindow();
2482 Maybe
<ClientInfo
> nsPIDOMWindowInner::GetClientInfo() const {
2483 return nsGlobalWindowInner::Cast(this)->GetClientInfo();
2486 Maybe
<ClientState
> nsPIDOMWindowInner::GetClientState() const {
2487 return nsGlobalWindowInner::Cast(this)->GetClientState();
2490 Maybe
<ServiceWorkerDescriptor
> nsPIDOMWindowInner::GetController() const {
2491 return nsGlobalWindowInner::Cast(this)->GetController();
2494 void nsPIDOMWindowInner::SetCsp(nsIContentSecurityPolicy
* aCsp
) {
2495 return nsGlobalWindowInner::Cast(this)->SetCsp(aCsp
);
2498 void nsPIDOMWindowInner::SetPreloadCsp(nsIContentSecurityPolicy
* aPreloadCsp
) {
2499 return nsGlobalWindowInner::Cast(this)->SetPreloadCsp(aPreloadCsp
);
2502 nsIContentSecurityPolicy
* nsPIDOMWindowInner::GetCsp() {
2503 return nsGlobalWindowInner::Cast(this)->GetCsp();
2506 void nsPIDOMWindowInner::NoteCalledRegisterForServiceWorkerScope(
2507 const nsACString
& aScope
) {
2508 nsGlobalWindowInner::Cast(this)->NoteCalledRegisterForServiceWorkerScope(
2512 void nsPIDOMWindowInner::NoteDOMContentLoaded() {
2513 nsGlobalWindowInner::Cast(this)->NoteDOMContentLoaded();
2516 bool nsGlobalWindowInner::ShouldReportForServiceWorkerScope(
2517 const nsAString
& aScope
) {
2518 bool result
= false;
2520 nsPIDOMWindowOuter
* topOuter
= GetInProcessScriptableTop();
2521 NS_ENSURE_TRUE(topOuter
, false);
2523 nsGlobalWindowInner
* topInner
=
2524 nsGlobalWindowInner::Cast(topOuter
->GetCurrentInnerWindow());
2525 NS_ENSURE_TRUE(topInner
, false);
2527 topInner
->ShouldReportForServiceWorkerScopeInternal(
2528 NS_ConvertUTF16toUTF8(aScope
), &result
);
2532 InstallTriggerImpl
* nsGlobalWindowInner::GetInstallTrigger() {
2533 if (!mInstallTrigger
&&
2534 !StaticPrefs::extensions_InstallTriggerImpl_enabled()) {
2535 // Return nullptr when InstallTriggerImpl is disabled by pref,
2536 // which does not yet break the "typeof InstallTrigger !== 'undefined"
2537 // "UA detection" use case, but prevents access to the InstallTriggerImpl
2538 // methods and properties.
2540 // NOTE: a separate pref ("extensions.InstallTrigger.enabled"), associated
2541 // to this property using the [Pref] extended attribute in Window.webidl,
2542 // does instead hide the entire InstallTrigger property.
2544 // See Bug 1754441 for more details about this deprecation.
2547 if (!mInstallTrigger
) {
2549 mInstallTrigger
= ConstructJSImplementation
<InstallTriggerImpl
>(
2550 "@mozilla.org/addons/installtrigger;1", this, rv
);
2552 rv
.SuppressException();
2557 return mInstallTrigger
;
2560 nsIDOMWindowUtils
* nsGlobalWindowInner::GetWindowUtils(ErrorResult
& aRv
) {
2561 FORWARD_TO_OUTER_OR_THROW(WindowUtils
, (), aRv
, nullptr);
2564 CallState
nsGlobalWindowInner::ShouldReportForServiceWorkerScopeInternal(
2565 const nsACString
& aScope
, bool* aResultOut
) {
2566 MOZ_DIAGNOSTIC_ASSERT(aResultOut
);
2568 // First check to see if this window is controlled. If so, then we have
2569 // found a match and are done.
2570 const Maybe
<ServiceWorkerDescriptor
> swd
= GetController();
2571 if (swd
.isSome() && swd
.ref().Scope() == aScope
) {
2573 return CallState::Stop
;
2576 // Next, check to see if this window has called
2577 // navigator.serviceWorker.register() for this scope. If so, then treat this
2578 // as a match so console reports appear in the devtools console.
2579 if (mClientSource
&&
2580 mClientSource
->CalledRegisterForServiceWorkerScope(aScope
)) {
2582 return CallState::Stop
;
2585 // Finally check the current docshell nsILoadGroup to see if there are any
2586 // outstanding navigation requests. If so, match the scope against the
2587 // channel's URL. We want to show console reports during the FetchEvent
2588 // intercepting the navigation itself.
2589 nsCOMPtr
<nsIDocumentLoader
> loader(do_QueryInterface(GetDocShell()));
2591 nsCOMPtr
<nsILoadGroup
> loadgroup
;
2592 Unused
<< loader
->GetLoadGroup(getter_AddRefs(loadgroup
));
2594 nsCOMPtr
<nsISimpleEnumerator
> iter
;
2595 Unused
<< loadgroup
->GetRequests(getter_AddRefs(iter
));
2597 nsCOMPtr
<nsISupports
> tmp
;
2598 bool hasMore
= true;
2599 // Check each network request in the load group.
2600 while (NS_SUCCEEDED(iter
->HasMoreElements(&hasMore
)) && hasMore
) {
2601 iter
->GetNext(getter_AddRefs(tmp
));
2602 nsCOMPtr
<nsIChannel
> loadingChannel(do_QueryInterface(tmp
));
2603 // Ignore subresource requests. Logging for a subresource
2604 // FetchEvent should be handled above since the client is
2605 // already controlled.
2606 if (!loadingChannel
||
2607 !nsContentUtils::IsNonSubresourceRequest(loadingChannel
)) {
2610 nsCOMPtr
<nsIURI
> loadingURL
;
2611 Unused
<< loadingChannel
->GetURI(getter_AddRefs(loadingURL
));
2615 nsAutoCString loadingSpec
;
2616 Unused
<< loadingURL
->GetSpec(loadingSpec
);
2617 // Perform a simple substring comparison to match the scope
2618 // against the channel URL.
2619 if (StringBeginsWith(loadingSpec
, aScope
)) {
2621 return CallState::Stop
;
2628 // The current window doesn't care about this service worker, but maybe
2629 // one of our child frames does.
2630 return CallOnInProcessChildren(
2631 &nsGlobalWindowInner::ShouldReportForServiceWorkerScopeInternal
, aScope
,
2635 void nsGlobalWindowInner::NoteCalledRegisterForServiceWorkerScope(
2636 const nsACString
& aScope
) {
2637 if (!mClientSource
) {
2641 mClientSource
->NoteCalledRegisterForServiceWorkerScope(aScope
);
2644 void nsGlobalWindowInner::NoteDOMContentLoaded() {
2645 if (!mClientSource
) {
2649 mClientSource
->NoteDOMContentLoaded();
2652 void nsGlobalWindowInner::UpdateTopInnerWindow() {
2653 if (IsTopInnerWindow() || !mTopInnerWindow
) {
2657 mTopInnerWindow
->UpdateWebSocketCount(-(int32_t)mNumOfOpenWebSockets
);
2660 bool nsGlobalWindowInner::IsInSyncOperation() {
2661 return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
2664 bool nsGlobalWindowInner::IsSharedMemoryAllowedInternal(
2665 nsIPrincipal
* aPrincipal
) const {
2666 MOZ_ASSERT(NS_IsMainThread());
2669 dom_postMessage_sharedArrayBuffer_bypassCOOP_COEP_insecure_enabled()) {
2673 if (ExtensionPolicyService::GetSingleton().IsExtensionProcess()) {
2674 if (auto* basePrincipal
= BasePrincipal::Cast(aPrincipal
)) {
2675 if (auto* policy
= basePrincipal
->AddonPolicy()) {
2676 return policy
->IsPrivileged();
2681 return CrossOriginIsolated();
2684 bool nsGlobalWindowInner::CrossOriginIsolated() const {
2685 MOZ_ASSERT(NS_IsMainThread());
2687 RefPtr
<BrowsingContext
> bc
= GetBrowsingContext();
2688 MOZ_DIAGNOSTIC_ASSERT(bc
);
2689 return bc
->CrossOriginIsolated();
2692 WindowContext
* TopWindowContext(nsPIDOMWindowInner
& aWindow
) {
2693 WindowContext
* wc
= aWindow
.GetWindowContext();
2698 return wc
->TopWindowContext();
2701 void nsPIDOMWindowInner::AddPeerConnection() {
2702 MOZ_ASSERT(NS_IsMainThread());
2703 ++mActivePeerConnections
;
2704 if (mActivePeerConnections
== 1 && mWindowGlobalChild
) {
2705 mWindowGlobalChild
->SendUpdateActivePeerConnectionStatus(
2708 // We need to present having active peer connections immediately. If we need
2709 // to wait for the parent process to come back with this information we
2710 // might start throttling.
2711 if (WindowContext
* top
= TopWindowContext(*this)) {
2712 top
->TransientSetHasActivePeerConnections();
2717 void nsPIDOMWindowInner::RemovePeerConnection() {
2718 MOZ_ASSERT(NS_IsMainThread());
2719 MOZ_ASSERT(mActivePeerConnections
> 0);
2720 --mActivePeerConnections
;
2721 if (mActivePeerConnections
== 0 && mWindowGlobalChild
) {
2722 mWindowGlobalChild
->SendUpdateActivePeerConnectionStatus(
2723 /*aIsAdded*/ false);
2727 bool nsPIDOMWindowInner::HasActivePeerConnections() {
2728 MOZ_ASSERT(NS_IsMainThread());
2730 WindowContext
* topWindowContext
= TopWindowContext(*this);
2731 return topWindowContext
&& topWindowContext
->GetHasActivePeerConnections();
2734 void nsPIDOMWindowInner::AddMediaKeysInstance(MediaKeys
* aMediaKeys
) {
2735 MOZ_ASSERT(NS_IsMainThread());
2736 mMediaKeysInstances
.AppendElement(aMediaKeys
);
2737 if (mWindowGlobalChild
&& mMediaKeysInstances
.Length() == 1) {
2738 mWindowGlobalChild
->BlockBFCacheFor(BFCacheStatus::CONTAINS_EME_CONTENT
);
2742 void nsPIDOMWindowInner::RemoveMediaKeysInstance(MediaKeys
* aMediaKeys
) {
2743 MOZ_ASSERT(NS_IsMainThread());
2744 mMediaKeysInstances
.RemoveElement(aMediaKeys
);
2745 if (mWindowGlobalChild
&& mMediaKeysInstances
.IsEmpty()) {
2746 mWindowGlobalChild
->UnblockBFCacheFor(BFCacheStatus::CONTAINS_EME_CONTENT
);
2750 bool nsPIDOMWindowInner::HasActiveMediaKeysInstance() {
2751 MOZ_ASSERT(NS_IsMainThread());
2752 return !mMediaKeysInstances
.IsEmpty();
2755 bool nsPIDOMWindowInner::IsPlayingAudio() {
2756 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); i
++) {
2757 if (mAudioContexts
[i
]->IsRunning()) {
2761 RefPtr
<AudioChannelService
> acs
= AudioChannelService::Get();
2765 auto outer
= GetOuterWindow();
2767 // We've been unlinked and are about to die. Not a good time to pretend to
2768 // be playing audio.
2771 return acs
->IsWindowActive(outer
);
2774 bool nsPIDOMWindowInner::IsDocumentLoaded() const { return mIsDocumentLoaded
; }
2776 mozilla::dom::TimeoutManager
& nsPIDOMWindowInner::TimeoutManager() {
2777 return *mTimeoutManager
;
2780 bool nsPIDOMWindowInner::IsRunningTimeout() {
2781 return TimeoutManager().IsRunningTimeout();
2784 void nsPIDOMWindowInner::TryToCacheTopInnerWindow() {
2785 if (mHasTriedToCacheTopInnerWindow
) {
2789 nsGlobalWindowInner
* window
= nsGlobalWindowInner::Cast(this);
2791 MOZ_ASSERT(!window
->IsDying());
2793 mHasTriedToCacheTopInnerWindow
= true;
2797 if (nsCOMPtr
<nsPIDOMWindowOuter
> topOutter
=
2798 window
->GetInProcessScriptableTop()) {
2799 mTopInnerWindow
= topOutter
->GetCurrentInnerWindow();
2803 void nsPIDOMWindowInner::UpdateActiveIndexedDBDatabaseCount(int32_t aDelta
) {
2804 MOZ_ASSERT(NS_IsMainThread());
2810 // We count databases but not transactions because only active databases
2811 // could block throttling.
2812 uint32_t& counter
= mTopInnerWindow
2813 ? mTopInnerWindow
->mNumOfIndexedDBDatabases
2814 : mNumOfIndexedDBDatabases
;
2819 bool nsPIDOMWindowInner::HasActiveIndexedDBDatabases() {
2820 MOZ_ASSERT(NS_IsMainThread());
2822 return mTopInnerWindow
? mTopInnerWindow
->mNumOfIndexedDBDatabases
> 0
2823 : mNumOfIndexedDBDatabases
> 0;
2826 void nsPIDOMWindowInner::UpdateWebSocketCount(int32_t aDelta
) {
2827 MOZ_ASSERT(NS_IsMainThread());
2833 if (mTopInnerWindow
&& !IsTopInnerWindow()) {
2834 mTopInnerWindow
->UpdateWebSocketCount(aDelta
);
2837 MOZ_DIAGNOSTIC_ASSERT(
2838 aDelta
> 0 || ((aDelta
+ mNumOfOpenWebSockets
) < mNumOfOpenWebSockets
));
2840 mNumOfOpenWebSockets
+= aDelta
;
2843 bool nsPIDOMWindowInner::HasOpenWebSockets() const {
2844 MOZ_ASSERT(NS_IsMainThread());
2846 return mNumOfOpenWebSockets
||
2847 (mTopInnerWindow
&& mTopInnerWindow
->mNumOfOpenWebSockets
);
2850 bool nsPIDOMWindowInner::IsCurrentInnerWindow() const {
2851 if (mozilla::SessionHistoryInParent() && mBrowsingContext
&&
2852 mBrowsingContext
->IsInBFCache()) {
2856 if (!mBrowsingContext
|| mBrowsingContext
->IsDiscarded()) {
2857 // If our BrowsingContext has been discarded, we consider ourselves
2858 // still-current if we were current at the time it was discarded.
2859 return mOuterWindow
&& WasCurrentInnerWindow();
2862 nsPIDOMWindowOuter
* outer
= mBrowsingContext
->GetDOMWindow();
2863 return outer
&& outer
->GetCurrentInnerWindow() == this;
2866 bool nsPIDOMWindowInner::IsFullyActive() const {
2867 WindowContext
* wc
= GetWindowContext();
2868 if (!wc
|| wc
->IsDiscarded() || !wc
->IsCurrent()) {
2871 return GetBrowsingContext()->AncestorsAreCurrent();
2874 void nsPIDOMWindowInner::SetAudioCapture(bool aCapture
) {
2875 RefPtr
<AudioChannelService
> service
= AudioChannelService::GetOrCreate();
2877 service
->SetWindowAudioCaptured(GetOuterWindow(), mWindowID
, aCapture
);
2881 void nsGlobalWindowInner::SetActiveLoadingState(bool aIsLoading
) {
2883 gTimeoutLog
, mozilla::LogLevel::Debug
,
2884 ("SetActiveLoadingState innerwindow %p: %d", (void*)this, aIsLoading
));
2885 if (GetBrowsingContext()) {
2886 // Setting loading on a discarded context has no effect.
2887 Unused
<< GetBrowsingContext()->SetLoading(aIsLoading
);
2890 if (!nsGlobalWindowInner::Cast(this)->IsChromeWindow()) {
2891 mTimeoutManager
->SetLoading(aIsLoading
);
2894 HintIsLoading(aIsLoading
);
2897 void nsGlobalWindowInner::HintIsLoading(bool aIsLoading
) {
2898 // Hint to tell the JS GC to use modified triggers during pageload.
2899 if (mHintedWasLoading
!= aIsLoading
) {
2900 using namespace js::gc
;
2901 SetPerformanceHint(danger::GetJSContext(), aIsLoading
2902 ? PerformanceHint::InPageLoad
2903 : PerformanceHint::Normal
);
2904 mHintedWasLoading
= aIsLoading
;
2908 // nsISpeechSynthesisGetter
2910 #ifdef MOZ_WEBSPEECH
2911 SpeechSynthesis
* nsGlobalWindowInner::GetSpeechSynthesis(ErrorResult
& aError
) {
2912 if (!mSpeechSynthesis
) {
2913 mSpeechSynthesis
= new SpeechSynthesis(this);
2916 return mSpeechSynthesis
;
2919 bool nsGlobalWindowInner::HasActiveSpeechSynthesis() {
2920 if (mSpeechSynthesis
) {
2921 return !mSpeechSynthesis
->HasEmptyQueue();
2929 mozilla::glean::Glean
* nsGlobalWindowInner::Glean() {
2931 mGlean
= new mozilla::glean::Glean(this);
2937 mozilla::glean::GleanPings
* nsGlobalWindowInner::GleanPings() {
2939 mGleanPings
= new mozilla::glean::GleanPings();
2945 Nullable
<WindowProxyHolder
> nsGlobalWindowInner::GetParent(
2946 ErrorResult
& aError
) {
2947 FORWARD_TO_OUTER_OR_THROW(GetParentOuter
, (), aError
, nullptr);
2951 * GetInProcessScriptableParent used to be called when a script read
2952 * window.parent. Under Fission, that is now handled by
2953 * BrowsingContext::GetParent, and the result is a WindowProxyHolder rather than
2954 * an actual global window. This method still exists for legacy callers which
2955 * relied on the old logic, and require in-process windows. However, it only
2956 * works correctly when no out-of-process frames exist between this window and
2957 * the top-level window, so it should not be used in new code.
2959 * In contrast to GetRealParent, GetInProcessScriptableParent respects <iframe
2960 * mozbrowser> boundaries, so if |this| is contained by an <iframe
2961 * mozbrowser>, we will return |this| as its own parent.
2963 nsPIDOMWindowOuter
* nsGlobalWindowInner::GetInProcessScriptableParent() {
2964 FORWARD_TO_OUTER(GetInProcessScriptableParent
, (), nullptr);
2968 * GetInProcessScriptableTop used to be called when a script read window.top.
2969 * Under Fission, that is now handled by BrowsingContext::Top, and the result is
2970 * a WindowProxyHolder rather than an actual global window. This method still
2971 * exists for legacy callers which relied on the old logic, and require
2972 * in-process windows. However, it only works correctly when no out-of-process
2973 * frames exist between this window and the top-level window, so it should not
2974 * be used in new code.
2976 * In contrast to GetRealTop, GetInProcessScriptableTop respects <iframe
2977 * mozbrowser> boundaries. If we encounter a window owned by an <iframe
2978 * mozbrowser> while walking up the window hierarchy, we'll stop and return that
2981 nsPIDOMWindowOuter
* nsGlobalWindowInner::GetInProcessScriptableTop() {
2982 FORWARD_TO_OUTER(GetInProcessScriptableTop
, (), nullptr);
2985 void nsGlobalWindowInner::GetContent(JSContext
* aCx
,
2986 JS::MutableHandle
<JSObject
*> aRetval
,
2987 CallerType aCallerType
,
2988 ErrorResult
& aError
) {
2989 FORWARD_TO_OUTER_OR_THROW(GetContentOuter
,
2990 (aCx
, aRetval
, aCallerType
, aError
), aError
, );
2993 BarProp
* nsGlobalWindowInner::GetMenubar(ErrorResult
& aError
) {
2995 mMenubar
= new MenubarProp(this);
3001 BarProp
* nsGlobalWindowInner::GetToolbar(ErrorResult
& aError
) {
3003 mToolbar
= new ToolbarProp(this);
3009 BarProp
* nsGlobalWindowInner::GetLocationbar(ErrorResult
& aError
) {
3010 if (!mLocationbar
) {
3011 mLocationbar
= new LocationbarProp(this);
3013 return mLocationbar
;
3016 BarProp
* nsGlobalWindowInner::GetPersonalbar(ErrorResult
& aError
) {
3017 if (!mPersonalbar
) {
3018 mPersonalbar
= new PersonalbarProp(this);
3020 return mPersonalbar
;
3023 BarProp
* nsGlobalWindowInner::GetStatusbar(ErrorResult
& aError
) {
3025 mStatusbar
= new StatusbarProp(this);
3030 BarProp
* nsGlobalWindowInner::GetScrollbars(ErrorResult
& aError
) {
3032 mScrollbars
= new ScrollbarsProp(this);
3038 bool nsGlobalWindowInner::GetClosed(ErrorResult
& aError
) {
3039 // If we're called from JS (which is the only way we should be getting called
3040 // here) and we reach this point, that means our JS global is the current
3041 // target of the WindowProxy, which means that we are the "current inner"
3042 // of our outer. So if FORWARD_TO_OUTER fails to forward, that means the
3043 // outer is already torn down, which corresponds to the closed state.
3044 FORWARD_TO_OUTER(GetClosedOuter
, (), true);
3047 Nullable
<WindowProxyHolder
> nsGlobalWindowInner::IndexedGetter(
3049 FORWARD_TO_OUTER(IndexedGetterOuter
, (aIndex
), nullptr);
3054 struct InterfaceShimEntry
{
3055 const char* geckoName
;
3056 const char* domName
;
3059 } // anonymous namespace
3061 // We add shims from Components.interfaces.nsIDOMFoo to window.Foo for each
3062 // interface that has interface constants that sites might be getting off
3064 const InterfaceShimEntry kInterfaceShimMap
[] = {
3065 {"nsIXMLHttpRequest", "XMLHttpRequest"},
3066 {"nsIDOMDOMException", "DOMException"},
3067 {"nsIDOMNode", "Node"},
3068 {"nsIDOMCSSRule", "CSSRule"},
3069 {"nsIDOMEvent", "Event"},
3070 {"nsIDOMNSEvent", "Event"},
3071 {"nsIDOMKeyEvent", "KeyEvent"},
3072 {"nsIDOMMouseEvent", "MouseEvent"},
3073 {"nsIDOMMouseScrollEvent", "MouseScrollEvent"},
3074 {"nsIDOMMutationEvent", "MutationEvent"},
3075 {"nsIDOMUIEvent", "UIEvent"},
3076 {"nsIDOMHTMLMediaElement", "HTMLMediaElement"},
3077 {"nsIDOMRange", "Range"},
3078 // Think about whether Ci.nsINodeFilter can just go away for websites!
3079 {"nsIDOMNodeFilter", "NodeFilter"},
3080 {"nsIDOMXPathResult", "XPathResult"}};
3082 bool nsGlobalWindowInner::ResolveComponentsShim(
3083 JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
,
3084 JS::MutableHandle
<mozilla::Maybe
<JS::PropertyDescriptor
>> aDesc
) {
3085 // Keep track of how often this happens.
3086 Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT
, true);
3089 nsCOMPtr
<Document
> doc
= GetExtantDoc();
3091 doc
->WarnOnceAbout(DeprecatedOperations::eComponents
, /* asError = */ true);
3094 // Create a fake Components object.
3095 AssertSameCompartment(aCx
, aGlobal
);
3096 JS::Rooted
<JSObject
*> components(aCx
, JS_NewPlainObject(aCx
));
3097 if (NS_WARN_IF(!components
)) {
3101 // Create a fake interfaces object.
3102 JS::Rooted
<JSObject
*> interfaces(aCx
, JS_NewPlainObject(aCx
));
3103 if (NS_WARN_IF(!interfaces
)) {
3107 JS_DefineProperty(aCx
, components
, "interfaces", interfaces
,
3108 JSPROP_ENUMERATE
| JSPROP_PERMANENT
| JSPROP_READONLY
);
3109 if (NS_WARN_IF(!ok
)) {
3113 // Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM
3114 // interfaces with constants.
3115 for (uint32_t i
= 0; i
< ArrayLength(kInterfaceShimMap
); ++i
) {
3116 // Grab the names from the table.
3117 const char* geckoName
= kInterfaceShimMap
[i
].geckoName
;
3118 const char* domName
= kInterfaceShimMap
[i
].domName
;
3120 // Look up the appopriate interface object on the global.
3121 JS::Rooted
<JS::Value
> v(aCx
, JS::UndefinedValue());
3122 ok
= JS_GetProperty(aCx
, aGlobal
, domName
, &v
);
3123 if (NS_WARN_IF(!ok
)) {
3126 if (!v
.isObject()) {
3127 NS_WARNING("Unable to find interface object on global");
3131 // Define the shim on the interfaces object.
3132 ok
= JS_DefineProperty(
3133 aCx
, interfaces
, geckoName
, v
,
3134 JSPROP_ENUMERATE
| JSPROP_PERMANENT
| JSPROP_READONLY
);
3135 if (NS_WARN_IF(!ok
)) {
3140 aDesc
.set(mozilla::Some(JS::PropertyDescriptor::Data(
3141 JS::ObjectValue(*components
),
3142 {JS::PropertyAttribute::Configurable
, JS::PropertyAttribute::Enumerable
,
3143 JS::PropertyAttribute::Writable
})));
3147 #ifdef RELEASE_OR_BETA
3148 # define USE_CONTROLLERS_SHIM
3151 #ifdef USE_CONTROLLERS_SHIM
3152 static const JSClass ControllersShimClass
= {"Controllers", 0};
3153 static const JSClass XULControllersShimClass
= {"XULControllers", 0};
3156 bool nsGlobalWindowInner::DoResolve(
3157 JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
, JS::Handle
<jsid
> aId
,
3158 JS::MutableHandle
<mozilla::Maybe
<JS::PropertyDescriptor
>> aDesc
) {
3159 // Note: Keep this in sync with MayResolve.
3161 // Note: The infallibleInit call in GlobalResolve depends on this check.
3162 if (!aId
.isString()) {
3167 if (!WebIDLGlobalNameHash::DefineIfEnabled(aCx
, aObj
, aId
, aDesc
, &found
)) {
3175 // We support a cut-down Components.interfaces in case websites are
3176 // using Components.interfaces.nsIFoo.CONSTANT_NAME for the ones
3177 // that have constants.
3178 if (StaticPrefs::dom_use_components_shim() &&
3179 aId
== XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS
)) {
3180 return ResolveComponentsShim(aCx
, aObj
, aDesc
);
3183 // We also support a "window.controllers" thing; apparently some
3184 // sites use it for browser-sniffing. See bug 1010577.
3185 #ifdef USE_CONTROLLERS_SHIM
3186 // Note: We use |aObj| rather than |this| to get the principal here, because
3187 // this is called during Window setup when the Document isn't necessarily
3189 if ((aId
== XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS
) ||
3190 aId
== XPCJSRuntime::Get()->GetStringID(
3191 XPCJSContext::IDX_CONTROLLERS_CLASS
)) &&
3192 !xpc::IsXrayWrapper(aObj
) &&
3193 !nsContentUtils::ObjectPrincipal(aObj
)->IsSystemPrincipal()) {
3194 if (GetExtantDoc()) {
3195 GetExtantDoc()->WarnOnceAbout(
3196 DeprecatedOperations::eWindow_Cc_ontrollers
);
3198 const JSClass
* clazz
;
3200 XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS
)) {
3201 clazz
= &XULControllersShimClass
;
3203 clazz
= &ControllersShimClass
;
3205 MOZ_ASSERT(JS_IsGlobalObject(aObj
));
3206 JS::Rooted
<JSObject
*> shim(aCx
, JS_NewObject(aCx
, clazz
));
3207 if (NS_WARN_IF(!shim
)) {
3211 aDesc
.set(mozilla::Some(JS::PropertyDescriptor::Data(
3212 JS::ObjectValue(*shim
),
3213 {JS::PropertyAttribute::Configurable
, JS::PropertyAttribute::Enumerable
,
3214 JS::PropertyAttribute::Writable
})));
3223 bool nsGlobalWindowInner::MayResolve(jsid aId
) {
3224 // Note: This function does not fail and may not have any side-effects.
3225 // Note: Keep this in sync with DoResolve.
3226 if (!aId
.isString()) {
3230 if (aId
== XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS
)) {
3234 if (aId
== XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS
) ||
3235 aId
== XPCJSRuntime::Get()->GetStringID(
3236 XPCJSContext::IDX_CONTROLLERS_CLASS
)) {
3237 // We only resolve .controllers/.Controllers in release builds and on
3238 // non-chrome windows, but let's not worry about any of that stuff.
3242 return WebIDLGlobalNameHash::MayResolve(aId
);
3245 void nsGlobalWindowInner::GetOwnPropertyNames(
3246 JSContext
* aCx
, JS::MutableHandleVector
<jsid
> aNames
, bool aEnumerableOnly
,
3248 if (aEnumerableOnly
) {
3249 // The names we would return from here get defined on the window via one of
3250 // two codepaths. The ones coming from the WebIDLGlobalNameHash will end up
3251 // in the DefineConstructor function in BindingUtils, which always defines
3252 // things as non-enumerable. The ones coming from the script namespace
3253 // manager get defined by our resolve hook using FillPropertyDescriptor with
3254 // 0 for the property attributes, so non-enumerable as well.
3256 // So in the aEnumerableOnly case we have nothing to do.
3260 // "Components" is marked as enumerable but only resolved on demand :-/.
3261 // aNames.AppendElement(u"Components"_ns);
3263 JS::Rooted
<JSObject
*> wrapper(aCx
, GetWrapper());
3265 // There are actually two ways we can get called here: For normal
3266 // enumeration or for Xray enumeration. In the latter case, we want to
3267 // return all possible WebIDL names, because we don't really support
3268 // deleting these names off our Xray; trying to resolve them will just make
3269 // them come back. In the former case, we want to avoid returning deleted
3270 // names. But the JS engine already knows about the non-deleted
3271 // already-resolved names, so we can just return the so-far-unresolved ones.
3273 // We can tell which case we're in by whether aCx is in our wrapper's
3274 // compartment. If not, we're in the Xray case.
3275 WebIDLGlobalNameHash::NameType nameType
=
3276 js::IsObjectInContextCompartment(wrapper
, aCx
)
3277 ? WebIDLGlobalNameHash::UnresolvedNamesOnly
3278 : WebIDLGlobalNameHash::AllNames
;
3279 if (!WebIDLGlobalNameHash::GetNames(aCx
, wrapper
, nameType
, aNames
)) {
3280 aRv
.NoteJSContextException(aCx
);
3285 bool nsGlobalWindowInner::IsPrivilegedChromeWindow(JSContext
*, JSObject
* aObj
) {
3286 // For now, have to deal with XPConnect objects here.
3287 nsGlobalWindowInner
* win
= xpc::WindowOrNull(aObj
);
3288 return win
&& win
->IsChromeWindow() &&
3289 nsContentUtils::ObjectPrincipal(aObj
) ==
3290 nsContentUtils::GetSystemPrincipal();
3294 bool nsGlobalWindowInner::DeviceSensorsEnabled(JSContext
*, JSObject
*) {
3295 return Preferences::GetBool("device.sensors.enabled");
3299 bool nsGlobalWindowInner::CachesEnabled(JSContext
* aCx
, JSObject
* aObj
) {
3300 if (!IsSecureContextOrObjectIsFromSecureContext(aCx
, aObj
)) {
3301 return StaticPrefs::dom_caches_testing_enabled() ||
3302 StaticPrefs::dom_serviceWorkers_testing_enabled();
3308 bool nsGlobalWindowInner::IsSizeToContentEnabled(JSContext
* aCx
, JSObject
*) {
3309 return StaticPrefs::dom_window_sizeToContent_enabled() ||
3310 nsContentUtils::IsSystemCaller(aCx
);
3314 bool nsGlobalWindowInner::IsGleanNeeded(JSContext
* aCx
, JSObject
* aObj
) {
3315 // Glean is needed in ChromeOnly contexts and also in privileged about pages.
3316 nsIPrincipal
* principal
= nsContentUtils::SubjectPrincipal(aCx
);
3317 if (principal
->IsSystemPrincipal()) {
3322 if (NS_FAILED(principal
->GetAboutModuleFlags(&flags
))) {
3325 return flags
& nsIAboutModule::IS_SECURE_CHROME_UI
;
3328 Crypto
* nsGlobalWindowInner::GetCrypto(ErrorResult
& aError
) {
3330 mCrypto
= new Crypto(this);
3335 nsIControllers
* nsGlobalWindowInner::GetControllers(ErrorResult
& aError
) {
3336 FORWARD_TO_OUTER_OR_THROW(GetControllersOuter
, (aError
), aError
, nullptr);
3339 nsresult
nsGlobalWindowInner::GetControllers(nsIControllers
** aResult
) {
3341 nsCOMPtr
<nsIControllers
> controllers
= GetControllers(rv
);
3342 controllers
.forget(aResult
);
3344 return rv
.StealNSResult();
3347 Nullable
<WindowProxyHolder
> nsGlobalWindowInner::GetOpenerWindow(
3348 ErrorResult
& aError
) {
3349 FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter
, (), aError
, nullptr);
3352 void nsGlobalWindowInner::GetOpener(JSContext
* aCx
,
3353 JS::MutableHandle
<JS::Value
> aRetval
,
3354 ErrorResult
& aError
) {
3355 Nullable
<WindowProxyHolder
> opener
= GetOpenerWindow(aError
);
3356 if (aError
.Failed() || opener
.IsNull()) {
3361 if (!ToJSValue(aCx
, opener
.Value(), aRetval
)) {
3362 aError
.NoteJSContextException(aCx
);
3366 void nsGlobalWindowInner::SetOpener(JSContext
* aCx
,
3367 JS::Handle
<JS::Value
> aOpener
,
3368 ErrorResult
& aError
) {
3369 if (aOpener
.isNull()) {
3370 RefPtr
<BrowsingContext
> bc(GetBrowsingContext());
3371 if (!bc
->IsDiscarded()) {
3372 bc
->SetOpener(nullptr);
3377 // If something other than null is passed, just define aOpener on our inner
3378 // window's JS object, wrapped into the current compartment so that for Xrays
3379 // we define on the Xray expando object, but don't set it on the outer window,
3380 // so that it'll get reset on navigation. This is just like replaceable
3381 // properties, but we're not quite readonly.
3382 RedefineProperty(aCx
, "opener", aOpener
, aError
);
3385 void nsGlobalWindowInner::GetEvent(OwningEventOrUndefined
& aRetval
) {
3387 aRetval
.SetAsEvent() = mEvent
;
3389 aRetval
.SetUndefined();
3393 void nsGlobalWindowInner::GetStatus(nsAString
& aStatus
, ErrorResult
& aError
) {
3394 FORWARD_TO_OUTER_OR_THROW(GetStatusOuter
, (aStatus
), aError
, );
3397 void nsGlobalWindowInner::SetStatus(const nsAString
& aStatus
,
3398 ErrorResult
& aError
) {
3399 FORWARD_TO_OUTER_OR_THROW(SetStatusOuter
, (aStatus
), aError
, );
3402 void nsGlobalWindowInner::GetName(nsAString
& aName
, ErrorResult
& aError
) {
3403 FORWARD_TO_OUTER_OR_THROW(GetNameOuter
, (aName
), aError
, );
3406 void nsGlobalWindowInner::SetName(const nsAString
& aName
,
3407 mozilla::ErrorResult
& aError
) {
3408 FORWARD_TO_OUTER_OR_THROW(SetNameOuter
, (aName
, aError
), aError
, );
3411 double nsGlobalWindowInner::GetInnerWidth(ErrorResult
& aError
) {
3412 FORWARD_TO_OUTER_OR_THROW(GetInnerWidthOuter
, (aError
), aError
, 0);
3415 nsresult
nsGlobalWindowInner::GetInnerWidth(double* aWidth
) {
3417 // Callee doesn't care about the caller type, but play it safe.
3418 *aWidth
= GetInnerWidth(rv
);
3419 return rv
.StealNSResult();
3422 double nsGlobalWindowInner::GetInnerHeight(ErrorResult
& aError
) {
3423 // We ignore aCallerType; we only have that argument because some other things
3424 // called by GetReplaceableWindowCoord need it. If this ever changes, fix
3425 // nsresult nsGlobalWindowInner::GetInnerHeight(double* aInnerWidth)
3426 // to actually take a useful CallerType and pass it in here.
3427 FORWARD_TO_OUTER_OR_THROW(GetInnerHeightOuter
, (aError
), aError
, 0);
3430 nsresult
nsGlobalWindowInner::GetInnerHeight(double* aHeight
) {
3432 // Callee doesn't care about the caller type, but play it safe.
3433 *aHeight
= GetInnerHeight(rv
);
3434 return rv
.StealNSResult();
3437 int32_t nsGlobalWindowInner::GetOuterWidth(CallerType aCallerType
,
3438 ErrorResult
& aError
) {
3439 FORWARD_TO_OUTER_OR_THROW(GetOuterWidthOuter
, (aCallerType
, aError
), aError
,
3443 int32_t nsGlobalWindowInner::GetOuterHeight(CallerType aCallerType
,
3444 ErrorResult
& aError
) {
3445 FORWARD_TO_OUTER_OR_THROW(GetOuterHeightOuter
, (aCallerType
, aError
), aError
,
3449 double nsGlobalWindowInner::ScreenEdgeSlopX() const {
3450 FORWARD_TO_OUTER(ScreenEdgeSlopX
, (), 0);
3453 double nsGlobalWindowInner::ScreenEdgeSlopY() const {
3454 FORWARD_TO_OUTER(ScreenEdgeSlopY
, (), 0);
3457 int32_t nsGlobalWindowInner::GetScreenX(CallerType aCallerType
,
3458 ErrorResult
& aError
) {
3459 FORWARD_TO_OUTER_OR_THROW(GetScreenXOuter
, (aCallerType
, aError
), aError
, 0);
3462 int32_t nsGlobalWindowInner::GetScreenY(CallerType aCallerType
,
3463 ErrorResult
& aError
) {
3464 FORWARD_TO_OUTER_OR_THROW(GetScreenYOuter
, (aCallerType
, aError
), aError
, 0);
3467 float nsGlobalWindowInner::GetMozInnerScreenX(CallerType aCallerType
,
3468 ErrorResult
& aError
) {
3469 FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenXOuter
, (aCallerType
), aError
, 0);
3472 float nsGlobalWindowInner::GetMozInnerScreenY(CallerType aCallerType
,
3473 ErrorResult
& aError
) {
3474 FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenYOuter
, (aCallerType
), aError
, 0);
3477 static nsPresContext
* GetPresContextForRatio(Document
* aDoc
) {
3478 if (nsPresContext
* presContext
= aDoc
->GetPresContext()) {
3481 // We're in an undisplayed subdocument... There's not really an awesome way
3482 // to tell what the right DPI is from here, so we try to walk up our parent
3483 // document chain to the extent that the docs can observe each other.
3484 Document
* doc
= aDoc
;
3485 while (doc
->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) {
3486 doc
= doc
->GetInProcessParentDocument();
3487 if (nsPresContext
* presContext
= doc
->GetPresContext()) {
3494 double nsGlobalWindowInner::GetDevicePixelRatio(CallerType aCallerType
,
3495 ErrorResult
& aError
) {
3496 ENSURE_ACTIVE_DOCUMENT(aError
, 0.0);
3498 RefPtr
<nsPresContext
> presContext
= GetPresContextForRatio(mDoc
);
3499 if (NS_WARN_IF(!presContext
)) {
3500 // Still nothing, oh well.
3504 if (nsIGlobalObject::ShouldResistFingerprinting(
3505 aCallerType
, RFPTarget::WindowDevicePixelRatio
)) {
3506 // Spoofing the DevicePixelRatio causes blurriness in some situations
3507 // on HiDPI displays. pdf.js is a non-system caller; but it can't
3508 // expose the fingerprintable information, so we can safely disable
3509 // spoofing in this situation. It doesn't address the issue for
3510 // web-rendered content (including pdf.js instances on the web.)
3511 // In the future we hope to have a better solution to fix all HiDPI
3513 nsAutoCString origin
;
3514 nsresult rv
= this->GetPrincipal()->GetOrigin(origin
);
3515 if (NS_FAILED(rv
) || origin
!= "resource://pdf.js"_ns
) {
3520 if (aCallerType
== CallerType::NonSystem
) {
3521 float overrideDPPX
= presContext
->GetOverrideDPPX();
3522 if (overrideDPPX
> 0.0f
) {
3523 return overrideDPPX
;
3527 return double(AppUnitsPerCSSPixel()) /
3528 double(presContext
->AppUnitsPerDevPixel());
3531 double nsGlobalWindowInner::GetDesktopToDeviceScale(ErrorResult
& aError
) {
3532 ENSURE_ACTIVE_DOCUMENT(aError
, 0.0);
3533 nsPresContext
* presContext
= GetPresContextForRatio(mDoc
);
3537 return presContext
->DeviceContext()->GetDesktopToDeviceScale().scale
;
3540 int32_t nsGlobalWindowInner::RequestAnimationFrame(
3541 FrameRequestCallback
& aCallback
, ErrorResult
& aError
) {
3546 if (GetWrapperPreserveColor()) {
3547 js::NotifyAnimationActivity(GetWrapperPreserveColor());
3550 DebuggerNotificationDispatch(this,
3551 DebuggerNotificationType::RequestAnimationFrame
);
3554 aError
= mDoc
->ScheduleFrameRequestCallback(aCallback
, &handle
);
3558 void nsGlobalWindowInner::CancelAnimationFrame(int32_t aHandle
,
3559 ErrorResult
& aError
) {
3564 DebuggerNotificationDispatch(this,
3565 DebuggerNotificationType::CancelAnimationFrame
);
3567 mDoc
->CancelFrameRequestCallback(aHandle
);
3570 already_AddRefed
<MediaQueryList
> nsGlobalWindowInner::MatchMedia(
3571 const nsACString
& aMediaQueryList
, CallerType aCallerType
,
3572 ErrorResult
& aError
) {
3573 ENSURE_ACTIVE_DOCUMENT(aError
, nullptr);
3574 return mDoc
->MatchMedia(aMediaQueryList
, aCallerType
);
3577 int32_t nsGlobalWindowInner::GetScrollMinX(ErrorResult
& aError
) {
3578 FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter
, (eSideLeft
), aError
, 0);
3581 int32_t nsGlobalWindowInner::GetScrollMinY(ErrorResult
& aError
) {
3582 FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter
, (eSideTop
), aError
, 0);
3585 int32_t nsGlobalWindowInner::GetScrollMaxX(ErrorResult
& aError
) {
3586 FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter
, (eSideRight
), aError
, 0);
3589 int32_t nsGlobalWindowInner::GetScrollMaxY(ErrorResult
& aError
) {
3590 FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter
, (eSideBottom
), aError
, 0);
3593 double nsGlobalWindowInner::GetScrollX(ErrorResult
& aError
) {
3594 FORWARD_TO_OUTER_OR_THROW(GetScrollXOuter
, (), aError
, 0);
3597 double nsGlobalWindowInner::GetScrollY(ErrorResult
& aError
) {
3598 FORWARD_TO_OUTER_OR_THROW(GetScrollYOuter
, (), aError
, 0);
3601 uint32_t nsGlobalWindowInner::Length() { FORWARD_TO_OUTER(Length
, (), 0); }
3603 Nullable
<WindowProxyHolder
> nsGlobalWindowInner::GetTop(
3604 mozilla::ErrorResult
& aError
) {
3605 FORWARD_TO_OUTER_OR_THROW(GetTopOuter
, (), aError
, nullptr);
3608 already_AddRefed
<BrowsingContext
> nsGlobalWindowInner::GetChildWindow(
3609 const nsAString
& aName
) {
3610 if (GetOuterWindowInternal()) {
3611 return GetOuterWindowInternal()->GetChildWindow(aName
);
3616 void nsGlobalWindowInner::RefreshRealmPrincipal() {
3617 JS::SetRealmPrincipals(js::GetNonCCWObjectRealm(GetWrapperPreserveColor()),
3618 nsJSPrincipals::get(mDoc
->NodePrincipal()));
3621 void nsGlobalWindowInner::RefreshReduceTimerPrecisionCallerType() {
3622 JS::SetRealmReduceTimerPrecisionCallerType(
3623 js::GetNonCCWObjectRealm(GetWrapperPreserveColor()),
3624 RTPCallerTypeToToken(GetRTPCallerType()));
3627 already_AddRefed
<nsIWidget
> nsGlobalWindowInner::GetMainWidget() {
3628 FORWARD_TO_OUTER(GetMainWidget
, (), nullptr);
3631 nsIWidget
* nsGlobalWindowInner::GetNearestWidget() const {
3632 if (GetOuterWindowInternal()) {
3633 return GetOuterWindowInternal()->GetNearestWidget();
3638 void nsGlobalWindowInner::SetFullScreen(bool aFullscreen
,
3639 mozilla::ErrorResult
& aError
) {
3640 FORWARD_TO_OUTER_OR_THROW(SetFullscreenOuter
, (aFullscreen
, aError
), aError
,
3644 bool nsGlobalWindowInner::GetFullScreen(ErrorResult
& aError
) {
3645 FORWARD_TO_OUTER_OR_THROW(GetFullscreenOuter
, (), aError
, false);
3648 bool nsGlobalWindowInner::GetFullScreen() {
3650 bool fullscreen
= GetFullScreen(dummy
);
3651 dummy
.SuppressException();
3655 void nsGlobalWindowInner::Dump(const nsAString
& aStr
) {
3656 if (!nsJSUtils::DumpEnabled()) {
3660 char* cstr
= ToNewUTF8String(aStr
);
3662 #if defined(XP_MACOSX)
3663 // have to convert \r to \n so that printing to the console works
3664 char *c
= cstr
, *cEnd
= cstr
+ strlen(cstr
);
3666 if (*c
== '\r') *c
= '\n';
3672 MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug
,
3673 ("[Window.Dump] %s", cstr
));
3675 PrintToDebugger(cstr
);
3678 __android_log_write(ANDROID_LOG_INFO
, "GeckoDump", cstr
);
3680 FILE* fp
= gDumpFile
? gDumpFile
: stdout
;
3687 void nsGlobalWindowInner::Alert(nsIPrincipal
& aSubjectPrincipal
,
3688 ErrorResult
& aError
) {
3689 Alert(u
""_ns
, aSubjectPrincipal
, aError
);
3692 void nsGlobalWindowInner::Alert(const nsAString
& aMessage
,
3693 nsIPrincipal
& aSubjectPrincipal
,
3694 ErrorResult
& aError
) {
3695 FORWARD_TO_OUTER_OR_THROW(AlertOuter
, (aMessage
, aSubjectPrincipal
, aError
),
3699 bool nsGlobalWindowInner::Confirm(const nsAString
& aMessage
,
3700 nsIPrincipal
& aSubjectPrincipal
,
3701 ErrorResult
& aError
) {
3702 FORWARD_TO_OUTER_OR_THROW(ConfirmOuter
, (aMessage
, aSubjectPrincipal
, aError
),
3706 already_AddRefed
<Promise
> nsGlobalWindowInner::Fetch(
3707 const RequestOrUTF8String
& aInput
, const RequestInit
& aInit
,
3708 CallerType aCallerType
, ErrorResult
& aRv
) {
3709 return FetchRequest(this, aInput
, aInit
, aCallerType
, aRv
);
3712 void nsGlobalWindowInner::Prompt(const nsAString
& aMessage
,
3713 const nsAString
& aInitial
, nsAString
& aReturn
,
3714 nsIPrincipal
& aSubjectPrincipal
,
3715 ErrorResult
& aError
) {
3716 FORWARD_TO_OUTER_OR_THROW(
3717 PromptOuter
, (aMessage
, aInitial
, aReturn
, aSubjectPrincipal
, aError
),
3721 void nsGlobalWindowInner::Focus(CallerType aCallerType
, ErrorResult
& aError
) {
3722 FORWARD_TO_OUTER_OR_THROW(FocusOuter
,
3723 (aCallerType
, /* aFromOtherProcess */ false,
3724 nsFocusManager::GenerateFocusActionId()),
3728 nsresult
nsGlobalWindowInner::Focus(CallerType aCallerType
) {
3730 Focus(aCallerType
, rv
);
3732 return rv
.StealNSResult();
3735 void nsGlobalWindowInner::Blur(CallerType aCallerType
, ErrorResult
& aError
) {
3736 FORWARD_TO_OUTER_OR_THROW(BlurOuter
, (aCallerType
), aError
, );
3739 void nsGlobalWindowInner::Stop(ErrorResult
& aError
) {
3740 FORWARD_TO_OUTER_OR_THROW(StopOuter
, (aError
), aError
, );
3743 void nsGlobalWindowInner::Print(ErrorResult
& aError
) {
3744 FORWARD_TO_OUTER_OR_THROW(PrintOuter
, (aError
), aError
, );
3747 Nullable
<WindowProxyHolder
> nsGlobalWindowInner::PrintPreview(
3748 nsIPrintSettings
* aSettings
, nsIWebProgressListener
* aListener
,
3749 nsIDocShell
* aDocShellToCloneInto
, ErrorResult
& aError
) {
3750 FORWARD_TO_OUTER_OR_THROW(
3753 /* aRemotePrintJob = */ nullptr, aListener
, aDocShellToCloneInto
,
3754 nsGlobalWindowOuter::IsPreview::Yes
,
3755 nsGlobalWindowOuter::IsForWindowDotPrint::No
,
3756 /* aPrintPreviewCallback = */ nullptr, nullptr, aError
),
3760 void nsGlobalWindowInner::MoveTo(int32_t aXPos
, int32_t aYPos
,
3761 CallerType aCallerType
, ErrorResult
& aError
) {
3762 FORWARD_TO_OUTER_OR_THROW(MoveToOuter
, (aXPos
, aYPos
, aCallerType
, aError
),
3766 void nsGlobalWindowInner::MoveBy(int32_t aXDif
, int32_t aYDif
,
3767 CallerType aCallerType
, ErrorResult
& aError
) {
3768 FORWARD_TO_OUTER_OR_THROW(MoveByOuter
, (aXDif
, aYDif
, aCallerType
, aError
),
3772 void nsGlobalWindowInner::ResizeTo(int32_t aWidth
, int32_t aHeight
,
3773 CallerType aCallerType
,
3774 ErrorResult
& aError
) {
3775 FORWARD_TO_OUTER_OR_THROW(ResizeToOuter
,
3776 (aWidth
, aHeight
, aCallerType
, aError
), aError
, );
3779 void nsGlobalWindowInner::ResizeBy(int32_t aWidthDif
, int32_t aHeightDif
,
3780 CallerType aCallerType
,
3781 ErrorResult
& aError
) {
3782 FORWARD_TO_OUTER_OR_THROW(
3783 ResizeByOuter
, (aWidthDif
, aHeightDif
, aCallerType
, aError
), aError
, );
3786 void nsGlobalWindowInner::SizeToContent(CallerType aCallerType
,
3787 ErrorResult
& aError
) {
3788 FORWARD_TO_OUTER_OR_THROW(SizeToContentOuter
, (aCallerType
, {}, aError
),
3792 void nsGlobalWindowInner::SizeToContentConstrained(
3793 const SizeToContentConstraints
& aConstraints
, ErrorResult
& aError
) {
3794 FORWARD_TO_OUTER_OR_THROW(
3795 SizeToContentOuter
, (CallerType::System
, aConstraints
, aError
), aError
, );
3798 already_AddRefed
<nsPIWindowRoot
> nsGlobalWindowInner::GetTopWindowRoot() {
3799 nsGlobalWindowOuter
* outer
= GetOuterWindowInternal();
3803 return outer
->GetTopWindowRoot();
3806 void nsGlobalWindowInner::Scroll(double aXScroll
, double aYScroll
) {
3807 // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
3808 auto scrollPos
= CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll
),
3809 mozilla::ToZeroIfNonfinite(aYScroll
));
3810 ScrollTo(scrollPos
, ScrollOptions());
3813 void nsGlobalWindowInner::ScrollTo(double aXScroll
, double aYScroll
) {
3814 // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
3815 auto scrollPos
= CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll
),
3816 mozilla::ToZeroIfNonfinite(aYScroll
));
3817 ScrollTo(scrollPos
, ScrollOptions());
3820 void nsGlobalWindowInner::ScrollTo(const ScrollToOptions
& aOptions
) {
3821 // When scrolling to a non-zero offset, we need to determine whether that
3822 // position is within our scrollable range, so we need updated layout
3823 // information which requires a layout flush, otherwise all we need is to
3824 // flush frames to be able to access our scrollable frame here.
3825 FlushType flushType
=
3826 ((aOptions
.mLeft
.WasPassed() && aOptions
.mLeft
.Value() > 0) ||
3827 (aOptions
.mTop
.WasPassed() && aOptions
.mTop
.Value() > 0))
3829 : FlushType::Frames
;
3830 FlushPendingNotifications(flushType
);
3831 nsIScrollableFrame
* sf
= GetScrollFrame();
3834 CSSIntPoint scrollPos
= sf
->GetRoundedScrollPositionCSSPixels();
3835 if (aOptions
.mLeft
.WasPassed()) {
3836 scrollPos
.x
= static_cast<int32_t>(
3837 mozilla::ToZeroIfNonfinite(aOptions
.mLeft
.Value()));
3839 if (aOptions
.mTop
.WasPassed()) {
3840 scrollPos
.y
= static_cast<int32_t>(
3841 mozilla::ToZeroIfNonfinite(aOptions
.mTop
.Value()));
3844 ScrollTo(scrollPos
, aOptions
);
3848 void nsGlobalWindowInner::Scroll(const ScrollToOptions
& aOptions
) {
3852 void nsGlobalWindowInner::ScrollTo(const CSSIntPoint
& aScroll
,
3853 const ScrollOptions
& aOptions
) {
3854 // When scrolling to a non-zero offset, we need to determine whether that
3855 // position is within our scrollable range, so we need updated layout
3856 // information which requires a layout flush, otherwise all we need is to
3857 // flush frames to be able to access our scrollable frame here.
3858 FlushType flushType
=
3859 (aScroll
.x
|| aScroll
.y
) ? FlushType::Layout
: FlushType::Frames
;
3860 FlushPendingNotifications(flushType
);
3861 nsIScrollableFrame
* sf
= GetScrollFrame();
3864 // Here we calculate what the max pixel value is that we can
3865 // scroll to, we do this by dividing maxint with the pixel to
3866 // twips conversion factor, and subtracting 4, the 4 comes from
3867 // experimenting with this value, anything less makes the view
3868 // code not scroll correctly, I have no idea why. -- jst
3869 const int32_t maxpx
= nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
3871 CSSIntPoint
scroll(aScroll
);
3872 if (scroll
.x
> maxpx
) {
3876 if (scroll
.y
> maxpx
) {
3880 ScrollMode scrollMode
= sf
->IsSmoothScroll(aOptions
.mBehavior
)
3881 ? ScrollMode::SmoothMsd
3882 : ScrollMode::Instant
;
3884 sf
->ScrollToCSSPixels(scroll
, scrollMode
);
3888 void nsGlobalWindowInner::ScrollBy(double aXScrollDif
, double aYScrollDif
) {
3889 FlushPendingNotifications(FlushType::Layout
);
3890 nsIScrollableFrame
* sf
= GetScrollFrame();
3893 // It seems like it would make more sense for ScrollBy to use
3894 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
3895 // Perhaps Web content does too.
3896 ScrollToOptions options
;
3897 options
.mLeft
.Construct(aXScrollDif
);
3898 options
.mTop
.Construct(aYScrollDif
);
3903 void nsGlobalWindowInner::ScrollBy(const ScrollToOptions
& aOptions
) {
3904 FlushPendingNotifications(FlushType::Layout
);
3905 nsIScrollableFrame
* sf
= GetScrollFrame();
3908 CSSIntPoint scrollDelta
;
3909 if (aOptions
.mLeft
.WasPassed()) {
3910 scrollDelta
.x
= static_cast<int32_t>(
3911 mozilla::ToZeroIfNonfinite(aOptions
.mLeft
.Value()));
3913 if (aOptions
.mTop
.WasPassed()) {
3914 scrollDelta
.y
= static_cast<int32_t>(
3915 mozilla::ToZeroIfNonfinite(aOptions
.mTop
.Value()));
3918 ScrollMode scrollMode
= sf
->IsSmoothScroll(aOptions
.mBehavior
)
3919 ? ScrollMode::SmoothMsd
3920 : ScrollMode::Instant
;
3922 sf
->ScrollByCSSPixels(scrollDelta
, scrollMode
);
3926 void nsGlobalWindowInner::ScrollByLines(int32_t numLines
,
3927 const ScrollOptions
& aOptions
) {
3928 FlushPendingNotifications(FlushType::Layout
);
3929 nsIScrollableFrame
* sf
= GetScrollFrame();
3931 // It seems like it would make more sense for ScrollByLines to use
3932 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
3933 // Perhaps Web content does too.
3934 ScrollMode scrollMode
= sf
->IsSmoothScroll(aOptions
.mBehavior
)
3935 ? ScrollMode::SmoothMsd
3936 : ScrollMode::Instant
;
3938 sf
->ScrollBy(nsIntPoint(0, numLines
), ScrollUnit::LINES
, scrollMode
);
3942 void nsGlobalWindowInner::ScrollByPages(int32_t numPages
,
3943 const ScrollOptions
& aOptions
) {
3944 FlushPendingNotifications(FlushType::Layout
);
3945 nsIScrollableFrame
* sf
= GetScrollFrame();
3947 // It seems like it would make more sense for ScrollByPages to use
3948 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
3949 // Perhaps Web content does too.
3950 ScrollMode scrollMode
= sf
->IsSmoothScroll(aOptions
.mBehavior
)
3951 ? ScrollMode::SmoothMsd
3952 : ScrollMode::Instant
;
3954 sf
->ScrollBy(nsIntPoint(0, numPages
), ScrollUnit::PAGES
, scrollMode
);
3958 void nsGlobalWindowInner::MozScrollSnap() {
3959 FlushPendingNotifications(FlushType::Layout
);
3960 nsIScrollableFrame
* sf
= GetScrollFrame();
3966 void nsGlobalWindowInner::ClearTimeout(int32_t aHandle
) {
3967 DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearTimeout
);
3970 mTimeoutManager
->ClearTimeout(aHandle
, Timeout::Reason::eTimeoutOrInterval
);
3974 void nsGlobalWindowInner::ClearInterval(int32_t aHandle
) {
3975 DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearInterval
);
3978 mTimeoutManager
->ClearTimeout(aHandle
, Timeout::Reason::eTimeoutOrInterval
);
3982 void nsGlobalWindowInner::SetResizable(bool aResizable
) const {
3986 void nsGlobalWindowInner::CaptureEvents() {
3988 mDoc
->WarnOnceAbout(DeprecatedOperations::eUseOfCaptureEvents
);
3992 void nsGlobalWindowInner::ReleaseEvents() {
3994 mDoc
->WarnOnceAbout(DeprecatedOperations::eUseOfReleaseEvents
);
3998 Nullable
<WindowProxyHolder
> nsGlobalWindowInner::Open(const nsAString
& aUrl
,
3999 const nsAString
& aName
,
4000 const nsAString
& aOptions
,
4001 ErrorResult
& aError
) {
4002 FORWARD_TO_OUTER_OR_THROW(OpenOuter
, (aUrl
, aName
, aOptions
, aError
), aError
,
4006 Nullable
<WindowProxyHolder
> nsGlobalWindowInner::OpenDialog(
4007 JSContext
* aCx
, const nsAString
& aUrl
, const nsAString
& aName
,
4008 const nsAString
& aOptions
, const Sequence
<JS::Value
>& aExtraArgument
,
4009 ErrorResult
& aError
) {
4010 FORWARD_TO_OUTER_OR_THROW(
4011 OpenDialogOuter
, (aCx
, aUrl
, aName
, aOptions
, aExtraArgument
, aError
),
4015 WindowProxyHolder
nsGlobalWindowInner::GetFrames(ErrorResult
& aError
) {
4016 FORWARD_TO_OUTER_OR_THROW(GetFramesOuter
, (), aError
, Window());
4019 void nsGlobalWindowInner::PostMessageMoz(JSContext
* aCx
,
4020 JS::Handle
<JS::Value
> aMessage
,
4021 const nsAString
& aTargetOrigin
,
4022 JS::Handle
<JS::Value
> aTransfer
,
4023 nsIPrincipal
& aSubjectPrincipal
,
4024 ErrorResult
& aError
) {
4025 FORWARD_TO_OUTER_OR_THROW(
4026 PostMessageMozOuter
,
4027 (aCx
, aMessage
, aTargetOrigin
, aTransfer
, aSubjectPrincipal
, aError
),
4031 void nsGlobalWindowInner::PostMessageMoz(JSContext
* aCx
,
4032 JS::Handle
<JS::Value
> aMessage
,
4033 const nsAString
& aTargetOrigin
,
4034 const Sequence
<JSObject
*>& aTransfer
,
4035 nsIPrincipal
& aSubjectPrincipal
,
4037 JS::Rooted
<JS::Value
> transferArray(aCx
, JS::UndefinedValue());
4039 aRv
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransfer
,
4041 if (NS_WARN_IF(aRv
.Failed())) {
4045 PostMessageMoz(aCx
, aMessage
, aTargetOrigin
, transferArray
, aSubjectPrincipal
,
4049 void nsGlobalWindowInner::PostMessageMoz(
4050 JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
4051 const WindowPostMessageOptions
& aOptions
, nsIPrincipal
& aSubjectPrincipal
,
4053 JS::Rooted
<JS::Value
> transferArray(aCx
, JS::UndefinedValue());
4055 aRv
= nsContentUtils::CreateJSValueFromSequenceOfObject(
4056 aCx
, aOptions
.mTransfer
, &transferArray
);
4057 if (NS_WARN_IF(aRv
.Failed())) {
4061 PostMessageMoz(aCx
, aMessage
, aOptions
.mTargetOrigin
, transferArray
,
4062 aSubjectPrincipal
, aRv
);
4065 void nsGlobalWindowInner::Close(CallerType aCallerType
, ErrorResult
& aError
) {
4066 FORWARD_TO_OUTER_OR_THROW(CloseOuter
, (aCallerType
== CallerType::System
),
4070 nsresult
nsGlobalWindowInner::Close() {
4071 FORWARD_TO_OUTER(Close
, (), NS_ERROR_UNEXPECTED
);
4074 bool nsGlobalWindowInner::IsInModalState() {
4075 FORWARD_TO_OUTER(IsInModalState
, (), false);
4079 void nsGlobalWindowInner::NotifyDOMWindowDestroyed(
4080 nsGlobalWindowInner
* aWindow
) {
4081 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
4082 if (observerService
) {
4083 observerService
->NotifyObservers(ToSupports(aWindow
),
4084 DOM_WINDOW_DESTROYED_TOPIC
, nullptr);
4088 void nsGlobalWindowInner::NotifyWindowIDDestroyed(const char* aTopic
) {
4089 nsCOMPtr
<nsIRunnable
> runnable
=
4090 new WindowDestroyedEvent(this, mWindowID
, aTopic
);
4091 Dispatch(runnable
.forget());
4095 void nsGlobalWindowInner::NotifyDOMWindowFrozen(nsGlobalWindowInner
* aWindow
) {
4097 nsCOMPtr
<nsIObserverService
> observerService
=
4098 services::GetObserverService();
4099 if (observerService
) {
4100 observerService
->NotifyObservers(ToSupports(aWindow
),
4101 DOM_WINDOW_FROZEN_TOPIC
, nullptr);
4107 void nsGlobalWindowInner::NotifyDOMWindowThawed(nsGlobalWindowInner
* aWindow
) {
4109 nsCOMPtr
<nsIObserverService
> observerService
=
4110 services::GetObserverService();
4111 if (observerService
) {
4112 observerService
->NotifyObservers(ToSupports(aWindow
),
4113 DOM_WINDOW_THAWED_TOPIC
, nullptr);
4118 Element
* nsGlobalWindowInner::GetFrameElement(nsIPrincipal
& aSubjectPrincipal
,
4119 ErrorResult
& aError
) {
4120 FORWARD_TO_OUTER_OR_THROW(GetFrameElement
, (aSubjectPrincipal
), aError
,
4124 Element
* nsGlobalWindowInner::GetRealFrameElement(ErrorResult
& aError
) {
4125 FORWARD_TO_OUTER_OR_THROW(GetFrameElement
, (), aError
, nullptr);
4128 void nsGlobalWindowInner::UpdateCommands(const nsAString
& anAction
) {
4129 if (GetOuterWindowInternal()) {
4130 GetOuterWindowInternal()->UpdateCommands(anAction
);
4134 Selection
* nsGlobalWindowInner::GetSelection(ErrorResult
& aError
) {
4135 FORWARD_TO_OUTER_OR_THROW(GetSelectionOuter
, (), aError
, nullptr);
4138 WebTaskScheduler
* nsGlobalWindowInner::Scheduler() {
4139 if (!mWebTaskScheduler
) {
4140 mWebTaskScheduler
= WebTaskScheduler::CreateForMainThread(this);
4142 MOZ_ASSERT(mWebTaskScheduler
);
4143 return mWebTaskScheduler
;
4146 bool nsGlobalWindowInner::Find(const nsAString
& aString
, bool aCaseSensitive
,
4147 bool aBackwards
, bool aWrapAround
,
4148 bool aWholeWord
, bool aSearchInFrames
,
4149 bool aShowDialog
, ErrorResult
& aError
) {
4150 FORWARD_TO_OUTER_OR_THROW(FindOuter
,
4151 (aString
, aCaseSensitive
, aBackwards
, aWrapAround
,
4152 aWholeWord
, aSearchInFrames
, aShowDialog
, aError
),
4156 void nsGlobalWindowInner::GetOrigin(nsAString
& aOrigin
) {
4157 nsContentUtils::GetWebExposedOriginSerialization(GetPrincipal(), aOrigin
);
4160 // See also AutoJSAPI::ReportException
4161 void nsGlobalWindowInner::ReportError(JSContext
* aCx
,
4162 JS::Handle
<JS::Value
> aError
,
4163 CallerType aCallerType
,
4165 if (MOZ_UNLIKELY(!HasActiveDocument())) {
4166 return aRv
.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO
);
4169 JS::ErrorReportBuilder
jsReport(aCx
);
4170 JS::ExceptionStack
exnStack(aCx
, aError
, nullptr);
4171 if (!jsReport
.init(aCx
, exnStack
, JS::ErrorReportBuilder::NoSideEffects
)) {
4172 return aRv
.NoteJSContextException(aCx
);
4175 RefPtr
<xpc::ErrorReport
> xpcReport
= new xpc::ErrorReport();
4176 bool isChrome
= aCallerType
== CallerType::System
;
4177 xpcReport
->Init(jsReport
.report(), jsReport
.toStringResult().c_str(),
4178 isChrome
, WindowID());
4180 JS::RootingContext
* rcx
= JS::RootingContext::get(aCx
);
4181 DispatchScriptErrorEvent(this, rcx
, xpcReport
, exnStack
.exception(),
4185 void nsGlobalWindowInner::Atob(const nsAString
& aAsciiBase64String
,
4186 nsAString
& aBinaryData
, ErrorResult
& aError
) {
4187 aError
= nsContentUtils::Atob(aAsciiBase64String
, aBinaryData
);
4190 void nsGlobalWindowInner::Btoa(const nsAString
& aBinaryData
,
4191 nsAString
& aAsciiBase64String
,
4192 ErrorResult
& aError
) {
4193 aError
= nsContentUtils::Btoa(aBinaryData
, aAsciiBase64String
);
4196 //*****************************************************************************
4198 //*****************************************************************************
4200 nsPIDOMWindowOuter
* nsGlobalWindowInner::GetOwnerGlobalForBindingsInternal() {
4201 return nsPIDOMWindowOuter::GetFromCurrentInner(this);
4204 bool nsGlobalWindowInner::DispatchEvent(Event
& aEvent
, CallerType aCallerType
,
4206 if (!IsCurrentInnerWindow()) {
4208 "DispatchEvent called on non-current inner window, dropping. "
4209 "Please check the window in the caller instead.");
4210 aRv
.Throw(NS_ERROR_FAILURE
);
4215 aRv
.Throw(NS_ERROR_FAILURE
);
4219 // Obtain a presentation shell
4220 RefPtr
<nsPresContext
> presContext
= mDoc
->GetPresContext();
4222 nsEventStatus status
= nsEventStatus_eIgnore
;
4223 nsresult rv
= EventDispatcher::DispatchDOMEvent(this, nullptr, &aEvent
,
4224 presContext
, &status
);
4225 bool retval
= !aEvent
.DefaultPrevented(aCallerType
);
4226 if (NS_FAILED(rv
)) {
4232 mozilla::Maybe
<mozilla::dom::EventCallbackDebuggerNotificationType
>
4233 nsGlobalWindowInner::GetDebuggerNotificationType() const {
4234 return mozilla::Some(
4235 mozilla::dom::EventCallbackDebuggerNotificationType::Global
);
4238 bool nsGlobalWindowInner::ComputeDefaultWantsUntrusted(ErrorResult
& aRv
) {
4239 return !nsContentUtils::IsChromeDoc(mDoc
);
4242 EventListenerManager
* nsGlobalWindowInner::GetOrCreateListenerManager() {
4243 if (!mListenerManager
) {
4245 new EventListenerManager(static_cast<EventTarget
*>(this));
4248 return mListenerManager
;
4251 EventListenerManager
* nsGlobalWindowInner::GetExistingListenerManager() const {
4252 return mListenerManager
;
4255 mozilla::dom::DebuggerNotificationManager
*
4256 nsGlobalWindowInner::GetOrCreateDebuggerNotificationManager() {
4257 if (!mDebuggerNotificationManager
) {
4258 mDebuggerNotificationManager
= new DebuggerNotificationManager(this);
4261 return mDebuggerNotificationManager
;
4264 mozilla::dom::DebuggerNotificationManager
*
4265 nsGlobalWindowInner::GetExistingDebuggerNotificationManager() {
4266 return mDebuggerNotificationManager
;
4269 //*****************************************************************************
4270 // nsGlobalWindowInner::nsPIDOMWindow
4271 //*****************************************************************************
4273 Location
* nsGlobalWindowInner::Location() {
4275 mLocation
= new dom::Location(this);
4281 void nsGlobalWindowInner::MaybeUpdateTouchState() {
4282 if (mMayHaveTouchEventListener
) {
4283 nsCOMPtr
<nsIObserverService
> observerService
=
4284 services::GetObserverService();
4286 if (observerService
) {
4287 observerService
->NotifyObservers(static_cast<nsIDOMWindow
*>(this),
4288 DOM_TOUCH_LISTENER_ADDED
, nullptr);
4293 void nsGlobalWindowInner::EnableGamepadUpdates() {
4295 RefPtr
<GamepadManager
> gamepadManager(GamepadManager::GetService());
4296 if (gamepadManager
) {
4297 gamepadManager
->AddListener(this);
4302 void nsGlobalWindowInner::DisableGamepadUpdates() {
4304 RefPtr
<GamepadManager
> gamepadManager(GamepadManager::GetService());
4305 if (gamepadManager
) {
4306 gamepadManager
->RemoveListener(this);
4311 void nsGlobalWindowInner::EnableVRUpdates() {
4312 // We need to create a VREventObserver before we can either detect XR runtimes
4313 // or start an XR session
4314 if (!mVREventObserver
&& (mHasXRSession
|| mXRRuntimeDetectionInFlight
)) {
4315 // Assert that we are not creating the observer while IsDying() as
4316 // that would result in a leak. VREventObserver holds a RefPtr to
4317 // this nsGlobalWindowInner and would prevent it from being deallocated.
4318 MOZ_ASSERT(!IsDying(),
4319 "Creating a VREventObserver for an nsGlobalWindow that is "
4320 "dying would cause it to leak.");
4321 mVREventObserver
= new VREventObserver(this);
4323 // If the content has an XR session, then we need to tell
4324 // VREventObserver that there is VR activity.
4325 if (mHasXRSession
) {
4326 nsPIDOMWindowOuter
* outer
= GetOuterWindow();
4327 if (outer
&& !outer
->IsBackground()) {
4333 void nsGlobalWindowInner::DisableVRUpdates() {
4334 if (mVREventObserver
) {
4335 mVREventObserver
->DisconnectFromOwner();
4336 mVREventObserver
= nullptr;
4340 void nsGlobalWindowInner::ResetVRTelemetry(bool aUpdate
) {
4341 if (mVREventObserver
) {
4342 mVREventObserver
->UpdateSpentTimeIn2DTelemetry(aUpdate
);
4346 void nsGlobalWindowInner::StartVRActivity() {
4348 * If the content has an XR session, tell
4349 * the VREventObserver that the window is accessing
4352 * It's possible to have a VREventObserver without
4353 * and XR session, if we are using it to get updates
4354 * about XR runtime enumeration. In this case,
4355 * we would not tell the VREventObserver that
4356 * we are accessing VR devices.
4358 if (mVREventObserver
&& mHasXRSession
) {
4359 mVREventObserver
->StartActivity();
4363 void nsGlobalWindowInner::StopVRActivity() {
4365 * If the content has an XR session, tell
4366 * the VReventObserver that the window is no longer
4367 * accessing VR devices. This does not stop the
4368 * XR session itself, which may be resumed with
4370 * It's possible to have a VREventObserver without
4371 * and XR session, if we are using it to get updates
4372 * about XR runtime enumeration. In this case,
4373 * we would not tell the VREventObserver that
4374 * we ending an activity that accesses VR devices.
4376 if (mVREventObserver
&& mHasXRSession
) {
4377 mVREventObserver
->StopActivity();
4381 void nsGlobalWindowInner::SetFocusedElement(Element
* aElement
,
4382 uint32_t aFocusMethod
,
4384 if (aElement
&& aElement
->GetComposedDoc() != mDoc
) {
4385 NS_WARNING("Trying to set focus to a node from a wrong document");
4390 NS_ASSERTION(!aElement
, "Trying to focus cleaned up window!");
4392 aNeedsFocus
= false;
4394 if (mFocusedElement
!= aElement
) {
4395 UpdateCanvasFocus(false, aElement
);
4396 mFocusedElement
= aElement
;
4397 // TODO: Maybe this should be set on refocus too?
4398 mFocusMethod
= aFocusMethod
& nsIFocusManager::METHOD_MASK
;
4401 if (mFocusedElement
) {
4402 // if a node was focused by a keypress, turn on focus rings for the
4404 if (mFocusMethod
& nsIFocusManager::FLAG_BYKEY
) {
4405 mUnknownFocusMethodShouldShowOutline
= true;
4406 mFocusByKeyOccurred
= true;
4407 } else if (nsFocusManager::GetFocusMoveActionCause(mFocusMethod
) !=
4408 widget::InputContextAction::CAUSE_UNKNOWN
) {
4409 mUnknownFocusMethodShouldShowOutline
= false;
4410 } else if (aFocusMethod
& nsIFocusManager::FLAG_NOSHOWRING
) {
4411 // If we get focused via script, and script has explicitly opted out of
4412 // outlines via FLAG_NOSHOWRING, we don't want to make a refocus start
4413 // showing outlines.
4414 mUnknownFocusMethodShouldShowOutline
= false;
4419 mNeedsFocus
= aNeedsFocus
;
4423 uint32_t nsGlobalWindowInner::GetFocusMethod() { return mFocusMethod
; }
4425 bool nsGlobalWindowInner::ShouldShowFocusRing() {
4426 if (mFocusByKeyOccurred
&&
4427 StaticPrefs::browser_display_always_show_rings_after_key_focus()) {
4430 return StaticPrefs::browser_display_show_focus_rings();
4433 bool nsGlobalWindowInner::TakeFocus(bool aFocus
, uint32_t aFocusMethod
) {
4439 mFocusMethod
= aFocusMethod
& nsIFocusManager::METHOD_MASK
;
4442 if (mHasFocus
!= aFocus
) {
4444 UpdateCanvasFocus(true, mFocusedElement
);
4447 // if mNeedsFocus is true, then the document has not yet received a
4448 // document-level focus event. If there is a root content node, then return
4449 // true to tell the calling focus manager that a focus event is expected. If
4450 // there is no root content node, the document hasn't loaded enough yet, or
4451 // there isn't one and there is no point in firing a focus event.
4452 if (aFocus
&& mNeedsFocus
&& mDoc
&& mDoc
->GetRootElement() != nullptr) {
4453 mNeedsFocus
= false;
4457 mNeedsFocus
= false;
4461 void nsGlobalWindowInner::SetReadyForFocus() {
4462 bool oldNeedsFocus
= mNeedsFocus
;
4463 mNeedsFocus
= false;
4465 if (RefPtr
<nsFocusManager
> fm
= nsFocusManager::GetFocusManager()) {
4466 nsCOMPtr
<nsPIDOMWindowOuter
> outerWindow
= GetOuterWindow();
4467 fm
->WindowShown(outerWindow
, oldNeedsFocus
);
4471 void nsGlobalWindowInner::PageHidden() {
4472 // the window is being hidden, so tell the focus manager that the frame is
4473 // no longer valid. Use the persisted field to determine if the document
4474 // is being destroyed.
4476 if (RefPtr
<nsFocusManager
> fm
= nsFocusManager::GetFocusManager()) {
4477 nsCOMPtr
<nsPIDOMWindowOuter
> outerWindow
= GetOuterWindow();
4478 fm
->WindowHidden(outerWindow
, nsFocusManager::GenerateFocusActionId());
4484 class HashchangeCallback
: public Runnable
{
4486 HashchangeCallback(const nsAString
& aOldURL
, const nsAString
& aNewURL
,
4487 nsGlobalWindowInner
* aWindow
)
4488 : mozilla::Runnable("HashchangeCallback"), mWindow(aWindow
) {
4489 MOZ_ASSERT(mWindow
);
4490 mOldURL
.Assign(aOldURL
);
4491 mNewURL
.Assign(aNewURL
);
4494 NS_IMETHOD
Run() override
{
4495 MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread.");
4496 return mWindow
->FireHashchange(mOldURL
, mNewURL
);
4502 RefPtr
<nsGlobalWindowInner
> mWindow
;
4505 nsresult
nsGlobalWindowInner::DispatchAsyncHashchange(nsIURI
* aOldURI
,
4507 // Make sure that aOldURI and aNewURI are identical up to the '#', and that
4508 // their hashes are different.
4510 NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI
->EqualsExceptRef(aNewURI
, &equal
)) &&
4512 nsAutoCString oldHash
, newHash
;
4513 bool oldHasHash
, newHasHash
;
4514 NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI
->GetRef(oldHash
)) &&
4515 NS_SUCCEEDED(aNewURI
->GetRef(newHash
)) &&
4516 NS_SUCCEEDED(aOldURI
->GetHasRef(&oldHasHash
)) &&
4517 NS_SUCCEEDED(aNewURI
->GetHasRef(&newHasHash
)) &&
4518 (oldHasHash
!= newHasHash
|| !oldHash
.Equals(newHash
)));
4520 nsAutoCString oldSpec
, newSpec
;
4521 nsresult rv
= aOldURI
->GetSpec(oldSpec
);
4522 NS_ENSURE_SUCCESS(rv
, rv
);
4523 rv
= aNewURI
->GetSpec(newSpec
);
4524 NS_ENSURE_SUCCESS(rv
, rv
);
4526 NS_ConvertUTF8toUTF16
oldWideSpec(oldSpec
);
4527 NS_ConvertUTF8toUTF16
newWideSpec(newSpec
);
4529 nsCOMPtr
<nsIRunnable
> callback
=
4530 new HashchangeCallback(oldWideSpec
, newWideSpec
, this);
4531 return Dispatch(callback
.forget());
4534 nsresult
nsGlobalWindowInner::FireHashchange(const nsAString
& aOldURL
,
4535 const nsAString
& aNewURL
) {
4536 // Don't do anything if the window is frozen.
4541 // Get a presentation shell for use in creating the hashchange event.
4542 NS_ENSURE_STATE(IsCurrentInnerWindow());
4544 HashChangeEventInit init
;
4545 init
.mNewURL
= aNewURL
;
4546 init
.mOldURL
= aOldURL
;
4548 RefPtr
<HashChangeEvent
> event
=
4549 HashChangeEvent::Constructor(this, u
"hashchange"_ns
, init
);
4551 event
->SetTrusted(true);
4554 DispatchEvent(*event
, rv
);
4555 return rv
.StealNSResult();
4558 nsresult
nsGlobalWindowInner::DispatchSyncPopState() {
4559 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
4560 "Must be safe to run script here.");
4562 // Bail if the window is frozen.
4568 bool result
= jsapi
.Init(this);
4569 NS_ENSURE_TRUE(result
, NS_ERROR_FAILURE
);
4571 JSContext
* cx
= jsapi
.cx();
4573 // Get the document's pending state object -- it contains the data we're
4574 // going to send along with the popstate event. The object is serialized
4575 // using structured clone.
4576 JS::Rooted
<JS::Value
> stateJSValue(cx
);
4577 nsresult rv
= mDoc
->GetStateObject(&stateJSValue
);
4578 NS_ENSURE_SUCCESS(rv
, rv
);
4580 if (!JS_WrapValue(cx
, &stateJSValue
)) {
4581 return NS_ERROR_OUT_OF_MEMORY
;
4584 RootedDictionary
<PopStateEventInit
> init(cx
);
4585 init
.mState
= stateJSValue
;
4587 RefPtr
<PopStateEvent
> event
=
4588 PopStateEvent::Constructor(this, u
"popstate"_ns
, init
);
4589 event
->SetTrusted(true);
4590 event
->SetTarget(this);
4593 DispatchEvent(*event
, err
);
4594 return err
.StealNSResult();
4597 //-------------------------------------------------------
4598 // Tells the HTMLFrame/CanvasFrame that is now has focus
4599 void nsGlobalWindowInner::UpdateCanvasFocus(bool aFocusChanged
,
4600 nsIContent
* aNewContent
) {
4601 // this is called from the inner window so use GetDocShell
4602 nsIDocShell
* docShell
= GetDocShell();
4603 if (!docShell
) return;
4606 docShell
->GetEditable(&editable
);
4607 if (editable
) return;
4609 PresShell
* presShell
= docShell
->GetPresShell();
4610 if (!presShell
|| !mDoc
) {
4614 Element
* rootElement
= mDoc
->GetRootElement();
4616 if ((mHasFocus
|| aFocusChanged
) &&
4617 (mFocusedElement
== rootElement
|| aNewContent
== rootElement
)) {
4618 nsCanvasFrame
* canvasFrame
= presShell
->GetCanvasFrame();
4620 canvasFrame
->SetHasFocus(mHasFocus
&& rootElement
== aNewContent
);
4624 // XXXbz I would expect that there is never a canvasFrame in this case...
4625 nsCanvasFrame
* canvasFrame
= presShell
->GetCanvasFrame();
4627 canvasFrame
->SetHasFocus(false);
4632 already_AddRefed
<nsICSSDeclaration
> nsGlobalWindowInner::GetComputedStyle(
4633 Element
& aElt
, const nsAString
& aPseudoElt
, ErrorResult
& aError
) {
4634 return GetComputedStyleHelper(aElt
, aPseudoElt
, false, aError
);
4637 already_AddRefed
<nsICSSDeclaration
>
4638 nsGlobalWindowInner::GetDefaultComputedStyle(Element
& aElt
,
4639 const nsAString
& aPseudoElt
,
4640 ErrorResult
& aError
) {
4641 return GetComputedStyleHelper(aElt
, aPseudoElt
, true, aError
);
4644 already_AddRefed
<nsICSSDeclaration
> nsGlobalWindowInner::GetComputedStyleHelper(
4645 Element
& aElt
, const nsAString
& aPseudoElt
, bool aDefaultStylesOnly
,
4646 ErrorResult
& aError
) {
4647 FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelperOuter
,
4648 (aElt
, aPseudoElt
, aDefaultStylesOnly
, aError
),
4652 void nsGlobalWindowInner::MaybeNotifyStorageKeyUsed() {
4653 // Only notify once per window lifetime.
4654 if (hasNotifiedStorageKeyUsed
) {
4658 BounceTrackingStorageObserver::OnInitialStorageAccess(GetWindowContext());
4659 if (NS_WARN_IF(NS_FAILED(rv
))) {
4662 hasNotifiedStorageKeyUsed
= true;
4665 Storage
* nsGlobalWindowInner::GetSessionStorage(ErrorResult
& aError
) {
4666 nsIPrincipal
* principal
= GetPrincipal();
4667 nsIPrincipal
* storagePrincipal
;
4669 privacy_partition_always_partition_third_party_non_cookie_storage_exempt_sessionstorage()) {
4670 storagePrincipal
= GetEffectiveCookiePrincipal();
4672 storagePrincipal
= GetEffectiveStoragePrincipal();
4674 BrowsingContext
* browsingContext
= GetBrowsingContext();
4676 if (!principal
|| !storagePrincipal
|| !browsingContext
||
4677 !Storage::StoragePrefIsEnabled()) {
4681 if (mSessionStorage
) {
4682 MOZ_LOG(gDOMLeakPRLogInner
, LogLevel::Debug
,
4683 ("nsGlobalWindowInner %p has %p sessionStorage", this,
4684 mSessionStorage
.get()));
4686 principal
->Subsumes(mSessionStorage
->Principal()) &&
4687 storagePrincipal
->Subsumes(mSessionStorage
->StoragePrincipal());
4689 mSessionStorage
= nullptr;
4693 if (!mSessionStorage
) {
4694 nsString documentURI
;
4696 aError
= mDoc
->GetDocumentURI(documentURI
);
4697 if (NS_WARN_IF(aError
.Failed())) {
4703 aError
.Throw(NS_ERROR_FAILURE
);
4707 // If the document's sandboxed origin flag is set, then accessing
4708 // sessionStorage is prohibited.
4709 if (mDoc
->GetSandboxFlags() & SANDBOXED_ORIGIN
) {
4710 aError
.ThrowSecurityError(
4711 "Forbidden in a sandboxed document without the 'allow-same-origin' "
4716 uint32_t rejectedReason
= 0;
4717 StorageAccess access
= StorageAllowedForWindow(this, &rejectedReason
);
4719 // SessionStorage is an ephemeral per-tab per-origin storage that only lives
4720 // as long as the tab is open, although it may survive browser restarts
4721 // thanks to the session store. So we interpret storage access differently
4722 // than we would for persistent per-origin storage like LocalStorage and so
4723 // it may be okay to provide SessionStorage even when we receive a value of
4726 // ContentBlocking::ShouldAllowAccessFor will return false for 3 main
4729 // 1. Cookies are entirely blocked due to a per-origin permission
4730 // (nsICookiePermission::ACCESS_DENY for the top-level principal or this
4731 // window's principal) or the very broad BEHAVIOR_REJECT. This will return
4732 // eDeny with a reason of STATE_COOKIES_BLOCKED_BY_PERMISSION or
4733 // STATE_COOKIES_BLOCKED_ALL.
4735 // 2. Third-party cookies are limited via BEHAVIOR_REJECT_FOREIGN and
4736 // BEHAVIOR_LIMIT_FOREIGN and this is a third-party window. This will return
4737 // eDeny with a reason of STATE_COOKIES_BLOCKED_FOREIGN.
4739 // 3. Tracking protection (BEHAVIOR_REJECT_TRACKER and
4740 // BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) is in effect and
4741 // IsThirdPartyTrackingResourceWindow() returned true and there wasn't a
4742 // permission that allows it. This will return ePartitionTrackersOrDeny with
4743 // a reason of STATE_COOKIES_BLOCKED_TRACKER or
4744 // STATE_COOKIES_BLOCKED_SOCIALTRACKER.
4746 // In the 1st case, the user has explicitly indicated that they don't want
4747 // to allow any storage to the origin or all origins and so we throw an
4748 // error and deny access to SessionStorage. In the 2nd case, a legacy
4749 // decision reasoned that there's no harm in providing SessionStorage
4750 // because the information is not durable and cannot escape the current tab.
4751 // The rationale is similar for the 3rd case.
4752 if (access
== StorageAccess::eDeny
&&
4754 nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN
) {
4755 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
4759 const RefPtr
<SessionStorageManager
> storageManager
=
4760 browsingContext
->GetSessionStorageManager();
4761 if (!storageManager
) {
4762 aError
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
4766 RefPtr
<Storage
> storage
;
4767 aError
= storageManager
->CreateStorage(this, principal
, storagePrincipal
,
4768 documentURI
, IsPrivateBrowsing(),
4769 getter_AddRefs(storage
));
4770 if (aError
.Failed()) {
4774 mSessionStorage
= storage
;
4775 MOZ_ASSERT(mSessionStorage
);
4777 MOZ_LOG(gDOMLeakPRLogInner
, LogLevel::Debug
,
4778 ("nsGlobalWindowInner %p tried to get a new sessionStorage %p",
4779 this, mSessionStorage
.get()));
4781 if (!mSessionStorage
) {
4782 aError
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
4787 MaybeNotifyStorageKeyUsed();
4789 MOZ_LOG(gDOMLeakPRLogInner
, LogLevel::Debug
,
4790 ("nsGlobalWindowInner %p returns %p sessionStorage", this,
4791 mSessionStorage
.get()));
4793 return mSessionStorage
;
4796 Storage
* nsGlobalWindowInner::GetLocalStorage(ErrorResult
& aError
) {
4797 if (!Storage::StoragePrefIsEnabled()) {
4801 // If the document's sandboxed origin flag is set, then accessing localStorage
4803 if (mDoc
&& mDoc
->GetSandboxFlags() & SANDBOXED_ORIGIN
) {
4804 aError
.ThrowSecurityError(
4805 "Forbidden in a sandboxed document without the 'allow-same-origin' "
4810 // LocalStorage needs to be exposed in every context except for sandboxes and
4811 // NullPrincipals (data: URLs, for instance). But we need to keep data
4812 // separate in some scenarios: private-browsing and partitioned trackers.
4813 // In private-browsing, LocalStorage keeps data in memory, and it shares
4814 // StorageEvents just with other origins in the same private-browsing
4816 // For Partitioned Trackers, we expose a partitioned LocalStorage, which
4817 // doesn't share data with other contexts, and it's just in memory.
4818 // Partitioned localStorage is available only for trackers listed in the
4819 // privacy.restrict3rdpartystorage.partitionedHosts pref. See
4820 // nsContentUtils::IsURIInPrefList to know the syntax for the pref value.
4821 // This is a temporary web-compatibility hack.
4823 StorageAccess access
= StorageAllowedForWindow(this);
4825 // We allow partitioned localStorage only to some hosts.
4826 bool isolated
= false;
4827 if (ShouldPartitionStorage(access
)) {
4829 access
= StorageAccess::eDeny
;
4830 } else if (!StoragePartitioningEnabled(access
, mDoc
->CookieJarSettings())) {
4831 static const char* kPrefName
=
4832 "privacy.restrict3rdpartystorage.partitionedHosts";
4834 bool isInList
= false;
4835 mDoc
->NodePrincipal()->IsURIInPrefList(kPrefName
, &isInList
);
4837 access
= StorageAccess::eDeny
;
4844 if (access
== StorageAccess::eDeny
) {
4845 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
4849 nsCOMPtr
<nsICookieJarSettings
> cookieJarSettings
;
4851 cookieJarSettings
= mDoc
->CookieJarSettings();
4853 cookieJarSettings
= net::CookieJarSettings::GetBlockingAll(
4854 ShouldResistFingerprinting(RFPTarget::IsAlwaysEnabledForPrecompute
));
4857 // Note that this behavior is observable: if we grant storage permission to a
4858 // tracker, we pass from the partitioned LocalStorage (or a partitioned cookie
4859 // jar) to the 'normal' one. The previous data is lost and the 2
4860 // window.localStorage objects, before and after the permission granted, will
4862 if (mLocalStorage
) {
4863 if ((mLocalStorage
->Type() == (isolated
? Storage::ePartitionedLocalStorage
4864 : Storage::eLocalStorage
)) &&
4865 (mLocalStorage
->StoragePrincipal() == GetEffectiveStoragePrincipal())) {
4866 return mLocalStorage
;
4869 // storage needs change
4870 mLocalStorage
= nullptr;
4873 MOZ_ASSERT(!mLocalStorage
);
4876 RefPtr
<Storage
> storage
;
4878 if (NextGenLocalStorageEnabled()) {
4879 aError
= LSObject::CreateForWindow(this, getter_AddRefs(storage
));
4882 nsCOMPtr
<nsIDOMStorageManager
> storageManager
=
4883 do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv
);
4884 if (NS_FAILED(rv
)) {
4889 nsString documentURI
;
4891 aError
= mDoc
->GetDocumentURI(documentURI
);
4892 if (NS_WARN_IF(aError
.Failed())) {
4897 nsIPrincipal
* principal
= GetPrincipal();
4899 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
4903 nsIPrincipal
* storagePrincipal
= GetEffectiveStoragePrincipal();
4904 if (!storagePrincipal
) {
4905 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
4909 aError
= storageManager
->CreateStorage(this, principal
, storagePrincipal
,
4910 documentURI
, IsPrivateBrowsing(),
4911 getter_AddRefs(storage
));
4914 if (aError
.Failed()) {
4918 mLocalStorage
= storage
;
4921 nsCOMPtr
<nsIDOMSessionStorageManager
> storageManager
=
4922 do_GetService("@mozilla.org/dom/sessionStorage-manager;1", &rv
);
4923 if (NS_FAILED(rv
)) {
4928 nsIPrincipal
* principal
= GetPrincipal();
4930 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
4934 nsIPrincipal
* storagePrincipal
= GetEffectiveStoragePrincipal();
4935 if (!storagePrincipal
) {
4936 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
4940 RefPtr
<SessionStorageCache
> cache
;
4942 cache
= new SessionStorageCache();
4944 // This will clone the session storage if it exists.
4945 rv
= storageManager
->GetSessionStorageCache(principal
, storagePrincipal
,
4947 if (NS_FAILED(rv
)) {
4954 new PartitionedLocalStorage(this, principal
, storagePrincipal
, cache
);
4957 MaybeNotifyStorageKeyUsed();
4959 MOZ_ASSERT(mLocalStorage
);
4961 mLocalStorage
->Type() ==
4962 (isolated
? Storage::ePartitionedLocalStorage
: Storage::eLocalStorage
));
4963 return mLocalStorage
;
4966 IDBFactory
* nsGlobalWindowInner::GetIndexedDB(JSContext
* aCx
,
4967 ErrorResult
& aError
) {
4969 // This may keep mIndexedDB null without setting an error.
4970 auto res
= IDBFactory::CreateForWindow(this);
4972 aError
= res
.unwrapErr();
4974 mIndexedDB
= res
.unwrap();
4978 MaybeNotifyStorageKeyUsed();
4983 //*****************************************************************************
4984 // nsGlobalWindowInner::nsIInterfaceRequestor
4985 //*****************************************************************************
4988 nsGlobalWindowInner::GetInterface(const nsIID
& aIID
, void** aSink
) {
4989 nsGlobalWindowOuter
* outer
= GetOuterWindowInternal();
4990 NS_ENSURE_TRUE(outer
, NS_ERROR_NOT_INITIALIZED
);
4992 nsresult rv
= outer
->GetInterfaceInternal(aIID
, aSink
);
4993 if (rv
== NS_ERROR_NO_INTERFACE
) {
4994 return QueryInterface(aIID
, aSink
);
4999 void nsGlobalWindowInner::GetInterface(JSContext
* aCx
,
5000 JS::Handle
<JS::Value
> aIID
,
5001 JS::MutableHandle
<JS::Value
> aRetval
,
5002 ErrorResult
& aError
) {
5003 dom::GetInterface(aCx
, this, aIID
, aRetval
, aError
);
5006 already_AddRefed
<CacheStorage
> nsGlobalWindowInner::GetCaches(
5008 if (!mCacheStorage
) {
5009 bool forceTrustedOrigin
=
5010 GetBrowsingContext() &&
5011 GetBrowsingContext()->Top()->GetServiceWorkersTestingEnabled();
5012 mCacheStorage
= CacheStorage::CreateOnMainThread(
5013 cache::DEFAULT_NAMESPACE
, this, GetEffectiveStoragePrincipal(),
5014 forceTrustedOrigin
, aRv
);
5017 RefPtr
<CacheStorage
> ref
= mCacheStorage
;
5018 return ref
.forget();
5021 void nsGlobalWindowInner::FireOfflineStatusEventIfChanged() {
5022 if (!IsCurrentInnerWindow()) return;
5024 // Don't fire an event if the status hasn't changed
5025 if (mWasOffline
== NS_IsOffline()) {
5029 mWasOffline
= !mWasOffline
;
5033 name
.AssignLiteral("offline");
5035 name
.AssignLiteral("online");
5037 nsContentUtils::DispatchTrustedEvent(mDoc
, this, name
, CanBubble::eNo
,
5041 nsGlobalWindowInner::SlowScriptResponse
5042 nsGlobalWindowInner::ShowSlowScriptDialog(JSContext
* aCx
,
5043 const nsString
& aAddonId
,
5044 const double aDuration
) {
5047 if (Preferences::GetBool("dom.always_stop_slow_scripts")) {
5048 return KillSlowScript
;
5051 // If it isn't safe to run script, then it isn't safe to bring up the prompt
5052 // (since that spins the event loop). In that (rare) case, we just kill the
5053 // script and report a warning.
5054 if (!nsContentUtils::IsSafeToRunScript()) {
5055 JS::WarnASCII(aCx
, "A long running script was terminated");
5056 return KillSlowScript
;
5059 // If our document is not active, just kill the script: we've been unloaded
5060 if (!HasActiveDocument()) {
5061 return KillSlowScript
;
5064 // Check if we should offer the option to debug
5065 JS::AutoFilename filename
;
5067 // Computing the line number can be very expensive (see bug 1330231 for
5068 // example), and we don't use the line number anywhere except than in the
5069 // parent process, so we avoid computing it elsewhere. This gives us most of
5070 // the wins we are interested in, since the source of the slowness here is
5071 // minified scripts which is more common in Web content that is loaded in the
5073 uint32_t* linenop
= XRE_IsParentProcess() ? &lineno
: nullptr;
5074 bool hasFrame
= JS::DescribeScriptedCaller(aCx
, &filename
, linenop
);
5076 // Record the slow script event if we haven't done so already for this inner
5077 // window (which represents a particular page to the user).
5078 if (!mHasHadSlowScript
) {
5079 Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT
, 1);
5081 mHasHadSlowScript
= true;
5083 // Override the cursor to something that we're sure the user can see.
5084 SetCursor("auto"_ns
, IgnoreErrors());
5086 if (XRE_IsContentProcess() && ProcessHangMonitor::Get()) {
5087 ProcessHangMonitor::SlowScriptAction action
;
5088 RefPtr
<ProcessHangMonitor
> monitor
= ProcessHangMonitor::Get();
5089 nsIDocShell
* docShell
= GetDocShell();
5090 nsCOMPtr
<nsIBrowserChild
> child
=
5091 docShell
? docShell
->GetBrowserChild() : nullptr;
5093 monitor
->NotifySlowScript(child
, filename
.get(), aAddonId
, aDuration
);
5094 if (action
== ProcessHangMonitor::Terminate
) {
5095 return KillSlowScript
;
5098 if (action
== ProcessHangMonitor::StartDebugger
) {
5099 // Spin a nested event loop so that the debugger in the parent can fetch
5100 // any information it needs. Once the debugger has started, return to the
5102 RefPtr
<nsGlobalWindowOuter
> outer
= GetOuterWindowInternal();
5103 outer
->EnterModalState();
5104 SpinEventLoopUntil("nsGlobalWindowInner::ShowSlowScriptDialog"_ns
, [&]() {
5105 return monitor
->IsDebuggerStartupComplete();
5107 outer
->LeaveModalState();
5108 return ContinueSlowScript
;
5111 return ContinueSlowScriptAndKeepNotifying
;
5114 // Reached only on non-e10s - once per slow script dialog.
5115 // On e10s - we probe once at ProcessHangsMonitor.sys.mjs
5116 Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTICE_COUNT
, 1);
5118 // Get the nsIPrompt interface from the docshell
5119 nsCOMPtr
<nsIDocShell
> ds
= GetDocShell();
5120 NS_ENSURE_TRUE(ds
, KillSlowScript
);
5121 nsCOMPtr
<nsIPrompt
> prompt
= do_GetInterface(ds
);
5122 NS_ENSURE_TRUE(prompt
, KillSlowScript
);
5124 // Prioritize the SlowScriptDebug interface over JSD1.
5125 nsCOMPtr
<nsISlowScriptDebugCallback
> debugCallback
;
5128 const char* debugCID
= "@mozilla.org/dom/slow-script-debug;1";
5129 nsCOMPtr
<nsISlowScriptDebug
> debugService
= do_GetService(debugCID
, &rv
);
5130 if (NS_SUCCEEDED(rv
)) {
5131 debugService
->GetActivationHandler(getter_AddRefs(debugCallback
));
5135 bool failed
= false;
5136 auto getString
= [&](const char* name
,
5137 nsContentUtils::PropertiesFile propFile
=
5138 nsContentUtils::eDOM_PROPERTIES
) {
5139 nsAutoString result
;
5140 nsresult rv
= nsContentUtils::GetLocalizedString(propFile
, name
, result
);
5142 // GetStringFromName can return NS_OK and still give nullptr string
5143 failed
= failed
|| NS_FAILED(rv
) || result
.IsEmpty();
5147 bool isAddonScript
= !aAddonId
.IsEmpty();
5148 bool showDebugButton
= debugCallback
&& !isAddonScript
;
5150 // Get localizable strings
5152 nsAutoString title
, checkboxMsg
, debugButton
, msg
;
5153 if (isAddonScript
) {
5154 title
= getString("KillAddonScriptTitle");
5155 checkboxMsg
= getString("KillAddonScriptGlobalMessage");
5158 getString("brandShortName", nsContentUtils::eBRAND_PROPERTIES
);
5160 nsCOMPtr
<nsIAddonPolicyService
> aps
=
5161 do_GetService("@mozilla.org/addons/policy-service;1");
5163 if (!aps
|| NS_FAILED(aps
->GetExtensionName(aAddonId
, addonName
))) {
5164 addonName
= aAddonId
;
5167 rv
= nsContentUtils::FormatLocalizedString(
5168 msg
, nsContentUtils::eDOM_PROPERTIES
, "KillAddonScriptMessage",
5169 addonName
, appName
);
5171 failed
= failed
|| NS_FAILED(rv
);
5173 title
= getString("KillScriptTitle");
5174 checkboxMsg
= getString("DontAskAgain");
5176 if (showDebugButton
) {
5177 debugButton
= getString("DebugScriptButton");
5178 msg
= getString("KillScriptWithDebugMessage");
5180 msg
= getString("KillScriptMessage");
5184 auto stopButton
= getString("StopScriptButton");
5185 auto waitButton
= getString("WaitForScriptButton");
5188 NS_ERROR("Failed to get localized strings.");
5189 return ContinueSlowScript
;
5192 // Append file and line number information, if available
5193 if (filename
.get()) {
5194 nsAutoString scriptLocation
;
5195 // We want to drop the middle part of too-long locations. We'll
5196 // define "too-long" as longer than 60 UTF-16 code units. Just
5197 // have to be a bit careful about unpaired surrogates.
5198 NS_ConvertUTF8toUTF16
filenameUTF16(filename
.get());
5199 if (filenameUTF16
.Length() > 60) {
5200 // XXXbz Do we need to insert any bidi overrides here?
5201 size_t cutStart
= 30;
5202 size_t cutLength
= filenameUTF16
.Length() - 60;
5203 MOZ_ASSERT(cutLength
> 0);
5204 if (NS_IS_LOW_SURROGATE(filenameUTF16
[cutStart
])) {
5205 // Don't truncate before the low surrogate, in case it's preceded by a
5206 // high surrogate and forms a single Unicode character. Instead, just
5207 // include the low surrogate.
5211 if (NS_IS_LOW_SURROGATE(filenameUTF16
[cutStart
+ cutLength
])) {
5212 // Likewise, don't drop a trailing low surrogate here. We want to
5213 // increase cutLength, since it might be 0 already so we can't very well
5218 // Insert U+2026 HORIZONTAL ELLIPSIS
5219 filenameUTF16
.ReplaceLiteral(cutStart
, cutLength
, u
"\x2026");
5221 rv
= nsContentUtils::FormatLocalizedString(
5222 scriptLocation
, nsContentUtils::eDOM_PROPERTIES
, "KillScriptLocation",
5225 if (NS_SUCCEEDED(rv
)) {
5226 msg
.AppendLiteral("\n\n");
5227 msg
.Append(scriptLocation
);
5229 msg
.AppendInt(lineno
);
5233 uint32_t buttonFlags
= nsIPrompt::BUTTON_POS_1_DEFAULT
+
5234 (nsIPrompt::BUTTON_TITLE_IS_STRING
*
5235 (nsIPrompt::BUTTON_POS_0
+ nsIPrompt::BUTTON_POS_1
));
5237 // Add a third button if necessary.
5238 if (showDebugButton
)
5239 buttonFlags
+= nsIPrompt::BUTTON_TITLE_IS_STRING
* nsIPrompt::BUTTON_POS_2
;
5241 bool checkboxValue
= false;
5242 int32_t buttonPressed
= 0; // In case the user exits dialog by clicking X.
5244 // Null out the operation callback while we're re-entering JS here.
5245 AutoDisableJSInterruptCallback
disabler(aCx
);
5248 rv
= prompt
->ConfirmEx(
5249 title
.get(), msg
.get(), buttonFlags
, waitButton
.get(), stopButton
.get(),
5250 debugButton
.get(), checkboxMsg
.get(), &checkboxValue
, &buttonPressed
);
5253 if (buttonPressed
== 0) {
5254 if (checkboxValue
&& !isAddonScript
&& NS_SUCCEEDED(rv
))
5255 return AlwaysContinueSlowScript
;
5256 return ContinueSlowScript
;
5259 if (buttonPressed
== 2) {
5260 MOZ_RELEASE_ASSERT(debugCallback
);
5262 rv
= debugCallback
->HandleSlowScriptDebug(this);
5263 return NS_SUCCEEDED(rv
) ? ContinueSlowScript
: KillSlowScript
;
5266 JS_ClearPendingException(aCx
);
5268 return KillSlowScript
;
5271 nsresult
nsGlobalWindowInner::Observe(nsISupports
* aSubject
, const char* aTopic
,
5272 const char16_t
* aData
) {
5273 if (!nsCRT::strcmp(aTopic
, NS_IOSERVICE_OFFLINE_STATUS_TOPIC
)) {
5275 // Fires an offline status event if the offline status has changed
5276 FireOfflineStatusEventIfChanged();
5281 if (!nsCRT::strcmp(aTopic
, MEMORY_PRESSURE_OBSERVER_TOPIC
)) {
5283 mPerformance
->MemoryPressure();
5285 RemoveReportRecords();
5289 if (!nsCRT::strcmp(aTopic
, PERMISSION_CHANGED_TOPIC
)) {
5290 nsCOMPtr
<nsIPermission
> perm(do_QueryInterface(aSubject
));
5292 // A null permission indicates that the entire permission list
5294 MOZ_ASSERT(!nsCRT::strcmp(aData
, u
"cleared"));
5295 UpdatePermissions();
5300 perm
->GetType(type
);
5301 if (type
== "autoplay-media"_ns
) {
5302 UpdateAutoplayPermission();
5303 } else if (type
== "shortcuts"_ns
) {
5304 UpdateShortcutsPermission();
5305 } else if (type
== "popup"_ns
) {
5306 UpdatePopupPermission();
5313 RefPtr
<PermissionDelegateHandler
> permDelegateHandler
=
5314 mDoc
->GetPermissionDelegateHandler();
5316 if (permDelegateHandler
) {
5317 permDelegateHandler
->UpdateDelegatedPermission(type
);
5323 if (!nsCRT::strcmp(aTopic
, "screen-information-changed")) {
5325 if (RefPtr
<ScreenOrientation
> orientation
=
5326 mScreen
->GetOrientationIfExists()) {
5327 orientation
->MaybeChanged();
5330 if (mHasOrientationChangeListeners
) {
5331 int32_t oldAngle
= mOrientationAngle
;
5332 mOrientationAngle
= Orientation(CallerType::System
);
5333 if (mOrientationAngle
!= oldAngle
&& IsCurrentInnerWindow()) {
5334 nsCOMPtr
<nsPIDOMWindowOuter
> outer
= GetOuterWindow();
5335 outer
->DispatchCustomEvent(u
"orientationchange"_ns
);
5341 if (!nsCRT::strcmp(aTopic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
)) {
5342 MOZ_ASSERT(!NS_strcmp(aData
, u
"intl.accept_languages"));
5344 // The user preferred languages have changed, we need to fire an event on
5345 // Window object and invalidate the cache for navigator.languages. It is
5346 // done for every change which can be a waste of cycles but those should be
5348 // We MUST invalidate navigator.languages before sending the event in the
5349 // very likely situation where an event handler will try to read its value.
5352 Navigator_Binding::ClearCachedLanguageValue(mNavigator
);
5353 Navigator_Binding::ClearCachedLanguagesValue(mNavigator
);
5356 // The event has to be dispatched only to the current inner window.
5357 if (!IsCurrentInnerWindow()) {
5361 RefPtr
<Event
> event
= NS_NewDOMEvent(this, nullptr, nullptr);
5362 event
->InitEvent(u
"languagechange"_ns
, false, false);
5363 event
->SetTrusted(true);
5366 DispatchEvent(*event
, rv
);
5367 return rv
.StealNSResult();
5370 NS_WARNING("unrecognized topic in nsGlobalWindowInner::Observe");
5371 return NS_ERROR_FAILURE
;
5374 void nsGlobalWindowInner::ObserveStorageNotification(
5375 StorageEvent
* aEvent
, const char16_t
* aStorageType
, bool aPrivateBrowsing
) {
5378 // The private browsing check must be done here again because this window
5379 // could have changed its state before the notification check and now. This
5380 // happens in case this window did have a docShell at that time.
5381 if (aPrivateBrowsing
!= IsPrivateBrowsing()) {
5385 // LocalStorage can only exist on an inner window, and we don't want to
5386 // generate events on frozen or otherwise-navigated-away from windows.
5387 // (Actually, this code used to try and buffer events for frozen windows,
5388 // but it never worked, so we've removed it. See bug 1285898.)
5389 if (!IsCurrentInnerWindow() || IsFrozen()) {
5393 nsIPrincipal
* principal
= GetPrincipal();
5398 bool fireMozStorageChanged
= false;
5399 nsAutoString eventType
;
5400 eventType
.AssignLiteral("storage");
5402 if (!NS_strcmp(aStorageType
, u
"sessionStorage")) {
5403 RefPtr
<Storage
> changingStorage
= aEvent
->GetStorageArea();
5404 MOZ_ASSERT(changingStorage
);
5408 if (const RefPtr
<SessionStorageManager
> storageManager
=
5409 GetBrowsingContext()->GetSessionStorageManager()) {
5410 nsresult rv
= storageManager
->CheckStorage(GetEffectiveStoragePrincipal(),
5411 changingStorage
, &check
);
5412 if (NS_FAILED(rv
)) {
5418 // This storage event is not coming from our storage or is coming
5419 // from a different docshell, i.e. it is a clone, ignore this event.
5424 gDOMLeakPRLogInner
, LogLevel::Debug
,
5425 ("nsGlobalWindowInner %p with sessionStorage %p passing event from %p",
5426 this, mSessionStorage
.get(), changingStorage
.get()));
5428 fireMozStorageChanged
= mSessionStorage
== changingStorage
;
5429 if (fireMozStorageChanged
) {
5430 eventType
.AssignLiteral("MozSessionStorageChanged");
5435 MOZ_ASSERT(!NS_strcmp(aStorageType
, u
"localStorage"));
5437 nsIPrincipal
* storagePrincipal
= GetEffectiveStoragePrincipal();
5438 if (!storagePrincipal
) {
5442 MOZ_DIAGNOSTIC_ASSERT(StorageUtils::PrincipalsEqual(aEvent
->GetPrincipal(),
5445 fireMozStorageChanged
=
5446 mLocalStorage
&& mLocalStorage
== aEvent
->GetStorageArea();
5448 if (fireMozStorageChanged
) {
5449 eventType
.AssignLiteral("MozLocalStorageChanged");
5453 // Clone the storage event included in the observer notification. We want
5454 // to dispatch clones rather than the original event.
5455 IgnoredErrorResult error
;
5456 RefPtr
<StorageEvent
> clonedEvent
=
5457 CloneStorageEvent(eventType
, aEvent
, error
);
5458 if (error
.Failed() || !clonedEvent
) {
5462 clonedEvent
->SetTrusted(true);
5464 if (fireMozStorageChanged
) {
5465 WidgetEvent
* internalEvent
= clonedEvent
->WidgetEventPtr();
5466 internalEvent
->mFlags
.mOnlyChromeDispatch
= true;
5469 DispatchEvent(*clonedEvent
);
5472 already_AddRefed
<StorageEvent
> nsGlobalWindowInner::CloneStorageEvent(
5473 const nsAString
& aType
, const RefPtr
<StorageEvent
>& aEvent
,
5475 StorageEventInit dict
;
5477 dict
.mBubbles
= aEvent
->Bubbles();
5478 dict
.mCancelable
= aEvent
->Cancelable();
5479 aEvent
->GetKey(dict
.mKey
);
5480 aEvent
->GetOldValue(dict
.mOldValue
);
5481 aEvent
->GetNewValue(dict
.mNewValue
);
5482 aEvent
->GetUrl(dict
.mUrl
);
5484 RefPtr
<Storage
> storageArea
= aEvent
->GetStorageArea();
5486 RefPtr
<Storage
> storage
;
5488 // If null, this is a localStorage event received by IPC.
5490 storage
= GetLocalStorage(aRv
);
5491 if (!NextGenLocalStorageEnabled()) {
5492 if (aRv
.Failed() || !storage
) {
5496 if (storage
->Type() == Storage::eLocalStorage
) {
5497 RefPtr
<LocalStorage
> localStorage
=
5498 static_cast<LocalStorage
*>(storage
.get());
5500 // We must apply the current change to the 'local' localStorage.
5501 localStorage
->ApplyEvent(aEvent
);
5504 } else if (storageArea
->Type() == Storage::eSessionStorage
) {
5505 storage
= GetSessionStorage(aRv
);
5507 MOZ_ASSERT(storageArea
->Type() == Storage::eLocalStorage
);
5508 storage
= GetLocalStorage(aRv
);
5511 if (aRv
.Failed() || !storage
) {
5515 if (storage
->Type() == Storage::ePartitionedLocalStorage
) {
5516 // This error message is not exposed.
5517 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
5521 MOZ_ASSERT(storage
);
5522 MOZ_ASSERT_IF(storageArea
, storage
->IsForkOf(storageArea
));
5524 dict
.mStorageArea
= storage
;
5526 RefPtr
<StorageEvent
> event
= StorageEvent::Constructor(this, aType
, dict
);
5527 return event
.forget();
5530 void nsGlobalWindowInner::Suspend(bool aIncludeSubWindows
) {
5531 MOZ_ASSERT(NS_IsMainThread());
5533 // We can only safely suspend windows that are the current inner window. If
5534 // its not the current inner, then we are in one of two different cases.
5535 // Either we are in the bfcache or we are doomed window that is going away.
5536 // When a window becomes inactive we purposely avoid placing already suspended
5537 // windows into the bfcache. It only expects windows suspended due to the
5538 // Freeze() method which occurs while the window is still the current inner.
5539 // So we must not call Suspend() on bfcache windows at this point or this
5540 // invariant will be broken. If the window is doomed there is no point in
5541 // suspending it since it will soon be gone.
5542 if (!IsCurrentInnerWindow()) {
5546 // All in-process descendants are also suspended. This ensure mSuspendDepth
5547 // is set properly and the timers are properly canceled for each in-process
5549 if (aIncludeSubWindows
) {
5550 CallOnInProcessDescendants(&nsGlobalWindowInner::Suspend
, false);
5554 if (mSuspendDepth
!= 1) {
5558 if (mWindowGlobalChild
) {
5559 mWindowGlobalChild
->BlockBFCacheFor(BFCacheStatus::SUSPENDED
);
5562 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
5564 for (uint32_t i
= 0; i
< mEnabledSensors
.Length(); i
++)
5565 ac
->RemoveWindowListener(mEnabledSensors
[i
], this);
5567 DisableGamepadUpdates();
5570 SuspendWorkersForWindow(*this);
5572 for (RefPtr
<mozilla::dom::SharedWorker
> pinnedWorker
:
5573 mSharedWorkers
.ForwardRange()) {
5574 pinnedWorker
->Suspend();
5577 SuspendIdleRequests();
5579 mTimeoutManager
->Suspend();
5581 // Suspend all of the AudioContexts for this window
5582 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
5583 mAudioContexts
[i
]->SuspendFromChrome();
5587 void nsGlobalWindowInner::Resume(bool aIncludeSubWindows
) {
5588 MOZ_ASSERT(NS_IsMainThread());
5590 // We can only safely resume a window if its the current inner window. If
5591 // its not the current inner, then we are in one of two different cases.
5592 // Either we are in the bfcache or we are doomed window that is going away.
5593 // If a window is suspended when it becomes inactive we purposely do not
5594 // put it in the bfcache, so Resume should never be needed in that case.
5595 // If the window is doomed then there is no point in resuming it.
5596 if (!IsCurrentInnerWindow()) {
5600 // Resume all in-process descendants. This restores timers recursively
5601 // canceled in Suspend() and ensures all in-process descendants have the
5602 // correct mSuspendDepth.
5603 if (aIncludeSubWindows
) {
5604 CallOnInProcessDescendants(&nsGlobalWindowInner::Resume
, false);
5607 if (mSuspendDepth
== 0) {
5608 // Ignore if the window is not suspended.
5614 if (mSuspendDepth
!= 0) {
5618 // We should not be able to resume a frozen window. It must be Thaw()'d
5620 MOZ_ASSERT(mFreezeDepth
== 0);
5622 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
5624 for (uint32_t i
= 0; i
< mEnabledSensors
.Length(); i
++)
5625 ac
->AddWindowListener(mEnabledSensors
[i
], this);
5627 EnableGamepadUpdates();
5630 // Resume all of the AudioContexts for this window
5631 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
5632 mAudioContexts
[i
]->ResumeFromChrome();
5635 if (RefPtr
<MediaDevices
> devices
= GetExtantMediaDevices()) {
5636 devices
->WindowResumed();
5639 mTimeoutManager
->Resume();
5641 ResumeIdleRequests();
5643 // Resume all of the workers for this window. We must do this
5644 // after timeouts since workers may have queued events that can trigger
5646 ResumeWorkersForWindow(*this);
5648 for (RefPtr
<mozilla::dom::SharedWorker
> pinnedWorker
:
5649 mSharedWorkers
.ForwardRange()) {
5650 pinnedWorker
->Resume();
5653 if (mWindowGlobalChild
) {
5654 mWindowGlobalChild
->UnblockBFCacheFor(BFCacheStatus::SUSPENDED
);
5658 bool nsGlobalWindowInner::IsSuspended() const {
5659 MOZ_ASSERT(NS_IsMainThread());
5660 return mSuspendDepth
!= 0;
5663 void nsGlobalWindowInner::Freeze(bool aIncludeSubWindows
) {
5664 MOZ_ASSERT(NS_IsMainThread());
5665 Suspend(aIncludeSubWindows
);
5666 FreezeInternal(aIncludeSubWindows
);
5669 void nsGlobalWindowInner::FreezeInternal(bool aIncludeSubWindows
) {
5670 MOZ_ASSERT(NS_IsMainThread());
5671 MOZ_DIAGNOSTIC_ASSERT(IsCurrentInnerWindow());
5672 MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
5674 HintIsLoading(false);
5676 if (aIncludeSubWindows
) {
5677 CallOnInProcessChildren(&nsGlobalWindowInner::FreezeInternal
,
5678 aIncludeSubWindows
);
5682 MOZ_ASSERT(mSuspendDepth
>= mFreezeDepth
);
5683 if (mFreezeDepth
!= 1) {
5687 FreezeWorkersForWindow(*this);
5689 for (RefPtr
<mozilla::dom::SharedWorker
> pinnedWorker
:
5690 mSharedWorkers
.ForwardRange()) {
5691 pinnedWorker
->Freeze();
5694 mTimeoutManager
->Freeze();
5695 if (mClientSource
) {
5696 mClientSource
->Freeze();
5699 NotifyDOMWindowFrozen(this);
5702 void nsGlobalWindowInner::Thaw(bool aIncludeSubWindows
) {
5703 MOZ_ASSERT(NS_IsMainThread());
5704 ThawInternal(aIncludeSubWindows
);
5705 Resume(aIncludeSubWindows
);
5708 void nsGlobalWindowInner::ThawInternal(bool aIncludeSubWindows
) {
5709 MOZ_ASSERT(NS_IsMainThread());
5710 MOZ_DIAGNOSTIC_ASSERT(IsCurrentInnerWindow());
5711 MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
5713 if (aIncludeSubWindows
) {
5714 CallOnInProcessChildren(&nsGlobalWindowInner::ThawInternal
,
5715 aIncludeSubWindows
);
5718 MOZ_ASSERT(mFreezeDepth
!= 0);
5720 MOZ_ASSERT(mSuspendDepth
>= mFreezeDepth
);
5721 if (mFreezeDepth
!= 0) {
5725 if (mClientSource
) {
5726 mClientSource
->Thaw();
5728 mTimeoutManager
->Thaw();
5730 ThawWorkersForWindow(*this);
5732 for (RefPtr
<mozilla::dom::SharedWorker
> pinnedWorker
:
5733 mSharedWorkers
.ForwardRange()) {
5734 pinnedWorker
->Thaw();
5737 NotifyDOMWindowThawed(this);
5740 bool nsGlobalWindowInner::IsFrozen() const {
5741 MOZ_ASSERT(NS_IsMainThread());
5742 bool frozen
= mFreezeDepth
!= 0;
5743 MOZ_ASSERT_IF(frozen
, IsSuspended());
5747 void nsGlobalWindowInner::SyncStateFromParentWindow() {
5748 // This method should only be called on an inner window that has been
5749 // assigned to an outer window already.
5750 MOZ_ASSERT(IsCurrentInnerWindow());
5751 nsPIDOMWindowOuter
* outer
= GetOuterWindow();
5754 // Attempt to find our parent windows.
5755 nsCOMPtr
<Element
> frame
= outer
->GetFrameElementInternal();
5756 nsPIDOMWindowOuter
* parentOuter
=
5757 frame
? frame
->OwnerDoc()->GetWindow() : nullptr;
5758 nsGlobalWindowInner
* parentInner
=
5760 ? nsGlobalWindowInner::Cast(parentOuter
->GetCurrentInnerWindow())
5763 // If our outer is in a modal state, but our parent is not in a modal
5764 // state, then we must apply the suspend directly. If our parent is
5765 // in a modal state then we should get the suspend automatically
5766 // via the parentSuspendDepth application below.
5767 if ((!parentInner
|| !parentInner
->IsInModalState()) && IsInModalState()) {
5771 uint32_t parentFreezeDepth
= parentInner
? parentInner
->mFreezeDepth
: 0;
5772 uint32_t parentSuspendDepth
= parentInner
? parentInner
->mSuspendDepth
: 0;
5774 // Since every Freeze() calls Suspend(), the suspend count must
5775 // be equal or greater to the freeze count.
5776 MOZ_ASSERT(parentFreezeDepth
<= parentSuspendDepth
);
5778 // First apply the Freeze() calls.
5779 for (uint32_t i
= 0; i
< parentFreezeDepth
; ++i
) {
5783 // Now apply only the number of Suspend() calls to reach the target
5784 // suspend count after applying the Freeze() calls.
5785 for (uint32_t i
= 0; i
< (parentSuspendDepth
- parentFreezeDepth
); ++i
) {
5790 void nsGlobalWindowInner::UpdateBackgroundState() {
5791 if (RefPtr
<MediaDevices
> devices
= GetExtantMediaDevices()) {
5792 devices
->BackgroundStateChanged();
5794 mTimeoutManager
->UpdateBackgroundState();
5797 template <typename Method
, typename
... Args
>
5798 CallState
nsGlobalWindowInner::CallOnInProcessDescendantsInternal(
5799 BrowsingContext
* aBrowsingContext
, bool aChildOnly
, Method aMethod
,
5801 MOZ_ASSERT(NS_IsMainThread());
5802 MOZ_ASSERT(aBrowsingContext
);
5804 CallState state
= CallState::Continue
;
5805 for (const RefPtr
<BrowsingContext
>& bc
: aBrowsingContext
->Children()) {
5806 if (nsCOMPtr
<nsPIDOMWindowOuter
> pWin
= bc
->GetDOMWindow()) {
5807 auto* win
= nsGlobalWindowOuter::Cast(pWin
);
5808 if (nsGlobalWindowInner
* inner
=
5809 nsGlobalWindowInner::Cast(win
->GetCurrentInnerWindow())) {
5810 // Call the descendant method using our helper CallDescendant() template
5811 // method. This allows us to handle both void returning methods and
5812 // methods that return CallState explicitly. For void returning methods
5813 // we assume CallState::Continue.
5814 using returnType
= decltype((inner
->*aMethod
)(aArgs
...));
5815 state
= CallDescendant
<returnType
>(inner
, aMethod
, aArgs
...);
5817 if (state
== CallState::Stop
) {
5824 state
= CallOnInProcessDescendantsInternal(bc
.get(), aChildOnly
, aMethod
,
5826 if (state
== CallState::Stop
) {
5835 Maybe
<ClientInfo
> nsGlobalWindowInner::GetClientInfo() const {
5836 MOZ_ASSERT(NS_IsMainThread());
5837 if (mDoc
&& mDoc
->IsStaticDocument()) {
5838 if (Maybe
<ClientInfo
> info
= mDoc
->GetOriginalDocument()->GetClientInfo()) {
5843 Maybe
<ClientInfo
> clientInfo
;
5844 if (mClientSource
) {
5845 clientInfo
.emplace(mClientSource
->Info());
5850 Maybe
<ClientState
> nsGlobalWindowInner::GetClientState() const {
5851 MOZ_ASSERT(NS_IsMainThread());
5852 if (mDoc
&& mDoc
->IsStaticDocument()) {
5853 if (Maybe
<ClientState
> state
=
5854 mDoc
->GetOriginalDocument()->GetClientState()) {
5859 Maybe
<ClientState
> clientState
;
5860 if (mClientSource
) {
5861 Result
<ClientState
, ErrorResult
> res
= mClientSource
->SnapshotState();
5863 clientState
.emplace(res
.unwrap());
5865 res
.unwrapErr().SuppressException();
5871 Maybe
<ServiceWorkerDescriptor
> nsGlobalWindowInner::GetController() const {
5872 MOZ_ASSERT(NS_IsMainThread());
5873 if (mDoc
&& mDoc
->IsStaticDocument()) {
5874 if (Maybe
<ServiceWorkerDescriptor
> controller
=
5875 mDoc
->GetOriginalDocument()->GetController()) {
5880 Maybe
<ServiceWorkerDescriptor
> controller
;
5881 if (mClientSource
) {
5882 controller
= mClientSource
->GetController();
5887 void nsGlobalWindowInner::SetCsp(nsIContentSecurityPolicy
* aCsp
) {
5888 if (!mClientSource
) {
5891 mClientSource
->SetCsp(aCsp
);
5892 // Also cache the CSP within the document
5895 if (mWindowGlobalChild
) {
5896 mWindowGlobalChild
->SendSetClientInfo(mClientSource
->Info().ToIPC());
5900 void nsGlobalWindowInner::SetPreloadCsp(nsIContentSecurityPolicy
* aPreloadCsp
) {
5901 if (!mClientSource
) {
5904 mClientSource
->SetPreloadCsp(aPreloadCsp
);
5905 // Also cache the preload CSP within the document
5906 mDoc
->SetPreloadCsp(aPreloadCsp
);
5908 if (mWindowGlobalChild
) {
5909 mWindowGlobalChild
->SendSetClientInfo(mClientSource
->Info().ToIPC());
5913 nsIContentSecurityPolicy
* nsGlobalWindowInner::GetCsp() {
5915 return mDoc
->GetCsp();
5918 // If the window is partially torn down and has its document nulled out,
5919 // we query the CSP we snapshot in FreeInnerObjects.
5921 return mDocumentCsp
;
5926 RefPtr
<ServiceWorker
> nsGlobalWindowInner::GetOrCreateServiceWorker(
5927 const ServiceWorkerDescriptor
& aDescriptor
) {
5928 MOZ_ASSERT(NS_IsMainThread());
5929 RefPtr
<ServiceWorker
> ref
;
5930 ForEachGlobalTeardownObserver(
5931 [&](GlobalTeardownObserver
* aObserver
, bool* aDoneOut
) {
5932 RefPtr
<ServiceWorker
> sw
= do_QueryObject(aObserver
);
5933 if (!sw
|| !sw
->Descriptor().Matches(aDescriptor
)) {
5937 ref
= std::move(sw
);
5942 ref
= ServiceWorker::Create(this, aDescriptor
);
5948 RefPtr
<mozilla::dom::ServiceWorkerRegistration
>
5949 nsGlobalWindowInner::GetServiceWorkerRegistration(
5950 const mozilla::dom::ServiceWorkerRegistrationDescriptor
& aDescriptor
)
5952 MOZ_ASSERT(NS_IsMainThread());
5953 RefPtr
<ServiceWorkerRegistration
> ref
;
5954 ForEachGlobalTeardownObserver(
5955 [&](GlobalTeardownObserver
* aObserver
, bool* aDoneOut
) {
5956 RefPtr
<ServiceWorkerRegistration
> swr
= do_QueryObject(aObserver
);
5957 if (!swr
|| !swr
->MatchesDescriptor(aDescriptor
)) {
5961 ref
= std::move(swr
);
5967 RefPtr
<ServiceWorkerRegistration
>
5968 nsGlobalWindowInner::GetOrCreateServiceWorkerRegistration(
5969 const ServiceWorkerRegistrationDescriptor
& aDescriptor
) {
5970 MOZ_ASSERT(NS_IsMainThread());
5971 RefPtr
<ServiceWorkerRegistration
> ref
=
5972 GetServiceWorkerRegistration(aDescriptor
);
5974 ref
= ServiceWorkerRegistration::CreateForMainThread(this, aDescriptor
);
5979 StorageAccess
nsGlobalWindowInner::GetStorageAccess() {
5980 return StorageAllowedForWindow(this);
5983 nsresult
nsGlobalWindowInner::FireDelayedDOMEvents(bool aIncludeSubWindows
) {
5984 // Fires an offline status event if the offline status has changed
5985 FireOfflineStatusEventIfChanged();
5987 if (!aIncludeSubWindows
) {
5991 nsCOMPtr
<nsIDocShell
> docShell
= GetDocShell();
5993 int32_t childCount
= 0;
5994 docShell
->GetInProcessChildCount(&childCount
);
5996 // Take a copy of the current children so that modifications to
5997 // the child list don't affect to the iteration.
5998 AutoTArray
<nsCOMPtr
<nsIDocShellTreeItem
>, 8> children
;
5999 for (int32_t i
= 0; i
< childCount
; ++i
) {
6000 nsCOMPtr
<nsIDocShellTreeItem
> childShell
;
6001 docShell
->GetInProcessChildAt(i
, getter_AddRefs(childShell
));
6003 children
.AppendElement(childShell
);
6007 for (nsCOMPtr
<nsIDocShellTreeItem
> childShell
: children
) {
6008 if (nsCOMPtr
<nsPIDOMWindowOuter
> pWin
= childShell
->GetWindow()) {
6009 auto* win
= nsGlobalWindowOuter::Cast(pWin
);
6010 win
->FireDelayedDOMEvents(true);
6018 //*****************************************************************************
6019 // nsGlobalWindowInner: Window Control Functions
6020 //*****************************************************************************
6022 nsPIDOMWindowOuter
* nsGlobalWindowInner::GetInProcessParentInternal() {
6023 nsGlobalWindowOuter
* outer
= GetOuterWindowInternal();
6025 // No outer window available!
6028 return outer
->GetInProcessParentInternal();
6031 nsIPrincipal
* nsGlobalWindowInner::GetTopLevelAntiTrackingPrincipal() {
6032 nsPIDOMWindowOuter
* outerWindow
= GetOuterWindowInternal();
6037 nsPIDOMWindowOuter
* topLevelOuterWindow
=
6038 GetBrowsingContext()->Top()->GetDOMWindow();
6039 if (!topLevelOuterWindow
) {
6043 bool stopAtOurLevel
=
6044 mDoc
&& mDoc
->CookieJarSettings()->GetCookieBehavior() ==
6045 nsICookieService::BEHAVIOR_REJECT_TRACKER
;
6047 if (stopAtOurLevel
&& topLevelOuterWindow
== outerWindow
) {
6051 nsPIDOMWindowInner
* topLevelInnerWindow
=
6052 topLevelOuterWindow
->GetCurrentInnerWindow();
6053 if (NS_WARN_IF(!topLevelInnerWindow
)) {
6057 nsIPrincipal
* topLevelPrincipal
=
6058 nsGlobalWindowInner::Cast(topLevelInnerWindow
)->GetPrincipal();
6059 if (NS_WARN_IF(!topLevelPrincipal
)) {
6063 return topLevelPrincipal
;
6066 nsIPrincipal
* nsGlobalWindowInner::GetClientPrincipal() {
6067 return mClientSource
? mClientSource
->GetPrincipal() : nullptr;
6070 bool nsGlobalWindowInner::IsInFullScreenTransition() {
6075 nsGlobalWindowOuter
* outerWindow
= GetOuterWindowInternal();
6080 return outerWindow
->mIsInFullScreenTransition
;
6083 //*****************************************************************************
6084 // nsGlobalWindowInner: Timeout Functions
6085 //*****************************************************************************
6087 class WindowScriptTimeoutHandler final
: public ScriptTimeoutHandler
{
6089 NS_DECL_ISUPPORTS_INHERITED
6090 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WindowScriptTimeoutHandler
,
6091 ScriptTimeoutHandler
)
6093 WindowScriptTimeoutHandler(JSContext
* aCx
, nsIGlobalObject
* aGlobal
,
6094 const nsAString
& aExpression
)
6095 : ScriptTimeoutHandler(aCx
, aGlobal
, aExpression
),
6096 mInitiatingScript(ScriptLoader::GetActiveScript(aCx
)) {}
6098 MOZ_CAN_RUN_SCRIPT
virtual bool Call(const char* aExecutionReason
) override
;
6101 virtual ~WindowScriptTimeoutHandler() = default;
6103 // Initiating script for use when evaluating mExpr on the main thread.
6104 RefPtr
<JS::loader::LoadedScript
> mInitiatingScript
;
6107 NS_IMPL_CYCLE_COLLECTION_INHERITED(WindowScriptTimeoutHandler
,
6108 ScriptTimeoutHandler
, mInitiatingScript
)
6110 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowScriptTimeoutHandler
)
6111 NS_INTERFACE_MAP_END_INHERITING(ScriptTimeoutHandler
)
6113 NS_IMPL_ADDREF_INHERITED(WindowScriptTimeoutHandler
, ScriptTimeoutHandler
)
6114 NS_IMPL_RELEASE_INHERITED(WindowScriptTimeoutHandler
, ScriptTimeoutHandler
)
6116 bool WindowScriptTimeoutHandler::Call(const char* aExecutionReason
) {
6117 // New script entry point required, due to the "Create a script" sub-step
6119 // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
6121 AutoEntryScript
aes(mGlobal
, aExecutionReason
, true);
6122 JS::CompileOptions
options(aes
.cx());
6123 options
.setFileAndLine(mFileName
.get(), mLineNo
);
6124 options
.setNoScriptRval(true);
6125 options
.setIntroductionType("domTimer");
6126 JS::Rooted
<JSObject
*> global(aes
.cx(), mGlobal
->GetGlobalJSObject());
6128 JSExecutionContext
exec(aes
.cx(), global
, options
);
6129 nsresult rv
= exec
.Compile(mExpr
);
6131 JS::Rooted
<JSScript
*> script(aes
.cx(), exec
.MaybeGetScript());
6133 if (mInitiatingScript
) {
6134 mInitiatingScript
->AssociateWithScript(script
);
6137 rv
= exec
.ExecScript();
6140 if (rv
== NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE
) {
6148 nsGlobalWindowInner
* nsGlobalWindowInner::InnerForSetTimeoutOrInterval(
6149 ErrorResult
& aError
) {
6150 nsGlobalWindowOuter
* outer
= GetOuterWindowInternal();
6151 nsPIDOMWindowInner
* currentInner
=
6152 outer
? outer
->GetCurrentInnerWindow() : this;
6154 // If forwardTo is not the window with an active document then we want the
6155 // call to setTimeout/Interval to be a noop, so return null but don't set an
6157 return HasActiveDocument() ? nsGlobalWindowInner::Cast(currentInner
)
6161 int32_t nsGlobalWindowInner::SetTimeout(JSContext
* aCx
, Function
& aFunction
,
6163 const Sequence
<JS::Value
>& aArguments
,
6164 ErrorResult
& aError
) {
6165 return SetTimeoutOrInterval(aCx
, aFunction
, aTimeout
, aArguments
, false,
6169 int32_t nsGlobalWindowInner::SetTimeout(JSContext
* aCx
,
6170 const nsAString
& aHandler
,
6172 const Sequence
<JS::Value
>& /* unused */,
6173 ErrorResult
& aError
) {
6174 return SetTimeoutOrInterval(aCx
, aHandler
, aTimeout
, false, aError
);
6177 int32_t nsGlobalWindowInner::SetInterval(JSContext
* aCx
, Function
& aFunction
,
6178 const int32_t aTimeout
,
6179 const Sequence
<JS::Value
>& aArguments
,
6180 ErrorResult
& aError
) {
6181 return SetTimeoutOrInterval(aCx
, aFunction
, aTimeout
, aArguments
, true,
6185 int32_t nsGlobalWindowInner::SetInterval(
6186 JSContext
* aCx
, const nsAString
& aHandler
, const int32_t aTimeout
,
6187 const Sequence
<JS::Value
>& /* unused */, ErrorResult
& aError
) {
6188 return SetTimeoutOrInterval(aCx
, aHandler
, aTimeout
, true, aError
);
6191 int32_t nsGlobalWindowInner::SetTimeoutOrInterval(
6192 JSContext
* aCx
, Function
& aFunction
, int32_t aTimeout
,
6193 const Sequence
<JS::Value
>& aArguments
, bool aIsInterval
,
6194 ErrorResult
& aError
) {
6195 nsGlobalWindowInner
* inner
= InnerForSetTimeoutOrInterval(aError
);
6200 if (inner
!= this) {
6201 RefPtr
<nsGlobalWindowInner
> innerRef(inner
);
6202 return innerRef
->SetTimeoutOrInterval(aCx
, aFunction
, aTimeout
, aArguments
,
6203 aIsInterval
, aError
);
6206 DebuggerNotificationDispatch(
6207 this, aIsInterval
? DebuggerNotificationType::SetInterval
6208 : DebuggerNotificationType::SetTimeout
);
6210 if (!GetContextInternal() || !HasJSGlobal()) {
6211 // This window was already closed, or never properly initialized,
6212 // don't let a timer be scheduled on such a window.
6213 aError
.Throw(NS_ERROR_NOT_INITIALIZED
);
6217 nsTArray
<JS::Heap
<JS::Value
>> args
;
6218 if (!args
.AppendElements(aArguments
, fallible
)) {
6219 aError
.Throw(NS_ERROR_OUT_OF_MEMORY
);
6223 RefPtr
<TimeoutHandler
> handler
=
6224 new CallbackTimeoutHandler(aCx
, this, &aFunction
, std::move(args
));
6228 mTimeoutManager
->SetTimeout(handler
, aTimeout
, aIsInterval
,
6229 Timeout::Reason::eTimeoutOrInterval
, &result
);
6233 int32_t nsGlobalWindowInner::SetTimeoutOrInterval(JSContext
* aCx
,
6234 const nsAString
& aHandler
,
6237 ErrorResult
& aError
) {
6238 nsGlobalWindowInner
* inner
= InnerForSetTimeoutOrInterval(aError
);
6243 if (inner
!= this) {
6244 RefPtr
<nsGlobalWindowInner
> innerRef(inner
);
6245 return innerRef
->SetTimeoutOrInterval(aCx
, aHandler
, aTimeout
, aIsInterval
,
6249 DebuggerNotificationDispatch(
6250 this, aIsInterval
? DebuggerNotificationType::SetInterval
6251 : DebuggerNotificationType::SetTimeout
);
6253 if (!GetContextInternal() || !HasJSGlobal()) {
6254 // This window was already closed, or never properly initialized,
6255 // don't let a timer be scheduled on such a window.
6256 aError
.Throw(NS_ERROR_NOT_INITIALIZED
);
6260 bool allowEval
= false;
6261 aError
= CSPEvalChecker::CheckForWindow(aCx
, this, aHandler
, &allowEval
);
6262 if (NS_WARN_IF(aError
.Failed()) || !allowEval
) {
6266 RefPtr
<TimeoutHandler
> handler
=
6267 new WindowScriptTimeoutHandler(aCx
, this, aHandler
);
6271 mTimeoutManager
->SetTimeout(handler
, aTimeout
, aIsInterval
,
6272 Timeout::Reason::eTimeoutOrInterval
, &result
);
6276 static const char* GetTimeoutReasonString(Timeout
* aTimeout
) {
6277 switch (aTimeout
->mReason
) {
6278 case Timeout::Reason::eTimeoutOrInterval
:
6279 if (aTimeout
->mIsInterval
) {
6280 return "setInterval handler";
6282 return "setTimeout handler";
6283 case Timeout::Reason::eIdleCallbackTimeout
:
6284 return "setIdleCallback handler (timed out)";
6285 case Timeout::Reason::eAbortSignalTimeout
:
6286 return "AbortSignal timeout";
6287 case Timeout::Reason::eDelayedWebTaskTimeout
:
6288 return "delayedWebTaskCallback handler (timed out)";
6290 MOZ_CRASH("Unexpected enum value");
6293 MOZ_CRASH("Unexpected enum value");
6297 bool nsGlobalWindowInner::RunTimeoutHandler(Timeout
* aTimeout
,
6298 nsIScriptContext
* aScx
) {
6299 // Hold on to the timeout in case mExpr or mFunObj releases its
6301 // XXXbz Our caller guarantees it'll hold on to the timeout (because
6302 // we're MOZ_CAN_RUN_SCRIPT), so we can probably stop doing that...
6303 RefPtr
<Timeout
> timeout
= aTimeout
;
6304 Timeout
* last_running_timeout
= mTimeoutManager
->BeginRunningTimeout(timeout
);
6305 timeout
->mRunning
= true;
6307 // Push this timeout's popup control state, which should only be
6308 // enabled the first time a timeout fires that was created while
6309 // popups were enabled and with a delay less than
6310 // "dom.disable_open_click_delay".
6311 AutoPopupStatePusher
popupStatePusher(timeout
->mPopupState
);
6313 // Clear the timeout's popup state, if any, to prevent interval
6314 // timeouts from repeatedly opening poups.
6315 timeout
->mPopupState
= PopupBlocker::openAbused
;
6317 uint32_t nestingLevel
= TimeoutManager::GetNestingLevel();
6318 TimeoutManager::SetNestingLevel(timeout
->mNestingLevel
);
6320 const char* reason
= GetTimeoutReasonString(timeout
);
6323 if (profiler_thread_is_being_profiled_for_markers()) {
6324 TimeDuration originalInterval
= timeout
->When() - timeout
->SubmitTime();
6326 str
.Append(" with interval ");
6327 str
.AppendInt(int(originalInterval
.ToMilliseconds()));
6329 nsCString handlerDescription
;
6330 timeout
->mScriptHandler
->GetDescription(handlerDescription
);
6331 str
.Append(handlerDescription
);
6333 AUTO_PROFILER_MARKER_TEXT("setTimeout callback", DOM
,
6334 MarkerOptions(MarkerStack::TakeBacktrace(
6335 timeout
->TakeProfilerBacktrace()),
6336 MarkerInnerWindowId(mWindowID
)),
6339 bool abortIntervalHandler
;
6341 RefPtr
<TimeoutHandler
> handler(timeout
->mScriptHandler
);
6343 CallbackDebuggerNotificationGuard
guard(
6344 this, timeout
->mIsInterval
6345 ? DebuggerNotificationType::SetIntervalCallback
6346 : DebuggerNotificationType::SetTimeoutCallback
);
6347 abortIntervalHandler
= !handler
->Call(reason
);
6350 // If we received an uncatchable exception, do not schedule the timeout again.
6351 // This allows the slow script dialog to break easy DoS attacks like
6352 // setInterval(function() { while(1); }, 100);
6353 if (abortIntervalHandler
) {
6354 // If it wasn't an interval timer to begin with, this does nothing. If it
6355 // was, we'll treat it as a timeout that we just ran and discard it when
6357 timeout
->mIsInterval
= false;
6360 // We ignore any failures from calling EvaluateString() on the context or
6361 // Call() on a Function here since we're in a loop
6362 // where we're likely to be running timeouts whose OS timers
6363 // didn't fire in time and we don't want to not fire those timers
6364 // now just because execution of one timer failed. We can't
6365 // propagate the error to anyone who cares about it from this
6366 // point anyway, and the script context should have already reported
6367 // the script error in the usual way - so we just drop it.
6369 TimeoutManager::SetNestingLevel(nestingLevel
);
6371 mTimeoutManager
->EndRunningTimeout(last_running_timeout
);
6372 timeout
->mRunning
= false;
6374 return timeout
->mCleared
;
6377 //*****************************************************************************
6378 // nsGlobalWindowInner: Helper Functions
6379 //*****************************************************************************
6381 already_AddRefed
<nsIDocShellTreeOwner
> nsGlobalWindowInner::GetTreeOwner() {
6382 FORWARD_TO_OUTER(GetTreeOwner
, (), nullptr);
6385 already_AddRefed
<nsIWebBrowserChrome
>
6386 nsGlobalWindowInner::GetWebBrowserChrome() {
6387 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
= GetTreeOwner();
6389 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
= do_GetInterface(treeOwner
);
6390 return browserChrome
.forget();
6393 nsIScrollableFrame
* nsGlobalWindowInner::GetScrollFrame() {
6394 FORWARD_TO_OUTER(GetScrollFrame
, (), nullptr);
6397 bool nsGlobalWindowInner::IsPrivateBrowsing() {
6398 nsCOMPtr
<nsILoadContext
> loadContext
= do_QueryInterface(GetDocShell());
6399 return loadContext
&& loadContext
->UsePrivateBrowsing();
6402 void nsGlobalWindowInner::FlushPendingNotifications(FlushType aType
) {
6404 mDoc
->FlushPendingNotifications(aType
);
6408 void nsGlobalWindowInner::EnableDeviceSensor(uint32_t aType
) {
6409 bool alreadyEnabled
= false;
6410 for (uint32_t i
= 0; i
< mEnabledSensors
.Length(); i
++) {
6411 if (mEnabledSensors
[i
] == aType
) {
6412 alreadyEnabled
= true;
6417 mEnabledSensors
.AppendElement(aType
);
6419 if (alreadyEnabled
) {
6423 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
6425 ac
->AddWindowListener(aType
, this);
6429 void nsGlobalWindowInner::DisableDeviceSensor(uint32_t aType
) {
6430 int32_t doomedElement
= -1;
6431 int32_t listenerCount
= 0;
6432 for (uint32_t i
= 0; i
< mEnabledSensors
.Length(); i
++) {
6433 if (mEnabledSensors
[i
] == aType
) {
6439 if (doomedElement
== -1) {
6443 mEnabledSensors
.RemoveElementAt(doomedElement
);
6445 if (listenerCount
> 1) {
6449 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
6451 ac
->RemoveWindowListener(aType
, this);
6455 #if defined(MOZ_WIDGET_ANDROID)
6456 void nsGlobalWindowInner::EnableOrientationChangeListener() {
6457 if (!ShouldResistFingerprinting(RFPTarget::ScreenOrientation
)) {
6458 mHasOrientationChangeListeners
= true;
6459 mOrientationAngle
= Orientation(CallerType::System
);
6463 void nsGlobalWindowInner::DisableOrientationChangeListener() {
6464 mHasOrientationChangeListeners
= false;
6468 void nsGlobalWindowInner::SetHasGamepadEventListener(
6469 bool aHasGamepad
/* = true*/) {
6470 mHasGamepad
= aHasGamepad
;
6472 EnableGamepadUpdates();
6476 void nsGlobalWindowInner::NotifyDetectXRRuntimesCompleted() {
6477 if (!mXRRuntimeDetectionInFlight
) {
6480 mXRRuntimeDetectionInFlight
= false;
6481 if (mXRPermissionRequestInFlight
) {
6484 gfx::VRManagerChild
* vm
= gfx::VRManagerChild::Get();
6485 bool supported
= vm
->RuntimeSupportsVR();
6487 // A VR runtime was not installed; we can suppress
6488 // the permission prompt
6489 OnXRPermissionRequestCancel();
6492 // A VR runtime was found. Display a permission prompt before
6493 // allowing it to be accessed.
6494 // Connect to the VRManager in order to receive the runtime
6495 // detection results.
6496 mXRPermissionRequestInFlight
= true;
6497 RefPtr
<XRPermissionRequest
> request
=
6498 new XRPermissionRequest(this, WindowID());
6499 Unused
<< NS_WARN_IF(NS_FAILED(request
->Start()));
6502 void nsGlobalWindowInner::RequestXRPermission() {
6504 // Do not proceed if the window is dying, as that will result
6505 // in leaks of objects that get re-allocated after FreeInnerObjects
6506 // has been called, including mVREventObserver.
6509 if (mXRPermissionGranted
) {
6510 // Don't prompt redundantly once permission to
6511 // access XR devices has been granted.
6512 OnXRPermissionRequestAllow();
6515 if (mXRRuntimeDetectionInFlight
|| mXRPermissionRequestInFlight
) {
6516 // Don't allow multiple simultaneous permissions requests;
6519 // Before displaying a permission prompt, detect
6520 // if there is any VR runtime installed.
6521 gfx::VRManagerChild
* vm
= gfx::VRManagerChild::Get();
6522 mXRRuntimeDetectionInFlight
= true;
6524 vm
->DetectRuntimes();
6527 void nsGlobalWindowInner::OnXRPermissionRequestAllow() {
6528 mXRPermissionRequestInFlight
= false;
6530 // The window may have started dying while the permission request
6532 // Do not proceed if the window is dying, as that will result
6533 // in leaks of objects that get re-allocated after FreeInnerObjects
6534 // has been called, including mNavigator.
6537 mXRPermissionGranted
= true;
6539 NotifyHasXRSession();
6541 dom::Navigator
* nav
= Navigator();
6542 MOZ_ASSERT(nav
!= nullptr);
6543 nav
->OnXRPermissionRequestAllow();
6546 void nsGlobalWindowInner::OnXRPermissionRequestCancel() {
6547 mXRPermissionRequestInFlight
= false;
6549 // The window may have started dying while the permission request
6551 // Do not proceed if the window is dying, as that will result
6552 // in leaks of objects that get re-allocated after FreeInnerObjects
6553 // has been called, including mNavigator.
6556 dom::Navigator
* nav
= Navigator();
6557 MOZ_ASSERT(nav
!= nullptr);
6558 nav
->OnXRPermissionRequestCancel();
6561 void nsGlobalWindowInner::EventListenerAdded(nsAtom
* aType
) {
6562 if (aType
== nsGkAtoms::onvrdisplayactivate
||
6563 aType
== nsGkAtoms::onvrdisplayconnect
||
6564 aType
== nsGkAtoms::onvrdisplaydeactivate
||
6565 aType
== nsGkAtoms::onvrdisplaydisconnect
||
6566 aType
== nsGkAtoms::onvrdisplaypresentchange
) {
6567 RequestXRPermission();
6570 if (aType
== nsGkAtoms::onvrdisplayactivate
) {
6571 mHasVRDisplayActivateEvents
= true;
6574 if (aType
== nsGkAtoms::onunload
&& mWindowGlobalChild
) {
6575 if (++mUnloadOrBeforeUnloadListenerCount
== 1) {
6576 mWindowGlobalChild
->BlockBFCacheFor(BFCacheStatus::UNLOAD_LISTENER
);
6580 if (aType
== nsGkAtoms::onbeforeunload
&& mWindowGlobalChild
) {
6581 if (!mozilla::SessionHistoryInParent() ||
6583 docshell_shistory_bfcache_ship_allow_beforeunload_listeners()) {
6584 if (++mUnloadOrBeforeUnloadListenerCount
== 1) {
6585 mWindowGlobalChild
->BlockBFCacheFor(
6586 BFCacheStatus::BEFOREUNLOAD_LISTENER
);
6589 if (!mDoc
|| !(mDoc
->GetSandboxFlags() & SANDBOXED_MODALS
)) {
6590 mWindowGlobalChild
->BeforeUnloadAdded();
6591 MOZ_ASSERT(mWindowGlobalChild
->BeforeUnloadListeners() > 0);
6595 // We need to initialize localStorage in order to receive notifications.
6596 if (aType
== nsGkAtoms::onstorage
) {
6598 GetLocalStorage(rv
);
6599 rv
.SuppressException();
6601 if (NextGenLocalStorageEnabled() && mLocalStorage
&&
6602 mLocalStorage
->Type() == Storage::eLocalStorage
) {
6603 auto object
= static_cast<LSObject
*>(mLocalStorage
.get());
6605 Unused
<< NS_WARN_IF(NS_FAILED(object
->EnsureObserver()));
6610 void nsGlobalWindowInner::EventListenerRemoved(nsAtom
* aType
) {
6611 if (aType
== nsGkAtoms::onunload
&& mWindowGlobalChild
) {
6612 MOZ_ASSERT(mUnloadOrBeforeUnloadListenerCount
> 0);
6613 if (--mUnloadOrBeforeUnloadListenerCount
== 0) {
6614 mWindowGlobalChild
->UnblockBFCacheFor(BFCacheStatus::UNLOAD_LISTENER
);
6618 if (aType
== nsGkAtoms::onbeforeunload
&& mWindowGlobalChild
) {
6619 if (!mozilla::SessionHistoryInParent() ||
6621 docshell_shistory_bfcache_ship_allow_beforeunload_listeners()) {
6622 if (--mUnloadOrBeforeUnloadListenerCount
== 0) {
6623 mWindowGlobalChild
->UnblockBFCacheFor(
6624 BFCacheStatus::BEFOREUNLOAD_LISTENER
);
6627 if (!mDoc
|| !(mDoc
->GetSandboxFlags() & SANDBOXED_MODALS
)) {
6628 mWindowGlobalChild
->BeforeUnloadRemoved();
6629 MOZ_ASSERT(mWindowGlobalChild
->BeforeUnloadListeners() >= 0);
6633 if (aType
== nsGkAtoms::onstorage
) {
6634 if (NextGenLocalStorageEnabled() && mLocalStorage
&&
6635 mLocalStorage
->Type() == Storage::eLocalStorage
&&
6636 // The remove event is fired even if this isn't the last listener, so
6637 // only remove if there are no other listeners left.
6639 !mListenerManager
->HasListenersFor(nsGkAtoms::onstorage
)) {
6640 auto object
= static_cast<LSObject
*>(mLocalStorage
.get());
6642 object
->DropObserver();
6647 void nsGlobalWindowInner::NotifyHasXRSession() {
6649 // Do not proceed if the window is dying, as that will result
6650 // in leaks of objects that get re-allocated after FreeInnerObjects
6651 // has been called, including mVREventObserver.
6654 if (mWindowGlobalChild
&& !mHasXRSession
) {
6655 mWindowGlobalChild
->BlockBFCacheFor(BFCacheStatus::HAS_USED_VR
);
6657 mHasXRSession
= true;
6661 bool nsGlobalWindowInner::HasUsedVR() const {
6662 // Returns true only if content has enumerated and activated
6663 // XR devices. Detection of XR runtimes without activation
6664 // will not cause true to be returned.
6665 return mHasXRSession
;
6668 bool nsGlobalWindowInner::IsVRContentDetected() const {
6669 // Returns true only if the content will respond to
6670 // the VRDisplayActivate event.
6671 return mHasVRDisplayActivateEvents
;
6674 bool nsGlobalWindowInner::IsVRContentPresenting() const {
6675 for (const auto& display
: mVRDisplays
) {
6676 if (display
->IsAnyPresenting(gfx::kVRGroupAll
)) {
6683 void nsGlobalWindowInner::AddSizeOfIncludingThis(
6684 nsWindowSizes
& aWindowSizes
) const {
6685 aWindowSizes
.mDOMSizes
.mDOMOtherSize
+=
6686 aWindowSizes
.mState
.mMallocSizeOf(this);
6687 aWindowSizes
.mDOMSizes
.mDOMOtherSize
+=
6688 nsIGlobalObject::ShallowSizeOfExcludingThis(
6689 aWindowSizes
.mState
.mMallocSizeOf
);
6691 EventListenerManager
* elm
= GetExistingListenerManager();
6693 aWindowSizes
.mDOMSizes
.mDOMOtherSize
+=
6694 elm
->SizeOfIncludingThis(aWindowSizes
.mState
.mMallocSizeOf
);
6695 aWindowSizes
.mDOMEventListenersCount
+= elm
->ListenerCount();
6698 // Multiple global windows can share a document. So only measure the
6699 // document if it (a) doesn't have a global window, or (b) it's the
6700 // primary document for the window.
6701 if (!mDoc
->GetInnerWindow() || mDoc
->GetInnerWindow() == this) {
6702 mDoc
->DocAddSizeOfIncludingThis(aWindowSizes
);
6707 aWindowSizes
.mDOMSizes
.mDOMOtherSize
+=
6708 mNavigator
->SizeOfIncludingThis(aWindowSizes
.mState
.mMallocSizeOf
);
6711 ForEachGlobalTeardownObserver([&](GlobalTeardownObserver
* et
,
6713 if (nsCOMPtr
<nsISizeOfEventTarget
> iSizeOf
= do_QueryObject(et
)) {
6714 aWindowSizes
.mDOMSizes
.mDOMEventTargetsSize
+=
6715 iSizeOf
->SizeOfEventTargetIncludingThis(
6716 aWindowSizes
.mState
.mMallocSizeOf
);
6718 if (nsCOMPtr
<DOMEventTargetHelper
> helper
= do_QueryObject(et
)) {
6719 if (EventListenerManager
* elm
= helper
->GetExistingListenerManager()) {
6720 aWindowSizes
.mDOMEventListenersCount
+= elm
->ListenerCount();
6723 ++aWindowSizes
.mDOMEventTargetsCount
;
6727 aWindowSizes
.mDOMSizes
.mDOMPerformanceUserEntries
=
6728 mPerformance
->SizeOfUserEntries(aWindowSizes
.mState
.mMallocSizeOf
);
6729 aWindowSizes
.mDOMSizes
.mDOMPerformanceResourceEntries
=
6730 mPerformance
->SizeOfResourceEntries(aWindowSizes
.mState
.mMallocSizeOf
);
6731 aWindowSizes
.mDOMSizes
.mDOMPerformanceEventEntries
=
6732 mPerformance
->SizeOfEventEntries(aWindowSizes
.mState
.mMallocSizeOf
);
6736 void nsGlobalWindowInner::RegisterDataDocumentForMemoryReporting(
6737 Document
* aDocument
) {
6738 aDocument
->SetAddedToMemoryReportAsDataDocument();
6739 mDataDocumentsForMemoryReporting
.AppendElement(aDocument
);
6742 void nsGlobalWindowInner::UnregisterDataDocumentForMemoryReporting(
6743 Document
* aDocument
) {
6744 DebugOnly
<bool> found
=
6745 mDataDocumentsForMemoryReporting
.RemoveElement(aDocument
);
6749 void nsGlobalWindowInner::CollectDOMSizesForDataDocuments(
6750 nsWindowSizes
& aSize
) const {
6751 for (Document
* doc
: mDataDocumentsForMemoryReporting
) {
6753 doc
->DocAddSizeOfIncludingThis(aSize
);
6758 void nsGlobalWindowInner::AddGamepad(GamepadHandle aHandle
, Gamepad
* aGamepad
) {
6759 // Create the index we will present to content based on which indices are
6760 // already taken, as required by the spec.
6761 // https://w3c.github.io/gamepad/gamepad.html#widl-Gamepad-index
6763 while (mGamepadIndexSet
.Contains(index
)) {
6766 mGamepadIndexSet
.Put(index
);
6767 aGamepad
->SetIndex(index
);
6768 mGamepads
.InsertOrUpdate(aHandle
, RefPtr
{aGamepad
});
6771 void nsGlobalWindowInner::RemoveGamepad(GamepadHandle aHandle
) {
6772 RefPtr
<Gamepad
> gamepad
;
6773 if (!mGamepads
.Get(aHandle
, getter_AddRefs(gamepad
))) {
6776 // Free up the index we were using so it can be reused
6777 mGamepadIndexSet
.Remove(gamepad
->Index());
6778 mGamepads
.Remove(aHandle
);
6781 void nsGlobalWindowInner::GetGamepads(nsTArray
<RefPtr
<Gamepad
>>& aGamepads
) {
6784 // navigator.getGamepads() always returns an empty array when
6785 // privacy.resistFingerprinting is true.
6786 if (ShouldResistFingerprinting(RFPTarget::Gamepad
)) {
6790 // mGamepads.Count() may not be sufficient, but it's not harmful.
6791 aGamepads
.SetCapacity(mGamepads
.Count());
6792 for (const auto& entry
: mGamepads
) {
6793 Gamepad
* gamepad
= entry
.GetWeak();
6794 aGamepads
.EnsureLengthAtLeast(gamepad
->Index() + 1);
6795 aGamepads
[gamepad
->Index()] = gamepad
;
6799 already_AddRefed
<Gamepad
> nsGlobalWindowInner::GetGamepad(
6800 GamepadHandle aHandle
) {
6801 RefPtr
<Gamepad
> gamepad
;
6803 if (mGamepads
.Get(aHandle
, getter_AddRefs(gamepad
))) {
6804 return gamepad
.forget();
6810 void nsGlobalWindowInner::SetHasSeenGamepadInput(bool aHasSeen
) {
6811 mHasSeenGamepadInput
= aHasSeen
;
6814 bool nsGlobalWindowInner::HasSeenGamepadInput() { return mHasSeenGamepadInput
; }
6816 void nsGlobalWindowInner::SyncGamepadState() {
6817 if (mHasSeenGamepadInput
) {
6818 RefPtr
<GamepadManager
> gamepadManager(GamepadManager::GetService());
6819 for (const auto& entry
: mGamepads
) {
6820 gamepadManager
->SyncGamepadState(entry
.GetKey(), this, entry
.GetWeak());
6825 void nsGlobalWindowInner::StopGamepadHaptics() {
6826 if (mHasSeenGamepadInput
) {
6827 RefPtr
<GamepadManager
> gamepadManager(GamepadManager::GetService());
6828 gamepadManager
->StopHaptics();
6832 bool nsGlobalWindowInner::UpdateVRDisplays(
6833 nsTArray
<RefPtr
<mozilla::dom::VRDisplay
>>& aDevices
) {
6834 VRDisplay::UpdateVRDisplays(mVRDisplays
, this);
6835 aDevices
= mVRDisplays
.Clone();
6839 void nsGlobalWindowInner::NotifyActiveVRDisplaysChanged() {
6841 mNavigator
->NotifyActiveVRDisplaysChanged();
6845 void nsGlobalWindowInner::NotifyPresentationGenerationChanged(
6846 uint32_t aDisplayID
) {
6847 for (const auto& display
: mVRDisplays
) {
6848 if (display
->DisplayId() == aDisplayID
) {
6849 display
->OnPresentationGenerationChanged();
6854 void nsGlobalWindowInner::DispatchVRDisplayActivate(
6855 uint32_t aDisplayID
, mozilla::dom::VRDisplayEventReason aReason
) {
6856 // Ensure that our list of displays is up to date
6857 VRDisplay::UpdateVRDisplays(mVRDisplays
, this);
6859 // Search for the display identified with aDisplayID and fire the
6861 for (const auto& display
: mVRDisplays
) {
6862 if (display
->DisplayId() == aDisplayID
) {
6863 if (aReason
!= VRDisplayEventReason::Navigation
&&
6864 display
->IsAnyPresenting(gfx::kVRGroupContent
)) {
6865 // We only want to trigger this event if nobody is presenting to the
6866 // display already or when a page is loaded by navigating away
6867 // from a page with an active VR Presentation.
6871 VRDisplayEventInit init
;
6872 init
.mBubbles
= false;
6873 init
.mCancelable
= false;
6874 init
.mDisplay
= display
;
6875 init
.mReason
.Construct(aReason
);
6877 RefPtr
<VRDisplayEvent
> event
=
6878 VRDisplayEvent::Constructor(this, u
"vrdisplayactivate"_ns
, init
);
6879 // vrdisplayactivate is a trusted event, allowing VRDisplay.requestPresent
6880 // to be used in response to link traversal, user request (chrome UX), and
6881 // HMD mounting detection sensors.
6882 event
->SetTrusted(true);
6883 // VRDisplay.requestPresent normally requires a user gesture; however, an
6884 // exception is made to allow it to be called in response to
6885 // vrdisplayactivate during VR link traversal.
6886 display
->StartHandlingVRNavigationEvent();
6887 DispatchEvent(*event
);
6888 display
->StopHandlingVRNavigationEvent();
6889 // Once we dispatch the event, we must not access any members as an event
6890 // listener can do anything, including closing windows.
6896 void nsGlobalWindowInner::DispatchVRDisplayDeactivate(
6897 uint32_t aDisplayID
, mozilla::dom::VRDisplayEventReason aReason
) {
6898 // Ensure that our list of displays is up to date
6899 VRDisplay::UpdateVRDisplays(mVRDisplays
, this);
6901 // Search for the display identified with aDisplayID and fire the
6903 for (const auto& display
: mVRDisplays
) {
6904 if (display
->DisplayId() == aDisplayID
&& display
->IsPresenting()) {
6905 // We only want to trigger this event to content that is presenting to
6906 // the display already.
6908 VRDisplayEventInit init
;
6909 init
.mBubbles
= false;
6910 init
.mCancelable
= false;
6911 init
.mDisplay
= display
;
6912 init
.mReason
.Construct(aReason
);
6914 RefPtr
<VRDisplayEvent
> event
=
6915 VRDisplayEvent::Constructor(this, u
"vrdisplaydeactivate"_ns
, init
);
6916 event
->SetTrusted(true);
6917 DispatchEvent(*event
);
6918 // Once we dispatch the event, we must not access any members as an event
6919 // listener can do anything, including closing windows.
6925 void nsGlobalWindowInner::DispatchVRDisplayConnect(uint32_t aDisplayID
) {
6926 // Ensure that our list of displays is up to date
6927 VRDisplay::UpdateVRDisplays(mVRDisplays
, this);
6929 // Search for the display identified with aDisplayID and fire the
6931 for (const auto& display
: mVRDisplays
) {
6932 if (display
->DisplayId() == aDisplayID
) {
6933 // Fire event even if not presenting to the display.
6934 VRDisplayEventInit init
;
6935 init
.mBubbles
= false;
6936 init
.mCancelable
= false;
6937 init
.mDisplay
= display
;
6938 // VRDisplayEvent.reason is not set for vrdisplayconnect
6940 RefPtr
<VRDisplayEvent
> event
=
6941 VRDisplayEvent::Constructor(this, u
"vrdisplayconnect"_ns
, init
);
6942 event
->SetTrusted(true);
6943 DispatchEvent(*event
);
6944 // Once we dispatch the event, we must not access any members as an event
6945 // listener can do anything, including closing windows.
6951 void nsGlobalWindowInner::DispatchVRDisplayDisconnect(uint32_t aDisplayID
) {
6952 // Ensure that our list of displays is up to date
6953 VRDisplay::UpdateVRDisplays(mVRDisplays
, this);
6955 // Search for the display identified with aDisplayID and fire the
6957 for (const auto& display
: mVRDisplays
) {
6958 if (display
->DisplayId() == aDisplayID
) {
6959 // Fire event even if not presenting to the display.
6960 VRDisplayEventInit init
;
6961 init
.mBubbles
= false;
6962 init
.mCancelable
= false;
6963 init
.mDisplay
= display
;
6964 // VRDisplayEvent.reason is not set for vrdisplaydisconnect
6966 RefPtr
<VRDisplayEvent
> event
=
6967 VRDisplayEvent::Constructor(this, u
"vrdisplaydisconnect"_ns
, init
);
6968 event
->SetTrusted(true);
6969 DispatchEvent(*event
);
6970 // Once we dispatch the event, we must not access any members as an event
6971 // listener can do anything, including closing windows.
6977 void nsGlobalWindowInner::DispatchVRDisplayPresentChange(uint32_t aDisplayID
) {
6978 // Ensure that our list of displays is up to date
6979 VRDisplay::UpdateVRDisplays(mVRDisplays
, this);
6981 // Search for the display identified with aDisplayID and fire the
6983 for (const auto& display
: mVRDisplays
) {
6984 if (display
->DisplayId() == aDisplayID
) {
6985 // Fire event even if not presenting to the display.
6986 VRDisplayEventInit init
;
6987 init
.mBubbles
= false;
6988 init
.mCancelable
= false;
6989 init
.mDisplay
= display
;
6990 // VRDisplayEvent.reason is not set for vrdisplaypresentchange
6991 RefPtr
<VRDisplayEvent
> event
=
6992 VRDisplayEvent::Constructor(this, u
"vrdisplaypresentchange"_ns
, init
);
6993 event
->SetTrusted(true);
6994 DispatchEvent(*event
);
6995 // Once we dispatch the event, we must not access any members as an event
6996 // listener can do anything, including closing windows.
7003 // These constants need to match the constants in Window.webidl
7004 STATE_MAXIMIZED
= 1,
7005 STATE_MINIMIZED
= 2,
7007 STATE_FULLSCREEN
= 4
7010 uint16_t nsGlobalWindowInner::WindowState() {
7011 nsCOMPtr
<nsIWidget
> widget
= GetMainWidget();
7013 int32_t mode
= widget
? widget
->SizeMode() : 0;
7016 case nsSizeMode_Minimized
:
7017 return STATE_MINIMIZED
;
7018 case nsSizeMode_Maximized
:
7019 return STATE_MAXIMIZED
;
7020 case nsSizeMode_Fullscreen
:
7021 return STATE_FULLSCREEN
;
7022 case nsSizeMode_Normal
:
7023 return STATE_NORMAL
;
7025 NS_WARNING("Illegal window state for this chrome window");
7029 return STATE_NORMAL
;
7032 bool nsGlobalWindowInner::IsFullyOccluded() {
7033 nsCOMPtr
<nsIWidget
> widget
= GetMainWidget();
7034 return widget
&& widget
->IsFullyOccluded();
7037 void nsGlobalWindowInner::Maximize() {
7038 if (nsCOMPtr
<nsIWidget
> widget
= GetMainWidget()) {
7039 widget
->SetSizeMode(nsSizeMode_Maximized
);
7043 void nsGlobalWindowInner::Minimize() {
7044 if (nsCOMPtr
<nsIWidget
> widget
= GetMainWidget()) {
7045 widget
->SetSizeMode(nsSizeMode_Minimized
);
7049 void nsGlobalWindowInner::Restore() {
7050 if (nsCOMPtr
<nsIWidget
> widget
= GetMainWidget()) {
7051 widget
->SetSizeMode(nsSizeMode_Normal
);
7055 void nsGlobalWindowInner::GetWorkspaceID(nsAString
& workspaceID
) {
7056 workspaceID
.Truncate();
7057 if (nsCOMPtr
<nsIWidget
> widget
= GetMainWidget()) {
7058 return widget
->GetWorkspaceID(workspaceID
);
7062 void nsGlobalWindowInner::MoveToWorkspace(const nsAString
& workspaceID
) {
7063 if (nsCOMPtr
<nsIWidget
> widget
= GetMainWidget()) {
7064 widget
->MoveToWorkspace(workspaceID
);
7068 void nsGlobalWindowInner::GetAttention(ErrorResult
& aResult
) {
7069 return GetAttentionWithCycleCount(-1, aResult
);
7072 void nsGlobalWindowInner::GetAttentionWithCycleCount(int32_t aCycleCount
,
7073 ErrorResult
& aError
) {
7074 nsCOMPtr
<nsIWidget
> widget
= GetMainWidget();
7077 aError
= widget
->GetAttention(aCycleCount
);
7081 already_AddRefed
<Promise
> nsGlobalWindowInner::PromiseDocumentFlushed(
7082 PromiseDocumentFlushedCallback
& aCallback
, ErrorResult
& aError
) {
7083 MOZ_RELEASE_ASSERT(IsChromeWindow());
7085 if (!IsCurrentInnerWindow()) {
7086 aError
.ThrowInvalidStateError("Not the current inner window");
7090 aError
.ThrowInvalidStateError("No document");
7094 if (mIteratingDocumentFlushedResolvers
) {
7095 aError
.ThrowInvalidStateError("Already iterating through resolvers");
7099 PresShell
* presShell
= mDoc
->GetPresShell();
7101 aError
.ThrowInvalidStateError("No pres shell");
7105 // We need to associate the lifetime of the Promise to the lifetime
7106 // of the caller's global. That way, if the window we're observing
7107 // refresh driver ticks on goes away before our observer is fired,
7108 // we can still resolve the Promise.
7109 nsIGlobalObject
* global
= GetIncumbentGlobal();
7111 aError
.ThrowInvalidStateError("No incumbent global");
7115 RefPtr
<Promise
> resultPromise
= Promise::Create(global
, aError
);
7116 if (aError
.Failed()) {
7120 UniquePtr
<PromiseDocumentFlushedResolver
> flushResolver(
7121 new PromiseDocumentFlushedResolver(resultPromise
, aCallback
));
7123 if (!presShell
->NeedStyleFlush() && !presShell
->NeedLayoutFlush()) {
7124 flushResolver
->Call();
7125 return resultPromise
.forget();
7128 if (!TryToObserveRefresh()) {
7129 aError
.ThrowInvalidStateError("Couldn't observe refresh");
7133 mDocumentFlushedResolvers
.AppendElement(std::move(flushResolver
));
7134 return resultPromise
.forget();
7137 bool nsGlobalWindowInner::TryToObserveRefresh() {
7138 if (mObservingRefresh
) {
7146 nsPresContext
* pc
= mDoc
->GetPresContext();
7151 mObservingRefresh
= true;
7152 auto observer
= MakeRefPtr
<ManagedPostRefreshObserver
>(
7153 pc
, [win
= RefPtr
{this}](bool aWasCanceled
) {
7154 if (win
->MaybeCallDocumentFlushedResolvers(
7155 /* aUntilExhaustion = */ aWasCanceled
)) {
7156 return ManagedPostRefreshObserver::Unregister::No
;
7158 win
->mObservingRefresh
= false;
7159 return ManagedPostRefreshObserver::Unregister::Yes
;
7161 pc
->RegisterManagedPostRefreshObserver(observer
.get());
7162 return mObservingRefresh
;
7165 void nsGlobalWindowInner::CallDocumentFlushedResolvers(bool aUntilExhaustion
) {
7168 // To coalesce MicroTask checkpoints inside callback call, enclose the
7169 // inner loop with nsAutoMicroTask, and perform a MicroTask checkpoint
7173 mIteratingDocumentFlushedResolvers
= true;
7175 auto resolvers
= std::move(mDocumentFlushedResolvers
);
7176 for (const auto& resolver
: resolvers
) {
7180 mIteratingDocumentFlushedResolvers
= false;
7183 // Leaving nsAutoMicroTask above will perform MicroTask checkpoint, and
7184 // Promise callbacks there may create mDocumentFlushedResolvers items.
7186 // If there's no new resolvers, or we're not exhausting the queue, there's
7187 // nothing to do (we'll keep observing if there's any new observer).
7189 // Otherwise, keep looping to call all promises. This case can happen while
7190 // destroying the window. This violates the constraint that the
7191 // promiseDocumentFlushed callback only ever run when no flush is needed,
7192 // but it's necessary to resolve the Promise returned by that.
7193 if (!aUntilExhaustion
|| mDocumentFlushedResolvers
.IsEmpty()) {
7199 bool nsGlobalWindowInner::MaybeCallDocumentFlushedResolvers(
7200 bool aUntilExhaustion
) {
7203 PresShell
* presShell
= mDoc
->GetPresShell();
7204 if (!presShell
|| aUntilExhaustion
) {
7205 CallDocumentFlushedResolvers(/* aUntilExhaustion = */ true);
7209 if (presShell
->NeedStyleFlush() || presShell
->NeedLayoutFlush()) {
7210 // By the time our observer fired, something has already invalidated
7211 // style or layout - or perhaps we're still in the middle of a flush that
7212 // was interrupted. In either case, we'll wait until the next refresh driver
7213 // tick instead and try again.
7217 CallDocumentFlushedResolvers(/* aUntilExhaustion = */ false);
7218 return !mDocumentFlushedResolvers
.IsEmpty();
7221 already_AddRefed
<nsWindowRoot
> nsGlobalWindowInner::GetWindowRoot(
7222 mozilla::ErrorResult
& aError
) {
7223 FORWARD_TO_OUTER_OR_THROW(GetWindowRootOuter
, (), aError
, nullptr);
7226 void nsGlobalWindowInner::SetCursor(const nsACString
& aCursor
,
7227 ErrorResult
& aError
) {
7228 FORWARD_TO_OUTER_OR_THROW(SetCursorOuter
, (aCursor
, aError
), aError
, );
7231 nsIBrowserDOMWindow
* nsGlobalWindowInner::GetBrowserDOMWindow(
7232 ErrorResult
& aError
) {
7233 FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindow
, (), aError
, nullptr);
7236 void nsGlobalWindowInner::SetBrowserDOMWindow(
7237 nsIBrowserDOMWindow
* aBrowserWindow
, ErrorResult
& aError
) {
7238 FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindowOuter
, (aBrowserWindow
),
7242 void nsGlobalWindowInner::NotifyDefaultButtonLoaded(Element
& aDefaultButton
,
7243 ErrorResult
& aError
) {
7244 // Don't snap to a disabled button.
7245 nsCOMPtr
<nsIDOMXULControlElement
> xulControl
= aDefaultButton
.AsXULControl();
7247 aError
.Throw(NS_ERROR_FAILURE
);
7251 aError
= xulControl
->GetDisabled(&disabled
);
7252 if (aError
.Failed() || disabled
) {
7256 // Get the button rect in screen coordinates.
7257 nsIFrame
* frame
= aDefaultButton
.GetPrimaryFrame();
7259 aError
.Throw(NS_ERROR_FAILURE
);
7262 LayoutDeviceIntRect buttonRect
= LayoutDeviceIntRect::FromAppUnitsToNearest(
7263 frame
->GetScreenRectInAppUnits(),
7264 frame
->PresContext()->AppUnitsPerDevPixel());
7266 // Get the widget rect in screen coordinates.
7267 nsIWidget
* widget
= GetNearestWidget();
7269 aError
.Throw(NS_ERROR_FAILURE
);
7272 LayoutDeviceIntRect widgetRect
= widget
->GetScreenBounds();
7274 // Convert the buttonRect coordinates from screen to the widget.
7275 buttonRect
-= widgetRect
.TopLeft();
7276 nsresult rv
= widget
->OnDefaultButtonLoaded(buttonRect
);
7277 if (NS_FAILED(rv
) && rv
!= NS_ERROR_NOT_IMPLEMENTED
) {
7282 ChromeMessageBroadcaster
* nsGlobalWindowInner::MessageManager() {
7283 MOZ_ASSERT(IsChromeWindow());
7284 if (!mChromeFields
.mMessageManager
) {
7285 RefPtr
<ChromeMessageBroadcaster
> globalMM
=
7286 nsFrameMessageManager::GetGlobalMessageManager();
7287 mChromeFields
.mMessageManager
= new ChromeMessageBroadcaster(globalMM
);
7289 return mChromeFields
.mMessageManager
;
7292 ChromeMessageBroadcaster
* nsGlobalWindowInner::GetGroupMessageManager(
7293 const nsAString
& aGroup
) {
7294 MOZ_ASSERT(IsChromeWindow());
7296 return mChromeFields
.mGroupMessageManagers
7297 .LookupOrInsertWith(
7300 return MakeAndAddRef
<ChromeMessageBroadcaster
>(MessageManager());
7305 void nsGlobalWindowInner::InitWasOffline() { mWasOffline
= NS_IsOffline(); }
7307 int16_t nsGlobalWindowInner::Orientation(CallerType aCallerType
) {
7308 // GetOrientationAngle() returns 0, 90, 180 or 270.
7309 // window.orientation returns -90, 0, 90 or 180.
7310 if (nsIGlobalObject::ShouldResistFingerprinting(
7311 aCallerType
, RFPTarget::ScreenOrientation
)) {
7314 int16_t angle
= AssertedCast
<int16_t>(Screen()->GetOrientationAngle());
7315 return angle
<= 180 ? angle
: angle
- 360;
7318 already_AddRefed
<Console
> nsGlobalWindowInner::GetConsole(JSContext
* aCx
,
7321 mConsole
= Console::Create(aCx
, this, aRv
);
7322 if (NS_WARN_IF(aRv
.Failed())) {
7327 RefPtr
<Console
> console
= mConsole
;
7328 return console
.forget();
7331 bool nsGlobalWindowInner::IsSecureContext() const {
7332 JS::Realm
* realm
= js::GetNonCCWObjectRealm(GetWrapperPreserveColor());
7333 return JS::GetIsSecureContext(realm
);
7336 External
* nsGlobalWindowInner::External() {
7338 mExternal
= new dom::External(ToSupports(this));
7344 void nsGlobalWindowInner::ClearDocumentDependentSlots(JSContext
* aCx
) {
7345 // If JSAPI OOMs here, there is basically nothing we can do to recover safely.
7346 if (!Window_Binding::ClearCachedDocumentValue(aCx
, this) ||
7347 !Window_Binding::ClearCachedPerformanceValue(aCx
, this)) {
7348 MOZ_CRASH("Unhandlable OOM while clearing document dependent slots.");
7353 JSObject
* nsGlobalWindowInner::CreateNamedPropertiesObject(
7354 JSContext
* aCx
, JS::Handle
<JSObject
*> aProto
) {
7355 return WindowNamedPropertiesHandler::Create(aCx
, aProto
);
7358 void nsGlobalWindowInner::RedefineProperty(JSContext
* aCx
,
7359 const char* aPropName
,
7360 JS::Handle
<JS::Value
> aValue
,
7361 ErrorResult
& aError
) {
7362 JS::Rooted
<JSObject
*> thisObj(aCx
, GetWrapperPreserveColor());
7364 aError
.Throw(NS_ERROR_UNEXPECTED
);
7368 if (!JS_WrapObject(aCx
, &thisObj
) ||
7369 !JS_DefineProperty(aCx
, thisObj
, aPropName
, aValue
, JSPROP_ENUMERATE
)) {
7370 aError
.Throw(NS_ERROR_FAILURE
);
7374 void nsGlobalWindowInner::FireOnNewGlobalObject() {
7375 // AutoEntryScript required to invoke debugger hook, which is a
7376 // Gecko-specific concept at present.
7377 AutoEntryScript
aes(this, "nsGlobalWindowInner report new global");
7378 JS::Rooted
<JSObject
*> global(aes
.cx(), GetWrapper());
7379 JS_FireOnNewGlobalObject(aes
.cx(), global
);
7382 #if defined(_WINDOWS_) && !defined(MOZ_WRAPPED_WINDOWS_H)
7384 "wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)
7385 # error "Never include unwrapped windows.h in this file!"
7388 already_AddRefed
<Promise
> nsGlobalWindowInner::CreateImageBitmap(
7389 const ImageBitmapSource
& aImage
, const ImageBitmapOptions
& aOptions
,
7391 return ImageBitmap::Create(this, aImage
, Nothing(), aOptions
, aRv
);
7394 already_AddRefed
<Promise
> nsGlobalWindowInner::CreateImageBitmap(
7395 const ImageBitmapSource
& aImage
, int32_t aSx
, int32_t aSy
, int32_t aSw
,
7396 int32_t aSh
, const ImageBitmapOptions
& aOptions
, ErrorResult
& aRv
) {
7397 return ImageBitmap::Create(
7398 this, aImage
, Some(gfx::IntRect(aSx
, aSy
, aSw
, aSh
)), aOptions
, aRv
);
7401 // https://html.spec.whatwg.org/#structured-cloning
7402 void nsGlobalWindowInner::StructuredClone(
7403 JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
7404 const StructuredSerializeOptions
& aOptions
,
7405 JS::MutableHandle
<JS::Value
> aRetval
, ErrorResult
& aError
) {
7406 nsContentUtils::StructuredClone(aCx
, this, aValue
, aOptions
, aRetval
, aError
);
7409 nsresult
nsGlobalWindowInner::Dispatch(
7410 already_AddRefed
<nsIRunnable
>&& aRunnable
) const {
7411 MOZ_RELEASE_ASSERT(NS_IsMainThread());
7412 return NS_DispatchToCurrentThread(std::move(aRunnable
));
7415 nsISerialEventTarget
* nsGlobalWindowInner::SerialEventTarget() const {
7416 MOZ_RELEASE_ASSERT(NS_IsMainThread());
7417 return GetMainThreadSerialEventTarget();
7420 Worklet
* nsGlobalWindowInner::GetPaintWorklet(ErrorResult
& aRv
) {
7421 if (!mPaintWorklet
) {
7422 nsIPrincipal
* principal
= GetPrincipal();
7424 aRv
.Throw(NS_ERROR_FAILURE
);
7428 mPaintWorklet
= PaintWorkletImpl::CreateWorklet(this, principal
);
7431 return mPaintWorklet
;
7434 void nsGlobalWindowInner::GetRegionalPrefsLocales(
7435 nsTArray
<nsString
>& aLocales
) {
7436 MOZ_ASSERT(mozilla::intl::LocaleService::GetInstance());
7438 AutoTArray
<nsCString
, 10> rpLocales
;
7439 mozilla::intl::LocaleService::GetInstance()->GetRegionalPrefsLocales(
7442 for (const auto& loc
: rpLocales
) {
7443 aLocales
.AppendElement(NS_ConvertUTF8toUTF16(loc
));
7447 void nsGlobalWindowInner::GetWebExposedLocales(nsTArray
<nsString
>& aLocales
) {
7448 MOZ_ASSERT(mozilla::intl::LocaleService::GetInstance());
7450 AutoTArray
<nsCString
, 10> rpLocales
;
7451 mozilla::intl::LocaleService::GetInstance()->GetWebExposedLocales(rpLocales
);
7453 for (const auto& loc
: rpLocales
) {
7454 aLocales
.AppendElement(NS_ConvertUTF8toUTF16(loc
));
7458 IntlUtils
* nsGlobalWindowInner::GetIntlUtils(ErrorResult
& aError
) {
7460 mIntlUtils
= new IntlUtils(this);
7466 void nsGlobalWindowInner::StoreSharedWorker(SharedWorker
* aSharedWorker
) {
7467 MOZ_ASSERT(aSharedWorker
);
7468 MOZ_ASSERT(!mSharedWorkers
.Contains(aSharedWorker
));
7470 mSharedWorkers
.AppendElement(aSharedWorker
);
7473 void nsGlobalWindowInner::ForgetSharedWorker(SharedWorker
* aSharedWorker
) {
7474 MOZ_ASSERT(aSharedWorker
);
7475 MOZ_ASSERT(mSharedWorkers
.Contains(aSharedWorker
));
7477 mSharedWorkers
.RemoveElement(aSharedWorker
);
7480 RefPtr
<GenericPromise
> nsGlobalWindowInner::StorageAccessPermissionChanged(
7482 // Invalidate cached StorageAllowed field so that calls to GetLocalStorage
7483 // give us the updated localStorage object.
7484 ClearStorageAllowedCache();
7486 // If we're always partitioning non-cookie third party storage then
7487 // there is no need to clear it when the user accepts requestStorageAccess.
7489 privacy_partition_always_partition_third_party_non_cookie_storage()) {
7490 // Just reset the active cookie and storage principals
7491 nsCOMPtr
<nsICookieJarSettings
> cjs
;
7493 cjs
= mDoc
->CookieJarSettings();
7495 StorageAccess storageAccess
= StorageAllowedForWindow(this);
7496 if (ShouldPartitionStorage(storageAccess
) &&
7497 StoragePartitioningEnabled(storageAccess
, cjs
)) {
7499 mDoc
->ClearActiveCookieAndStoragePrincipals();
7501 // When storage access is granted the content process needs to request the
7502 // updated cookie list from the parent process. Otherwise the site won't
7503 // have access to unpartitioned cookies via document.cookie without a
7506 nsIChannel
* channel
= mDoc
->GetChannel();
7508 // The promise resolves when the updated cookie list has been received
7510 return ContentChild::UpdateCookieStatus(channel
);
7516 PropagateStorageAccessPermissionGrantedToWorkers(*this);
7518 // If we have a partitioned localStorage, it's time to replace it with a real
7519 // one in order to receive notifications.
7521 if (mLocalStorage
) {
7522 IgnoredErrorResult error
;
7523 GetLocalStorage(error
);
7524 if (NS_WARN_IF(error
.Failed())) {
7525 return MozPromise
<bool, nsresult
, true>::CreateAndReject(
7526 error
.StealNSResult(), __func__
);
7529 MOZ_ASSERT(mLocalStorage
&&
7530 mLocalStorage
->Type() == Storage::eLocalStorage
);
7532 if (NextGenLocalStorageEnabled() && mListenerManager
&&
7533 mListenerManager
->HasListenersFor(nsGkAtoms::onstorage
)) {
7534 auto object
= static_cast<LSObject
*>(mLocalStorage
.get());
7536 object
->EnsureObserver();
7540 // Reset the IndexedDB factory.
7541 mIndexedDB
= nullptr;
7544 mCacheStorage
= nullptr;
7546 // Reset the active cookie and storage principals
7548 mDoc
->ClearActiveCookieAndStoragePrincipals();
7549 if (mWindowGlobalChild
) {
7550 // XXX(farre): This is a bit backwards, but clearing the cookie
7551 // principal might make us end up with a new effective storage
7552 // principal on the child side than on the parent side, which
7553 // means that we need to sync it. See bug 1705359.
7554 mWindowGlobalChild
->SetDocumentPrincipal(
7555 mDoc
->NodePrincipal(), mDoc
->EffectiveStoragePrincipal());
7559 // When storage access is granted the content process needs to request the
7560 // updated cookie list from the parent process. Otherwise the site won't have
7561 // access to unpartitioned cookies via document.cookie without a reload.
7563 nsIChannel
* channel
= mDoc
->GetChannel();
7565 // The promise resolves when the updated cookie list has been received
7567 return ContentChild::UpdateCookieStatus(channel
);
7570 return MozPromise
<bool, nsresult
, true>::CreateAndResolve(true, __func__
);
7573 ContentMediaController
* nsGlobalWindowInner::GetContentMediaController() {
7574 if (mContentMediaController
) {
7575 return mContentMediaController
;
7577 if (!mBrowsingContext
) {
7581 mContentMediaController
= new ContentMediaController(mBrowsingContext
->Id());
7582 return mContentMediaController
;
7585 void nsGlobalWindowInner::SetScrollMarks(const nsTArray
<uint32_t>& aScrollMarks
,
7586 bool aOnHScrollbar
) {
7587 mScrollMarks
.Assign(aScrollMarks
);
7588 mScrollMarksOnHScrollbar
= aOnHScrollbar
;
7590 // Mark the scrollbar for repainting.
7592 PresShell
* presShell
= mDoc
->GetPresShell();
7594 nsIScrollableFrame
* sf
= presShell
->GetRootScrollFrameAsScrollable();
7596 sf
->InvalidateScrollbars();
7603 already_AddRefed
<nsGlobalWindowInner
> nsGlobalWindowInner::Create(
7604 nsGlobalWindowOuter
* aOuterWindow
, bool aIsChrome
,
7605 WindowGlobalChild
* aActor
) {
7606 RefPtr
<nsGlobalWindowInner
> window
=
7607 new nsGlobalWindowInner(aOuterWindow
, aActor
);
7609 window
->mIsChrome
= true;
7610 window
->mCleanMessageManager
= true;
7614 aActor
->InitWindowGlobal(window
);
7617 window
->InitWasOffline();
7618 return window
.forget();
7621 JS::loader::ModuleLoaderBase
* nsGlobalWindowInner::GetModuleLoader(
7623 Document
* document
= GetDocument();
7628 ScriptLoader
* loader
= document
->ScriptLoader();
7633 return loader
->GetModuleLoader();
7636 void nsGlobalWindowInner::SetCurrentPasteDataTransfer(
7637 DataTransfer
* aDataTransfer
) {
7638 MOZ_ASSERT_IF(aDataTransfer
, aDataTransfer
->GetEventMessage() == ePaste
);
7639 MOZ_ASSERT_IF(aDataTransfer
, aDataTransfer
->ClipboardType() ==
7640 nsIClipboard::kGlobalClipboard
);
7641 MOZ_ASSERT_IF(aDataTransfer
, aDataTransfer
->GetAsyncGetClipboardData());
7642 mCurrentPasteDataTransfer
= aDataTransfer
;
7645 DataTransfer
* nsGlobalWindowInner::GetCurrentPasteDataTransfer() const {
7646 return mCurrentPasteDataTransfer
;
7649 TrustedTypePolicyFactory
* nsGlobalWindowInner::TrustedTypes() {
7650 if (!mTrustedTypePolicyFactory
) {
7651 mTrustedTypePolicyFactory
= MakeRefPtr
<TrustedTypePolicyFactory
>(this);
7654 return mTrustedTypePolicyFactory
;
7657 nsIURI
* nsPIDOMWindowInner::GetDocumentURI() const {
7658 return mDoc
? mDoc
->GetDocumentURI() : mDocumentURI
.get();
7661 nsIURI
* nsPIDOMWindowInner::GetDocBaseURI() const {
7662 return mDoc
? mDoc
->GetDocBaseURI() : mDocBaseURI
.get();
7665 mozilla::dom::WindowContext
* nsPIDOMWindowInner::GetWindowContext() const {
7666 return mWindowGlobalChild
? mWindowGlobalChild
->WindowContext() : nullptr;
7669 bool nsPIDOMWindowInner::RemoveFromBFCacheSync() {
7670 if (Document
* doc
= GetExtantDoc()) {
7671 return doc
->RemoveFromBFCacheSync();
7676 void nsPIDOMWindowInner::MaybeCreateDoc() {
7677 // XXX: Forward to outer?
7679 if (nsIDocShell
* docShell
= GetDocShell()) {
7680 // Note that |document| here is the same thing as our mDoc, but we
7681 // don't have to explicitly set the member variable because the docshell
7682 // has already called SetNewDocument().
7683 nsCOMPtr
<Document
> document
= docShell
->GetDocument();
7688 mozilla::dom::DocGroup
* nsPIDOMWindowInner::GetDocGroup() const {
7689 Document
* doc
= GetExtantDoc();
7691 return doc
->GetDocGroup();
7696 mozilla::dom::BrowsingContextGroup
*
7697 nsPIDOMWindowInner::GetBrowsingContextGroup() const {
7698 return mBrowsingContext
? mBrowsingContext
->Group() : nullptr;
7701 nsIGlobalObject
* nsPIDOMWindowInner::AsGlobal() {
7702 return nsGlobalWindowInner::Cast(this);
7705 const nsIGlobalObject
* nsPIDOMWindowInner::AsGlobal() const {
7706 return nsGlobalWindowInner::Cast(this);
7709 RefPtr
<GenericPromise
>
7710 nsPIDOMWindowInner::SaveStorageAccessPermissionGranted() {
7711 WindowContext
* wc
= GetWindowContext();
7713 Unused
<< wc
->SetUsingStorageAccess(true);
7716 return nsGlobalWindowInner::Cast(this)->StorageAccessPermissionChanged(true);
7719 RefPtr
<GenericPromise
>
7720 nsPIDOMWindowInner::SaveStorageAccessPermissionRevoked() {
7721 WindowContext
* wc
= GetWindowContext();
7723 Unused
<< wc
->SetUsingStorageAccess(false);
7726 return nsGlobalWindowInner::Cast(this)->StorageAccessPermissionChanged(false);
7729 bool nsPIDOMWindowInner::UsingStorageAccess() {
7730 WindowContext
* wc
= GetWindowContext();
7735 return wc
->GetUsingStorageAccess();
7738 nsPIDOMWindowInner::nsPIDOMWindowInner(nsPIDOMWindowOuter
* aOuterWindow
,
7739 WindowGlobalChild
* aActor
)
7741 mIsDocumentLoaded(false),
7742 mIsHandlingResizeEvent(false),
7743 mMayHaveDOMActivateEventListeners(false),
7744 mMayHavePaintEventListener(false),
7745 mMayHaveTouchEventListener(false),
7746 mMayHaveSelectionChangeEventListener(false),
7747 mMayHaveFormSelectEventListener(false),
7748 mMayHaveMouseEnterLeaveEventListener(false),
7749 mMayHavePointerEnterLeaveEventListener(false),
7750 mMayHaveTransitionEventListener(false),
7751 mMayHaveBeforeInputEventListenerForTelemetry(false),
7752 mMutationObserverHasObservedNodeForTelemetry(false),
7753 mOuterWindow(aOuterWindow
),
7755 mHasNotifiedGlobalCreated(false),
7756 mMarkedCCGeneration(0),
7757 mHasTriedToCacheTopInnerWindow(false),
7758 mNumOfIndexedDBDatabases(0),
7759 mNumOfOpenWebSockets(0),
7761 mWindowGlobalChild(aActor
),
7762 mWasSuspendedByGroup(false) {
7763 MOZ_ASSERT(aOuterWindow
);
7764 mBrowsingContext
= aOuterWindow
->GetBrowsingContext();
7766 if (mWindowGlobalChild
) {
7767 mWindowID
= aActor
->InnerWindowId();
7769 MOZ_ASSERT(mWindowGlobalChild
->BrowsingContext() == mBrowsingContext
);
7771 mWindowID
= nsContentUtils::GenerateWindowId();
7775 nsPIDOMWindowInner::~nsPIDOMWindowInner() = default;
7777 #undef FORWARD_TO_OUTER
7778 #undef FORWARD_TO_OUTER_OR_THROW
7779 #undef FORWARD_TO_OUTER_VOID