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