Coverage Report

Created: 2018-09-25 14:53

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