Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsGlobalWindowOuter.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 "nsICookieService.h"
20
#include "nsIDOMStorageManager.h"
21
#include "nsISecureBrowserUI.h"
22
#include "nsIWebProgressListener.h"
23
#include "mozilla/AntiTrackingCommon.h"
24
#include "mozilla/dom/ContentFrameMessageManager.h"
25
#include "mozilla/dom/EventTarget.h"
26
#include "mozilla/dom/LocalStorage.h"
27
#include "mozilla/dom/Storage.h"
28
#include "mozilla/dom/IdleRequest.h"
29
#include "mozilla/dom/Performance.h"
30
#include "mozilla/dom/StorageEvent.h"
31
#include "mozilla/dom/StorageEventBinding.h"
32
#include "mozilla/dom/StorageNotifierService.h"
33
#include "mozilla/dom/StorageUtils.h"
34
#include "mozilla/dom/Timeout.h"
35
#include "mozilla/dom/TimeoutHandler.h"
36
#include "mozilla/dom/TimeoutManager.h"
37
#include "mozilla/IntegerPrintfMacros.h"
38
#if defined(MOZ_WIDGET_ANDROID)
39
#include "mozilla/dom/WindowOrientationObserver.h"
40
#endif
41
#include "nsError.h"
42
#include "nsIIdleService.h"
43
#include "nsISizeOfEventTarget.h"
44
#include "nsDOMJSUtils.h"
45
#include "nsArrayUtils.h"
46
#include "nsDOMWindowList.h"
47
#include "mozilla/dom/WakeLock.h"
48
#include "mozilla/dom/power/PowerManagerService.h"
49
#include "nsIDocShellTreeOwner.h"
50
#include "nsIInterfaceRequestorUtils.h"
51
#include "nsIPermissionManager.h"
52
#include "nsIScriptContext.h"
53
#include "nsIScriptTimeoutHandler.h"
54
#include "nsITimeoutHandler.h"
55
#include "nsIController.h"
56
#include "nsISlowScriptDebug.h"
57
#include "nsWindowMemoryReporter.h"
58
#include "nsWindowSizes.h"
59
#include "WindowNamedPropertiesHandler.h"
60
#include "nsFrameSelection.h"
61
#include "nsNetUtil.h"
62
#include "nsVariant.h"
63
#include "nsPrintfCString.h"
64
#include "mozilla/intl/LocaleService.h"
65
#include "WindowDestroyedEvent.h"
66
#include "nsDocShellLoadInfo.h"
67
68
// Helper Classes
69
#include "nsJSUtils.h"
70
#include "jsapi.h"
71
#include "js/Wrapper.h"
72
#include "nsCharSeparatedTokenizer.h"
73
#include "nsReadableUtils.h"
74
#include "nsJSEnvironment.h"
75
#include "mozilla/dom/ScriptSettings.h"
76
#include "mozilla/Preferences.h"
77
#include "mozilla/Likely.h"
78
#include "mozilla/Sprintf.h"
79
#include "mozilla/Unused.h"
80
81
// Other Classes
82
#include "mozilla/dom/BarProps.h"
83
#include "nsContentCID.h"
84
#include "nsLayoutStatics.h"
85
#include "nsCCUncollectableMarker.h"
86
#include "mozilla/dom/WorkerCommon.h"
87
#include "mozilla/dom/ToJSValue.h"
88
#include "nsJSPrincipals.h"
89
#include "mozilla/Attributes.h"
90
#include "mozilla/Debug.h"
91
#include "mozilla/EventListenerManager.h"
92
#include "mozilla/EventStates.h"
93
#include "mozilla/MouseEvents.h"
94
#include "mozilla/ProcessHangMonitor.h"
95
#include "mozilla/StaticPrefs.h"
96
#include "mozilla/ThrottledEventQueue.h"
97
#include "AudioChannelService.h"
98
#include "nsAboutProtocolUtils.h"
99
#include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
100
#include "PostMessageEvent.h"
101
#include "mozilla/dom/DocGroup.h"
102
#include "mozilla/dom/TabGroup.h"
103
104
// Interfaces Needed
105
#include "nsIFrame.h"
106
#include "nsCanvasFrame.h"
107
#include "nsIWidget.h"
108
#include "nsIWidgetListener.h"
109
#include "nsIBaseWindow.h"
110
#include "nsIDeviceSensors.h"
111
#include "nsIContent.h"
112
#include "nsIDocShell.h"
113
#include "nsIDocument.h"
114
#include "Crypto.h"
115
#include "nsDOMString.h"
116
#include "nsIEmbeddingSiteWindow.h"
117
#include "nsThreadUtils.h"
118
#include "nsILoadContext.h"
119
#include "nsIPresShell.h"
120
#include "nsIScrollableFrame.h"
121
#include "nsView.h"
122
#include "nsViewManager.h"
123
#include "nsISelectionController.h"
124
#include "nsIPrompt.h"
125
#include "nsIPromptService.h"
126
#include "nsIPromptFactory.h"
127
#include "nsIAddonPolicyService.h"
128
#include "nsIWritablePropertyBag2.h"
129
#include "nsIWebNavigation.h"
130
#include "nsIWebBrowserChrome.h"
131
#include "nsIWebBrowserFind.h"  // For window.find()
132
#include "nsIWindowMediator.h"  // For window.find()
133
#include "nsComputedDOMStyle.h"
134
#include "nsDOMCID.h"
135
#include "nsDOMWindowUtils.h"
136
#include "nsIWindowWatcher.h"
137
#include "nsPIWindowWatcher.h"
138
#include "nsIContentViewer.h"
139
#include "nsIScriptError.h"
140
#include "nsIControllers.h"
141
#include "nsIControllerContext.h"
142
#include "nsGlobalWindowCommands.h"
143
#include "nsQueryObject.h"
144
#include "nsContentUtils.h"
145
#include "nsCSSProps.h"
146
#include "nsIURIFixup.h"
147
#include "nsIURIMutator.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
169
#include "xpcprivate.h"
170
171
#ifdef NS_PRINTING
172
#include "nsIPrintSettings.h"
173
#include "nsIPrintSettingsService.h"
174
#include "nsIWebBrowserPrint.h"
175
#endif
176
177
#include "nsWindowRoot.h"
178
#include "nsNetCID.h"
179
#include "nsIArray.h"
180
181
#include "XULDocument.h"
182
#include "nsIDOMXULCommandDispatcher.h"
183
184
#include "nsBindingManager.h"
185
#include "nsXBLService.h"
186
187
#include "nsIDragService.h"
188
#include "mozilla/dom/Element.h"
189
#include "mozilla/dom/Selection.h"
190
#include "nsFrameLoader.h"
191
#include "nsISupportsPrimitives.h"
192
#include "nsXPCOMCID.h"
193
#include "mozilla/Logging.h"
194
#include "prenv.h"
195
196
#include "mozilla/dom/IDBFactory.h"
197
#include "mozilla/dom/MessageChannel.h"
198
#include "mozilla/dom/Promise.h"
199
200
#include "mozilla/dom/Gamepad.h"
201
#include "mozilla/dom/GamepadManager.h"
202
203
#include "gfxVR.h"
204
#include "mozilla/dom/VRDisplay.h"
205
#include "mozilla/dom/VRDisplayEvent.h"
206
#include "mozilla/dom/VRDisplayEventBinding.h"
207
#include "mozilla/dom/VREventObserver.h"
208
209
#include "nsRefreshDriver.h"
210
#include "Layers.h"
211
212
#include "mozilla/BasePrincipal.h"
213
#include "mozilla/Services.h"
214
#include "mozilla/Telemetry.h"
215
#include "mozilla/dom/Location.h"
216
#include "nsHTMLDocument.h"
217
#include "nsWrapperCacheInlines.h"
218
#include "mozilla/DOMEventTargetHelper.h"
219
#include "prrng.h"
220
#include "nsSandboxFlags.h"
221
#include "nsBaseCommandController.h"
222
#include "nsXULControllers.h"
223
#include "mozilla/dom/AudioContext.h"
224
#include "mozilla/dom/BrowserElementDictionariesBinding.h"
225
#include "mozilla/dom/cache/CacheStorage.h"
226
#include "mozilla/dom/Console.h"
227
#include "mozilla/dom/Fetch.h"
228
#include "mozilla/dom/FunctionBinding.h"
229
#include "mozilla/dom/HashChangeEvent.h"
230
#include "mozilla/dom/IntlUtils.h"
231
#include "mozilla/dom/PopStateEvent.h"
232
#include "mozilla/dom/PopupBlockedEvent.h"
233
#include "mozilla/dom/PrimitiveConversions.h"
234
#include "mozilla/dom/WindowBinding.h"
235
#include "nsITabChild.h"
236
#include "mozilla/dom/MediaQueryList.h"
237
#include "mozilla/dom/ScriptSettings.h"
238
#include "mozilla/dom/NavigatorBinding.h"
239
#include "mozilla/dom/ImageBitmap.h"
240
#include "mozilla/dom/ImageBitmapBinding.h"
241
#include "mozilla/dom/ServiceWorkerRegistration.h"
242
#include "mozilla/dom/U2F.h"
243
#include "mozilla/dom/WebIDLGlobalNameHash.h"
244
#include "mozilla/dom/Worklet.h"
245
#ifdef HAVE_SIDEBAR
246
#include "mozilla/dom/ExternalBinding.h"
247
#endif
248
249
#ifdef MOZ_WEBSPEECH
250
#include "mozilla/dom/SpeechSynthesis.h"
251
#endif
252
253
// Apple system headers seem to have a check() macro.  <sigh>
254
#ifdef check
255
class nsIScriptTimeoutHandler;
256
#undef check
257
#endif // check
258
#include "AccessCheck.h"
259
260
#ifdef ANDROID
261
#include <android/log.h>
262
#endif
263
264
#ifdef XP_WIN
265
#include <process.h>
266
#define getpid _getpid
267
#else
268
#include <unistd.h> // for getpid()
269
#endif
270
271
using namespace mozilla;
272
using namespace mozilla::dom;
273
using namespace mozilla::dom::ipc;
274
using mozilla::BasePrincipal;
275
using mozilla::OriginAttributes;
276
using mozilla::TimeStamp;
277
278
#define FORWARD_TO_INNER(method, args, err_rval)                        \
279
0
  PR_BEGIN_MACRO                                                        \
280
0
  if (!mInnerWindow) {                                                  \
281
0
    NS_WARNING("No inner window available!");                           \
282
0
    return err_rval;                                                    \
283
0
  }                                                                     \
284
0
  return GetCurrentInnerWindowInternal()->method args;                  \
285
0
  PR_END_MACRO
286
287
#define FORWARD_TO_INNER_VOID(method, args)                             \
288
0
  PR_BEGIN_MACRO                                                        \
289
0
  if (!mInnerWindow) {                                                  \
290
0
    NS_WARNING("No inner window available!");                           \
291
0
    return;                                                             \
292
0
  }                                                                     \
293
0
  GetCurrentInnerWindowInternal()->method args;                         \
294
0
  return;                                                               \
295
0
  PR_END_MACRO
296
297
// Same as FORWARD_TO_INNER, but this will create a fresh inner if an
298
// inner doesn't already exists.
299
#define FORWARD_TO_INNER_CREATE(method, args, err_rval)                 \
300
0
  PR_BEGIN_MACRO                                                        \
301
0
  if (!mInnerWindow) {                                                  \
302
0
    if (mIsClosed) {                                                    \
303
0
      return err_rval;                                                  \
304
0
    }                                                                   \
305
0
    nsCOMPtr<nsIDocument> kungFuDeathGrip = GetDoc();                   \
306
0
    ::mozilla::Unused << kungFuDeathGrip;                               \
307
0
    if (!mInnerWindow) {                                                \
308
0
      return err_rval;                                                  \
309
0
    }                                                                   \
310
0
  }                                                                     \
311
0
  return GetCurrentInnerWindowInternal()->method args;                  \
312
0
  PR_END_MACRO
313
314
static LazyLogModule gDOMLeakPRLogOuter("DOMLeakOuter");
315
316
static int32_t              gOpenPopupSpamCount               = 0;
317
318
nsGlobalWindowOuter::OuterWindowByIdTable *nsGlobalWindowOuter::sOuterWindowsById = nullptr;
319
320
/* static */
321
nsPIDOMWindowOuter*
322
nsPIDOMWindowOuter::GetFromCurrentInner(nsPIDOMWindowInner* aInner)
323
0
{
324
0
  if (!aInner) {
325
0
    return nullptr;
326
0
  }
327
0
328
0
  nsPIDOMWindowOuter* outer = aInner->GetOuterWindow();
329
0
  if (!outer || outer->GetCurrentInnerWindow() != aInner) {
330
0
    return nullptr;
331
0
  }
332
0
333
0
  return outer;
334
0
}
335
336
//*****************************************************************************
337
// nsOuterWindowProxy: Outer Window Proxy
338
//*****************************************************************************
339
340
class nsOuterWindowProxy : public js::Wrapper
341
{
342
public:
343
0
  constexpr nsOuterWindowProxy() : js::Wrapper(0) { }
344
345
0
  bool finalizeInBackground(const JS::Value& priv) const override {
346
0
    return false;
347
0
  }
348
349
  // Standard internal methods
350
  bool getOwnPropertyDescriptor(JSContext* cx,
351
                                JS::Handle<JSObject*> proxy,
352
                                JS::Handle<jsid> id,
353
                                JS::MutableHandle<JS::PropertyDescriptor> desc)
354
                                const override;
355
  bool defineProperty(JSContext* cx,
356
                      JS::Handle<JSObject*> proxy,
357
                      JS::Handle<jsid> id,
358
                      JS::Handle<JS::PropertyDescriptor> desc,
359
                      JS::ObjectOpResult &result) const override;
360
  bool ownPropertyKeys(JSContext *cx,
361
                       JS::Handle<JSObject*> proxy,
362
                       JS::AutoIdVector &props) const override;
363
  bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
364
                       JS::Handle<jsid> id,
365
                       JS::ObjectOpResult &result) const override;
366
367
  bool getPrototypeIfOrdinary(JSContext* cx,
368
                              JS::Handle<JSObject*> proxy,
369
                              bool* isOrdinary,
370
                              JS::MutableHandle<JSObject*> protop) const override;
371
372
  JSObject* enumerate(JSContext *cx, JS::Handle<JSObject*> proxy) const override;
373
  bool preventExtensions(JSContext* cx,
374
                         JS::Handle<JSObject*> proxy,
375
                         JS::ObjectOpResult& result) const override;
376
  bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
377
                    const override;
378
  bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
379
           JS::Handle<jsid> id, bool *bp) const override;
380
  bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
381
           JS::Handle<JS::Value> receiver,
382
           JS::Handle<jsid> id,
383
           JS::MutableHandle<JS::Value> vp) const override;
384
  bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
385
           JS::Handle<jsid> id, JS::Handle<JS::Value> v,
386
           JS::Handle<JS::Value> receiver,
387
           JS::ObjectOpResult &result) const override;
388
389
  // SpiderMonkey extensions
390
  bool getPropertyDescriptor(JSContext* cx,
391
                             JS::Handle<JSObject*> proxy,
392
                             JS::Handle<jsid> id,
393
                             JS::MutableHandle<JS::PropertyDescriptor> desc)
394
                             const override;
395
  bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
396
              JS::Handle<jsid> id, bool *bp) const override;
397
  bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
398
                                    JS::AutoIdVector &props) const override;
399
  const char *className(JSContext *cx,
400
                        JS::Handle<JSObject*> wrapper) const override;
401
402
  void finalize(JSFreeOp *fop, JSObject *proxy) const override;
403
  size_t objectMoved(JSObject* proxy, JSObject* old) const override;
404
405
0
  bool isCallable(JSObject *obj) const override {
406
0
    return false;
407
0
  }
408
0
  bool isConstructor(JSObject *obj) const override {
409
0
    return false;
410
0
  }
411
412
  static const nsOuterWindowProxy singleton;
413
414
protected:
415
  static nsGlobalWindowOuter* GetOuterWindow(JSObject *proxy)
416
0
  {
417
0
    nsGlobalWindowOuter* outerWindow = nsGlobalWindowOuter::FromSupports(
418
0
      static_cast<nsISupports*>(js::GetProxyReservedSlot(proxy, 0).toPrivate()));
419
0
    return outerWindow;
420
0
  }
421
422
  // False return value means we threw an exception.  True return value
423
  // but false "found" means we didn't have a subframe at that index.
424
  bool GetSubframeWindow(JSContext *cx, JS::Handle<JSObject*> proxy,
425
                         JS::Handle<jsid> id,
426
                         JS::MutableHandle<JS::Value> vp,
427
                         bool &found) const;
428
429
  // Returns a non-null window only if id is an index and we have a
430
  // window at that index.
431
  already_AddRefed<nsPIDOMWindowOuter>
432
  GetSubframeWindow(JSContext *cx,
433
                    JS::Handle<JSObject*> proxy,
434
                    JS::Handle<jsid> id) const;
435
436
  bool AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
437
                                  JS::AutoIdVector &props) const;
438
};
439
440
// Give OuterWindowProxyClass 2 reserved slots, like the other wrappers, so
441
// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
442
// malloc.
443
const js::Class OuterWindowProxyClass = PROXY_CLASS_DEF(
444
    "Proxy",
445
    JSCLASS_HAS_RESERVED_SLOTS(2)); /* additional class flags */
446
447
const char *
448
nsOuterWindowProxy::className(JSContext *cx, JS::Handle<JSObject*> proxy) const
449
0
{
450
0
    MOZ_ASSERT(js::IsProxy(proxy));
451
0
452
0
    return "Window";
453
0
}
454
455
void
456
nsOuterWindowProxy::finalize(JSFreeOp *fop, JSObject *proxy) const
457
0
{
458
0
  nsGlobalWindowOuter* outerWindow = GetOuterWindow(proxy);
459
0
  if (outerWindow) {
460
0
    outerWindow->ClearWrapper(proxy);
461
0
462
0
    // Ideally we would use OnFinalize here, but it's possible that
463
0
    // EnsureScriptEnvironment will later be called on the window, and we don't
464
0
    // want to create a new script object in that case. Therefore, we need to
465
0
    // write a non-null value that will reliably crash when dereferenced.
466
0
    outerWindow->PoisonOuterWindowProxy(proxy);
467
0
  }
468
0
}
469
470
bool
471
nsOuterWindowProxy::getPropertyDescriptor(JSContext* cx,
472
                                          JS::Handle<JSObject*> proxy,
473
                                          JS::Handle<jsid> id,
474
                                          JS::MutableHandle<JS::PropertyDescriptor> desc) const
475
0
{
476
0
  // The only thing we can do differently from js::Wrapper is shadow stuff with
477
0
  // our indexed properties, so we can just try getOwnPropertyDescriptor and if
478
0
  // that gives us nothing call on through to js::Wrapper.
479
0
  desc.object().set(nullptr);
480
0
  if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) {
481
0
    return false;
482
0
  }
483
0
484
0
  if (desc.object()) {
485
0
    return true;
486
0
  }
487
0
488
0
  return js::Wrapper::getPropertyDescriptor(cx, proxy, id, desc);
489
0
}
490
491
bool
492
nsOuterWindowProxy::getOwnPropertyDescriptor(JSContext* cx,
493
                                             JS::Handle<JSObject*> proxy,
494
                                             JS::Handle<jsid> id,
495
                                             JS::MutableHandle<JS::PropertyDescriptor> desc)
496
                                             const
497
0
{
498
0
  bool found;
499
0
  if (!GetSubframeWindow(cx, proxy, id, desc.value(), found)) {
500
0
    return false;
501
0
  }
502
0
  if (found) {
503
0
    FillPropertyDescriptor(desc, proxy, true);
504
0
    return true;
505
0
  }
506
0
  // else fall through to js::Wrapper
507
0
508
0
  return js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
509
0
}
510
511
bool
512
nsOuterWindowProxy::defineProperty(JSContext* cx,
513
                                   JS::Handle<JSObject*> proxy,
514
                                   JS::Handle<jsid> id,
515
                                   JS::Handle<JS::PropertyDescriptor> desc,
516
                                   JS::ObjectOpResult &result) const
517
0
{
518
0
  if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
519
0
    // Spec says to Reject whether this is a supported index or not,
520
0
    // since we have no indexed setter or indexed creator.  It is up
521
0
    // to the caller to decide whether to throw a TypeError.
522
0
    return result.failCantDefineWindowElement();
523
0
  }
524
0
525
0
  return js::Wrapper::defineProperty(cx, proxy, id, desc, result);
526
0
}
527
528
bool
529
nsOuterWindowProxy::ownPropertyKeys(JSContext *cx,
530
                                    JS::Handle<JSObject*> proxy,
531
                                    JS::AutoIdVector &props) const
532
0
{
533
0
  // Just our indexed stuff followed by our "normal" own property names.
534
0
  if (!AppendIndexedPropertyNames(cx, proxy, props)) {
535
0
    return false;
536
0
  }
537
0
538
0
  JS::AutoIdVector innerProps(cx);
539
0
  if (!js::Wrapper::ownPropertyKeys(cx, proxy, innerProps)) {
540
0
    return false;
541
0
  }
542
0
  return js::AppendUnique(cx, props, innerProps);
543
0
}
544
545
bool
546
nsOuterWindowProxy::delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
547
                            JS::Handle<jsid> id, JS::ObjectOpResult &result) const
548
0
{
549
0
  if (nsCOMPtr<nsPIDOMWindowOuter> frame = GetSubframeWindow(cx, proxy, id)) {
550
0
    // Fail (which means throw if strict, else return false).
551
0
    return result.failCantDeleteWindowElement();
552
0
  }
553
0
554
0
  if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
555
0
    // Indexed, but not supported.  Spec says return true.
556
0
    return result.succeed();
557
0
  }
558
0
559
0
  return js::Wrapper::delete_(cx, proxy, id, result);
560
0
}
561
562
bool
563
nsOuterWindowProxy::getPrototypeIfOrdinary(JSContext* cx,
564
                                           JS::Handle<JSObject*> proxy,
565
                                           bool* isOrdinary,
566
                                           JS::MutableHandle<JSObject*> protop) const
567
0
{
568
0
  // Window's [[GetPrototypeOf]] trap isn't the ordinary definition:
569
0
  //
570
0
  //   https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof
571
0
  //
572
0
  // We nonetheless can implement it with a static [[Prototype]], because
573
0
  // wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) supply
574
0
  // all non-ordinary behavior.
575
0
  //
576
0
  // But from a spec point of view, it's the exact same object in both cases --
577
0
  // only the observer's changed.  So this getPrototypeIfOrdinary trap on the
578
0
  // non-wrapper object *must* report non-ordinary, even if static [[Prototype]]
579
0
  // usually means ordinary.
580
0
  *isOrdinary = false;
581
0
  return true;
582
0
}
583
584
bool
585
nsOuterWindowProxy::preventExtensions(JSContext* cx,
586
                                      JS::Handle<JSObject*> proxy,
587
                                      JS::ObjectOpResult& result) const
588
0
{
589
0
  // If [[Extensible]] could be false, then navigating a window could navigate
590
0
  // to a window that's [[Extensible]] after being at one that wasn't: an
591
0
  // invariant violation.  So never change a window's extensibility.
592
0
  return result.failCantPreventExtensions();
593
0
}
594
595
bool
596
nsOuterWindowProxy::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy,
597
                                 bool *extensible) const
598
0
{
599
0
  // See above.
600
0
  *extensible = true;
601
0
  return true;
602
0
}
603
604
bool
605
nsOuterWindowProxy::has(JSContext *cx, JS::Handle<JSObject*> proxy,
606
                        JS::Handle<jsid> id, bool *bp) const
607
0
{
608
0
  if (nsCOMPtr<nsPIDOMWindowOuter> frame = GetSubframeWindow(cx, proxy, id)) {
609
0
    *bp = true;
610
0
    return true;
611
0
  }
612
0
613
0
  return js::Wrapper::has(cx, proxy, id, bp);
614
0
}
615
616
bool
617
nsOuterWindowProxy::hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
618
                           JS::Handle<jsid> id, bool *bp) const
619
0
{
620
0
  if (nsCOMPtr<nsPIDOMWindowOuter> frame = GetSubframeWindow(cx, proxy, id)) {
621
0
    *bp = true;
622
0
    return true;
623
0
  }
624
0
625
0
  return js::Wrapper::hasOwn(cx, proxy, id, bp);
626
0
}
627
628
bool
629
nsOuterWindowProxy::get(JSContext *cx, JS::Handle<JSObject*> proxy,
630
                        JS::Handle<JS::Value> receiver,
631
                        JS::Handle<jsid> id,
632
                        JS::MutableHandle<JS::Value> vp) const
633
0
{
634
0
  if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
635
0
      xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
636
0
    vp.set(JS::ObjectValue(*proxy));
637
0
    return true;
638
0
  }
639
0
640
0
  bool found;
641
0
  if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
642
0
    return false;
643
0
  }
644
0
  if (found) {
645
0
    return true;
646
0
  }
647
0
  // Else fall through to js::Wrapper
648
0
649
0
  return js::Wrapper::get(cx, proxy, receiver, id, vp);
650
0
}
651
652
bool
653
nsOuterWindowProxy::set(JSContext *cx, JS::Handle<JSObject*> proxy,
654
                        JS::Handle<jsid> id,
655
                        JS::Handle<JS::Value> v,
656
                        JS::Handle<JS::Value> receiver,
657
                        JS::ObjectOpResult &result) const
658
0
{
659
0
  if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
660
0
    // Reject the set.  It's up to the caller to decide whether to throw a
661
0
    // TypeError.  If the caller is strict mode JS code, it'll throw.
662
0
    return result.failReadOnly();
663
0
  }
664
0
665
0
  return js::Wrapper::set(cx, proxy, id, v, receiver, result);
666
0
}
667
668
bool
669
nsOuterWindowProxy::getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
670
                                                 JS::AutoIdVector &props) const
671
0
{
672
0
  // Like ownPropertyKeys, our indexed stuff followed by our "normal" enumerable
673
0
  // own property names.
674
0
  //
675
0
  // Note that this does not match current spec per
676
0
  // https://github.com/whatwg/html/issues/2753 but as that issue says I believe
677
0
  // the spec is wrong.
678
0
  if (!AppendIndexedPropertyNames(cx, proxy, props)) {
679
0
    return false;
680
0
  }
681
0
682
0
  JS::AutoIdVector innerProps(cx);
683
0
  if (!js::Wrapper::getOwnEnumerablePropertyKeys(cx, proxy, innerProps)) {
684
0
    return false;
685
0
  }
686
0
  return js::AppendUnique(cx, props, innerProps);
687
0
}
688
689
JSObject*
690
nsOuterWindowProxy::enumerate(JSContext *cx, JS::Handle<JSObject*> proxy) const
691
0
{
692
0
  // BaseProxyHandler::enumerate seems to do what we want here: fall
693
0
  // back on the property names returned from js::GetPropertyKeys()
694
0
  return js::BaseProxyHandler::enumerate(cx, proxy);
695
0
}
696
697
bool
698
nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
699
                                      JS::Handle<JSObject*> proxy,
700
                                      JS::Handle<jsid> id,
701
                                      JS::MutableHandle<JS::Value> vp,
702
                                      bool& found) const
703
0
{
704
0
  nsCOMPtr<nsPIDOMWindowOuter> frame = GetSubframeWindow(cx, proxy, id);
705
0
  if (!frame) {
706
0
    found = false;
707
0
    return true;
708
0
  }
709
0
710
0
  found = true;
711
0
  // Just return the window's global
712
0
  nsGlobalWindowOuter* global = nsGlobalWindowOuter::Cast(frame);
713
0
  frame->EnsureInnerWindow();
714
0
  JSObject* obj = global->FastGetGlobalJSObject();
715
0
  // This null check fixes a hard-to-reproduce crash that occurs when we
716
0
  // get here when we're mid-call to nsDocShell::Destroy. See bug 640904
717
0
  // comment 105.
718
0
  if (MOZ_UNLIKELY(!obj)) {
719
0
    return xpc::Throw(cx, NS_ERROR_FAILURE);
720
0
  }
721
0
  JS::ExposeObjectToActiveJS(obj);
722
0
  vp.setObject(*obj);
723
0
  return JS_WrapValue(cx, vp);
724
0
}
725
726
already_AddRefed<nsPIDOMWindowOuter>
727
nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
728
                                      JS::Handle<JSObject*> proxy,
729
                                      JS::Handle<jsid> id) const
730
0
{
731
0
  uint32_t index = GetArrayIndexFromId(cx, id);
732
0
  if (!IsArrayIndex(index)) {
733
0
    return nullptr;
734
0
  }
735
0
736
0
  nsGlobalWindowOuter* win = GetOuterWindow(proxy);
737
0
  return win->IndexedGetterOuter(index);
738
0
}
739
740
bool
741
nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
742
                                               JS::AutoIdVector &props) const
743
0
{
744
0
  uint32_t length = GetOuterWindow(proxy)->Length();
745
0
  MOZ_ASSERT(int32_t(length) >= 0);
746
0
  if (!props.reserve(props.length() + length)) {
747
0
    return false;
748
0
  }
749
0
  for (int32_t i = 0; i < int32_t(length); ++i) {
750
0
    if (!props.append(INT_TO_JSID(i))) {
751
0
      return false;
752
0
    }
753
0
  }
754
0
755
0
  return true;
756
0
}
757
758
size_t
759
nsOuterWindowProxy::objectMoved(JSObject *obj, JSObject *old) const
760
0
{
761
0
  nsGlobalWindowOuter* outerWindow = GetOuterWindow(obj);
762
0
  if (outerWindow) {
763
0
    outerWindow->UpdateWrapper(obj, old);
764
0
  }
765
0
  return 0;
766
0
}
767
768
const nsOuterWindowProxy
769
nsOuterWindowProxy::singleton;
770
771
class nsChromeOuterWindowProxy : public nsOuterWindowProxy
772
{
773
public:
774
0
  constexpr nsChromeOuterWindowProxy() : nsOuterWindowProxy() { }
775
776
  const char *className(JSContext *cx, JS::Handle<JSObject*> wrapper) const override;
777
778
  static const nsChromeOuterWindowProxy singleton;
779
};
780
781
const char *
782
nsChromeOuterWindowProxy::className(JSContext *cx,
783
                                    JS::Handle<JSObject*> proxy) const
784
0
{
785
0
    MOZ_ASSERT(js::IsProxy(proxy));
786
0
787
0
    return "ChromeWindow";
788
0
}
789
790
const nsChromeOuterWindowProxy
791
nsChromeOuterWindowProxy::singleton;
792
793
static JSObject*
794
NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> global, bool isChrome)
795
0
{
796
0
  MOZ_ASSERT(JS_IsGlobalObject(global));
797
0
798
0
  JSAutoRealm ar(cx, global);
799
0
800
0
  js::WrapperOptions options;
801
0
  options.setClass(&OuterWindowProxyClass);
802
0
  options.setSingleton(true);
803
0
  JSObject *obj = js::Wrapper::New(cx, global,
804
0
                                   isChrome ? &nsChromeOuterWindowProxy::singleton
805
0
                                            : &nsOuterWindowProxy::singleton,
806
0
                                   options);
807
0
  MOZ_ASSERT_IF(obj, js::IsWindowProxy(obj));
808
0
  return obj;
809
0
}
810
811
//*****************************************************************************
812
//***    nsGlobalWindowOuter: Object Management
813
//*****************************************************************************
814
815
nsGlobalWindowOuter::nsGlobalWindowOuter()
816
  : nsPIDOMWindowOuter(),
817
    mIdleFuzzFactor(0),
818
    mIdleCallbackIndex(-1),
819
    mCurrentlyIdle(false),
820
    mAddActiveEventFuzzTime(true),
821
    mFullscreen(false),
822
    mFullscreenMode(false),
823
    mIsClosed(false),
824
    mInClose(false),
825
    mHavePendingClose(false),
826
    mHadOriginalOpener(false),
827
    mIsPopupSpam(false),
828
    mBlockScriptedClosingFlag(false),
829
    mWasOffline(false),
830
    mCreatingInnerWindow(false),
831
    mIsChrome(false),
832
    mAllowScriptsToClose(false),
833
    mTopLevelOuterContentWindow(false),
834
    mHasStorageAccess(false),
835
    mSerial(0),
836
#ifdef DEBUG
837
    mSetOpenerWindowCalled(false),
838
#endif
839
    mCleanedUp(false),
840
#ifdef DEBUG
841
    mIsValidatingTabGroup(false),
842
#endif
843
    mCanSkipCCGeneration(0),
844
    mAutoActivateVRDisplayID(0)
845
0
{
846
0
  AssertIsOnMainThread();
847
0
848
0
  nsLayoutStatics::AddRef();
849
0
850
0
  // Initialize the PRCList (this).
851
0
  PR_INIT_CLIST(this);
852
0
853
0
  // |this| is an outer window. Outer windows start out frozen and
854
0
  // remain frozen until they get an inner window.
855
0
  MOZ_ASSERT(IsFrozen());
856
0
857
0
  // We could have failed the first time through trying
858
0
  // to create the entropy collector, so we should
859
0
  // try to get one until we succeed.
860
0
861
0
  mSerial = nsContentUtils::InnerOrOuterWindowCreated();
862
0
863
#ifdef DEBUG
864
  if (!PR_GetEnv("MOZ_QUIET")) {
865
    printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
866
                  nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
867
                  static_cast<void*>(ToCanonicalSupports(this)),
868
                  getpid(),
869
                  mSerial,
870
                  nullptr);
871
  }
872
#endif
873
874
0
  MOZ_LOG(gDOMLeakPRLogOuter, LogLevel::Debug,
875
0
          ("DOMWINDOW %p created outer=nullptr", this));
876
0
877
0
  // Add ourselves to the outer windows list.
878
0
  MOZ_ASSERT(sOuterWindowsById, "Outer Windows hash table must be created!");
879
0
880
0
  // |this| is an outer window, add to the outer windows list.
881
0
  MOZ_ASSERT(!sOuterWindowsById->Get(mWindowID),
882
0
             "This window shouldn't be in the hash table yet!");
883
0
  // We seem to see crashes in release builds because of null |sOuterWindowsById|.
884
0
  if (sOuterWindowsById) {
885
0
    sOuterWindowsById->Put(mWindowID, this);
886
0
  }
887
0
}
888
889
#ifdef DEBUG
890
891
/* static */
892
void
893
nsGlobalWindowOuter::AssertIsOnMainThread()
894
{
895
  MOZ_ASSERT(NS_IsMainThread());
896
}
897
898
#endif // DEBUG
899
900
/* static */
901
void
902
nsGlobalWindowOuter::Init()
903
3
{
904
3
  AssertIsOnMainThread();
905
3
906
3
  NS_ASSERTION(gDOMLeakPRLogOuter, "gDOMLeakPRLogOuter should have been initialized!");
907
3
908
3
  sOuterWindowsById = new OuterWindowByIdTable();
909
3
}
910
911
nsGlobalWindowOuter::~nsGlobalWindowOuter()
912
0
{
913
0
  AssertIsOnMainThread();
914
0
915
0
  if (sOuterWindowsById) {
916
0
    MOZ_ASSERT(sOuterWindowsById->Get(mWindowID),
917
0
                "This window should be in the hash table");
918
0
    sOuterWindowsById->Remove(mWindowID);
919
0
  }
920
0
921
0
  nsContentUtils::InnerOrOuterWindowDestroyed();
922
0
923
#ifdef DEBUG
924
  if (!PR_GetEnv("MOZ_QUIET")) {
925
    nsAutoCString url;
926
    if (mLastOpenedURI) {
927
      url = mLastOpenedURI->GetSpecOrDefault();
928
929
      // Data URLs can be very long, so truncate to avoid flooding the log.
930
      const uint32_t maxURLLength = 1000;
931
      if (url.Length() > maxURLLength) {
932
        url.Truncate(maxURLLength);
933
      }
934
    }
935
936
    printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n",
937
                  nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
938
                  static_cast<void*>(ToCanonicalSupports(this)),
939
                  getpid(),
940
                  mSerial,
941
                  nullptr,
942
                  url.get());
943
  }
944
#endif
945
946
0
  MOZ_LOG(gDOMLeakPRLogOuter, LogLevel::Debug, ("DOMWINDOW %p destroyed", this));
947
0
948
0
  JSObject *proxy = GetWrapperMaybeDead();
949
0
  if (proxy) {
950
0
    js::SetProxyReservedSlot(proxy, 0, js::PrivateValue(nullptr));
951
0
  }
952
0
953
0
  // An outer window is destroyed with inner windows still possibly
954
0
  // alive, iterate through the inner windows and null out their
955
0
  // back pointer to this outer, and pull them out of the list of
956
0
  // inner windows.
957
0
  //
958
0
  // Our linked list of inner windows both contains (an nsGlobalWindowOuter),
959
0
  // and our inner windows (nsGlobalWindowInners). This means that we need to
960
0
  // use PRCList*. We can then compare that PRCList* to `this` to see if its an
961
0
  // inner or outer window.
962
0
  PRCList* w;
963
0
  while ((w = PR_LIST_HEAD(this)) != this) {
964
0
    PR_REMOVE_AND_INIT_LINK(w);
965
0
  }
966
0
967
0
  DropOuterWindowDocs();
968
0
969
0
  if (mTabGroup) {
970
0
    mTabGroup->Leave(this);
971
0
  }
972
0
973
0
  // Outer windows are always supposed to call CleanUp before letting themselves
974
0
  // be destroyed.
975
0
  MOZ_ASSERT(mCleanedUp);
976
0
977
0
  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
978
0
  if (ac)
979
0
    ac->RemoveWindowAsListener(this);
980
0
981
0
  nsLayoutStatics::Release();
982
0
}
983
984
// static
985
void
986
nsGlobalWindowOuter::ShutDown()
987
0
{
988
0
  AssertIsOnMainThread();
989
0
990
0
  delete sOuterWindowsById;
991
0
  sOuterWindowsById = nullptr;
992
0
}
993
994
void
995
nsGlobalWindowOuter::MaybeForgiveSpamCount()
996
0
{
997
0
  if (IsPopupSpamWindow()) {
998
0
    SetIsPopupSpamWindow(false);
999
0
  }
1000
0
}
1001
1002
void
1003
nsGlobalWindowOuter::SetIsPopupSpamWindow(bool aIsPopupSpam)
1004
0
{
1005
0
  mIsPopupSpam = aIsPopupSpam;
1006
0
  if (aIsPopupSpam) {
1007
0
    ++gOpenPopupSpamCount;
1008
0
  } else {
1009
0
    --gOpenPopupSpamCount;
1010
0
    NS_ASSERTION(gOpenPopupSpamCount >= 0,
1011
0
                 "Unbalanced decrement of gOpenPopupSpamCount");
1012
0
  }
1013
0
}
1014
1015
void
1016
nsGlobalWindowOuter::DropOuterWindowDocs()
1017
0
{
1018
0
  MOZ_ASSERT_IF(mDoc, !mDoc->EventHandlingSuppressed());
1019
0
  mDoc = nullptr;
1020
0
  mSuspendedDoc = nullptr;
1021
0
}
1022
1023
void
1024
nsGlobalWindowOuter::CleanUp()
1025
0
{
1026
0
  // Guarantee idempotence.
1027
0
  if (mCleanedUp)
1028
0
    return;
1029
0
  mCleanedUp = true;
1030
0
1031
0
  StartDying();
1032
0
1033
0
  mFrames = nullptr;
1034
0
  mWindowUtils = nullptr;
1035
0
1036
0
  ClearControllers();
1037
0
1038
0
  mOpener = nullptr;             // Forces Release
1039
0
  if (mContext) {
1040
0
    mContext = nullptr;            // Forces Release
1041
0
  }
1042
0
  mChromeEventHandler = nullptr; // Forces Release
1043
0
  mParentTarget = nullptr;
1044
0
  mMessageManager = nullptr;
1045
0
1046
0
  mArguments = nullptr;
1047
0
1048
0
  if (mIdleTimer) {
1049
0
    mIdleTimer->Cancel();
1050
0
    mIdleTimer = nullptr;
1051
0
  }
1052
0
}
1053
1054
void
1055
nsGlobalWindowOuter::ClearControllers()
1056
0
{
1057
0
  if (mControllers) {
1058
0
    uint32_t count;
1059
0
    mControllers->GetControllerCount(&count);
1060
0
1061
0
    while (count--) {
1062
0
      nsCOMPtr<nsIController> controller;
1063
0
      mControllers->GetControllerAt(count, getter_AddRefs(controller));
1064
0
1065
0
      nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
1066
0
      if (context)
1067
0
        context->SetCommandContext(nullptr);
1068
0
    }
1069
0
1070
0
    mControllers = nullptr;
1071
0
  }
1072
0
}
1073
1074
//*****************************************************************************
1075
// nsGlobalWindowOuter::nsISupports
1076
//*****************************************************************************
1077
1078
// QueryInterface implementation for nsGlobalWindowOuter
1079
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowOuter)
1080
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1081
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
1082
0
  NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
1083
0
  NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
1084
0
  NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
1085
0
  NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
1086
0
  NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
1087
0
  NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowOuter)
1088
0
  NS_INTERFACE_MAP_ENTRY(mozIDOMWindowProxy)
1089
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMChromeWindow, IsChromeWindow())
1090
0
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
1091
0
  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
1092
0
NS_INTERFACE_MAP_END
1093
1094
1095
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowOuter)
1096
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowOuter)
1097
1098
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowOuter)
1099
0
  if (tmp->IsBlackForCC(false)) {
1100
0
    if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
1101
0
      return true;
1102
0
    }
1103
0
    tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
1104
0
    if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
1105
0
      elm->MarkForCC();
1106
0
    }
1107
0
    return true;
1108
0
  }
1109
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1110
0
1111
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowOuter)
1112
0
  return tmp->IsBlackForCC(true);
1113
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1114
1115
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowOuter)
1116
0
  return tmp->IsBlackForCC(false);
1117
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1118
1119
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowOuter)
1120
1121
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowOuter)
1122
0
  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
1123
0
    char name[512];
1124
0
    nsAutoCString uri;
1125
0
    if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
1126
0
      uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
1127
0
    }
1128
0
    SprintfLiteral(name, "nsGlobalWindowOuter # %" PRIu64 " outer %s", tmp->mWindowID,
1129
0
                   uri.get());
1130
0
    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
1131
0
  } else {
1132
0
    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowOuter, tmp->mRefCnt.get())
1133
0
  }
1134
0
1135
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
1136
0
1137
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
1138
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
1139
0
1140
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
1141
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
1142
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
1143
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
1144
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
1145
0
1146
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
1147
0
1148
0
  // Traverse stuff from nsPIDOMWindow
1149
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
1150
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
1151
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
1152
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
1153
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerForInitialContentBrowser)
1154
0
1155
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)
1156
0
1157
0
  tmp->TraverseHostObjectURIs(cb);
1158
0
1159
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mBrowserDOMWindow)
1160
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1161
1162
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowOuter)
1163
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
1164
0
1165
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
1166
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
1167
0
1168
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
1169
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
1170
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
1171
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
1172
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
1173
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
1174
0
1175
0
  // Unlink stuff from nsPIDOMWindow
1176
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
1177
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
1178
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
1179
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
1180
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenerForInitialContentBrowser)
1181
0
1182
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
1183
0
1184
0
  tmp->UnlinkHostObjectURIs();
1185
0
1186
0
  if (tmp->IsChromeWindow()) {
1187
0
    NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mBrowserDOMWindow)
1188
0
  }
1189
0
1190
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1191
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1192
1193
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowOuter)
1194
0
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
1195
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
1196
1197
bool
1198
nsGlobalWindowOuter::IsBlackForCC(bool aTracingNeeded)
1199
0
{
1200
0
  if (!nsCCUncollectableMarker::sGeneration) {
1201
0
    return false;
1202
0
  }
1203
0
1204
0
  return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
1205
0
          HasKnownLiveWrapper()) &&
1206
0
         (!aTracingNeeded ||
1207
0
          HasNothingToTrace(ToSupports(this)));
1208
0
}
1209
1210
//*****************************************************************************
1211
// nsGlobalWindowOuter::nsIScriptGlobalObject
1212
//*****************************************************************************
1213
1214
nsresult
1215
nsGlobalWindowOuter::EnsureScriptEnvironment()
1216
0
{
1217
0
  if (GetWrapperPreserveColor()) {
1218
0
    return NS_OK;
1219
0
  }
1220
0
1221
0
  NS_ASSERTION(!GetCurrentInnerWindowInternal(),
1222
0
               "No cached wrapper, but we have an inner window?");
1223
0
1224
0
  // If this window is a [i]frame, don't bother GC'ing when the frame's context
1225
0
  // is destroyed since a GC will happen when the frameset or host document is
1226
0
  // destroyed anyway.
1227
0
  nsCOMPtr<nsIScriptContext> context = new nsJSContext(!IsFrame(), this);
1228
0
1229
0
  NS_ASSERTION(!mContext, "Will overwrite mContext!");
1230
0
1231
0
  // should probably assert the context is clean???
1232
0
  context->WillInitializeContext();
1233
0
1234
0
  nsresult rv = context->InitContext();
1235
0
  NS_ENSURE_SUCCESS(rv, rv);
1236
0
1237
0
  mContext = context;
1238
0
  return NS_OK;
1239
0
}
1240
1241
nsIScriptContext *
1242
nsGlobalWindowOuter::GetScriptContext()
1243
0
{
1244
0
  return mContext;
1245
0
}
1246
1247
JSObject *
1248
nsGlobalWindowOuter::GetGlobalJSObject()
1249
0
{
1250
0
  return FastGetGlobalJSObject();
1251
0
}
1252
1253
bool
1254
nsGlobalWindowOuter::WouldReuseInnerWindow(nsIDocument* aNewDocument)
1255
0
{
1256
0
  // We reuse the inner window when:
1257
0
  // a. We are currently at our original document.
1258
0
  // b. At least one of the following conditions are true:
1259
0
  // -- The new document is the same as the old document. This means that we're
1260
0
  //    getting called from document.open().
1261
0
  // -- The new document has the same origin as what we have loaded right now.
1262
0
1263
0
  if (!mDoc || !aNewDocument) {
1264
0
    return false;
1265
0
  }
1266
0
1267
0
  if (!mDoc->IsInitialDocument()) {
1268
0
    return false;
1269
0
  }
1270
0
1271
#ifdef DEBUG
1272
{
1273
  nsCOMPtr<nsIURI> uri;
1274
  NS_GetURIWithoutRef(mDoc->GetDocumentURI(), getter_AddRefs(uri));
1275
  NS_ASSERTION(NS_IsAboutBlank(uri), "How'd this happen?");
1276
}
1277
#endif
1278
1279
0
  // Great, we're the original document, check for one of the other
1280
0
  // conditions.
1281
0
1282
0
  if (mDoc == aNewDocument) {
1283
0
    return true;
1284
0
  }
1285
0
1286
0
  bool equal;
1287
0
  if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
1288
0
                                                 &equal)) &&
1289
0
      equal) {
1290
0
    // The origin is the same.
1291
0
    return true;
1292
0
  }
1293
0
1294
0
  return false;
1295
0
}
1296
1297
void
1298
nsGlobalWindowOuter::SetInitialPrincipalToSubject()
1299
0
{
1300
0
  // First, grab the subject principal.
1301
0
  nsCOMPtr<nsIPrincipal> newWindowPrincipal = nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
1302
0
1303
0
  // We should never create windows with an expanded principal.
1304
0
  // If we have a system principal, make sure we're not using it for a content
1305
0
  // docshell.
1306
0
  // NOTE: Please keep this logic in sync with nsWebShellWindow::Initialize().
1307
0
  if (nsContentUtils::IsExpandedPrincipal(newWindowPrincipal) ||
1308
0
      (nsContentUtils::IsSystemPrincipal(newWindowPrincipal) &&
1309
0
       GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome)) {
1310
0
    newWindowPrincipal = nullptr;
1311
0
  }
1312
0
1313
0
  // If there's an existing document, bail if it either:
1314
0
  if (mDoc) {
1315
0
    // (a) is not an initial about:blank document, or
1316
0
    if (!mDoc->IsInitialDocument())
1317
0
      return;
1318
0
    // (b) already has the correct principal.
1319
0
    if (mDoc->NodePrincipal() == newWindowPrincipal)
1320
0
      return;
1321
0
1322
#ifdef DEBUG
1323
    // If we have a document loaded at this point, it had better be about:blank.
1324
    // Otherwise, something is really weird. An about:blank page has a
1325
    // NullPrincipal.
1326
    bool isNullPrincipal;
1327
    MOZ_ASSERT(NS_SUCCEEDED(mDoc->NodePrincipal()->GetIsNullPrincipal(&isNullPrincipal)) &&
1328
               isNullPrincipal);
1329
#endif
1330
  }
1331
0
1332
0
  GetDocShell()->CreateAboutBlankContentViewer(newWindowPrincipal);
1333
0
1334
0
  if (mDoc) {
1335
0
    mDoc->SetIsInitialDocument(true);
1336
0
  }
1337
0
1338
0
  nsCOMPtr<nsIPresShell> shell = GetDocShell()->GetPresShell();
1339
0
1340
0
  if (shell && !shell->DidInitialize()) {
1341
0
    // Ensure that if someone plays with this document they will get
1342
0
    // layout happening.
1343
0
    shell->Initialize();
1344
0
  }
1345
0
}
1346
1347
PopupControlState
1348
nsGlobalWindowOuter::PushPopupControlState(PopupControlState aState,
1349
                                           bool aForce) const
1350
0
{
1351
0
  return nsContentUtils::PushPopupControlState(aState, aForce);
1352
0
}
1353
1354
void
1355
nsGlobalWindowOuter::PopPopupControlState(PopupControlState aState) const
1356
0
{
1357
0
  nsContentUtils::PopPopupControlState(aState);
1358
0
}
1359
1360
PopupControlState
1361
nsGlobalWindowOuter::GetPopupControlState() const
1362
0
{
1363
0
  return nsContentUtils::GetPopupControlState();
1364
0
}
1365
1366
#define WINDOWSTATEHOLDER_IID \
1367
{0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
1368
1369
class WindowStateHolder final : public nsISupports
1370
{
1371
public:
1372
  NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
1373
  NS_DECL_ISUPPORTS
1374
1375
  explicit WindowStateHolder(nsGlobalWindowInner *aWindow);
1376
1377
0
  nsGlobalWindowInner* GetInnerWindow() { return mInnerWindow; }
1378
1379
  void DidRestoreWindow()
1380
0
  {
1381
0
    mInnerWindow = nullptr;
1382
0
    mInnerWindowReflector = nullptr;
1383
0
  }
1384
1385
protected:
1386
  ~WindowStateHolder();
1387
1388
  nsGlobalWindowInner *mInnerWindow;
1389
  // We hold onto this to make sure the inner window doesn't go away. The outer
1390
  // window ends up recalculating it anyway.
1391
  JS::PersistentRooted<JSObject*> mInnerWindowReflector;
1392
};
1393
1394
NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
1395
1396
WindowStateHolder::WindowStateHolder(nsGlobalWindowInner* aWindow)
1397
  : mInnerWindow(aWindow),
1398
    mInnerWindowReflector(RootingCx(), aWindow->GetWrapper())
1399
0
{
1400
0
  MOZ_ASSERT(aWindow, "null window");
1401
0
1402
0
  aWindow->Suspend();
1403
0
1404
0
  // When a global goes into the bfcache, we disable script.
1405
0
  xpc::Scriptability::Get(mInnerWindowReflector).SetDocShellAllowsScript(false);
1406
0
}
1407
1408
WindowStateHolder::~WindowStateHolder()
1409
0
{
1410
0
  if (mInnerWindow) {
1411
0
    // This window was left in the bfcache and is now going away. We need to
1412
0
    // free it up.
1413
0
    // Note that FreeInnerObjects may already have been called on the
1414
0
    // inner window if its outer has already had SetDocShell(null)
1415
0
    // called.
1416
0
    mInnerWindow->FreeInnerObjects();
1417
0
  }
1418
0
}
1419
1420
NS_IMPL_ISUPPORTS(WindowStateHolder, WindowStateHolder)
1421
1422
bool
1423
nsGlobalWindowOuter::ComputeIsSecureContext(nsIDocument* aDocument, SecureContextFlags aFlags)
1424
0
{
1425
0
  nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
1426
0
  if (nsContentUtils::IsSystemPrincipal(principal)) {
1427
0
    return true;
1428
0
  }
1429
0
1430
0
  // Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
1431
0
  // With some modifications to allow for aFlags.
1432
0
1433
0
  bool hadNonSecureContextCreator = false;
1434
0
1435
0
  nsPIDOMWindowOuter* parentOuterWin = GetScriptableParent();
1436
0
  MOZ_ASSERT(parentOuterWin, "How can we get here? No docShell somehow?");
1437
0
  if (nsGlobalWindowOuter::Cast(parentOuterWin) != this) {
1438
0
    // There may be a small chance that parentOuterWin has navigated in
1439
0
    // the time that it took us to start loading this sub-document.  If that
1440
0
    // were the case then parentOuterWin->GetCurrentInnerWindow() wouldn't
1441
0
    // return the window for the document that is embedding us.  For this
1442
0
    // reason we only use the GetScriptableParent call above to check that we
1443
0
    // have a same-type parent, but actually get the inner window via the
1444
0
    // document that we know is embedding us.
1445
0
    nsIDocument* creatorDoc = aDocument->GetParentDocument();
1446
0
    if (!creatorDoc) {
1447
0
      return false; // we must be tearing down
1448
0
    }
1449
0
    nsGlobalWindowInner* parentWin =
1450
0
      nsGlobalWindowInner::Cast(creatorDoc->GetInnerWindow());
1451
0
    if (!parentWin) {
1452
0
      return false; // we must be tearing down
1453
0
    }
1454
0
    MOZ_ASSERT(parentWin ==
1455
0
               nsGlobalWindowInner::Cast(parentOuterWin->GetCurrentInnerWindow()),
1456
0
               "Creator window mismatch while setting Secure Context state");
1457
0
    hadNonSecureContextCreator = !parentWin->IsSecureContext();
1458
0
  }
1459
0
1460
0
  if (hadNonSecureContextCreator) {
1461
0
    return false;
1462
0
  }
1463
0
1464
0
  if (nsContentUtils::HttpsStateIsModern(aDocument)) {
1465
0
    return true;
1466
0
  }
1467
0
1468
0
  if (principal->GetIsNullPrincipal()) {
1469
0
    nsCOMPtr<nsIURI> uri = aDocument->GetOriginalURI();
1470
0
    // IsOriginPotentiallyTrustworthy doesn't care about origin attributes so
1471
0
    // it doesn't actually matter what we use here, but reusing the document
1472
0
    // principal's attributes is convenient.
1473
0
    const OriginAttributes& attrs = principal->OriginAttributesRef();
1474
0
    // CreateCodebasePrincipal correctly gets a useful principal for blob: and
1475
0
    // other URI_INHERITS_SECURITY_CONTEXT URIs.
1476
0
    principal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
1477
0
    if (NS_WARN_IF(!principal)) {
1478
0
      return false;
1479
0
    }
1480
0
  }
1481
0
1482
0
  nsCOMPtr<nsIContentSecurityManager> csm =
1483
0
    do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
1484
0
  NS_WARNING_ASSERTION(csm, "csm is null");
1485
0
  if (csm) {
1486
0
    bool isTrustworthyOrigin = false;
1487
0
    csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin);
1488
0
    if (isTrustworthyOrigin) {
1489
0
      return true;
1490
0
    }
1491
0
  }
1492
0
1493
0
  return false;
1494
0
}
1495
1496
// We need certain special behavior for remote XUL whitelisted domains, but we
1497
// don't want that behavior to take effect in automation, because we whitelist
1498
// all the mochitest domains. So we need to check a pref here.
1499
static bool
1500
TreatAsRemoteXUL(nsIPrincipal* aPrincipal)
1501
0
{
1502
0
  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(aPrincipal));
1503
0
  return nsContentUtils::AllowXULXBLForPrincipal(aPrincipal) &&
1504
0
    !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
1505
0
}
1506
1507
static bool
1508
EnablePrivilege(JSContext* cx, unsigned argc, JS::Value* vp)
1509
0
{
1510
0
  Telemetry::Accumulate(Telemetry::ENABLE_PRIVILEGE_EVER_CALLED, true);
1511
0
  return xpc::EnableUniversalXPConnect(cx);
1512
0
}
1513
1514
static const JSFunctionSpec EnablePrivilegeSpec[] = {
1515
  JS_FN("enablePrivilege", EnablePrivilege, 1, 0),
1516
  JS_FS_END
1517
};
1518
1519
static bool
1520
InitializeLegacyNetscapeObject(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
1521
0
{
1522
0
  JSAutoRealm ar(aCx, aGlobal);
1523
0
1524
0
  // Note: MathJax depends on window.netscape being exposed. See bug 791526.
1525
0
  JS::Rooted<JSObject*> obj(aCx);
1526
0
  obj = JS_DefineObject(aCx, aGlobal, "netscape", nullptr);
1527
0
  NS_ENSURE_TRUE(obj, false);
1528
0
1529
0
  obj = JS_DefineObject(aCx, obj, "security", nullptr);
1530
0
  NS_ENSURE_TRUE(obj, false);
1531
0
1532
0
  // We hide enablePrivilege behind a pref because it has been altered in a
1533
0
  // way that makes it fundamentally insecure to use in production. Mozilla
1534
0
  // uses this pref during automated testing to support legacy test code that
1535
0
  // uses enablePrivilege. If you're not doing test automation, you _must_ not
1536
0
  // flip this pref, or you will be exposing all your users to security
1537
0
  // vulnerabilities.
1538
0
  if (!xpc::IsInAutomation()) {
1539
0
    return true;
1540
0
  }
1541
0
1542
0
  /* Define PrivilegeManager object with the necessary "static" methods. */
1543
0
  obj = JS_DefineObject(aCx, obj, "PrivilegeManager", nullptr);
1544
0
  NS_ENSURE_TRUE(obj, false);
1545
0
1546
0
  return JS_DefineFunctions(aCx, obj, EnablePrivilegeSpec);
1547
0
}
1548
1549
static JS::RealmCreationOptions&
1550
SelectZone(nsGlobalWindowInner* aNewInner,
1551
           JS::RealmCreationOptions& aOptions)
1552
0
{
1553
0
  if (aNewInner->GetOuterWindow()) {
1554
0
    nsGlobalWindowOuter *top = aNewInner->GetTopInternal();
1555
0
1556
0
    // If we have a top-level window, use its zone.
1557
0
    if (top && top->GetGlobalJSObject()) {
1558
0
      return aOptions.setNewCompartmentInExistingZone(top->GetGlobalJSObject());
1559
0
    }
1560
0
  }
1561
0
1562
0
  return aOptions.setNewCompartmentAndZone();
1563
0
}
1564
1565
/**
1566
 * Create a new global object that will be used for an inner window.
1567
 * Return the native global and an nsISupports 'holder' that can be used
1568
 * to manage the lifetime of it.
1569
 */
1570
static nsresult
1571
CreateNativeGlobalForInner(JSContext* aCx,
1572
                           nsGlobalWindowInner* aNewInner,
1573
                           nsIURI* aURI,
1574
                           nsIPrincipal* aPrincipal,
1575
                           JS::MutableHandle<JSObject*> aGlobal,
1576
                           bool aIsSecureContext)
1577
0
{
1578
0
  MOZ_ASSERT(aCx);
1579
0
  MOZ_ASSERT(aNewInner);
1580
0
  MOZ_ASSERT(aPrincipal);
1581
0
1582
0
  // DOMWindow with nsEP is not supported, we have to make sure
1583
0
  // no one creates one accidentally.
1584
0
  nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(aPrincipal);
1585
0
  MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported");
1586
0
1587
0
  JS::RealmOptions options;
1588
0
1589
0
  SelectZone(aNewInner, options.creationOptions());
1590
0
1591
0
  options.creationOptions().setSecureContext(aIsSecureContext);
1592
0
1593
0
  xpc::InitGlobalObjectOptions(options, aPrincipal);
1594
0
1595
0
  // Determine if we need the Components object.
1596
0
  bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
1597
0
                        TreatAsRemoteXUL(aPrincipal);
1598
0
  uint32_t flags = needComponents ? 0 : xpc::OMIT_COMPONENTS_OBJECT;
1599
0
  flags |= xpc::DONT_FIRE_ONNEWGLOBALHOOK;
1600
0
1601
0
  if (!Window_Binding::Wrap(aCx, aNewInner, aNewInner, options,
1602
0
                           nsJSPrincipals::get(aPrincipal), false, aGlobal) ||
1603
0
      !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
1604
0
    return NS_ERROR_FAILURE;
1605
0
  }
1606
0
1607
0
  MOZ_ASSERT(aNewInner->GetWrapperPreserveColor() == aGlobal);
1608
0
1609
0
  // Set the location information for the new global, so that tools like
1610
0
  // about:memory may use that information
1611
0
  xpc::SetLocationForGlobal(aGlobal, aURI);
1612
0
1613
0
  if (!InitializeLegacyNetscapeObject(aCx, aGlobal)) {
1614
0
    return NS_ERROR_FAILURE;
1615
0
  }
1616
0
1617
0
  return NS_OK;
1618
0
}
1619
1620
nsresult
1621
nsGlobalWindowOuter::SetNewDocument(nsIDocument* aDocument,
1622
                                    nsISupports* aState,
1623
                                    bool aForceReuseInnerWindow)
1624
0
{
1625
0
  MOZ_ASSERT(mDocumentPrincipal == nullptr,
1626
0
                  "mDocumentPrincipal prematurely set!");
1627
0
  MOZ_ASSERT(aDocument);
1628
0
1629
0
  // Bail out early if we're in process of closing down the window.
1630
0
  NS_ENSURE_STATE(!mCleanedUp);
1631
0
1632
0
  NS_ASSERTION(!GetCurrentInnerWindow() ||
1633
0
               GetCurrentInnerWindow()->GetExtantDoc() == mDoc,
1634
0
               "Uh, mDoc doesn't match the current inner window "
1635
0
               "document!");
1636
0
1637
0
  bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
1638
0
  if (aForceReuseInnerWindow &&
1639
0
      !wouldReuseInnerWindow &&
1640
0
      mDoc &&
1641
0
      mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
1642
0
    NS_ERROR("Attempted forced inner window reuse while changing principal");
1643
0
    return NS_ERROR_UNEXPECTED;
1644
0
  }
1645
0
1646
0
  nsCOMPtr<nsIDocument> oldDoc = mDoc;
1647
0
1648
0
  AutoJSAPI jsapi;
1649
0
  jsapi.Init();
1650
0
  JSContext *cx = jsapi.cx();
1651
0
1652
0
  // Check if we're anywhere near the stack limit before we reach the
1653
0
  // transplanting code, since it has no good way to handle errors. This uses
1654
0
  // the untrusted script limit, which is not strictly necessary since no
1655
0
  // actual script should run.
1656
0
  if (!js::CheckRecursionLimitConservativeDontReport(cx)) {
1657
0
    NS_WARNING("Overrecursion in SetNewDocument");
1658
0
    return NS_ERROR_FAILURE;
1659
0
  }
1660
0
1661
0
  if (!mDoc) {
1662
0
    // First document load.
1663
0
1664
0
    // Get our private root. If it is equal to us, then we need to
1665
0
    // attach our global key bindings that handles browser scrolling
1666
0
    // and other browser commands.
1667
0
    nsPIDOMWindowOuter* privateRoot = GetPrivateRoot();
1668
0
1669
0
    if (privateRoot == this) {
1670
0
      nsXBLService::AttachGlobalKeyHandler(mChromeEventHandler);
1671
0
    }
1672
0
  }
1673
0
1674
0
  /* No mDocShell means we're already been partially closed down.  When that
1675
0
     happens, setting status isn't a big requirement, so don't. (Doesn't happen
1676
0
     under normal circumstances, but bug 49615 describes a case.) */
1677
0
1678
0
  nsContentUtils::AddScriptRunner(NewRunnableMethod(
1679
0
    "nsGlobalWindowOuter::ClearStatus", this, &nsGlobalWindowOuter::ClearStatus));
1680
0
1681
0
  // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
1682
0
  // window (see bug 776497). Be safe.
1683
0
  bool reUseInnerWindow = (aForceReuseInnerWindow || wouldReuseInnerWindow) &&
1684
0
                          GetCurrentInnerWindowInternal();
1685
0
1686
0
  nsresult rv;
1687
0
1688
0
  // We set mDoc even though this is an outer window to avoid
1689
0
  // having to *always* reach into the inner window to find the
1690
0
  // document.
1691
0
  mDoc = aDocument;
1692
0
1693
0
  // Take this opportunity to clear mSuspendedDoc. Our old inner window is now
1694
0
  // responsible for unsuspending it.
1695
0
  mSuspendedDoc = nullptr;
1696
0
1697
#ifdef DEBUG
1698
  mLastOpenedURI = aDocument->GetDocumentURI();
1699
#endif
1700
1701
0
  mContext->WillInitializeContext();
1702
0
1703
0
  RefPtr<nsGlobalWindowInner> currentInner = GetCurrentInnerWindowInternal();
1704
0
1705
0
  if (currentInner && currentInner->mNavigator) {
1706
0
    currentInner->mNavigator->OnNavigation();
1707
0
  }
1708
0
1709
0
  RefPtr<nsGlobalWindowInner> newInnerWindow;
1710
0
  bool createdInnerWindow = false;
1711
0
1712
0
  bool thisChrome = IsChromeWindow();
1713
0
1714
0
  nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
1715
0
  NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
1716
0
1717
0
  bool handleDocumentOpen = false;
1718
0
  bool doomCurrentInner = false;
1719
0
1720
0
  JS::Rooted<JSObject*> newInnerGlobal(cx);
1721
0
  if (reUseInnerWindow) {
1722
0
    // We're reusing the current inner window.
1723
0
    NS_ASSERTION(!currentInner->IsFrozen(),
1724
0
                 "We should never be reusing a shared inner window");
1725
0
    newInnerWindow = currentInner;
1726
0
    newInnerGlobal = currentInner->GetWrapperPreserveColor();
1727
0
1728
0
    if (aDocument != oldDoc) {
1729
0
      JS::ExposeObjectToActiveJS(newInnerGlobal);
1730
0
    }
1731
0
1732
0
    // We're reusing the inner window, but this still counts as a navigation,
1733
0
    // so all expandos and such defined on the outer window should go away. Force
1734
0
    // all Xray wrappers to be recomputed.
1735
0
    JS::Rooted<JSObject*> rootedObject(cx, GetWrapper());
1736
0
    if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
1737
0
      return NS_ERROR_FAILURE;
1738
0
    }
1739
0
1740
0
    // Inner windows are only reused for same-origin principals, but the principals
1741
0
    // don't necessarily match exactly. Update the principal on the realm to match
1742
0
    // the new document.
1743
0
    // NB: We don't just call currentInner->RefreshRealmPrincipals() here
1744
0
    // because we haven't yet set its mDoc to aDocument.
1745
0
    JS::Realm* realm = js::GetNonCCWObjectRealm(newInnerGlobal);
1746
#ifdef DEBUG
1747
    bool sameOrigin = false;
1748
    nsIPrincipal *existing =
1749
      nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
1750
    aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
1751
    MOZ_ASSERT(sameOrigin);
1752
    MOZ_ASSERT_IF(aDocument == oldDoc,
1753
                  xpc::GetRealmPrincipal(realm) == aDocument->NodePrincipal());
1754
#endif
1755
0
    if (aDocument != oldDoc) {
1756
0
      JS::SetRealmPrincipals(realm,
1757
0
                             nsJSPrincipals::get(aDocument->NodePrincipal()));
1758
0
      // Make sure we clear out the old content XBL scope, so the new one will
1759
0
      // get created with a principal that subsumes our new principal.
1760
0
      xpc::ClearContentXBLScope(newInnerGlobal);
1761
0
    }
1762
0
  } else {
1763
0
    if (aState) {
1764
0
      newInnerWindow = wsh->GetInnerWindow();
1765
0
      newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
1766
0
    } else {
1767
0
      newInnerWindow = nsGlobalWindowInner::Create(this, thisChrome);
1768
0
1769
0
      // The outer window is automatically treated as frozen when we
1770
0
      // null out the inner window. As a result, initializing classes
1771
0
      // on the new inner won't end up reaching into the old inner
1772
0
      // window for classes etc.
1773
0
      //
1774
0
      // [This happens with Object.prototype when XPConnect creates
1775
0
      // a temporary global while initializing classes; the reason
1776
0
      // being that xpconnect creates the temp global w/o a parent
1777
0
      // and proto, which makes the JS engine look up classes in
1778
0
      // cx->globalObject, i.e. this outer window].
1779
0
1780
0
      mInnerWindow = nullptr;
1781
0
1782
0
      mCreatingInnerWindow = true;
1783
0
      // Every script context we are initialized with must create a
1784
0
      // new global.
1785
0
      rv = CreateNativeGlobalForInner(cx, newInnerWindow,
1786
0
                                      aDocument->GetDocumentURI(),
1787
0
                                      aDocument->NodePrincipal(),
1788
0
                                      &newInnerGlobal,
1789
0
                                      ComputeIsSecureContext(aDocument));
1790
0
      NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
1791
0
                   newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
1792
0
                   "Failed to get script global");
1793
0
1794
0
      mCreatingInnerWindow = false;
1795
0
      createdInnerWindow = true;
1796
0
1797
0
      NS_ENSURE_SUCCESS(rv, rv);
1798
0
    }
1799
0
1800
0
    if (currentInner && currentInner->GetWrapperPreserveColor()) {
1801
0
      if (oldDoc == aDocument) {
1802
0
        handleDocumentOpen = true;
1803
0
      }
1804
0
1805
0
      // Don't free objects on our current inner window if it's going to be
1806
0
      // held in the bfcache.
1807
0
      if (!currentInner->IsFrozen()) {
1808
0
        doomCurrentInner = true;
1809
0
      }
1810
0
    }
1811
0
1812
0
    mInnerWindow = newInnerWindow->AsInner();
1813
0
    MOZ_ASSERT(mInnerWindow);
1814
0
    mInnerWindow->TryToCacheTopInnerWindow();
1815
0
1816
0
    if (!GetWrapperPreserveColor()) {
1817
0
      JS::Rooted<JSObject*> outer(cx,
1818
0
        NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
1819
0
      NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
1820
0
1821
0
      js::SetProxyReservedSlot(outer, 0, js::PrivateValue(ToSupports(this)));
1822
0
1823
0
      // Inform the nsJSContext, which is the canonical holder of the outer.
1824
0
      mContext->SetWindowProxy(outer);
1825
0
      mContext->DidInitializeContext();
1826
0
1827
0
      SetWrapper(mContext->GetWindowProxy());
1828
0
    } else {
1829
0
      JS::ExposeObjectToActiveJS(newInnerGlobal);
1830
0
      JS::Rooted<JSObject*> outerObject(cx,
1831
0
        NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
1832
0
      if (!outerObject) {
1833
0
        NS_ERROR("out of memory");
1834
0
        return NS_ERROR_FAILURE;
1835
0
      }
1836
0
1837
0
      JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
1838
0
1839
0
      js::SetProxyReservedSlot(obj, 0, js::PrivateValue(nullptr));
1840
0
      js::SetProxyReservedSlot(outerObject, 0, js::PrivateValue(nullptr));
1841
0
1842
0
      outerObject = xpc::TransplantObject(cx, obj, outerObject);
1843
0
      if (!outerObject) {
1844
0
        NS_ERROR("unable to transplant wrappers, probably OOM");
1845
0
        return NS_ERROR_FAILURE;
1846
0
      }
1847
0
1848
0
      js::SetProxyReservedSlot(outerObject, 0, js::PrivateValue(ToSupports(this)));
1849
0
1850
0
      SetWrapper(outerObject);
1851
0
1852
0
      MOZ_ASSERT(JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal);
1853
0
1854
0
      // Inform the nsJSContext, which is the canonical holder of the outer.
1855
0
      mContext->SetWindowProxy(outerObject);
1856
0
    }
1857
0
1858
0
    // Enter the new global's realm.
1859
0
    JSAutoRealm ar(cx, GetWrapperPreserveColor());
1860
0
1861
0
    {
1862
0
      JS::Rooted<JSObject*> outer(cx, GetWrapperPreserveColor());
1863
0
      js::SetWindowProxy(cx, newInnerGlobal, outer);
1864
0
    }
1865
0
1866
0
    // Set scriptability based on the state of the docshell.
1867
0
    bool allow = GetDocShell()->GetCanExecuteScripts();
1868
0
    xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);
1869
0
1870
0
    if (!aState) {
1871
0
      // Get the "window" property once so it will be cached on our inner.  We
1872
0
      // have to do this here, not in binding code, because this has to happen
1873
0
      // after we've created the outer window proxy and stashed it in the outer
1874
0
      // nsGlobalWindowOuter, so GetWrapperPreserveColor() on that outer
1875
0
      // nsGlobalWindowOuter doesn't return null and nsGlobalWindowOuter::OuterObject
1876
0
      // works correctly.
1877
0
      JS::Rooted<JS::Value> unused(cx);
1878
0
      if (!JS_GetProperty(cx, newInnerGlobal, "window", &unused)) {
1879
0
        NS_ERROR("can't create the 'window' property");
1880
0
        return NS_ERROR_FAILURE;
1881
0
      }
1882
0
1883
0
      // And same thing for the "self" property.
1884
0
      if (!JS_GetProperty(cx, newInnerGlobal, "self", &unused)) {
1885
0
        NS_ERROR("can't create the 'self' property");
1886
0
        return NS_ERROR_FAILURE;
1887
0
      }
1888
0
    }
1889
0
  }
1890
0
1891
0
  JSAutoRealm ar(cx, GetWrapperPreserveColor());
1892
0
1893
0
  if (!aState && !reUseInnerWindow) {
1894
0
    // Loading a new page and creating a new inner window, *not*
1895
0
    // restoring from session history.
1896
0
1897
0
    // Now that both the the inner and outer windows are initialized
1898
0
    // let the script context do its magic to hook them together.
1899
0
    MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor());
1900
#ifdef DEBUG
1901
    JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
1902
    JS::Rooted<JSObject*> proto1(cx), proto2(cx);
1903
    JS_GetPrototype(cx, rootedJSObject, &proto1);
1904
    JS_GetPrototype(cx, newInnerGlobal, &proto2);
1905
    NS_ASSERTION(proto1 == proto2,
1906
                 "outer and inner globals should have the same prototype");
1907
#endif
1908
1909
0
    mInnerWindow->SyncStateFromParentWindow();
1910
0
  }
1911
0
1912
0
  // Add an extra ref in case we release mContext during GC.
1913
0
  nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
1914
0
1915
0
  aDocument->SetScriptGlobalObject(newInnerWindow);
1916
0
  MOZ_ASSERT(newInnerWindow->mTabGroup,
1917
0
             "We must have a TabGroup cached at this point");
1918
0
1919
0
  if (!aState) {
1920
0
    if (reUseInnerWindow) {
1921
0
1922
0
      if (newInnerWindow->mDoc != aDocument) {
1923
0
        newInnerWindow->mDoc = aDocument;
1924
0
1925
0
        // The storage objects contain the URL of the window. We have to
1926
0
        // recreate them when the innerWindow is reused.
1927
0
        newInnerWindow->mLocalStorage = nullptr;
1928
0
        newInnerWindow->mSessionStorage = nullptr;
1929
0
        newInnerWindow->mPerformance = nullptr;
1930
0
1931
0
        // This must be called after nullifying the internal objects because
1932
0
        // here we could recreate them, calling the getter methods, and store
1933
0
        // them into the JS slots. If we nullify them after, the slot values and
1934
0
        // the objects will be out of sync.
1935
0
        newInnerWindow->ClearDocumentDependentSlots(cx);
1936
0
1937
0
        // When replacing an initial about:blank document we call
1938
0
        // ExecutionReady again to update the client creation URL.
1939
0
        rv = newInnerWindow->ExecutionReady();
1940
0
        NS_ENSURE_SUCCESS(rv, rv);
1941
0
      }
1942
0
    } else {
1943
0
      newInnerWindow->InnerSetNewDocument(cx, aDocument);
1944
0
1945
0
      // Initialize DOM classes etc on the inner window.
1946
0
      JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
1947
0
      rv = kungFuDeathGrip->InitClasses(obj);
1948
0
      NS_ENSURE_SUCCESS(rv, rv);
1949
0
1950
0
      rv = newInnerWindow->ExecutionReady();
1951
0
      NS_ENSURE_SUCCESS(rv, rv);
1952
0
    }
1953
0
1954
0
    if (mArguments) {
1955
0
      newInnerWindow->DefineArgumentsProperty(mArguments);
1956
0
      mArguments = nullptr;
1957
0
    }
1958
0
1959
0
    // Give the new inner window our chrome event handler (since it
1960
0
    // doesn't have one).
1961
0
    newInnerWindow->mChromeEventHandler = mChromeEventHandler;
1962
0
  }
1963
0
1964
0
  // Handle any document.open() logic after we setup the new inner window
1965
0
  // so that any bound DETH objects can see the top window, document, etc.
1966
0
  if (handleDocumentOpen) {
1967
0
    newInnerWindow->MigrateStateForDocumentOpen(currentInner);
1968
0
  }
1969
0
1970
0
  // We no longer need the old inner window.  Start its destruction if
1971
0
  // its not being reused and clear our reference.
1972
0
  if (doomCurrentInner) {
1973
0
    currentInner->FreeInnerObjects();
1974
0
  }
1975
0
  currentInner = nullptr;
1976
0
1977
0
  // Ask the JS engine to assert that it's valid to access our DocGroup whenever
1978
0
  // it runs JS code for this realm. We skip the check if this window is for
1979
0
  // chrome JS or an add-on.
1980
0
  nsCOMPtr<nsIPrincipal> principal = mDoc->NodePrincipal();
1981
0
  if (GetDocGroup() && !nsContentUtils::IsSystemPrincipal(principal) &&
1982
0
      !BasePrincipal::Cast(principal)->AddonPolicy()) {
1983
0
    js::SetRealmValidAccessPtr(cx, newInnerGlobal,
1984
0
                               newInnerWindow->GetDocGroup()->GetValidAccessPtr());
1985
0
  }
1986
0
1987
0
  kungFuDeathGrip->DidInitializeContext();
1988
0
1989
0
  // We wait to fire the debugger hook until the window is all set up and hooked
1990
0
  // up with the outer. See bug 969156.
1991
0
  if (createdInnerWindow) {
1992
0
    nsContentUtils::AddScriptRunner(
1993
0
      NewRunnableMethod("nsGlobalWindowInner::FireOnNewGlobalObject",
1994
0
                        newInnerWindow,
1995
0
                        &nsGlobalWindowInner::FireOnNewGlobalObject));
1996
0
  }
1997
0
1998
0
  if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
1999
0
    // We should probably notify. However if this is the, arguably bad,
2000
0
    // situation when we're creating a temporary non-chrome-about-blank
2001
0
    // document in a chrome docshell, don't notify just yet. Instead wait
2002
0
    // until we have a real chrome doc.
2003
0
    if (!mDocShell ||
2004
0
        mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome ||
2005
0
        nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
2006
0
      newInnerWindow->mHasNotifiedGlobalCreated = true;
2007
0
      nsContentUtils::AddScriptRunner(
2008
0
        NewRunnableMethod("nsGlobalWindowOuter::DispatchDOMWindowCreated",
2009
0
                          this,
2010
0
                          &nsGlobalWindowOuter::DispatchDOMWindowCreated));
2011
0
    }
2012
0
  }
2013
0
2014
0
  PreloadLocalStorage();
2015
0
2016
0
  // If we have a recorded interesting Large-Allocation header status, report it
2017
0
  // to the newly attached document.
2018
0
  ReportLargeAllocStatus();
2019
0
  mLargeAllocStatus = LargeAllocStatus::NONE;
2020
0
2021
0
  mHasStorageAccess = false;
2022
0
  nsIURI* uri = aDocument->GetDocumentURI();
2023
0
  if (newInnerWindow) {
2024
0
    if (AntiTrackingCommon::ShouldHonorContentBlockingCookieRestrictions() &&
2025
0
        StaticPrefs::network_cookie_cookieBehavior() ==
2026
0
          nsICookieService::BEHAVIOR_REJECT_TRACKER &&
2027
0
        nsContentUtils::IsThirdPartyWindowOrChannel(newInnerWindow, nullptr,
2028
0
                                                    uri) &&
2029
0
        nsContentUtils::IsTrackingResourceWindow(newInnerWindow)) {
2030
0
      // Grant storage access by default if the first-party storage access
2031
0
      // permission has been granted already.
2032
0
      // Don't notify in this case, since we would be notifying the user needlessly.
2033
0
      mHasStorageAccess =
2034
0
        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(newInnerWindow,
2035
0
                                                                uri,
2036
0
                                                                nullptr);
2037
0
    }
2038
0
  }
2039
0
2040
0
  return NS_OK;
2041
0
}
2042
2043
void
2044
nsGlobalWindowOuter::PreloadLocalStorage()
2045
0
{
2046
0
  if (!Storage::StoragePrefIsEnabled()) {
2047
0
    return;
2048
0
  }
2049
0
2050
0
  if (IsChromeWindow()) {
2051
0
    return;
2052
0
  }
2053
0
2054
0
  nsIPrincipal* principal = GetPrincipal();
2055
0
  if (!principal) {
2056
0
    return;
2057
0
  }
2058
0
2059
0
  nsresult rv;
2060
0
2061
0
  nsCOMPtr<nsIDOMStorageManager> storageManager =
2062
0
    do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
2063
0
  if (NS_FAILED(rv)) {
2064
0
    return;
2065
0
  }
2066
0
2067
0
  // private browsing windows do not persist local storage to disk so we should
2068
0
  // only try to precache storage when we're not a private browsing window.
2069
0
  if (principal->GetPrivateBrowsingId() == 0) {
2070
0
    RefPtr<Storage> storage;
2071
0
    rv = storageManager->PrecacheStorage(principal, getter_AddRefs(storage));
2072
0
    if (NS_SUCCEEDED(rv)) {
2073
0
      mLocalStorage = storage;
2074
0
    }
2075
0
  }
2076
0
}
2077
2078
void
2079
nsGlobalWindowOuter::DispatchDOMWindowCreated()
2080
0
{
2081
0
  if (!mDoc) {
2082
0
    return;
2083
0
  }
2084
0
2085
0
  // Fire DOMWindowCreated at chrome event listeners
2086
0
  nsContentUtils::DispatchChromeEvent(mDoc, mDoc, NS_LITERAL_STRING("DOMWindowCreated"),
2087
0
                                      CanBubble::eYes,
2088
0
                                      Cancelable::eNo);
2089
0
2090
0
  nsCOMPtr<nsIObserverService> observerService =
2091
0
    mozilla::services::GetObserverService();
2092
0
2093
0
  // The event dispatching could possibly cause docshell destory, and
2094
0
  // consequently cause mDoc to be set to nullptr by DropOuterWindowDocs(),
2095
0
  // so check it again here.
2096
0
  if (observerService && mDoc) {
2097
0
    nsAutoString origin;
2098
0
    nsIPrincipal* principal = mDoc->NodePrincipal();
2099
0
    nsContentUtils::GetUTFOrigin(principal, origin);
2100
0
    observerService->
2101
0
      NotifyObservers(static_cast<nsIDOMWindow*>(this),
2102
0
                      nsContentUtils::IsSystemPrincipal(principal) ?
2103
0
                        "chrome-document-global-created" :
2104
0
                        "content-document-global-created",
2105
0
                      origin.get());
2106
0
  }
2107
0
}
2108
2109
void
2110
nsGlobalWindowOuter::ClearStatus()
2111
0
{
2112
0
  SetStatusOuter(EmptyString());
2113
0
}
2114
2115
void
2116
nsGlobalWindowOuter::SetDocShell(nsIDocShell* aDocShell)
2117
0
{
2118
0
  MOZ_ASSERT(aDocShell);
2119
0
2120
0
  if (aDocShell == mDocShell) {
2121
0
    return;
2122
0
  }
2123
0
2124
0
  mDocShell = aDocShell; // Weak Reference
2125
0
2126
0
  nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetScriptableParentOrNull();
2127
0
  MOZ_RELEASE_ASSERT(!parentWindow || !mTabGroup ||
2128
0
                     mTabGroup == nsGlobalWindowOuter::Cast(parentWindow)->mTabGroup);
2129
0
2130
0
  mTopLevelOuterContentWindow =
2131
0
    !mIsChrome && GetScriptableTopInternal() == this;
2132
0
2133
0
  if (mFrames) {
2134
0
    mFrames->SetDocShell(aDocShell);
2135
0
  }
2136
0
2137
0
  // Get our enclosing chrome shell and retrieve its global window impl, so
2138
0
  // that we can do some forwarding to the chrome document.
2139
0
  RefPtr<EventTarget> chromeEventHandler;
2140
0
  mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2141
0
  mChromeEventHandler = chromeEventHandler;
2142
0
  if (!mChromeEventHandler) {
2143
0
    // We have no chrome event handler. If we have a parent,
2144
0
    // get our chrome event handler from the parent. If
2145
0
    // we don't have a parent, then we need to make a new
2146
0
    // window root object that will function as a chrome event
2147
0
    // handler and receive all events that occur anywhere inside
2148
0
    // our window.
2149
0
    nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetParent();
2150
0
    if (parentWindow.get() != this) {
2151
0
      mChromeEventHandler = parentWindow->GetChromeEventHandler();
2152
0
    }
2153
0
    else {
2154
0
      mChromeEventHandler = NS_NewWindowRoot(this);
2155
0
      mIsRootOuterWindow = true;
2156
0
    }
2157
0
  }
2158
0
2159
0
  bool docShellActive;
2160
0
  mDocShell->GetIsActive(&docShellActive);
2161
0
  SetIsBackgroundInternal(!docShellActive);
2162
0
}
2163
2164
void
2165
nsGlobalWindowOuter::DetachFromDocShell()
2166
0
{
2167
0
  // DetachFromDocShell means the window is being torn down. Drop our
2168
0
  // reference to the script context, allowing it to be deleted
2169
0
  // later. Meanwhile, keep our weak reference to the script object
2170
0
  // so that it can be retrieved later (until it is finalized by the JS GC).
2171
0
2172
0
  // Call FreeInnerObjects on all inner windows, not just the current
2173
0
  // one, since some could be held by WindowStateHolder objects that
2174
0
  // are GC-owned.
2175
0
  RefPtr<nsGlobalWindowInner> inner;
2176
0
  for (PRCList* node = PR_LIST_HEAD(this);
2177
0
       node != this;
2178
0
       node = PR_NEXT_LINK(inner)) {
2179
0
    // This cast is safe because `node != this`. Non-this nodes are inner windows.
2180
0
    inner = static_cast<nsGlobalWindowInner*>(node);
2181
0
    MOZ_ASSERT(!inner->mOuterWindow || inner->mOuterWindow == this);
2182
0
    inner->FreeInnerObjects();
2183
0
  }
2184
0
2185
0
  // Don't report that we were detached to the nsWindowMemoryReporter, as it
2186
0
  // only tracks inner windows.
2187
0
2188
0
  NotifyWindowIDDestroyed("outer-window-destroyed");
2189
0
2190
0
  nsGlobalWindowInner *currentInner = GetCurrentInnerWindowInternal();
2191
0
2192
0
  if (currentInner) {
2193
0
    NS_ASSERTION(mDoc, "Must have doc!");
2194
0
2195
0
    // Remember the document's principal and URI.
2196
0
    mDocumentPrincipal = mDoc->NodePrincipal();
2197
0
    mDocumentURI = mDoc->GetDocumentURI();
2198
0
2199
0
    // Release our document reference
2200
0
    DropOuterWindowDocs();
2201
0
  }
2202
0
2203
0
  ClearControllers();
2204
0
2205
0
  mChromeEventHandler = nullptr; // force release now
2206
0
2207
0
  if (mContext) {
2208
0
    // When we're about to destroy a top level content window
2209
0
    // (for example a tab), we trigger a full GC by passing null as the last
2210
0
    // param. We also trigger a full GC for chrome windows.
2211
0
    nsJSContext::PokeGC(JS::gcreason::SET_DOC_SHELL,
2212
0
                        (mTopLevelOuterContentWindow || mIsChrome) ?
2213
0
                          nullptr : GetWrapperPreserveColor());
2214
0
    mContext = nullptr;
2215
0
  }
2216
0
2217
0
  mDocShell = nullptr; // Weak Reference
2218
0
2219
0
  if (mFrames) {
2220
0
    mFrames->SetDocShell(nullptr);
2221
0
  }
2222
0
2223
0
  MaybeForgiveSpamCount();
2224
0
  CleanUp();
2225
0
}
2226
2227
void
2228
nsGlobalWindowOuter::SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
2229
                                     bool aOriginalOpener)
2230
0
{
2231
0
  nsWeakPtr opener = do_GetWeakReference(aOpener);
2232
0
  if (opener == mOpener) {
2233
0
    return;
2234
0
  }
2235
0
2236
0
  NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
2237
0
               "aOriginalOpener is true, but not first call to "
2238
0
               "SetOpenerWindow!");
2239
0
  NS_ASSERTION(aOpener || !aOriginalOpener,
2240
0
               "Shouldn't set mHadOriginalOpener if aOpener is null");
2241
0
2242
0
  mOpener = opener.forget();
2243
0
  NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
2244
0
2245
0
  // Check that the js visible opener matches! We currently don't depend on this
2246
0
  // being true outside of nightly, so we disable the assertion in optimized
2247
0
  // release / beta builds.
2248
0
  nsPIDOMWindowOuter* contentOpener = GetSanitizedOpener(aOpener);
2249
0
2250
0
  // contentOpener is not used when the DIAGNOSTIC_ASSERT is compiled out.
2251
0
  mozilla::Unused << contentOpener;
2252
0
  MOZ_DIAGNOSTIC_ASSERT(!contentOpener || !mTabGroup ||
2253
0
    mTabGroup == nsGlobalWindowOuter::Cast(contentOpener)->mTabGroup);
2254
0
2255
0
  if (aOriginalOpener) {
2256
0
    MOZ_ASSERT(!mHadOriginalOpener,
2257
0
               "Probably too late to call ComputeIsSecureContext again");
2258
0
    mHadOriginalOpener = true;
2259
0
  }
2260
0
2261
#ifdef DEBUG
2262
  mSetOpenerWindowCalled = true;
2263
#endif
2264
}
2265
2266
void
2267
nsGlobalWindowOuter::UpdateParentTarget()
2268
0
{
2269
0
  // NOTE: This method is nearly identical to
2270
0
  // nsGlobalWindowInner::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
2271
0
  // UPDATE THE OTHER ONE TOO!  The one difference is that this method updates
2272
0
  // mMessageManager as well, which inner windows don't have.
2273
0
2274
0
  // Try to get our frame element's tab child global (its in-process message
2275
0
  // manager).  If that fails, fall back to the chrome event handler's tab
2276
0
  // child global, and if it doesn't have one, just use the chrome event
2277
0
  // handler itself.
2278
0
2279
0
  nsCOMPtr<Element> frameElement = GetOuterWindow()->GetFrameElementInternal();
2280
0
  mMessageManager = nsContentUtils::TryGetTabChildGlobal(frameElement);
2281
0
2282
0
  if (!mMessageManager) {
2283
0
    nsGlobalWindowOuter* topWin = GetScriptableTopInternal();
2284
0
    if (topWin) {
2285
0
      frameElement = topWin->GetFrameElementInternal();
2286
0
      mMessageManager = nsContentUtils::TryGetTabChildGlobal(frameElement);
2287
0
    }
2288
0
  }
2289
0
2290
0
  if (!mMessageManager) {
2291
0
    mMessageManager = nsContentUtils::TryGetTabChildGlobal(mChromeEventHandler);
2292
0
  }
2293
0
2294
0
  if (mMessageManager) {
2295
0
    mParentTarget = mMessageManager;
2296
0
  } else {
2297
0
    mParentTarget = mChromeEventHandler;
2298
0
  }
2299
0
}
2300
2301
EventTarget*
2302
nsGlobalWindowOuter::GetTargetForEventTargetChain()
2303
0
{
2304
0
  return GetCurrentInnerWindowInternal();
2305
0
}
2306
2307
void
2308
nsGlobalWindowOuter::GetEventTargetParent(EventChainPreVisitor& aVisitor)
2309
0
{
2310
0
  MOZ_CRASH("The outer window should not be part of an event path");
2311
0
}
2312
2313
bool
2314
nsGlobalWindowOuter::ShouldPromptToBlockDialogs()
2315
0
{
2316
0
  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
2317
0
  if (!topWindowOuter) {
2318
0
    NS_ASSERTION(!mDocShell, "ShouldPromptToBlockDialogs() called without a top window?");
2319
0
    return true;
2320
0
  }
2321
0
2322
0
  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
2323
0
  if (!topWindow) {
2324
0
    return true;
2325
0
  }
2326
0
2327
0
  return topWindow->DialogsAreBeingAbused();
2328
0
}
2329
2330
bool
2331
nsGlobalWindowOuter::AreDialogsEnabled()
2332
0
{
2333
0
  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
2334
0
  if (!topWindowOuter) {
2335
0
    NS_ERROR("AreDialogsEnabled() called without a top window?");
2336
0
    return false;
2337
0
  }
2338
0
2339
0
  // TODO: Warn if no top window?
2340
0
  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
2341
0
  if (!topWindow) {
2342
0
    return false;
2343
0
  }
2344
0
2345
0
  // Dialogs are blocked if the content viewer is hidden
2346
0
  if (mDocShell) {
2347
0
    nsCOMPtr<nsIContentViewer> cv;
2348
0
    mDocShell->GetContentViewer(getter_AddRefs(cv));
2349
0
2350
0
    bool isHidden;
2351
0
    cv->GetIsHidden(&isHidden);
2352
0
    if (isHidden) {
2353
0
      return false;
2354
0
    }
2355
0
  }
2356
0
2357
0
  // Dialogs are also blocked if the document is sandboxed with SANDBOXED_MODALS
2358
0
  // (or if we have no document, of course).  Which document?  Who knows; the
2359
0
  // spec is daft.  See <https://github.com/whatwg/html/issues/1206>.  For now
2360
0
  // just go ahead and check mDoc, since in everything except edge cases in
2361
0
  // which a frame is allow-same-origin but not allow-scripts and is being poked
2362
0
  // at by some other window this should be the right thing anyway.
2363
0
  if (!mDoc || (mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
2364
0
    return false;
2365
0
  }
2366
0
2367
0
  return topWindow->mAreDialogsEnabled;
2368
0
}
2369
2370
bool
2371
nsGlobalWindowOuter::ConfirmDialogIfNeeded()
2372
0
{
2373
0
  NS_ENSURE_TRUE(mDocShell, false);
2374
0
  nsCOMPtr<nsIPromptService> promptSvc =
2375
0
    do_GetService("@mozilla.org/embedcomp/prompt-service;1");
2376
0
2377
0
  if (!promptSvc) {
2378
0
    return true;
2379
0
  }
2380
0
2381
0
  // Reset popup state while opening a modal dialog, and firing events
2382
0
  // about the dialog, to prevent the current state from being active
2383
0
  // the whole time a modal dialog is open.
2384
0
  nsAutoPopupStatePusher popupStatePusher(openAbused, true);
2385
0
2386
0
  bool disableDialog = false;
2387
0
  nsAutoString label, title;
2388
0
  nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2389
0
                                     "ScriptDialogLabel", label);
2390
0
  nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2391
0
                                     "ScriptDialogPreventTitle", title);
2392
0
  promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
2393
0
  if (disableDialog) {
2394
0
    DisableDialogs();
2395
0
    return false;
2396
0
  }
2397
0
2398
0
  return true;
2399
0
}
2400
2401
void
2402
nsGlobalWindowOuter::DisableDialogs()
2403
0
{
2404
0
  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
2405
0
  if (!topWindowOuter) {
2406
0
    NS_ERROR("DisableDialogs() called without a top window?");
2407
0
    return;
2408
0
  }
2409
0
2410
0
  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
2411
0
  // TODO: Warn if no top window?
2412
0
  if (topWindow) {
2413
0
    topWindow->mAreDialogsEnabled = false;
2414
0
  }
2415
0
}
2416
2417
void
2418
nsGlobalWindowOuter::EnableDialogs()
2419
0
{
2420
0
  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
2421
0
  if (!topWindowOuter) {
2422
0
    NS_ERROR("EnableDialogs() called without a top window?");
2423
0
    return;
2424
0
  }
2425
0
2426
0
  // TODO: Warn if no top window?
2427
0
  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
2428
0
  if (topWindow) {
2429
0
    topWindow->mAreDialogsEnabled = true;
2430
0
  }
2431
0
}
2432
2433
nsresult
2434
nsGlobalWindowOuter::PostHandleEvent(EventChainPostVisitor& aVisitor)
2435
0
{
2436
0
  MOZ_CRASH("The outer window should not be part of an event path");
2437
0
}
2438
2439
void
2440
nsGlobalWindowOuter::PoisonOuterWindowProxy(JSObject *aObject)
2441
0
{
2442
0
  if (aObject == GetWrapperMaybeDead()) {
2443
0
    PoisonWrapper();
2444
0
  }
2445
0
}
2446
2447
nsresult
2448
nsGlobalWindowOuter::SetArguments(nsIArray *aArguments)
2449
0
{
2450
0
  nsresult rv;
2451
0
2452
0
  // Historically, we've used the same machinery to handle openDialog arguments
2453
0
  // (exposed via window.arguments) and showModalDialog arguments (exposed via
2454
0
  // window.dialogArguments), even though the former is XUL-only and uses an XPCOM
2455
0
  // array while the latter is web-exposed and uses an arbitrary JS value.
2456
0
  // Moreover, per-spec |dialogArguments| is a property of the browsing context
2457
0
  // (outer), whereas |arguments| lives on the inner.
2458
0
  //
2459
0
  // We've now mostly separated them, but the difference is still opaque to
2460
0
  // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
2461
0
  // embedding waltz we do here).
2462
0
  //
2463
0
  // So we need to demultiplex the two cases here.
2464
0
  nsGlobalWindowInner *currentInner = GetCurrentInnerWindowInternal();
2465
0
2466
0
  mArguments = aArguments;
2467
0
  rv = currentInner->DefineArgumentsProperty(aArguments);
2468
0
  NS_ENSURE_SUCCESS(rv, rv);
2469
0
2470
0
  return NS_OK;
2471
0
}
2472
2473
//*****************************************************************************
2474
// nsGlobalWindowOuter::nsIScriptObjectPrincipal
2475
//*****************************************************************************
2476
2477
nsIPrincipal*
2478
nsGlobalWindowOuter::GetPrincipal()
2479
0
{
2480
0
  if (mDoc) {
2481
0
    // If we have a document, get the principal from the document
2482
0
    return mDoc->NodePrincipal();
2483
0
  }
2484
0
2485
0
  if (mDocumentPrincipal) {
2486
0
    return mDocumentPrincipal;
2487
0
  }
2488
0
2489
0
  // If we don't have a principal and we don't have a document we
2490
0
  // ask the parent window for the principal. This can happen when
2491
0
  // loading a frameset that has a <frame src="javascript:xxx">, in
2492
0
  // that case the global window is used in JS before we've loaded
2493
0
  // a document into the window.
2494
0
2495
0
  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2496
0
    do_QueryInterface(GetParentInternal());
2497
0
2498
0
  if (objPrincipal) {
2499
0
    return objPrincipal->GetPrincipal();
2500
0
  }
2501
0
2502
0
  return nullptr;
2503
0
}
2504
2505
//*****************************************************************************
2506
// nsGlobalWindowOuter::nsIDOMWindow
2507
//*****************************************************************************
2508
2509
void
2510
nsPIDOMWindowOuter::SetInitialKeyboardIndicators(
2511
  UIStateChangeType aShowAccelerators, UIStateChangeType aShowFocusRings)
2512
0
{
2513
0
  MOZ_ASSERT(!GetCurrentInnerWindow());
2514
0
2515
0
  nsPIDOMWindowOuter* piWin = GetPrivateRoot();
2516
0
  if (!piWin) {
2517
0
    return;
2518
0
  }
2519
0
2520
0
  MOZ_ASSERT(piWin == this);
2521
0
2522
0
  // only change the flags that have been modified
2523
0
  nsCOMPtr<nsPIWindowRoot> windowRoot = do_QueryInterface(mChromeEventHandler);
2524
0
  if (!windowRoot) {
2525
0
    return;
2526
0
  }
2527
0
2528
0
  if (aShowAccelerators != UIStateChangeType_NoChange) {
2529
0
    windowRoot->SetShowAccelerators(aShowAccelerators == UIStateChangeType_Set);
2530
0
  }
2531
0
  if (aShowFocusRings != UIStateChangeType_NoChange) {
2532
0
    windowRoot->SetShowFocusRings(aShowFocusRings == UIStateChangeType_Set);
2533
0
  }
2534
0
2535
0
  nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(GetOuterWindow(),
2536
0
                                                        aShowAccelerators,
2537
0
                                                        aShowFocusRings);
2538
0
}
2539
2540
Element*
2541
nsPIDOMWindowOuter::GetFrameElementInternal() const
2542
0
{
2543
0
  return mFrameElement;
2544
0
}
2545
2546
void
2547
nsPIDOMWindowOuter::SetFrameElementInternal(Element* aFrameElement)
2548
0
{
2549
0
  mFrameElement = aFrameElement;
2550
0
}
2551
2552
Navigator*
2553
nsGlobalWindowOuter::GetNavigator()
2554
0
{
2555
0
  FORWARD_TO_INNER(Navigator, (), nullptr);
2556
0
}
2557
2558
nsScreen*
2559
nsGlobalWindowOuter::GetScreen()
2560
0
{
2561
0
  FORWARD_TO_INNER(GetScreen, (IgnoreErrors()), nullptr);
2562
0
}
2563
2564
void
2565
nsPIDOMWindowOuter::MaybeActiveMediaComponents()
2566
0
{
2567
0
  if (mMediaSuspend != nsISuspendedTypes::SUSPENDED_BLOCK) {
2568
0
    return;
2569
0
  }
2570
0
2571
0
  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
2572
0
         ("nsPIDOMWindowOuter, MaybeActiveMediaComponents, "
2573
0
          "resume the window from blocked, this = %p\n", this));
2574
0
2575
0
  SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);
2576
0
}
2577
2578
SuspendTypes
2579
nsPIDOMWindowOuter::GetMediaSuspend() const
2580
0
{
2581
0
  return mMediaSuspend;
2582
0
}
2583
2584
void
2585
nsPIDOMWindowOuter::SetMediaSuspend(SuspendTypes aSuspend)
2586
0
{
2587
0
  if (!IsDisposableSuspend(aSuspend)) {
2588
0
    MaybeNotifyMediaResumedFromBlock(aSuspend);
2589
0
    mMediaSuspend = aSuspend;
2590
0
  }
2591
0
2592
0
  RefreshMediaElementsSuspend(aSuspend);
2593
0
}
2594
2595
void
2596
nsPIDOMWindowOuter::MaybeNotifyMediaResumedFromBlock(SuspendTypes aSuspend)
2597
0
{
2598
0
  if (mMediaSuspend == nsISuspendedTypes::SUSPENDED_BLOCK &&
2599
0
      aSuspend == nsISuspendedTypes::NONE_SUSPENDED) {
2600
0
    RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
2601
0
    if (service) {
2602
0
      service->NotifyMediaResumedFromBlock(GetOuterWindow());
2603
0
    }
2604
0
  }
2605
0
}
2606
2607
bool
2608
nsPIDOMWindowOuter::GetAudioMuted() const
2609
0
{
2610
0
  return mAudioMuted;
2611
0
}
2612
2613
void
2614
nsPIDOMWindowOuter::SetAudioMuted(bool aMuted)
2615
0
{
2616
0
  if (mAudioMuted == aMuted) {
2617
0
    return;
2618
0
  }
2619
0
2620
0
  mAudioMuted = aMuted;
2621
0
  RefreshMediaElementsVolume();
2622
0
}
2623
2624
float
2625
nsPIDOMWindowOuter::GetAudioVolume() const
2626
0
{
2627
0
  return mAudioVolume;
2628
0
}
2629
2630
nsresult
2631
nsPIDOMWindowOuter::SetAudioVolume(float aVolume)
2632
0
{
2633
0
  if (aVolume < 0.0) {
2634
0
    return NS_ERROR_DOM_INDEX_SIZE_ERR;
2635
0
  }
2636
0
2637
0
  if (mAudioVolume == aVolume) {
2638
0
    return NS_OK;
2639
0
  }
2640
0
2641
0
  mAudioVolume = aVolume;
2642
0
  RefreshMediaElementsVolume();
2643
0
  return NS_OK;
2644
0
}
2645
2646
void
2647
nsPIDOMWindowOuter::RefreshMediaElementsVolume()
2648
0
{
2649
0
  RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
2650
0
  if (service) {
2651
0
    service->RefreshAgentsVolume(GetOuterWindow());
2652
0
  }
2653
0
}
2654
2655
void
2656
nsPIDOMWindowOuter::RefreshMediaElementsSuspend(SuspendTypes aSuspend)
2657
0
{
2658
0
  RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
2659
0
  if (service) {
2660
0
    service->RefreshAgentsSuspend(GetOuterWindow(), aSuspend);
2661
0
  }
2662
0
}
2663
2664
bool
2665
nsPIDOMWindowOuter::IsDisposableSuspend(SuspendTypes aSuspend) const
2666
0
{
2667
0
  return (aSuspend == nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE ||
2668
0
          aSuspend == nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE);
2669
0
}
2670
2671
void
2672
nsPIDOMWindowOuter::SetServiceWorkersTestingEnabled(bool aEnabled)
2673
0
{
2674
0
  // Devtools should only be setting this on the top level window.  Its
2675
0
  // ok if devtools clears the flag on clean up of nested windows, though.
2676
0
  // It will have no affect.
2677
#ifdef DEBUG
2678
  nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetScriptableTop();
2679
  MOZ_ASSERT_IF(aEnabled, this == topWindow);
2680
#endif
2681
  mServiceWorkersTestingEnabled = aEnabled;
2682
0
}
2683
2684
bool
2685
nsPIDOMWindowOuter::GetServiceWorkersTestingEnabled()
2686
0
{
2687
0
  // Automatically get this setting from the top level window so that nested
2688
0
  // iframes get the correct devtools setting.
2689
0
  nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetScriptableTop();
2690
0
  if (!topWindow) {
2691
0
    return false;
2692
0
  }
2693
0
  return topWindow->mServiceWorkersTestingEnabled;
2694
0
}
2695
2696
already_AddRefed<nsPIDOMWindowOuter>
2697
nsGlobalWindowOuter::GetParentOuter()
2698
0
{
2699
0
  if (!mDocShell) {
2700
0
    return nullptr;
2701
0
  }
2702
0
2703
0
  nsCOMPtr<nsPIDOMWindowOuter> parent;
2704
0
  if (mDocShell->GetIsMozBrowser()) {
2705
0
    parent = this;
2706
0
  } else {
2707
0
    parent = GetParent();
2708
0
  }
2709
0
2710
0
  return parent.forget();
2711
0
}
2712
2713
/**
2714
 * GetScriptableParent is called when script reads window.parent.
2715
 *
2716
 * In contrast to GetRealParent, GetScriptableParent respects <iframe
2717
 * mozbrowser> boundaries, so if |this| is contained by an <iframe
2718
 * mozbrowser>, we will return |this| as its own parent.
2719
 */
2720
nsPIDOMWindowOuter*
2721
nsGlobalWindowOuter::GetScriptableParent()
2722
0
{
2723
0
  nsCOMPtr<nsPIDOMWindowOuter> parent = GetParentOuter();
2724
0
  return parent.get();
2725
0
}
2726
2727
/**
2728
 * Behavies identically to GetScriptableParent extept that it returns null
2729
 * if GetScriptableParent would return this window.
2730
 */
2731
nsPIDOMWindowOuter*
2732
nsGlobalWindowOuter::GetScriptableParentOrNull()
2733
0
{
2734
0
  nsPIDOMWindowOuter* parent = GetScriptableParent();
2735
0
  return (nsGlobalWindowOuter::Cast(parent) == this) ? nullptr : parent;
2736
0
}
2737
2738
/**
2739
 * nsPIDOMWindow::GetParent (when called from C++) is just a wrapper around
2740
 * GetRealParent.
2741
 */
2742
already_AddRefed<nsPIDOMWindowOuter>
2743
nsGlobalWindowOuter::GetParent()
2744
0
{
2745
0
  if (!mDocShell) {
2746
0
    return nullptr;
2747
0
  }
2748
0
2749
0
  nsCOMPtr<nsIDocShell> parent;
2750
0
  mDocShell->GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent));
2751
0
2752
0
  if (parent) {
2753
0
    nsCOMPtr<nsPIDOMWindowOuter> win = parent->GetWindow();
2754
0
    return win.forget();
2755
0
  }
2756
0
2757
0
  nsCOMPtr<nsPIDOMWindowOuter> win(this);
2758
0
  return win.forget();
2759
0
}
2760
2761
static nsresult
2762
GetTopImpl(nsGlobalWindowOuter* aWin, nsPIDOMWindowOuter** aTop, bool aScriptable)
2763
0
{
2764
0
  *aTop = nullptr;
2765
0
2766
0
  // Walk up the parent chain.
2767
0
2768
0
  nsCOMPtr<nsPIDOMWindowOuter> prevParent = aWin;
2769
0
  nsCOMPtr<nsPIDOMWindowOuter> parent = aWin;
2770
0
  do {
2771
0
    if (!parent) {
2772
0
      break;
2773
0
    }
2774
0
2775
0
    prevParent = parent;
2776
0
2777
0
    nsCOMPtr<nsPIDOMWindowOuter> newParent;
2778
0
    if (aScriptable) {
2779
0
      newParent = parent->GetScriptableParent();
2780
0
    }
2781
0
    else {
2782
0
      newParent = parent->GetParent();
2783
0
    }
2784
0
2785
0
    parent = newParent;
2786
0
2787
0
  } while (parent != prevParent);
2788
0
2789
0
  if (parent) {
2790
0
    parent.swap(*aTop);
2791
0
  }
2792
0
2793
0
  return NS_OK;
2794
0
}
2795
2796
/**
2797
 * GetScriptableTop is called when script reads window.top.
2798
 *
2799
 * In contrast to GetRealTop, GetScriptableTop respects <iframe mozbrowser>
2800
 * boundaries.  If we encounter a window owned by an <iframe mozbrowser> while
2801
 * walking up the window hierarchy, we'll stop and return that window.
2802
 */
2803
nsPIDOMWindowOuter*
2804
nsGlobalWindowOuter::GetScriptableTop()
2805
0
{
2806
0
  nsCOMPtr<nsPIDOMWindowOuter> window;
2807
0
  GetTopImpl(this, getter_AddRefs(window), /* aScriptable = */ true);
2808
0
  return window.get();
2809
0
}
2810
2811
already_AddRefed<nsPIDOMWindowOuter>
2812
nsGlobalWindowOuter::GetTop()
2813
0
{
2814
0
  nsCOMPtr<nsPIDOMWindowOuter> window;
2815
0
  GetTopImpl(this, getter_AddRefs(window), /* aScriptable = */ false);
2816
0
  return window.forget();
2817
0
}
2818
2819
void
2820
nsGlobalWindowOuter::GetContentOuter(JSContext* aCx,
2821
                                     JS::MutableHandle<JSObject*> aRetval,
2822
                                     CallerType aCallerType,
2823
                                     ErrorResult& aError)
2824
0
{
2825
0
  nsCOMPtr<nsPIDOMWindowOuter> content =
2826
0
    GetContentInternal(aError, aCallerType);
2827
0
  if (aError.Failed()) {
2828
0
    return;
2829
0
  }
2830
0
2831
0
  if (content) {
2832
0
    JS::Rooted<JS::Value> val(aCx);
2833
0
    aError = nsContentUtils::WrapNative(aCx, content, &val);
2834
0
    if (aError.Failed()) {
2835
0
      return;
2836
0
    }
2837
0
2838
0
    aRetval.set(&val.toObject());
2839
0
    return;
2840
0
  }
2841
0
2842
0
  aRetval.set(nullptr);
2843
0
}
2844
2845
already_AddRefed<nsPIDOMWindowOuter>
2846
nsGlobalWindowOuter::GetContentInternal(ErrorResult& aError, CallerType aCallerType)
2847
0
{
2848
0
  // First check for a named frame named "content"
2849
0
  nsCOMPtr<nsPIDOMWindowOuter> domWindow =
2850
0
    GetChildWindow(NS_LITERAL_STRING("content"));
2851
0
  if (domWindow) {
2852
0
    return domWindow.forget();
2853
0
  }
2854
0
2855
0
  // If we're contained in <iframe mozbrowser>, then GetContent is the same as
2856
0
  // window.top.
2857
0
  if (mDocShell && mDocShell->GetIsInMozBrowser()) {
2858
0
    return GetTopOuter();
2859
0
  }
2860
0
2861
0
  nsCOMPtr<nsIDocShellTreeItem> primaryContent;
2862
0
  if (aCallerType != CallerType::System) {
2863
0
    if (mDoc) {
2864
0
      mDoc->WarnOnceAbout(nsIDocument::eWindowContentUntrusted);
2865
0
    }
2866
0
    // If we're called by non-chrome code, make sure we don't return
2867
0
    // the primary content window if the calling tab is hidden. In
2868
0
    // such a case we return the same-type root in the hidden tab,
2869
0
    // which is "good enough", for now.
2870
0
    nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
2871
0
2872
0
    if (baseWin) {
2873
0
      bool visible = false;
2874
0
      baseWin->GetVisibility(&visible);
2875
0
2876
0
      if (!visible) {
2877
0
        mDocShell->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
2878
0
      }
2879
0
    }
2880
0
  }
2881
0
2882
0
  if (!primaryContent) {
2883
0
    nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
2884
0
    if (!treeOwner) {
2885
0
      aError.Throw(NS_ERROR_FAILURE);
2886
0
      return nullptr;
2887
0
    }
2888
0
2889
0
    treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
2890
0
  }
2891
0
2892
0
  if (!primaryContent) {
2893
0
    return nullptr;
2894
0
  }
2895
0
2896
0
  domWindow = primaryContent->GetWindow();
2897
0
  return domWindow.forget();
2898
0
}
2899
2900
nsresult
2901
nsGlobalWindowOuter::GetPrompter(nsIPrompt** aPrompt)
2902
0
{
2903
0
  if (!mDocShell)
2904
0
    return NS_ERROR_FAILURE;
2905
0
2906
0
  nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
2907
0
  NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
2908
0
2909
0
  prompter.forget(aPrompt);
2910
0
  return NS_OK;
2911
0
}
2912
2913
bool
2914
nsGlobalWindowOuter::GetClosedOuter()
2915
0
{
2916
0
  // If someone called close(), or if we don't have a docshell, we're closed.
2917
0
  return mIsClosed || !mDocShell;
2918
0
}
2919
2920
bool
2921
nsGlobalWindowOuter::Closed()
2922
0
{
2923
0
  return GetClosedOuter();
2924
0
}
2925
2926
nsDOMWindowList*
2927
nsGlobalWindowOuter::GetFrames()
2928
0
{
2929
0
  if (!mFrames && mDocShell) {
2930
0
    mFrames = new nsDOMWindowList(mDocShell);
2931
0
  }
2932
0
2933
0
  return mFrames;
2934
0
}
2935
2936
already_AddRefed<nsPIDOMWindowOuter>
2937
nsGlobalWindowOuter::IndexedGetterOuter(uint32_t aIndex)
2938
0
{
2939
0
  nsDOMWindowList* windows = GetFrames();
2940
0
  NS_ENSURE_TRUE(windows, nullptr);
2941
0
2942
0
  return windows->IndexedGetter(aIndex);
2943
0
}
2944
2945
nsIControllers*
2946
nsGlobalWindowOuter::GetControllersOuter(ErrorResult& aError)
2947
0
{
2948
0
  if (!mControllers) {
2949
0
    mControllers = new nsXULControllers();
2950
0
    if (!mControllers) {
2951
0
      aError.Throw(NS_ERROR_FAILURE);
2952
0
      return nullptr;
2953
0
    }
2954
0
2955
0
    // Add in the default controller
2956
0
    nsCOMPtr<nsIController> controller =
2957
0
      nsBaseCommandController::CreateWindowController();
2958
0
    if (!controller) {
2959
0
      aError.Throw(NS_ERROR_FAILURE);
2960
0
      return nullptr;
2961
0
    }
2962
0
2963
0
    mControllers->InsertControllerAt(0, controller);
2964
0
    nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
2965
0
    if (!controllerContext) {
2966
0
      aError.Throw(NS_ERROR_FAILURE);
2967
0
      return nullptr;
2968
0
    }
2969
0
2970
0
    controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
2971
0
  }
2972
0
2973
0
  return mControllers;
2974
0
}
2975
2976
nsresult
2977
nsGlobalWindowOuter::GetControllers(nsIControllers** aResult)
2978
0
{
2979
0
  FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED);
2980
0
}
2981
2982
nsPIDOMWindowOuter*
2983
nsGlobalWindowOuter::GetSanitizedOpener(nsPIDOMWindowOuter* aOpener)
2984
0
{
2985
0
  if (!aOpener) {
2986
0
    return nullptr;
2987
0
  }
2988
0
2989
0
  nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(aOpener);
2990
0
2991
0
  // First, ensure that we're not handing back a chrome window to content:
2992
0
  if (win->IsChromeWindow()) {
2993
0
    return nullptr;
2994
0
  }
2995
0
2996
0
  // We don't want to reveal the opener if the opener is a mail window,
2997
0
  // because opener can be used to spoof the contents of a message (bug 105050).
2998
0
  // So, we look in the opener's root docshell to see if it's a mail window.
2999
0
  nsCOMPtr<nsIDocShell> openerDocShell = aOpener->GetDocShell();
3000
0
3001
0
  if (openerDocShell) {
3002
0
    nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
3003
0
    openerDocShell->GetRootTreeItem(getter_AddRefs(openerRootItem));
3004
0
    nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
3005
0
    if (openerRootDocShell) {
3006
0
      uint32_t appType;
3007
0
      nsresult rv = openerRootDocShell->GetAppType(&appType);
3008
0
      if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
3009
0
        return aOpener;
3010
0
      }
3011
0
    }
3012
0
  }
3013
0
3014
0
  return nullptr;
3015
0
}
3016
3017
nsPIDOMWindowOuter*
3018
nsGlobalWindowOuter::GetOpenerWindowOuter()
3019
0
{
3020
0
  nsCOMPtr<nsPIDOMWindowOuter> opener = do_QueryReferent(mOpener);
3021
0
3022
0
  if (!opener) {
3023
0
    return nullptr;
3024
0
  }
3025
0
3026
0
  // First, check if we were called from a privileged chrome script
3027
0
  if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
3028
0
    // Catch the case where we're chrome but the opener is not...
3029
0
    if (GetPrincipal() == nsContentUtils::GetSystemPrincipal() &&
3030
0
        nsGlobalWindowOuter::Cast(opener)->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
3031
0
      return nullptr;
3032
0
    }
3033
0
    return opener;
3034
0
  }
3035
0
3036
0
  return GetSanitizedOpener(opener);
3037
0
}
3038
3039
already_AddRefed<nsPIDOMWindowOuter>
3040
nsGlobalWindowOuter::GetOpener()
3041
0
{
3042
0
  nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindowOuter();
3043
0
  return opener.forget();
3044
0
}
3045
3046
void
3047
nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus)
3048
0
{
3049
0
  aStatus = mStatus;
3050
0
}
3051
3052
void
3053
nsGlobalWindowOuter::SetStatusOuter(const nsAString& aStatus)
3054
0
{
3055
0
  mStatus = aStatus;
3056
0
3057
0
  // We don't support displaying window.status in the UI, so there's nothing
3058
0
  // left to do here.
3059
0
}
3060
3061
void
3062
nsGlobalWindowOuter::GetNameOuter(nsAString& aName)
3063
0
{
3064
0
  if (mDocShell) {
3065
0
    mDocShell->GetName(aName);
3066
0
  }
3067
0
}
3068
3069
void
3070
nsGlobalWindowOuter::SetNameOuter(const nsAString& aName, mozilla::ErrorResult& aError)
3071
0
{
3072
0
  if (mDocShell) {
3073
0
    aError = mDocShell->SetName(aName);
3074
0
  }
3075
0
}
3076
3077
// Helper functions used by many methods below.
3078
int32_t
3079
nsGlobalWindowOuter::DevToCSSIntPixels(int32_t px)
3080
0
{
3081
0
  if (!mDocShell)
3082
0
    return px; // assume 1:1
3083
0
3084
0
  RefPtr<nsPresContext> presContext;
3085
0
  mDocShell->GetPresContext(getter_AddRefs(presContext));
3086
0
  if (!presContext)
3087
0
    return px;
3088
0
3089
0
  return presContext->DevPixelsToIntCSSPixels(px);
3090
0
}
3091
3092
int32_t
3093
nsGlobalWindowOuter::CSSToDevIntPixels(int32_t px)
3094
0
{
3095
0
  if (!mDocShell)
3096
0
    return px; // assume 1:1
3097
0
3098
0
  RefPtr<nsPresContext> presContext;
3099
0
  mDocShell->GetPresContext(getter_AddRefs(presContext));
3100
0
  if (!presContext)
3101
0
    return px;
3102
0
3103
0
  return presContext->CSSPixelsToDevPixels(px);
3104
0
}
3105
3106
nsIntSize
3107
nsGlobalWindowOuter::DevToCSSIntPixels(nsIntSize px)
3108
0
{
3109
0
  if (!mDocShell)
3110
0
    return px; // assume 1:1
3111
0
3112
0
  RefPtr<nsPresContext> presContext;
3113
0
  mDocShell->GetPresContext(getter_AddRefs(presContext));
3114
0
  if (!presContext)
3115
0
    return px;
3116
0
3117
0
  return nsIntSize(
3118
0
      presContext->DevPixelsToIntCSSPixels(px.width),
3119
0
      presContext->DevPixelsToIntCSSPixels(px.height));
3120
0
}
3121
3122
nsIntSize
3123
nsGlobalWindowOuter::CSSToDevIntPixels(nsIntSize px)
3124
0
{
3125
0
  if (!mDocShell)
3126
0
    return px; // assume 1:1
3127
0
3128
0
  RefPtr<nsPresContext> presContext;
3129
0
  mDocShell->GetPresContext(getter_AddRefs(presContext));
3130
0
  if (!presContext)
3131
0
    return px;
3132
0
3133
0
  return nsIntSize(
3134
0
    presContext->CSSPixelsToDevPixels(px.width),
3135
0
    presContext->CSSPixelsToDevPixels(px.height));
3136
0
}
3137
3138
nsresult
3139
nsGlobalWindowOuter::GetInnerSize(CSSIntSize& aSize)
3140
0
{
3141
0
  EnsureSizeAndPositionUpToDate();
3142
0
3143
0
  NS_ENSURE_STATE(mDocShell);
3144
0
3145
0
  RefPtr<nsPresContext> presContext;
3146
0
  mDocShell->GetPresContext(getter_AddRefs(presContext));
3147
0
  RefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
3148
0
3149
0
  if (!presContext || !presShell) {
3150
0
    aSize = CSSIntSize(0, 0);
3151
0
    return NS_OK;
3152
0
  }
3153
0
3154
0
  /*
3155
0
   * On platforms with resolution-based zooming, the CSS viewport
3156
0
   * and visual viewport may not be the same. The inner size should
3157
0
   * be the visual viewport, but we fall back to the CSS viewport
3158
0
   * if it is not set.
3159
0
   */
3160
0
  if (presShell->IsVisualViewportSizeSet()) {
3161
0
    aSize = CSSIntRect::FromAppUnitsRounded(
3162
0
      presShell->GetVisualViewportSize());
3163
0
  } else {
3164
0
    RefPtr<nsViewManager> viewManager = presShell->GetViewManager();
3165
0
    if (viewManager) {
3166
0
      viewManager->FlushDelayedResize(false);
3167
0
    }
3168
0
3169
0
    aSize = CSSIntRect::FromAppUnitsRounded(
3170
0
      presContext->GetVisibleArea().Size());
3171
0
  }
3172
0
  return NS_OK;
3173
0
}
3174
3175
int32_t
3176
nsGlobalWindowOuter::GetInnerWidthOuter(ErrorResult& aError)
3177
0
{
3178
0
  CSSIntSize size;
3179
0
  aError = GetInnerSize(size);
3180
0
  return size.width;
3181
0
}
3182
3183
nsresult
3184
nsGlobalWindowOuter::GetInnerWidth(int32_t* aInnerWidth)
3185
0
{
3186
0
  FORWARD_TO_INNER(GetInnerWidth, (aInnerWidth), NS_ERROR_UNEXPECTED);
3187
0
}
3188
3189
void
3190
nsGlobalWindowOuter::SetInnerWidthOuter(int32_t aInnerWidth,
3191
                                        CallerType aCallerType,
3192
                                        ErrorResult& aError)
3193
0
{
3194
0
  if (!mDocShell) {
3195
0
    aError.Throw(NS_ERROR_UNEXPECTED);
3196
0
    return;
3197
0
  }
3198
0
3199
0
  CheckSecurityWidthAndHeight(&aInnerWidth, nullptr, aCallerType);
3200
0
3201
0
  RefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
3202
0
3203
0
  if (presShell && presShell->GetIsViewportOverridden())
3204
0
  {
3205
0
    nscoord height = 0;
3206
0
3207
0
    RefPtr<nsPresContext> presContext;
3208
0
    presContext = presShell->GetPresContext();
3209
0
3210
0
    nsRect shellArea = presContext->GetVisibleArea();
3211
0
    height = shellArea.Height();
3212
0
    SetCSSViewportWidthAndHeight(nsPresContext::CSSPixelsToAppUnits(aInnerWidth),
3213
0
                                 height);
3214
0
    return;
3215
0
  }
3216
0
3217
0
  int32_t height = 0;
3218
0
  int32_t unused  = 0;
3219
0
3220
0
  nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3221
0
  docShellAsWin->GetSize(&unused, &height);
3222
0
  aError = SetDocShellWidthAndHeight(CSSToDevIntPixels(aInnerWidth), height);
3223
0
}
3224
3225
int32_t
3226
nsGlobalWindowOuter::GetInnerHeightOuter(ErrorResult& aError)
3227
0
{
3228
0
  CSSIntSize size;
3229
0
  aError = GetInnerSize(size);
3230
0
  return size.height;
3231
0
}
3232
3233
nsresult
3234
nsGlobalWindowOuter::GetInnerHeight(int32_t* aInnerHeight)
3235
0
{
3236
0
  FORWARD_TO_INNER(GetInnerHeight, (aInnerHeight), NS_ERROR_UNEXPECTED);
3237
0
}
3238
3239
void
3240
nsGlobalWindowOuter::SetInnerHeightOuter(int32_t aInnerHeight,
3241
                                         CallerType aCallerType,
3242
                                         ErrorResult& aError)
3243
0
{
3244
0
  if (!mDocShell) {
3245
0
    aError.Throw(NS_ERROR_UNEXPECTED);
3246
0
    return;
3247
0
  }
3248
0
3249
0
  RefPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
3250
0
3251
0
  if (presShell && presShell->GetIsViewportOverridden())
3252
0
  {
3253
0
    RefPtr<nsPresContext> presContext;
3254
0
    presContext = presShell->GetPresContext();
3255
0
3256
0
    nsRect shellArea = presContext->GetVisibleArea();
3257
0
    nscoord height = aInnerHeight;
3258
0
    nscoord width = shellArea.Width();
3259
0
    CheckSecurityWidthAndHeight(nullptr, &height, aCallerType);
3260
0
    SetCSSViewportWidthAndHeight(width,
3261
0
                                 nsPresContext::CSSPixelsToAppUnits(height));
3262
0
    return;
3263
0
  }
3264
0
3265
0
  int32_t height = 0;
3266
0
  int32_t width  = 0;
3267
0
3268
0
  nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3269
0
  docShellAsWin->GetSize(&width, &height);
3270
0
  CheckSecurityWidthAndHeight(nullptr, &aInnerHeight, aCallerType);
3271
0
  aError = SetDocShellWidthAndHeight(width, CSSToDevIntPixels(aInnerHeight));
3272
0
}
3273
3274
nsIntSize
3275
nsGlobalWindowOuter::GetOuterSize(CallerType aCallerType, ErrorResult& aError)
3276
0
{
3277
0
  if (nsContentUtils::ResistFingerprinting(aCallerType)) {
3278
0
    CSSIntSize size;
3279
0
    aError = GetInnerSize(size);
3280
0
    return nsIntSize(size.width, size.height);
3281
0
  }
3282
0
3283
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3284
0
  if (!treeOwnerAsWin) {
3285
0
    aError.Throw(NS_ERROR_FAILURE);
3286
0
    return nsIntSize(0, 0);
3287
0
  }
3288
0
3289
0
  nsIntSize sizeDevPixels;
3290
0
  aError = treeOwnerAsWin->GetSize(&sizeDevPixels.width, &sizeDevPixels.height);
3291
0
  if (aError.Failed()) {
3292
0
    return nsIntSize();
3293
0
  }
3294
0
3295
0
  return DevToCSSIntPixels(sizeDevPixels);
3296
0
}
3297
3298
int32_t
3299
nsGlobalWindowOuter::GetOuterWidthOuter(CallerType aCallerType, ErrorResult& aError)
3300
0
{
3301
0
  return GetOuterSize(aCallerType, aError).width;
3302
0
}
3303
3304
int32_t
3305
nsGlobalWindowOuter::GetOuterHeightOuter(CallerType aCallerType, ErrorResult& aError)
3306
0
{
3307
0
  return GetOuterSize(aCallerType, aError).height;
3308
0
}
3309
3310
void
3311
nsGlobalWindowOuter::SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth,
3312
                                  CallerType aCallerType, ErrorResult& aError)
3313
0
{
3314
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3315
0
  if (!treeOwnerAsWin) {
3316
0
    aError.Throw(NS_ERROR_FAILURE);
3317
0
    return;
3318
0
  }
3319
0
3320
0
  CheckSecurityWidthAndHeight(aIsWidth ? &aLengthCSSPixels : nullptr,
3321
0
                              aIsWidth ? nullptr : &aLengthCSSPixels,
3322
0
                              aCallerType);
3323
0
3324
0
  int32_t width, height;
3325
0
  aError = treeOwnerAsWin->GetSize(&width, &height);
3326
0
  if (aError.Failed()) {
3327
0
    return;
3328
0
  }
3329
0
3330
0
  int32_t lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
3331
0
  if (aIsWidth) {
3332
0
    width = lengthDevPixels;
3333
0
  } else {
3334
0
    height = lengthDevPixels;
3335
0
  }
3336
0
  aError = treeOwnerAsWin->SetSize(width, height, true);
3337
0
3338
0
  CheckForDPIChange();
3339
0
}
3340
3341
void
3342
nsGlobalWindowOuter::SetOuterWidthOuter(int32_t aOuterWidth,
3343
                                        CallerType aCallerType,
3344
                                        ErrorResult& aError)
3345
0
{
3346
0
  SetOuterSize(aOuterWidth, true, aCallerType, aError);
3347
0
}
3348
3349
void
3350
nsGlobalWindowOuter::SetOuterHeightOuter(int32_t aOuterHeight,
3351
                                         CallerType aCallerType,
3352
                                         ErrorResult& aError)
3353
0
{
3354
0
  SetOuterSize(aOuterHeight, false, aCallerType, aError);
3355
0
}
3356
3357
CSSIntPoint
3358
nsGlobalWindowOuter::GetScreenXY(CallerType aCallerType, ErrorResult& aError)
3359
0
{
3360
0
  // When resisting fingerprinting, always return (0,0)
3361
0
  if (nsContentUtils::ResistFingerprinting(aCallerType)) {
3362
0
    return CSSIntPoint(0, 0);
3363
0
  }
3364
0
3365
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3366
0
  if (!treeOwnerAsWin) {
3367
0
    aError.Throw(NS_ERROR_FAILURE);
3368
0
    return CSSIntPoint(0, 0);
3369
0
  }
3370
0
3371
0
  int32_t x = 0, y = 0;
3372
0
  aError = treeOwnerAsWin->GetPosition(&x, &y); // LayoutDevice px values
3373
0
3374
0
  RefPtr<nsPresContext> presContext;
3375
0
  mDocShell->GetPresContext(getter_AddRefs(presContext));
3376
0
  if (!presContext) {
3377
0
    return CSSIntPoint(x, y);
3378
0
  }
3379
0
3380
0
  // Find the global desktop coordinate of the top-left of the screen.
3381
0
  // We'll use this as a "fake origin" when converting to CSS px units,
3382
0
  // to avoid overlapping coordinates in cases such as a hi-dpi screen
3383
0
  // placed to the right of a lo-dpi screen on Windows. (Instead, there
3384
0
  // may be "gaps" in the resulting CSS px coordinates in some cases.)
3385
0
  nsDeviceContext *dc = presContext->DeviceContext();
3386
0
  nsRect screenRect;
3387
0
  dc->GetRect(screenRect);
3388
0
  LayoutDeviceRect screenRectDev =
3389
0
    LayoutDevicePixel::FromAppUnits(screenRect, dc->AppUnitsPerDevPixel());
3390
0
3391
0
  DesktopToLayoutDeviceScale scale = dc->GetDesktopToDeviceScale();
3392
0
  DesktopRect screenRectDesk = screenRectDev / scale;
3393
0
3394
0
  CSSPoint cssPt =
3395
0
    LayoutDevicePoint(x - screenRectDev.x, y - screenRectDev.y) /
3396
0
    presContext->CSSToDevPixelScale();
3397
0
  cssPt.x += screenRectDesk.x;
3398
0
  cssPt.y += screenRectDesk.y;
3399
0
3400
0
  return CSSIntPoint(NSToIntRound(cssPt.x), NSToIntRound(cssPt.y));
3401
0
}
3402
3403
int32_t
3404
nsGlobalWindowOuter::GetScreenXOuter(CallerType aCallerType, ErrorResult& aError)
3405
0
{
3406
0
  return GetScreenXY(aCallerType, aError).x;
3407
0
}
3408
3409
nsRect
3410
nsGlobalWindowOuter::GetInnerScreenRect()
3411
0
{
3412
0
  if (!mDocShell) {
3413
0
    return nsRect();
3414
0
  }
3415
0
3416
0
  EnsureSizeAndPositionUpToDate();
3417
0
3418
0
  if (!mDocShell) {
3419
0
    return nsRect();
3420
0
  }
3421
0
3422
0
  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
3423
0
  if (!presShell) {
3424
0
    return nsRect();
3425
0
  }
3426
0
  nsIFrame* rootFrame = presShell->GetRootFrame();
3427
0
  if (!rootFrame) {
3428
0
    return nsRect();
3429
0
  }
3430
0
3431
0
  return rootFrame->GetScreenRectInAppUnits();
3432
0
}
3433
3434
float
3435
nsGlobalWindowOuter::GetMozInnerScreenXOuter(CallerType aCallerType)
3436
0
{
3437
0
  // When resisting fingerprinting, always return 0.
3438
0
  if (nsContentUtils::ResistFingerprinting(aCallerType)) {
3439
0
    return 0.0;
3440
0
  }
3441
0
3442
0
  nsRect r = GetInnerScreenRect();
3443
0
  return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3444
0
}
3445
3446
float
3447
nsGlobalWindowOuter::GetMozInnerScreenYOuter(CallerType aCallerType)
3448
0
{
3449
0
  // Return 0 to prevent fingerprinting.
3450
0
  if (nsContentUtils::ResistFingerprinting(aCallerType)) {
3451
0
    return 0.0;
3452
0
  }
3453
0
3454
0
  nsRect r = GetInnerScreenRect();
3455
0
  return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3456
0
}
3457
3458
double
3459
nsGlobalWindowOuter::GetDevicePixelRatioOuter(CallerType aCallerType)
3460
0
{
3461
0
  if (!mDocShell) {
3462
0
    return 1.0;
3463
0
  }
3464
0
3465
0
  RefPtr<nsPresContext> presContext;
3466
0
  mDocShell->GetPresContext(getter_AddRefs(presContext));
3467
0
  if (!presContext) {
3468
0
    return 1.0;
3469
0
  }
3470
0
3471
0
  if (nsContentUtils::ResistFingerprinting(aCallerType)) {
3472
0
    return 1.0;
3473
0
  }
3474
0
3475
0
  float overrideDPPX = presContext->GetOverrideDPPX();
3476
0
3477
0
  if (overrideDPPX > 0) {
3478
0
    return overrideDPPX;
3479
0
  }
3480
0
3481
0
  return double(AppUnitsPerCSSPixel()) /
3482
0
         double(presContext->AppUnitsPerDevPixel());
3483
0
}
3484
3485
float
3486
nsPIDOMWindowOuter::GetDevicePixelRatio(CallerType aCallerType)
3487
0
{
3488
0
  return nsGlobalWindowOuter::Cast(this)->GetDevicePixelRatioOuter(aCallerType);
3489
0
}
3490
3491
uint64_t
3492
nsGlobalWindowOuter::GetMozPaintCountOuter()
3493
0
{
3494
0
  if (!mDocShell) {
3495
0
    return 0;
3496
0
  }
3497
0
3498
0
  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
3499
0
  return presShell ? presShell->GetPaintCount() : 0;
3500
0
}
3501
3502
already_AddRefed<MediaQueryList>
3503
nsGlobalWindowOuter::MatchMediaOuter(const nsAString& aMediaQueryList,
3504
                                     CallerType aCallerType)
3505
0
{
3506
0
  if (!mDoc) {
3507
0
    return nullptr;
3508
0
  }
3509
0
3510
0
  return mDoc->MatchMedia(aMediaQueryList, aCallerType);
3511
0
}
3512
3513
void
3514
nsGlobalWindowOuter::SetScreenXOuter(int32_t aScreenX,
3515
                                     CallerType aCallerType,
3516
                                     ErrorResult& aError)
3517
0
{
3518
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3519
0
  if (!treeOwnerAsWin) {
3520
0
    aError.Throw(NS_ERROR_FAILURE);
3521
0
    return;
3522
0
  }
3523
0
3524
0
  int32_t x, y;
3525
0
  aError = treeOwnerAsWin->GetPosition(&x, &y);
3526
0
  if (aError.Failed()) {
3527
0
    return;
3528
0
  }
3529
0
3530
0
  CheckSecurityLeftAndTop(&aScreenX, nullptr, aCallerType);
3531
0
  x = CSSToDevIntPixels(aScreenX);
3532
0
3533
0
  aError = treeOwnerAsWin->SetPosition(x, y);
3534
0
3535
0
  CheckForDPIChange();
3536
0
}
3537
3538
int32_t
3539
nsGlobalWindowOuter::GetScreenYOuter(CallerType aCallerType, ErrorResult& aError)
3540
0
{
3541
0
  return GetScreenXY(aCallerType, aError).y;
3542
0
}
3543
3544
3545
void
3546
nsGlobalWindowOuter::SetScreenYOuter(int32_t aScreenY,
3547
                                     CallerType aCallerType,
3548
                                     ErrorResult& aError)
3549
0
{
3550
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3551
0
  if (!treeOwnerAsWin) {
3552
0
    aError.Throw(NS_ERROR_FAILURE);
3553
0
    return;
3554
0
  }
3555
0
3556
0
  int32_t x, y;
3557
0
  aError = treeOwnerAsWin->GetPosition(&x, &y);
3558
0
  if (aError.Failed()) {
3559
0
    return;
3560
0
  }
3561
0
3562
0
  CheckSecurityLeftAndTop(nullptr, &aScreenY, aCallerType);
3563
0
  y = CSSToDevIntPixels(aScreenY);
3564
0
3565
0
  aError = treeOwnerAsWin->SetPosition(x, y);
3566
0
3567
0
  CheckForDPIChange();
3568
0
}
3569
3570
// NOTE: Arguments to this function should have values scaled to
3571
// CSS pixels, not device pixels.
3572
void
3573
nsGlobalWindowOuter::CheckSecurityWidthAndHeight(int32_t* aWidth, int32_t* aHeight,
3574
                                                 CallerType aCallerType)
3575
0
{
3576
0
#ifdef MOZ_XUL
3577
0
  if (aCallerType != CallerType::System) {
3578
0
    // if attempting to resize the window, hide any open popups
3579
0
    nsContentUtils::HidePopupsInDocument(mDoc);
3580
0
  }
3581
0
#endif
3582
0
3583
0
  // This one is easy. Just ensure the variable is greater than 100;
3584
0
  if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
3585
0
    // Check security state for use in determing window dimensions
3586
0
3587
0
    if (aCallerType != CallerType::System) {
3588
0
      //sec check failed
3589
0
      if (aWidth && *aWidth < 100) {
3590
0
        *aWidth = 100;
3591
0
      }
3592
0
      if (aHeight && *aHeight < 100) {
3593
0
        *aHeight = 100;
3594
0
      }
3595
0
    }
3596
0
  }
3597
0
}
3598
3599
// NOTE: Arguments to this function should have values in device pixels
3600
nsresult
3601
nsGlobalWindowOuter::SetDocShellWidthAndHeight(int32_t aInnerWidth, int32_t aInnerHeight)
3602
0
{
3603
0
  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
3604
0
3605
0
  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3606
0
  mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
3607
0
  NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
3608
0
3609
0
  NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(mDocShell, aInnerWidth, aInnerHeight),
3610
0
                    NS_ERROR_FAILURE);
3611
0
3612
0
  return NS_OK;
3613
0
}
3614
3615
// NOTE: Arguments to this function should have values in app units
3616
void
3617
nsGlobalWindowOuter::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
3618
0
{
3619
0
  RefPtr<nsPresContext> presContext;
3620
0
  mDocShell->GetPresContext(getter_AddRefs(presContext));
3621
0
3622
0
  nsRect shellArea = presContext->GetVisibleArea();
3623
0
  shellArea.SetHeight(aInnerHeight);
3624
0
  shellArea.SetWidth(aInnerWidth);
3625
0
3626
0
  presContext->SetVisibleArea(shellArea);
3627
0
}
3628
3629
// NOTE: Arguments to this function should have values scaled to
3630
// CSS pixels, not device pixels.
3631
void
3632
nsGlobalWindowOuter::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop,
3633
                                             CallerType aCallerType)
3634
0
{
3635
0
  // This one is harder. We have to get the screen size and window dimensions.
3636
0
3637
0
  // Check security state for use in determing window dimensions
3638
0
3639
0
  if (aCallerType != CallerType::System) {
3640
0
#ifdef MOZ_XUL
3641
0
    // if attempting to move the window, hide any open popups
3642
0
    nsContentUtils::HidePopupsInDocument(mDoc);
3643
0
#endif
3644
0
3645
0
    if (nsGlobalWindowOuter* rootWindow = nsGlobalWindowOuter::Cast(GetPrivateRoot())) {
3646
0
      rootWindow->FlushPendingNotifications(FlushType::Layout);
3647
0
    }
3648
0
3649
0
    nsCOMPtr<nsIBaseWindow> treeOwner = GetTreeOwnerWindow();
3650
0
3651
0
    RefPtr<nsScreen> screen = GetScreen();
3652
0
3653
0
    if (treeOwner && screen) {
3654
0
      int32_t winLeft, winTop, winWidth, winHeight;
3655
0
3656
0
      // Get the window size
3657
0
      treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
3658
0
3659
0
      // convert those values to CSS pixels
3660
0
      // XXX four separate retrievals of the prescontext
3661
0
      winLeft   = DevToCSSIntPixels(winLeft);
3662
0
      winTop    = DevToCSSIntPixels(winTop);
3663
0
      winWidth  = DevToCSSIntPixels(winWidth);
3664
0
      winHeight = DevToCSSIntPixels(winHeight);
3665
0
3666
0
      // Get the screen dimensions
3667
0
      // XXX This should use nsIScreenManager once it's fully fleshed out.
3668
0
      int32_t screenLeft = screen->GetAvailLeft(IgnoreErrors());
3669
0
      int32_t screenWidth = screen->GetAvailWidth(IgnoreErrors());
3670
0
      int32_t screenHeight = screen->GetAvailHeight(IgnoreErrors());
3671
#if defined(XP_MACOSX)
3672
      /* The mac's coordinate system is different from the assumed Windows'
3673
         system. It offsets by the height of the menubar so that a window
3674
         placed at (0,0) will be entirely visible. Unfortunately that
3675
         correction is made elsewhere (in Widget) and the meaning of
3676
         the Avail... coordinates is overloaded. Here we allow a window
3677
         to be placed at (0,0) because it does make sense to do so.
3678
      */
3679
      int32_t screenTop = screen->GetTop(IgnoreErrors());
3680
#else
3681
      int32_t screenTop = screen->GetAvailTop(IgnoreErrors());
3682
0
#endif
3683
0
3684
0
      if (aLeft) {
3685
0
        if (screenLeft+screenWidth < *aLeft+winWidth)
3686
0
          *aLeft = screenLeft+screenWidth - winWidth;
3687
0
        if (screenLeft > *aLeft)
3688
0
          *aLeft = screenLeft;
3689
0
      }
3690
0
      if (aTop) {
3691
0
        if (screenTop+screenHeight < *aTop+winHeight)
3692
0
          *aTop = screenTop+screenHeight - winHeight;
3693
0
        if (screenTop > *aTop)
3694
0
          *aTop = screenTop;
3695
0
      }
3696
0
    } else {
3697
0
      if (aLeft)
3698
0
        *aLeft = 0;
3699
0
      if (aTop)
3700
0
        *aTop = 0;
3701
0
    }
3702
0
  }
3703
0
}
3704
3705
int32_t
3706
nsGlobalWindowOuter::GetScrollBoundaryOuter(Side aSide)
3707
0
{
3708
0
  FlushPendingNotifications(FlushType::Layout);
3709
0
  if (nsIScrollableFrame *sf = GetScrollFrame()) {
3710
0
    return nsPresContext::
3711
0
      AppUnitsToIntCSSPixels(sf->GetScrollRange().Edge(aSide));
3712
0
  }
3713
0
  return 0;
3714
0
}
3715
3716
CSSPoint
3717
nsGlobalWindowOuter::GetScrollXY(bool aDoFlush)
3718
0
{
3719
0
  if (aDoFlush) {
3720
0
    FlushPendingNotifications(FlushType::Layout);
3721
0
  } else {
3722
0
    EnsureSizeAndPositionUpToDate();
3723
0
  }
3724
0
3725
0
  nsIScrollableFrame *sf = GetScrollFrame();
3726
0
  if (!sf) {
3727
0
    return CSSIntPoint(0, 0);
3728
0
  }
3729
0
3730
0
  nsPoint scrollPos = sf->GetScrollPosition();
3731
0
  if (scrollPos != nsPoint(0,0) && !aDoFlush) {
3732
0
    // Oh, well.  This is the expensive case -- the window is scrolled and we
3733
0
    // didn't actually flush yet.  Repeat, but with a flush, since the content
3734
0
    // may get shorter and hence our scroll position may decrease.
3735
0
    return GetScrollXY(true);
3736
0
  }
3737
0
3738
0
  return CSSPoint::FromAppUnits(scrollPos);
3739
0
}
3740
3741
double
3742
nsGlobalWindowOuter::GetScrollXOuter()
3743
0
{
3744
0
  return GetScrollXY(false).x;
3745
0
}
3746
3747
double
3748
nsGlobalWindowOuter::GetScrollYOuter()
3749
0
{
3750
0
  return GetScrollXY(false).y;
3751
0
}
3752
3753
uint32_t
3754
nsGlobalWindowOuter::Length()
3755
0
{
3756
0
  nsDOMWindowList* windows = GetFrames();
3757
0
3758
0
  return windows ? windows->GetLength() : 0;
3759
0
}
3760
3761
already_AddRefed<nsPIDOMWindowOuter>
3762
nsGlobalWindowOuter::GetTopOuter()
3763
0
{
3764
0
  nsCOMPtr<nsPIDOMWindowOuter> top = GetScriptableTop();
3765
0
  return top.forget();
3766
0
}
3767
3768
nsPIDOMWindowOuter*
3769
nsGlobalWindowOuter::GetChildWindow(const nsAString& aName)
3770
0
{
3771
0
  nsCOMPtr<nsIDocShell> docShell(GetDocShell());
3772
0
  NS_ENSURE_TRUE(docShell, nullptr);
3773
0
3774
0
  nsCOMPtr<nsIDocShellTreeItem> child;
3775
0
  docShell->FindChildWithName(aName, false, true, nullptr, nullptr,
3776
0
                              getter_AddRefs(child));
3777
0
3778
0
  return child ? child->GetWindow() : nullptr;
3779
0
}
3780
3781
bool
3782
nsGlobalWindowOuter::DispatchCustomEvent(const nsAString& aEventName)
3783
0
{
3784
0
  bool defaultActionEnabled = true;
3785
0
  nsContentUtils::DispatchTrustedEvent(mDoc, ToSupports(this), aEventName,
3786
0
                                       CanBubble::eYes, Cancelable::eYes,
3787
0
                                       &defaultActionEnabled);
3788
0
3789
0
  return defaultActionEnabled;
3790
0
}
3791
3792
bool
3793
nsGlobalWindowOuter::DispatchResizeEvent(const CSSIntSize& aSize)
3794
0
{
3795
0
  ErrorResult res;
3796
0
  RefPtr<Event> domEvent =
3797
0
    mDoc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), CallerType::System,
3798
0
                      res);
3799
0
  if (res.Failed()) {
3800
0
    return false;
3801
0
  }
3802
0
3803
0
  // We don't init the AutoJSAPI with ourselves because we don't want it
3804
0
  // reporting errors to our onerror handlers.
3805
0
  AutoJSAPI jsapi;
3806
0
  jsapi.Init();
3807
0
  JSContext* cx = jsapi.cx();
3808
0
  JSAutoRealm ar(cx, GetWrapperPreserveColor());
3809
0
3810
0
  DOMWindowResizeEventDetail detail;
3811
0
  detail.mWidth = aSize.width;
3812
0
  detail.mHeight = aSize.height;
3813
0
  JS::Rooted<JS::Value> detailValue(cx);
3814
0
  if (!ToJSValue(cx, detail, &detailValue)) {
3815
0
    return false;
3816
0
  }
3817
0
3818
0
  CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
3819
0
  customEvent->InitCustomEvent(cx,
3820
0
                               NS_LITERAL_STRING("DOMWindowResize"),
3821
0
                               /* aCanBubble = */ true,
3822
0
                               /* aCancelable = */ true,
3823
0
                               detailValue);
3824
0
3825
0
  domEvent->SetTrusted(true);
3826
0
  domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3827
0
3828
0
  nsCOMPtr<EventTarget> target = do_QueryInterface(GetOuterWindow());
3829
0
  domEvent->SetTarget(target);
3830
0
3831
0
  return target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
3832
0
}
3833
3834
static already_AddRefed<nsIDocShellTreeItem>
3835
GetCallerDocShellTreeItem()
3836
0
{
3837
0
  nsCOMPtr<nsIWebNavigation> callerWebNav = do_GetInterface(GetEntryGlobal());
3838
0
  nsCOMPtr<nsIDocShellTreeItem> callerItem = do_QueryInterface(callerWebNav);
3839
0
3840
0
  return callerItem.forget();
3841
0
}
3842
3843
bool
3844
nsGlobalWindowOuter::WindowExists(const nsAString& aName,
3845
                                  bool aForceNoOpener,
3846
                                  bool aLookForCallerOnJSStack)
3847
0
{
3848
0
  MOZ_ASSERT(mDocShell, "Must have docshell");
3849
0
3850
0
  if (aForceNoOpener) {
3851
0
    return aName.LowerCaseEqualsLiteral("_self") ||
3852
0
           aName.LowerCaseEqualsLiteral("_top") ||
3853
0
           aName.LowerCaseEqualsLiteral("_parent");
3854
0
  }
3855
0
3856
0
  nsCOMPtr<nsIDocShellTreeItem> caller;
3857
0
  if (aLookForCallerOnJSStack) {
3858
0
    caller = GetCallerDocShellTreeItem();
3859
0
  }
3860
0
3861
0
  if (!caller) {
3862
0
    caller = mDocShell;
3863
0
  }
3864
0
3865
0
  nsCOMPtr<nsIDocShellTreeItem> namedItem;
3866
0
  mDocShell->FindItemWithName(aName, nullptr, caller,
3867
0
                              /* aSkipTabGroup = */ false,
3868
0
                              getter_AddRefs(namedItem));
3869
0
  return namedItem != nullptr;
3870
0
}
3871
3872
already_AddRefed<nsIWidget>
3873
nsGlobalWindowOuter::GetMainWidget()
3874
0
{
3875
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3876
0
3877
0
  nsCOMPtr<nsIWidget> widget;
3878
0
3879
0
  if (treeOwnerAsWin) {
3880
0
    treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
3881
0
  }
3882
0
3883
0
  return widget.forget();
3884
0
}
3885
3886
nsIWidget*
3887
nsGlobalWindowOuter::GetNearestWidget() const
3888
0
{
3889
0
  nsIDocShell* docShell = GetDocShell();
3890
0
  NS_ENSURE_TRUE(docShell, nullptr);
3891
0
  nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
3892
0
  NS_ENSURE_TRUE(presShell, nullptr);
3893
0
  nsIFrame* rootFrame = presShell->GetRootFrame();
3894
0
  NS_ENSURE_TRUE(rootFrame, nullptr);
3895
0
  return rootFrame->GetView()->GetNearestWidget(nullptr);
3896
0
}
3897
3898
void
3899
nsGlobalWindowOuter::SetFullscreenOuter(bool aFullscreen, mozilla::ErrorResult& aError)
3900
0
{
3901
0
  aError = SetFullscreenInternal(FullscreenReason::ForFullscreenMode, aFullscreen);
3902
0
}
3903
3904
nsresult
3905
nsGlobalWindowOuter::SetFullScreen(bool aFullscreen)
3906
0
{
3907
0
  return SetFullscreenInternal(FullscreenReason::ForFullscreenMode, aFullscreen);
3908
0
}
3909
3910
static void
3911
FinishDOMFullscreenChange(nsIDocument* aDoc, bool aInDOMFullscreen)
3912
0
{
3913
0
  if (aInDOMFullscreen) {
3914
0
    // Ask the document to handle any pending DOM fullscreen change.
3915
0
    if (!nsIDocument::HandlePendingFullscreenRequests(aDoc)) {
3916
0
      // If we don't end up having anything in fullscreen,
3917
0
      // async request exiting fullscreen.
3918
0
      nsIDocument::AsyncExitFullscreen(aDoc);
3919
0
    }
3920
0
  } else {
3921
0
    // If the window is leaving fullscreen state, also ask the document
3922
0
    // to exit from DOM Fullscreen.
3923
0
    nsIDocument::ExitFullscreenInDocTree(aDoc);
3924
0
  }
3925
0
}
3926
3927
struct FullscreenTransitionDuration
3928
{
3929
  // The unit of the durations is millisecond
3930
  uint16_t mFadeIn = 0;
3931
  uint16_t mFadeOut = 0;
3932
  bool IsSuppressed() const
3933
0
  {
3934
0
    return mFadeIn == 0 && mFadeOut == 0;
3935
0
  }
3936
};
3937
3938
static void
3939
GetFullscreenTransitionDuration(bool aEnterFullscreen,
3940
                                FullscreenTransitionDuration* aDuration)
3941
0
{
3942
0
  const char* pref = aEnterFullscreen ?
3943
0
    "full-screen-api.transition-duration.enter" :
3944
0
    "full-screen-api.transition-duration.leave";
3945
0
  nsAutoCString prefValue;
3946
0
  Preferences::GetCString(pref, prefValue);
3947
0
  if (!prefValue.IsEmpty()) {
3948
0
    sscanf(prefValue.get(), "%hu%hu",
3949
0
           &aDuration->mFadeIn, &aDuration->mFadeOut);
3950
0
  }
3951
0
}
3952
3953
class FullscreenTransitionTask : public Runnable
3954
{
3955
public:
3956
  FullscreenTransitionTask(const FullscreenTransitionDuration& aDuration,
3957
                           nsGlobalWindowOuter* aWindow,
3958
                           bool aFullscreen,
3959
                           nsIWidget* aWidget,
3960
                           nsIScreen* aScreen,
3961
                           nsISupports* aTransitionData)
3962
    : mozilla::Runnable("FullscreenTransitionTask")
3963
    , mWindow(aWindow)
3964
    , mWidget(aWidget)
3965
    , mScreen(aScreen)
3966
    , mTransitionData(aTransitionData)
3967
    , mDuration(aDuration)
3968
    , mStage(eBeforeToggle)
3969
    , mFullscreen(aFullscreen)
3970
0
  {
3971
0
  }
3972
3973
  NS_IMETHOD Run() override;
3974
3975
private:
3976
  ~FullscreenTransitionTask() override
3977
0
  {
3978
0
  }
3979
3980
  /**
3981
   * The flow of fullscreen transition:
3982
   *
3983
   *         parent process         |         child process
3984
   * ----------------------------------------------------------------
3985
   *
3986
   *                                    | request/exit fullscreen
3987
   *                              <-----|
3988
   *         BeforeToggle stage |
3989
   *                            |
3990
   *  ToggleFullscreen stage *1 |----->
3991
   *                                    | HandleFullscreenRequests
3992
   *                                    |
3993
   *                              <-----| MozAfterPaint event
3994
   *       AfterToggle stage *2 |
3995
   *                            |
3996
   *                  End stage |
3997
   *
3998
   * Note we also start a timer at *1 so that if we don't get MozAfterPaint
3999
   * from the child process in time, we continue going to *2.
4000
   */
4001
  enum Stage {
4002
    // BeforeToggle stage happens before we enter or leave fullscreen
4003
    // state. In this stage, the task triggers the pre-toggle fullscreen
4004
    // transition on the widget.
4005
    eBeforeToggle,
4006
    // ToggleFullscreen stage actually executes the fullscreen toggle,
4007
    // and wait for the next paint on the content to continue.
4008
    eToggleFullscreen,
4009
    // AfterToggle stage happens after we toggle the fullscreen state.
4010
    // In this stage, the task triggers the post-toggle fullscreen
4011
    // transition on the widget.
4012
    eAfterToggle,
4013
    // End stage is triggered after the final transition finishes.
4014
    eEnd
4015
  };
4016
4017
  class Observer final : public nsIObserver
4018
  {
4019
  public:
4020
    NS_DECL_ISUPPORTS
4021
    NS_DECL_NSIOBSERVER
4022
4023
    explicit Observer(FullscreenTransitionTask* aTask)
4024
0
      : mTask(aTask) { }
4025
4026
  private:
4027
0
    ~Observer() = default;
4028
4029
    RefPtr<FullscreenTransitionTask> mTask;
4030
  };
4031
4032
  static const char* const kPaintedTopic;
4033
4034
  RefPtr<nsGlobalWindowOuter> mWindow;
4035
  nsCOMPtr<nsIWidget> mWidget;
4036
  nsCOMPtr<nsIScreen> mScreen;
4037
  nsCOMPtr<nsITimer> mTimer;
4038
  nsCOMPtr<nsISupports> mTransitionData;
4039
4040
  TimeStamp mFullscreenChangeStartTime;
4041
  FullscreenTransitionDuration mDuration;
4042
  Stage mStage;
4043
  bool mFullscreen;
4044
};
4045
4046
const char* const
4047
FullscreenTransitionTask::kPaintedTopic = "fullscreen-painted";
4048
4049
NS_IMETHODIMP
4050
FullscreenTransitionTask::Run()
4051
0
{
4052
0
  Stage stage = mStage;
4053
0
  mStage = Stage(mStage + 1);
4054
0
  if (MOZ_UNLIKELY(mWidget->Destroyed())) {
4055
0
    // If the widget has been destroyed before we get here, don't try to
4056
0
    // do anything more. Just let it go and release ourselves.
4057
0
    NS_WARNING("The widget to fullscreen has been destroyed");
4058
0
    return NS_OK;
4059
0
  }
4060
0
  if (stage == eBeforeToggle) {
4061
0
    PROFILER_ADD_MARKER("Fullscreen transition start");
4062
0
    mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
4063
0
                                         mDuration.mFadeIn, mTransitionData,
4064
0
                                         this);
4065
0
  } else if (stage == eToggleFullscreen) {
4066
0
    PROFILER_ADD_MARKER("Fullscreen toggle start");
4067
0
    mFullscreenChangeStartTime = TimeStamp::Now();
4068
0
    if (MOZ_UNLIKELY(mWindow->mFullscreen != mFullscreen)) {
4069
0
      // This could happen in theory if several fullscreen requests in
4070
0
      // different direction happen continuously in a short time. We
4071
0
      // need to ensure the fullscreen state matches our target here,
4072
0
      // otherwise the widget would change the window state as if we
4073
0
      // toggle for Fullscreen Mode instead of Fullscreen API.
4074
0
      NS_WARNING("The fullscreen state of the window does not match");
4075
0
      mWindow->mFullscreen = mFullscreen;
4076
0
    }
4077
0
    // Toggle the fullscreen state on the widget
4078
0
    if (!mWindow->SetWidgetFullscreen(FullscreenReason::ForFullscreenAPI,
4079
0
                                      mFullscreen, mWidget, mScreen)) {
4080
0
      // Fail to setup the widget, call FinishFullscreenChange to
4081
0
      // complete fullscreen change directly.
4082
0
      mWindow->FinishFullscreenChange(mFullscreen);
4083
0
    }
4084
0
    // Set observer for the next content paint.
4085
0
    nsCOMPtr<nsIObserver> observer = new Observer(this);
4086
0
    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4087
0
    obs->AddObserver(observer, kPaintedTopic, false);
4088
0
    // There are several edge cases where we may never get the paint
4089
0
    // notification, including:
4090
0
    // 1. the window/tab is closed before the next paint;
4091
0
    // 2. the user has switched to another tab before we get here.
4092
0
    // Completely fixing those cases seems to be tricky, and since they
4093
0
    // should rarely happen, it probably isn't worth to fix. Hence we
4094
0
    // simply add a timeout here to ensure we never hang forever.
4095
0
    // In addition, if the page is complicated or the machine is less
4096
0
    // powerful, layout could take a long time, in which case, staying
4097
0
    // in black screen for that long could hurt user experience even
4098
0
    // more than exposing an intermediate state.
4099
0
    uint32_t timeout =
4100
0
      Preferences::GetUint("full-screen-api.transition.timeout", 1000);
4101
0
    NS_NewTimerWithObserver(getter_AddRefs(mTimer),
4102
0
                            observer, timeout, nsITimer::TYPE_ONE_SHOT);
4103
0
  } else if (stage == eAfterToggle) {
4104
0
    Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
4105
0
                                   mFullscreenChangeStartTime);
4106
0
    mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
4107
0
                                         mDuration.mFadeOut, mTransitionData,
4108
0
                                         this);
4109
0
  } else if (stage == eEnd) {
4110
0
    PROFILER_ADD_MARKER("Fullscreen transition end");
4111
0
    mWidget->CleanupFullscreenTransition();
4112
0
  }
4113
0
  return NS_OK;
4114
0
}
4115
4116
NS_IMPL_ISUPPORTS(FullscreenTransitionTask::Observer, nsIObserver)
4117
4118
NS_IMETHODIMP
4119
FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
4120
                                            const char* aTopic,
4121
                                            const char16_t* aData)
4122
0
{
4123
0
  bool shouldContinue = false;
4124
0
  if (strcmp(aTopic, FullscreenTransitionTask::kPaintedTopic) == 0) {
4125
0
    nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aSubject));
4126
0
    nsCOMPtr<nsIWidget> widget = win ?
4127
0
      nsGlobalWindowInner::Cast(win)->GetMainWidget() : nullptr;
4128
0
    if (widget == mTask->mWidget) {
4129
0
      // The paint notification arrives first. Cancel the timer.
4130
0
      mTask->mTimer->Cancel();
4131
0
      shouldContinue = true;
4132
0
      PROFILER_ADD_MARKER("Fullscreen toggle end");
4133
0
    }
4134
0
  } else {
4135
#ifdef DEBUG
4136
    MOZ_ASSERT(strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC) == 0,
4137
               "Should only get fullscreen-painted or timer-callback");
4138
    nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject));
4139
    MOZ_ASSERT(timer && timer == mTask->mTimer,
4140
               "Should only trigger this with the timer the task created");
4141
#endif
4142
    shouldContinue = true;
4143
0
    PROFILER_ADD_MARKER("Fullscreen toggle timeout");
4144
0
  }
4145
0
  if (shouldContinue) {
4146
0
    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4147
0
    obs->RemoveObserver(this, kPaintedTopic);
4148
0
    mTask->mTimer = nullptr;
4149
0
    mTask->Run();
4150
0
  }
4151
0
  return NS_OK;
4152
0
}
4153
4154
static bool
4155
MakeWidgetFullscreen(nsGlobalWindowOuter* aWindow, FullscreenReason aReason,
4156
                     bool aFullscreen)
4157
0
{
4158
0
  nsCOMPtr<nsIWidget> widget = aWindow->GetMainWidget();
4159
0
  if (!widget) {
4160
0
    return false;
4161
0
  }
4162
0
4163
0
  FullscreenTransitionDuration duration;
4164
0
  bool performTransition = false;
4165
0
  nsCOMPtr<nsISupports> transitionData;
4166
0
  if (aReason == FullscreenReason::ForFullscreenAPI) {
4167
0
    GetFullscreenTransitionDuration(aFullscreen, &duration);
4168
0
    if (!duration.IsSuppressed()) {
4169
0
      performTransition = widget->
4170
0
        PrepareForFullscreenTransition(getter_AddRefs(transitionData));
4171
0
    }
4172
0
  }
4173
0
  // We pass nullptr as the screen to SetWidgetFullscreen
4174
0
  // and FullscreenTransitionTask, as we do not wish to override
4175
0
  // the default screen selection behavior.  The screen containing
4176
0
  // most of the widget will be selected.
4177
0
  if (!performTransition) {
4178
0
    return aWindow->SetWidgetFullscreen(aReason, aFullscreen, widget, nullptr);
4179
0
  }
4180
0
  nsCOMPtr<nsIRunnable> task =
4181
0
    new FullscreenTransitionTask(duration, aWindow, aFullscreen,
4182
0
                                 widget, nullptr, transitionData);
4183
0
  task->Run();
4184
0
  return true;
4185
0
}
4186
4187
nsresult
4188
nsGlobalWindowOuter::SetFullscreenInternal(FullscreenReason aReason,
4189
                                           bool aFullscreen)
4190
0
{
4191
0
  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),
4192
0
             "Requires safe to run script as it "
4193
0
             "may call FinishDOMFullscreenChange");
4194
0
4195
0
  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
4196
0
4197
0
  MOZ_ASSERT(aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen,
4198
0
             "FullscreenReason::ForForceExitFullscreen can "
4199
0
             "only be used with exiting fullscreen");
4200
0
4201
0
  // Only chrome can change our fullscreen mode. Otherwise, the state
4202
0
  // can only be changed for DOM fullscreen.
4203
0
  if (aReason == FullscreenReason::ForFullscreenMode &&
4204
0
      !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
4205
0
    return NS_OK;
4206
0
  }
4207
0
4208
0
  // SetFullscreen needs to be called on the root window, so get that
4209
0
  // via the DocShell tree, and if we are not already the root,
4210
0
  // call SetFullscreen on that window instead.
4211
0
  nsCOMPtr<nsIDocShellTreeItem> rootItem;
4212
0
  mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
4213
0
  nsCOMPtr<nsPIDOMWindowOuter> window = rootItem ? rootItem->GetWindow() : nullptr;
4214
0
  if (!window)
4215
0
    return NS_ERROR_FAILURE;
4216
0
  if (rootItem != mDocShell)
4217
0
    return window->SetFullscreenInternal(aReason, aFullscreen);
4218
0
4219
0
  // make sure we don't try to set full screen on a non-chrome window,
4220
0
  // which might happen in embedding world
4221
0
  if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
4222
0
    return NS_ERROR_FAILURE;
4223
0
4224
0
  // If we are already in full screen mode, just return.
4225
0
  if (mFullscreen == aFullscreen) {
4226
0
    return NS_OK;
4227
0
  }
4228
0
4229
0
  // Note that although entering DOM fullscreen could also cause
4230
0
  // consequential calls to this method, those calls will be skipped
4231
0
  // at the condition above.
4232
0
  if (aReason == FullscreenReason::ForFullscreenMode) {
4233
0
    if (!aFullscreen && !mFullscreenMode) {
4234
0
      // If we are exiting fullscreen mode, but we actually didn't
4235
0
      // entered fullscreen mode, the fullscreen state was only for
4236
0
      // the Fullscreen API. Change the reason here so that we can
4237
0
      // perform transition for it.
4238
0
      aReason = FullscreenReason::ForFullscreenAPI;
4239
0
    } else {
4240
0
      mFullscreenMode = aFullscreen;
4241
0
    }
4242
0
  } else {
4243
0
    // If we are exiting from DOM fullscreen while we initially make
4244
0
    // the window fullscreen because of fullscreen mode, don't restore
4245
0
    // the window. But we still need to exit the DOM fullscreen state.
4246
0
    if (!aFullscreen && mFullscreenMode) {
4247
0
      FinishDOMFullscreenChange(mDoc, false);
4248
0
      return NS_OK;
4249
0
    }
4250
0
  }
4251
0
4252
0
  // Prevent chrome documents which are still loading from resizing
4253
0
  // the window after we set fullscreen mode.
4254
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4255
0
  nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
4256
0
  if (aFullscreen && xulWin) {
4257
0
    xulWin->SetIntrinsicallySized(false);
4258
0
  }
4259
0
4260
0
  // Set this before so if widget sends an event indicating its
4261
0
  // gone full screen, the state trap above works.
4262
0
  mFullscreen = aFullscreen;
4263
0
4264
0
  // Sometimes we don't want the top-level widget to actually go fullscreen,
4265
0
  // for example in the B2G desktop client, we don't want the emulated screen
4266
0
  // dimensions to appear to increase when entering fullscreen mode; we just
4267
0
  // want the content to fill the entire client area of the emulator window.
4268
0
  if (!Preferences::GetBool("full-screen-api.ignore-widgets", false)) {
4269
0
    if (MakeWidgetFullscreen(this, aReason, aFullscreen)) {
4270
0
      // The rest of code for switching fullscreen is in nsGlobalWindowOuter::
4271
0
      // FinishFullscreenChange() which will be called after sizemodechange
4272
0
      // event is dispatched.
4273
0
      return NS_OK;
4274
0
    }
4275
0
  }
4276
0
4277
0
  FinishFullscreenChange(aFullscreen);
4278
0
  return NS_OK;
4279
0
}
4280
4281
bool
4282
nsGlobalWindowOuter::SetWidgetFullscreen(FullscreenReason aReason, bool aIsFullscreen,
4283
                                         nsIWidget* aWidget, nsIScreen* aScreen)
4284
0
{
4285
0
  MOZ_ASSERT(this == GetTopInternal(), "Only topmost window should call this");
4286
0
  MOZ_ASSERT(!GetFrameElementInternal(), "Content window should not call this");
4287
0
  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
4288
0
4289
0
  if (!NS_WARN_IF(!IsChromeWindow())) {
4290
0
    if (!NS_WARN_IF(mChromeFields.mFullscreenPresShell)) {
4291
0
      if (nsIPresShell* shell = mDocShell->GetPresShell()) {
4292
0
        if (nsRefreshDriver* rd = shell->GetRefreshDriver()) {
4293
0
          mChromeFields.mFullscreenPresShell = do_GetWeakReference(shell);
4294
0
          MOZ_ASSERT(mChromeFields.mFullscreenPresShell);
4295
0
          rd->SetIsResizeSuppressed();
4296
0
          rd->Freeze();
4297
0
        }
4298
0
      }
4299
0
    }
4300
0
  }
4301
0
  nsresult rv = aReason == FullscreenReason::ForFullscreenMode ?
4302
0
    // If we enter fullscreen for fullscreen mode, we want
4303
0
    // the native system behavior.
4304
0
    aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen, aScreen) :
4305
0
    aWidget->MakeFullScreen(aIsFullscreen, aScreen);
4306
0
  return NS_SUCCEEDED(rv);
4307
0
}
4308
4309
/* virtual */ void
4310
nsGlobalWindowOuter::FullscreenWillChange(bool aIsFullscreen)
4311
0
{
4312
0
  if (aIsFullscreen) {
4313
0
    DispatchCustomEvent(NS_LITERAL_STRING("willenterfullscreen"));
4314
0
  } else {
4315
0
    DispatchCustomEvent(NS_LITERAL_STRING("willexitfullscreen"));
4316
0
  }
4317
0
}
4318
4319
/* virtual */ void
4320
nsGlobalWindowOuter::FinishFullscreenChange(bool aIsFullscreen)
4321
0
{
4322
0
  if (aIsFullscreen != mFullscreen) {
4323
0
    NS_WARNING("Failed to toggle fullscreen state of the widget");
4324
0
    // We failed to make the widget enter fullscreen.
4325
0
    // Stop further changes and restore the state.
4326
0
    if (!aIsFullscreen) {
4327
0
      mFullscreen = false;
4328
0
      mFullscreenMode = false;
4329
0
    } else {
4330
0
      MOZ_ASSERT_UNREACHABLE("Failed to exit fullscreen?");
4331
0
      mFullscreen = true;
4332
0
      // We don't know how code can reach here. Not sure
4333
0
      // what value should be set for fullscreen mode.
4334
0
      mFullscreenMode = false;
4335
0
    }
4336
0
    return;
4337
0
  }
4338
0
4339
0
  // Note that we must call this to toggle the DOM fullscreen state
4340
0
  // of the document before dispatching the "fullscreen" event, so
4341
0
  // that the chrome can distinguish between browser fullscreen mode
4342
0
  // and DOM fullscreen.
4343
0
  FinishDOMFullscreenChange(mDoc, mFullscreen);
4344
0
4345
0
  // dispatch a "fullscreen" DOM event so that XUL apps can
4346
0
  // respond visually if we are kicked into full screen mode
4347
0
  DispatchCustomEvent(NS_LITERAL_STRING("fullscreen"));
4348
0
4349
0
  if (!NS_WARN_IF(!IsChromeWindow())) {
4350
0
    if (nsCOMPtr<nsIPresShell> shell =
4351
0
        do_QueryReferent(mChromeFields.mFullscreenPresShell)) {
4352
0
      if (nsRefreshDriver* rd = shell->GetRefreshDriver()) {
4353
0
        rd->Thaw();
4354
0
      }
4355
0
      mChromeFields.mFullscreenPresShell = nullptr;
4356
0
    }
4357
0
  }
4358
0
4359
0
  if (!mWakeLock && mFullscreen) {
4360
0
    RefPtr<power::PowerManagerService> pmService =
4361
0
      power::PowerManagerService::GetInstance();
4362
0
    if (!pmService) {
4363
0
      return;
4364
0
    }
4365
0
4366
0
    // XXXkhuey using the inner here, do we need to do something if it changes?
4367
0
    ErrorResult rv;
4368
0
    mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"),
4369
0
                                       GetCurrentInnerWindow(), rv);
4370
0
    NS_WARNING_ASSERTION(!rv.Failed(), "Failed to lock the wakelock");
4371
0
    rv.SuppressException();
4372
0
  } else if (mWakeLock && !mFullscreen) {
4373
0
    ErrorResult rv;
4374
0
    mWakeLock->Unlock(rv);
4375
0
    mWakeLock = nullptr;
4376
0
    rv.SuppressException();
4377
0
  }
4378
0
}
4379
4380
bool
4381
nsGlobalWindowOuter::Fullscreen() const
4382
0
{
4383
0
  NS_ENSURE_TRUE(mDocShell, mFullscreen);
4384
0
4385
0
  // Get the fullscreen value of the root window, to always have the value
4386
0
  // accurate, even when called from content.
4387
0
  nsCOMPtr<nsIDocShellTreeItem> rootItem;
4388
0
  mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
4389
0
  if (rootItem == mDocShell) {
4390
0
    if (!XRE_IsContentProcess()) {
4391
0
      // We are the root window. Return our internal value.
4392
0
      return mFullscreen;
4393
0
    }
4394
0
    if (nsCOMPtr<nsIWidget> widget = GetNearestWidget()) {
4395
0
      // We are in content process, figure out the value from
4396
0
      // the sizemode of the puppet widget.
4397
0
      return widget->SizeMode() == nsSizeMode_Fullscreen;
4398
0
    }
4399
0
    return false;
4400
0
  }
4401
0
4402
0
  nsCOMPtr<nsPIDOMWindowOuter> window = rootItem->GetWindow();
4403
0
  NS_ENSURE_TRUE(window, mFullscreen);
4404
0
4405
0
  return nsGlobalWindowOuter::Cast(window)->Fullscreen();
4406
0
}
4407
4408
bool
4409
nsGlobalWindowOuter::GetFullscreenOuter()
4410
0
{
4411
0
  return Fullscreen();
4412
0
}
4413
4414
bool
4415
nsGlobalWindowOuter::GetFullScreen()
4416
0
{
4417
0
  FORWARD_TO_INNER(GetFullScreen, (), false);
4418
0
}
4419
4420
void
4421
nsGlobalWindowOuter::EnsureReflowFlushAndPaint()
4422
0
{
4423
0
  NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
4424
0
               "docshell!");
4425
0
4426
0
  if (!mDocShell)
4427
0
    return;
4428
0
4429
0
  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
4430
0
4431
0
  if (!presShell)
4432
0
    return;
4433
0
4434
0
  // Flush pending reflows.
4435
0
  if (mDoc) {
4436
0
    mDoc->FlushPendingNotifications(FlushType::Layout);
4437
0
  }
4438
0
4439
0
  // Unsuppress painting.
4440
0
  presShell->UnsuppressPainting();
4441
0
}
4442
4443
// static
4444
void
4445
nsGlobalWindowOuter::MakeScriptDialogTitle(nsAString& aOutTitle,
4446
                                           nsIPrincipal* aSubjectPrincipal)
4447
0
{
4448
0
  MOZ_ASSERT(aSubjectPrincipal);
4449
0
4450
0
  aOutTitle.Truncate();
4451
0
4452
0
  // Try to get a host from the running principal -- this will do the
4453
0
  // right thing for javascript: and data: documents.
4454
0
4455
0
  nsCOMPtr<nsIURI> uri;
4456
0
  nsresult rv = aSubjectPrincipal->GetURI(getter_AddRefs(uri));
4457
0
  // Note - The check for the current JSContext here isn't necessarily sensical.
4458
0
  // It's just designed to preserve existing behavior during a mass-conversion
4459
0
  // patch.
4460
0
  if (NS_SUCCEEDED(rv) && uri && nsContentUtils::GetCurrentJSContext()) {
4461
0
    // remove user:pass for privacy and spoof prevention
4462
0
4463
0
    nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
4464
0
    if (fixup) {
4465
0
      nsCOMPtr<nsIURI> fixedURI;
4466
0
      rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
4467
0
      if (NS_SUCCEEDED(rv) && fixedURI) {
4468
0
        nsAutoCString host;
4469
0
        fixedURI->GetHost(host);
4470
0
4471
0
        if (!host.IsEmpty()) {
4472
0
          // if this URI has a host we'll show it. For other
4473
0
          // schemes (e.g. file:) we fall back to the localized
4474
0
          // generic string
4475
0
4476
0
          nsAutoCString prepath;
4477
0
          fixedURI->GetDisplayPrePath(prepath);
4478
0
4479
0
          NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
4480
0
          const char16_t *formatStrings[] = { ucsPrePath.get() };
4481
0
          nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4482
0
                                                "ScriptDlgHeading",
4483
0
                                                formatStrings,
4484
0
                                                aOutTitle);
4485
0
        }
4486
0
      }
4487
0
    }
4488
0
  }
4489
0
4490
0
  if (aOutTitle.IsEmpty()) {
4491
0
    // We didn't find a host so use the generic heading
4492
0
    nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4493
0
                                       "ScriptDlgGenericHeading",
4494
0
                                       aOutTitle);
4495
0
  }
4496
0
4497
0
  // Just in case
4498
0
  if (aOutTitle.IsEmpty()) {
4499
0
    NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
4500
0
    aOutTitle.AssignLiteral("[Script]");
4501
0
  }
4502
0
}
4503
4504
bool
4505
nsGlobalWindowOuter::CanMoveResizeWindows(CallerType aCallerType)
4506
0
{
4507
0
  // When called from chrome, we can avoid the following checks.
4508
0
  if (aCallerType != CallerType::System) {
4509
0
    // Don't allow scripts to move or resize windows that were not opened by a
4510
0
    // script.
4511
0
    if (!mHadOriginalOpener) {
4512
0
      return false;
4513
0
    }
4514
0
4515
0
    if (!CanSetProperty("dom.disable_window_move_resize")) {
4516
0
      return false;
4517
0
    }
4518
0
4519
0
    // Ignore the request if we have more than one tab in the window.
4520
0
    if (XRE_IsContentProcess()) {
4521
0
      nsCOMPtr<nsIDocShell> docShell = GetDocShell();
4522
0
      if (docShell) {
4523
0
        nsCOMPtr<nsITabChild> child = docShell->GetTabChild();
4524
0
        bool hasSiblings = true;
4525
0
        if (child &&
4526
0
            NS_SUCCEEDED(child->GetHasSiblings(&hasSiblings)) &&
4527
0
            hasSiblings) {
4528
0
          return false;
4529
0
        }
4530
0
      }
4531
0
    } else {
4532
0
      nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
4533
0
      uint32_t itemCount = 0;
4534
0
      if (treeOwner && NS_SUCCEEDED(treeOwner->GetTabCount(&itemCount)) &&
4535
0
          itemCount > 1) {
4536
0
        return false;
4537
0
      }
4538
0
    }
4539
0
  }
4540
0
4541
0
  if (mDocShell) {
4542
0
    bool allow;
4543
0
    nsresult rv = mDocShell->GetAllowWindowControl(&allow);
4544
0
    if (NS_SUCCEEDED(rv) && !allow)
4545
0
      return false;
4546
0
  }
4547
0
4548
0
  if (nsGlobalWindowInner::sMouseDown && !nsGlobalWindowInner::sDragServiceDisabled) {
4549
0
    nsCOMPtr<nsIDragService> ds =
4550
0
      do_GetService("@mozilla.org/widget/dragservice;1");
4551
0
    if (ds) {
4552
0
      nsGlobalWindowInner::sDragServiceDisabled = true;
4553
0
      ds->Suppress();
4554
0
    }
4555
0
  }
4556
0
  return true;
4557
0
}
4558
4559
bool
4560
nsGlobalWindowOuter::AlertOrConfirm(bool aAlert,
4561
                                    const nsAString& aMessage,
4562
                                    nsIPrincipal& aSubjectPrincipal,
4563
                                    ErrorResult& aError)
4564
0
{
4565
0
  // XXX This method is very similar to nsGlobalWindowOuter::Prompt, make
4566
0
  // sure any modifications here don't need to happen over there!
4567
0
  if (!AreDialogsEnabled()) {
4568
0
    // Just silently return.  In the case of alert(), the return value is
4569
0
    // ignored.  In the case of confirm(), returning false is the same thing as
4570
0
    // would happen if the user cancels.
4571
0
    return false;
4572
0
  }
4573
0
4574
0
  // Reset popup state while opening a modal dialog, and firing events
4575
0
  // about the dialog, to prevent the current state from being active
4576
0
  // the whole time a modal dialog is open.
4577
0
  nsAutoPopupStatePusher popupStatePusher(openAbused, true);
4578
0
4579
0
  // Before bringing up the window, unsuppress painting and flush
4580
0
  // pending reflows.
4581
0
  EnsureReflowFlushAndPaint();
4582
0
4583
0
  nsAutoString title;
4584
0
  MakeScriptDialogTitle(title, &aSubjectPrincipal);
4585
0
4586
0
  // Remove non-terminating null characters from the
4587
0
  // string. See bug #310037.
4588
0
  nsAutoString final;
4589
0
  nsContentUtils::StripNullChars(aMessage, final);
4590
0
4591
0
  nsresult rv;
4592
0
  nsCOMPtr<nsIPromptFactory> promptFac =
4593
0
    do_GetService("@mozilla.org/prompter;1", &rv);
4594
0
  if (NS_FAILED(rv)) {
4595
0
    aError.Throw(rv);
4596
0
    return false;
4597
0
  }
4598
0
4599
0
  nsCOMPtr<nsIPrompt> prompt;
4600
0
  aError = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4601
0
                                getter_AddRefs(prompt));
4602
0
  if (aError.Failed()) {
4603
0
    return false;
4604
0
  }
4605
0
4606
0
  // Always allow tab modal prompts for alert and confirm.
4607
0
  if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4608
0
    promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
4609
0
  }
4610
0
4611
0
  bool result = false;
4612
0
  nsAutoSyncOperation sync(mDoc);
4613
0
  if (ShouldPromptToBlockDialogs()) {
4614
0
    bool disallowDialog = false;
4615
0
    nsAutoString label;
4616
0
    nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4617
0
                                       "ScriptDialogLabel", label);
4618
0
4619
0
    aError = aAlert ?
4620
0
               prompt->AlertCheck(title.get(), final.get(), label.get(),
4621
0
                                  &disallowDialog) :
4622
0
               prompt->ConfirmCheck(title.get(), final.get(), label.get(),
4623
0
                                    &disallowDialog, &result);
4624
0
4625
0
    if (disallowDialog)
4626
0
      DisableDialogs();
4627
0
  } else {
4628
0
    aError = aAlert ?
4629
0
               prompt->Alert(title.get(), final.get()) :
4630
0
               prompt->Confirm(title.get(), final.get(), &result);
4631
0
  }
4632
0
4633
0
  return result;
4634
0
}
4635
4636
void
4637
nsGlobalWindowOuter::AlertOuter(const nsAString& aMessage,
4638
                                nsIPrincipal& aSubjectPrincipal,
4639
                                ErrorResult& aError)
4640
0
{
4641
0
  AlertOrConfirm(/* aAlert = */ true, aMessage, aSubjectPrincipal, aError);
4642
0
}
4643
4644
bool
4645
nsGlobalWindowOuter::ConfirmOuter(const nsAString& aMessage,
4646
                                  nsIPrincipal& aSubjectPrincipal,
4647
                                  ErrorResult& aError)
4648
0
{
4649
0
  return AlertOrConfirm(/* aAlert = */ false, aMessage, aSubjectPrincipal,
4650
0
                        aError);
4651
0
}
4652
4653
void
4654
nsGlobalWindowOuter::PromptOuter(const nsAString& aMessage,
4655
                                 const nsAString& aInitial,
4656
                                 nsAString& aReturn,
4657
                                 nsIPrincipal& aSubjectPrincipal,
4658
                                 ErrorResult& aError)
4659
0
{
4660
0
  // XXX This method is very similar to nsGlobalWindowOuter::AlertOrConfirm, make
4661
0
  // sure any modifications here don't need to happen over there!
4662
0
  SetDOMStringToNull(aReturn);
4663
0
4664
0
  if (!AreDialogsEnabled()) {
4665
0
    // Return null, as if the user just canceled the prompt.
4666
0
    return;
4667
0
  }
4668
0
4669
0
  // Reset popup state while opening a modal dialog, and firing events
4670
0
  // about the dialog, to prevent the current state from being active
4671
0
  // the whole time a modal dialog is open.
4672
0
  nsAutoPopupStatePusher popupStatePusher(openAbused, true);
4673
0
4674
0
  // Before bringing up the window, unsuppress painting and flush
4675
0
  // pending reflows.
4676
0
  EnsureReflowFlushAndPaint();
4677
0
4678
0
  nsAutoString title;
4679
0
  MakeScriptDialogTitle(title, &aSubjectPrincipal);
4680
0
4681
0
  // Remove non-terminating null characters from the
4682
0
  // string. See bug #310037.
4683
0
  nsAutoString fixedMessage, fixedInitial;
4684
0
  nsContentUtils::StripNullChars(aMessage, fixedMessage);
4685
0
  nsContentUtils::StripNullChars(aInitial, fixedInitial);
4686
0
4687
0
  nsresult rv;
4688
0
  nsCOMPtr<nsIPromptFactory> promptFac =
4689
0
    do_GetService("@mozilla.org/prompter;1", &rv);
4690
0
  if (NS_FAILED(rv)) {
4691
0
    aError.Throw(rv);
4692
0
    return;
4693
0
  }
4694
0
4695
0
  nsCOMPtr<nsIPrompt> prompt;
4696
0
  aError = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4697
0
                                getter_AddRefs(prompt));
4698
0
  if (aError.Failed()) {
4699
0
    return;
4700
0
  }
4701
0
4702
0
  // Always allow tab modal prompts for prompt.
4703
0
  if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4704
0
    promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
4705
0
  }
4706
0
4707
0
  // Pass in the default value, if any.
4708
0
  char16_t *inoutValue = ToNewUnicode(fixedInitial);
4709
0
  bool disallowDialog = false;
4710
0
4711
0
  nsAutoString label;
4712
0
  label.SetIsVoid(true);
4713
0
  if (ShouldPromptToBlockDialogs()) {
4714
0
    nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4715
0
                                       "ScriptDialogLabel", label);
4716
0
  }
4717
0
4718
0
  nsAutoSyncOperation sync(mDoc);
4719
0
  bool ok;
4720
0
  aError = prompt->Prompt(title.get(), fixedMessage.get(), &inoutValue,
4721
0
                          label.IsVoid() ? nullptr : label.get(),
4722
0
                          &disallowDialog, &ok);
4723
0
4724
0
  if (disallowDialog) {
4725
0
    DisableDialogs();
4726
0
  }
4727
0
4728
0
  if (aError.Failed()) {
4729
0
    return;
4730
0
  }
4731
0
4732
0
  nsString outValue;
4733
0
  outValue.Adopt(inoutValue);
4734
0
4735
0
  if (ok && inoutValue) {
4736
0
    aReturn.Assign(outValue);
4737
0
  }
4738
0
}
4739
4740
void
4741
nsGlobalWindowOuter::FocusOuter(ErrorResult& aError)
4742
0
{
4743
0
  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4744
0
  if (!fm) {
4745
0
    return;
4746
0
  }
4747
0
4748
0
  nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
4749
0
4750
0
  bool isVisible = false;
4751
0
  if (baseWin) {
4752
0
    baseWin->GetVisibility(&isVisible);
4753
0
  }
4754
0
4755
0
  if (!isVisible) {
4756
0
    // A hidden tab is being focused, ignore this call.
4757
0
    return;
4758
0
  }
4759
0
4760
0
  nsCOMPtr<nsPIDOMWindowInner> caller = do_QueryInterface(GetEntryGlobal());
4761
0
  nsPIDOMWindowOuter* callerOuter = caller ? caller->GetOuterWindow() : nullptr;
4762
0
  nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpener();
4763
0
4764
0
  // Enforce dom.disable_window_flip (for non-chrome), but still allow the
4765
0
  // window which opened us to raise us at times when popups are allowed
4766
0
  // (bugs 355482 and 369306).
4767
0
  bool canFocus = CanSetProperty("dom.disable_window_flip") ||
4768
0
                    (opener == callerOuter &&
4769
0
                     RevisePopupAbuseLevel(GetPopupControlState()) < openBlocked);
4770
0
4771
0
  nsCOMPtr<mozIDOMWindowProxy> activeDOMWindow;
4772
0
  fm->GetActiveWindow(getter_AddRefs(activeDOMWindow));
4773
0
4774
0
  nsCOMPtr<nsIDocShellTreeItem> rootItem;
4775
0
  mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
4776
0
  nsCOMPtr<nsPIDOMWindowOuter> rootWin = rootItem ? rootItem->GetWindow() : nullptr;
4777
0
  auto* activeWindow = nsPIDOMWindowOuter::From(activeDOMWindow);
4778
0
  bool isActive = (rootWin == activeWindow);
4779
0
4780
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4781
0
  if (treeOwnerAsWin && (canFocus || isActive)) {
4782
0
    bool isEnabled = true;
4783
0
    if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
4784
0
      NS_WARNING( "Should not try to set the focus on a disabled window" );
4785
0
      return;
4786
0
    }
4787
0
4788
0
    // XXXndeakin not sure what this is for or if it should go somewhere else
4789
0
    nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
4790
0
    if (embeddingWin)
4791
0
      embeddingWin->SetFocus();
4792
0
  }
4793
0
4794
0
  if (!mDocShell) {
4795
0
    return;
4796
0
  }
4797
0
4798
0
  nsCOMPtr<nsIPresShell> presShell;
4799
0
  // Don't look for a presshell if we're a root chrome window that's got
4800
0
  // about:blank loaded.  We don't want to focus our widget in that case.
4801
0
  // XXXbz should we really be checking for IsInitialDocument() instead?
4802
0
  bool lookForPresShell = true;
4803
0
  if (mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome &&
4804
0
      GetPrivateRoot() == this && mDoc) {
4805
0
    nsIURI* ourURI = mDoc->GetDocumentURI();
4806
0
    if (ourURI) {
4807
0
      lookForPresShell = !NS_IsAboutBlank(ourURI);
4808
0
    }
4809
0
  }
4810
0
4811
0
  if (lookForPresShell) {
4812
0
    mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
4813
0
  }
4814
0
4815
0
  nsCOMPtr<nsIDocShellTreeItem> parentDsti;
4816
0
  mDocShell->GetParent(getter_AddRefs(parentDsti));
4817
0
4818
0
  // set the parent's current focus to the frame containing this window.
4819
0
  nsCOMPtr<nsPIDOMWindowOuter> parent =
4820
0
    parentDsti ? parentDsti->GetWindow() : nullptr;
4821
0
  if (parent) {
4822
0
    nsCOMPtr<nsIDocument> parentdoc = parent->GetDoc();
4823
0
    if (!parentdoc) {
4824
0
      return;
4825
0
    }
4826
0
4827
0
    RefPtr<Element> frame = parentdoc->FindContentForSubDocument(mDoc);
4828
0
    if (frame) {
4829
0
      uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
4830
0
      if (canFocus)
4831
0
        flags |= nsIFocusManager::FLAG_RAISE;
4832
0
      aError = fm->SetFocus(frame, flags);
4833
0
    }
4834
0
    return;
4835
0
  }
4836
0
4837
0
  if (canFocus) {
4838
0
    // if there is no parent, this must be a toplevel window, so raise the
4839
0
    // window if canFocus is true. If this is a child process, the raise
4840
0
    // window request will get forwarded to the parent by the puppet widget.
4841
0
    aError = fm->SetActiveWindow(this);
4842
0
  }
4843
0
}
4844
4845
nsresult
4846
nsGlobalWindowOuter::Focus()
4847
0
{
4848
0
  FORWARD_TO_INNER(Focus, (), NS_ERROR_UNEXPECTED);
4849
0
}
4850
4851
void
4852
nsGlobalWindowOuter::BlurOuter()
4853
0
{
4854
0
  // If dom.disable_window_flip == true, then content should not be allowed
4855
0
  // to call this function (this would allow popunders, bug 369306)
4856
0
  if (!CanSetProperty("dom.disable_window_flip")) {
4857
0
    return;
4858
0
  }
4859
0
4860
0
  // If embedding apps don't implement nsIEmbeddingSiteWindow, we
4861
0
  // shouldn't throw exceptions to web content.
4862
0
4863
0
  nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
4864
0
  nsCOMPtr<nsIEmbeddingSiteWindow> siteWindow(do_GetInterface(treeOwner));
4865
0
  if (siteWindow) {
4866
0
    // This method call may cause mDocShell to become nullptr.
4867
0
    siteWindow->Blur();
4868
0
4869
0
    // if the root is focused, clear the focus
4870
0
    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4871
0
    if (fm && mDoc) {
4872
0
      RefPtr<Element> element;
4873
0
      fm->GetFocusedElementForWindow(this, false, nullptr, getter_AddRefs(element));
4874
0
      if (element == mDoc->GetRootElement()) {
4875
0
        fm->ClearFocus(this);
4876
0
      }
4877
0
    }
4878
0
  }
4879
0
}
4880
4881
void
4882
nsGlobalWindowOuter::StopOuter(ErrorResult& aError)
4883
0
{
4884
0
  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4885
0
  if (webNav) {
4886
0
    aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
4887
0
  }
4888
0
}
4889
4890
void
4891
nsGlobalWindowOuter::PrintOuter(ErrorResult& aError)
4892
0
{
4893
0
#ifdef NS_PRINTING
4894
0
  if (!AreDialogsEnabled()) {
4895
0
    // We probably want to keep throwing here; silently doing nothing is a bit
4896
0
    // weird given the typical use cases of print().
4897
0
    aError.Throw(NS_ERROR_NOT_AVAILABLE);
4898
0
    return;
4899
0
  }
4900
0
4901
0
  if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
4902
0
    aError.Throw(NS_ERROR_NOT_AVAILABLE);
4903
0
    return;
4904
0
  }
4905
0
4906
0
  nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
4907
0
  if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
4908
0
                                getter_AddRefs(webBrowserPrint)))) {
4909
0
    nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ?
4910
0
                               GetCurrentInnerWindowInternal()->mDoc.get() :
4911
0
                               nullptr);
4912
0
4913
0
    nsCOMPtr<nsIPrintSettingsService> printSettingsService =
4914
0
      do_GetService("@mozilla.org/gfx/printsettings-service;1");
4915
0
4916
0
    nsCOMPtr<nsIPrintSettings> printSettings;
4917
0
    if (printSettingsService) {
4918
0
      bool printSettingsAreGlobal =
4919
0
        Preferences::GetBool("print.use_global_printsettings", false);
4920
0
4921
0
      if (printSettingsAreGlobal) {
4922
0
        printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
4923
0
4924
0
        nsAutoString printerName;
4925
0
        printSettings->GetPrinterName(printerName);
4926
0
4927
0
        bool shouldGetDefaultPrinterName = printerName.IsEmpty();
4928
0
#ifdef MOZ_X11
4929
0
        // In Linux, GTK backend does not support per printer settings.
4930
0
        // Calling GetDefaultPrinterName causes a sandbox violation (see Bug 1329216).
4931
0
        // The printer name is not needed anywhere else on Linux before it gets to the parent.
4932
0
        // In the parent, we will then query the default printer name if no name is set.
4933
0
        // Unless we are in the parent, we will skip this part.
4934
0
        if (!XRE_IsParentProcess()) {
4935
0
          shouldGetDefaultPrinterName = false;
4936
0
        }
4937
0
#endif
4938
0
        if (shouldGetDefaultPrinterName) {
4939
0
          printSettingsService->GetDefaultPrinterName(printerName);
4940
0
          printSettings->SetPrinterName(printerName);
4941
0
        }
4942
0
        printSettingsService->InitPrintSettingsFromPrinter(printerName,
4943
0
                                                           printSettings);
4944
0
        printSettingsService->InitPrintSettingsFromPrefs(printSettings,
4945
0
                                                         true,
4946
0
                                                         nsIPrintSettings::kInitSaveAll);
4947
0
      } else {
4948
0
        printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
4949
0
      }
4950
0
4951
0
      EnterModalState();
4952
0
      webBrowserPrint->Print(printSettings, nullptr);
4953
0
      LeaveModalState();
4954
0
4955
0
      bool savePrintSettings =
4956
0
        Preferences::GetBool("print.save_print_settings", false);
4957
0
      if (printSettingsAreGlobal && savePrintSettings) {
4958
0
        printSettingsService->
4959
0
          SavePrintSettingsToPrefs(printSettings,
4960
0
                                   true,
4961
0
                                   nsIPrintSettings::kInitSaveAll);
4962
0
        printSettingsService->
4963
0
          SavePrintSettingsToPrefs(printSettings,
4964
0
                                   false,
4965
0
                                   nsIPrintSettings::kInitSavePrinterName);
4966
0
      }
4967
0
    } else {
4968
0
      webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
4969
0
      webBrowserPrint->Print(printSettings, nullptr);
4970
0
    }
4971
0
  }
4972
0
#endif //NS_PRINTING
4973
0
}
4974
4975
void
4976
nsGlobalWindowOuter::MoveToOuter(int32_t aXPos, int32_t aYPos,
4977
                                 CallerType aCallerType, ErrorResult& aError)
4978
0
{
4979
0
  /*
4980
0
   * If caller is not chrome and the user has not explicitly exempted the site,
4981
0
   * prevent window.moveTo() by exiting early
4982
0
   */
4983
0
4984
0
  if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
4985
0
    return;
4986
0
  }
4987
0
4988
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4989
0
  if (!treeOwnerAsWin) {
4990
0
    aError.Throw(NS_ERROR_FAILURE);
4991
0
    return;
4992
0
  }
4993
0
4994
0
  nsCOMPtr<nsIScreenManager> screenMgr =
4995
0
    do_GetService("@mozilla.org/gfx/screenmanager;1");
4996
0
  nsCOMPtr<nsIScreen> screen;
4997
0
  if (screenMgr) {
4998
0
    CSSIntSize size;
4999
0
    GetInnerSize(size);
5000
0
    screenMgr->ScreenForRect(aXPos, aYPos, size.width, size.height,
5001
0
                             getter_AddRefs(screen));
5002
0
  }
5003
0
5004
0
  if (screen) {
5005
0
    // On secondary displays, the "CSS px" coordinates are offset so that they
5006
0
    // share their origin with global desktop pixels, to avoid ambiguities in
5007
0
    // the coordinate space when there are displays with different DPIs.
5008
0
    // (See the corresponding code in GetScreenXY() above.)
5009
0
    int32_t screenLeftDeskPx, screenTopDeskPx, w, h;
5010
0
    screen->GetRectDisplayPix(&screenLeftDeskPx, &screenTopDeskPx, &w, &h);
5011
0
    CSSIntPoint cssPos(aXPos - screenLeftDeskPx, aYPos - screenTopDeskPx);
5012
0
    CheckSecurityLeftAndTop(&cssPos.x, &cssPos.y, aCallerType);
5013
0
5014
0
    double scale;
5015
0
    screen->GetDefaultCSSScaleFactor(&scale);
5016
0
    LayoutDevicePoint devPos = cssPos * CSSToLayoutDeviceScale(scale);
5017
0
5018
0
    screen->GetContentsScaleFactor(&scale);
5019
0
    DesktopPoint deskPos = devPos / DesktopToLayoutDeviceScale(scale);
5020
0
    aError = treeOwnerAsWin->SetPositionDesktopPix(screenLeftDeskPx + deskPos.x,
5021
0
                                                   screenTopDeskPx + deskPos.y);
5022
0
  } else {
5023
0
    // We couldn't find a screen? Just assume a 1:1 mapping.
5024
0
    CSSIntPoint cssPos(aXPos, aXPos);
5025
0
    CheckSecurityLeftAndTop(&cssPos.x, &cssPos.y, aCallerType);
5026
0
    LayoutDevicePoint devPos = cssPos * CSSToLayoutDeviceScale(1.0);
5027
0
    aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y);
5028
0
  }
5029
0
5030
0
  CheckForDPIChange();
5031
0
}
5032
5033
void
5034
nsGlobalWindowOuter::MoveByOuter(int32_t aXDif, int32_t aYDif,
5035
                                 CallerType aCallerType, ErrorResult& aError)
5036
0
{
5037
0
  /*
5038
0
   * If caller is not chrome and the user has not explicitly exempted the site,
5039
0
   * prevent window.moveBy() by exiting early
5040
0
   */
5041
0
5042
0
  if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
5043
0
    return;
5044
0
  }
5045
0
5046
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5047
0
  if (!treeOwnerAsWin) {
5048
0
    aError.Throw(NS_ERROR_FAILURE);
5049
0
    return;
5050
0
  }
5051
0
5052
0
  // To do this correctly we have to convert what we get from GetPosition
5053
0
  // into CSS pixels, add the arguments, do the security check, and
5054
0
  // then convert back to device pixels for the call to SetPosition.
5055
0
5056
0
  int32_t x, y;
5057
0
  aError = treeOwnerAsWin->GetPosition(&x, &y);
5058
0
  if (aError.Failed()) {
5059
0
    return;
5060
0
  }
5061
0
5062
0
  // mild abuse of a "size" object so we don't need more helper functions
5063
0
  nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
5064
0
5065
0
  cssPos.width += aXDif;
5066
0
  cssPos.height += aYDif;
5067
0
5068
0
  CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height, aCallerType);
5069
0
5070
0
  nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
5071
0
5072
0
  aError = treeOwnerAsWin->SetPosition(newDevPos.width, newDevPos.height);
5073
0
5074
0
  CheckForDPIChange();
5075
0
}
5076
5077
nsresult
5078
nsGlobalWindowOuter::MoveBy(int32_t aXDif, int32_t aYDif)
5079
0
{
5080
0
  ErrorResult rv;
5081
0
  MoveByOuter(aXDif, aYDif, CallerType::System, rv);
5082
0
5083
0
  return rv.StealNSResult();
5084
0
}
5085
5086
void
5087
nsGlobalWindowOuter::ResizeToOuter(int32_t aWidth, int32_t aHeight,
5088
                                   CallerType aCallerType,
5089
                                   ErrorResult& aError)
5090
0
{
5091
0
  /*
5092
0
   * If caller is a browser-element then dispatch a resize event to
5093
0
   * the embedder.
5094
0
   */
5095
0
  if (mDocShell && mDocShell->GetIsMozBrowser()) {
5096
0
    CSSIntSize size(aWidth, aHeight);
5097
0
    if (!DispatchResizeEvent(size)) {
5098
0
      // The embedder chose to prevent the default action for this
5099
0
      // event, so let's not resize this window after all...
5100
0
      return;
5101
0
    }
5102
0
  }
5103
0
5104
0
  /*
5105
0
   * If caller is not chrome and the user has not explicitly exempted the site,
5106
0
   * prevent window.resizeTo() by exiting early
5107
0
   */
5108
0
5109
0
  if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
5110
0
    return;
5111
0
  }
5112
0
5113
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5114
0
  if (!treeOwnerAsWin) {
5115
0
    aError.Throw(NS_ERROR_FAILURE);
5116
0
    return;
5117
0
  }
5118
0
5119
0
  nsIntSize cssSize(aWidth, aHeight);
5120
0
  CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5121
0
5122
0
  nsIntSize devSz(CSSToDevIntPixels(cssSize));
5123
0
5124
0
  aError = treeOwnerAsWin->SetSize(devSz.width, devSz.height, true);
5125
0
5126
0
  CheckForDPIChange();
5127
0
}
5128
5129
void
5130
nsGlobalWindowOuter::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
5131
                                   CallerType aCallerType, ErrorResult& aError)
5132
0
{
5133
0
  /*
5134
0
   * If caller is a browser-element then dispatch a resize event to
5135
0
   * parent.
5136
0
   */
5137
0
  if (mDocShell && mDocShell->GetIsMozBrowser()) {
5138
0
    CSSIntSize size;
5139
0
    if (NS_FAILED(GetInnerSize(size))) {
5140
0
      return;
5141
0
    }
5142
0
5143
0
    size.width += aWidthDif;
5144
0
    size.height += aHeightDif;
5145
0
5146
0
    if (!DispatchResizeEvent(size)) {
5147
0
      // The embedder chose to prevent the default action for this
5148
0
      // event, so let's not resize this window after all...
5149
0
      return;
5150
0
    }
5151
0
  }
5152
0
5153
0
  /*
5154
0
   * If caller is not chrome and the user has not explicitly exempted the site,
5155
0
   * prevent window.resizeBy() by exiting early
5156
0
   */
5157
0
5158
0
  if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
5159
0
    return;
5160
0
  }
5161
0
5162
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5163
0
  if (!treeOwnerAsWin) {
5164
0
    aError.Throw(NS_ERROR_FAILURE);
5165
0
    return;
5166
0
  }
5167
0
5168
0
  int32_t width, height;
5169
0
  aError = treeOwnerAsWin->GetSize(&width, &height);
5170
0
  if (aError.Failed()) {
5171
0
    return;
5172
0
  }
5173
0
5174
0
  // To do this correctly we have to convert what we got from GetSize
5175
0
  // into CSS pixels, add the arguments, do the security check, and
5176
0
  // then convert back to device pixels for the call to SetSize.
5177
0
5178
0
  nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
5179
0
5180
0
  cssSize.width += aWidthDif;
5181
0
  cssSize.height += aHeightDif;
5182
0
5183
0
  CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5184
0
5185
0
  nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
5186
0
5187
0
  aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
5188
0
5189
0
  CheckForDPIChange();
5190
0
}
5191
5192
void
5193
nsGlobalWindowOuter::SizeToContentOuter(CallerType aCallerType, ErrorResult& aError)
5194
0
{
5195
0
  if (!mDocShell) {
5196
0
    return;
5197
0
  }
5198
0
5199
0
  /*
5200
0
   * If caller is not chrome and the user has not explicitly exempted the site,
5201
0
   * prevent window.sizeToContent() by exiting early
5202
0
   */
5203
0
5204
0
  if (!CanMoveResizeWindows(aCallerType) || IsFrame()) {
5205
0
    return;
5206
0
  }
5207
0
5208
0
  // The content viewer does a check to make sure that it's a content
5209
0
  // viewer for a toplevel docshell.
5210
0
  nsCOMPtr<nsIContentViewer> cv;
5211
0
  mDocShell->GetContentViewer(getter_AddRefs(cv));
5212
0
  if (!cv) {
5213
0
    aError.Throw(NS_ERROR_FAILURE);
5214
0
    return;
5215
0
  }
5216
0
5217
0
  int32_t width, height;
5218
0
  aError = cv->GetContentSize(&width, &height);
5219
0
  if (aError.Failed()) {
5220
0
    return;
5221
0
  }
5222
0
5223
0
  // Make sure the new size is following the CheckSecurityWidthAndHeight
5224
0
  // rules.
5225
0
  nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
5226
0
  if (!treeOwner) {
5227
0
    aError.Throw(NS_ERROR_FAILURE);
5228
0
    return;
5229
0
  }
5230
0
5231
0
  nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
5232
0
  CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5233
0
5234
0
  nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
5235
0
5236
0
  aError = treeOwner->SizeShellTo(mDocShell, newDevSize.width,
5237
0
                                  newDevSize.height);
5238
0
}
5239
5240
already_AddRefed<nsPIWindowRoot>
5241
nsGlobalWindowOuter::GetTopWindowRoot()
5242
0
{
5243
0
  nsPIDOMWindowOuter* piWin = GetPrivateRoot();
5244
0
  if (!piWin) {
5245
0
    return nullptr;
5246
0
  }
5247
0
5248
0
  nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
5249
0
  return window.forget();
5250
0
}
5251
5252
void
5253
nsGlobalWindowOuter::FirePopupBlockedEvent(nsIDocument* aDoc,
5254
                                           nsIURI* aPopupURI,
5255
                                           const nsAString& aPopupWindowName,
5256
                                           const nsAString& aPopupWindowFeatures)
5257
0
{
5258
0
  MOZ_ASSERT(aDoc);
5259
0
5260
0
  // Fire a "DOMPopupBlocked" event so that the UI can hear about
5261
0
  // blocked popups.
5262
0
  PopupBlockedEventInit init;
5263
0
  init.mBubbles = true;
5264
0
  init.mCancelable = true;
5265
0
  // XXX: This is a different object, but webidl requires an inner window here
5266
0
  // now.
5267
0
  init.mRequestingWindow = GetCurrentInnerWindowInternal();
5268
0
  init.mPopupWindowURI = aPopupURI;
5269
0
  init.mPopupWindowName = aPopupWindowName;
5270
0
  init.mPopupWindowFeatures = aPopupWindowFeatures;
5271
0
5272
0
  RefPtr<PopupBlockedEvent> event =
5273
0
    PopupBlockedEvent::Constructor(aDoc,
5274
0
                                   NS_LITERAL_STRING("DOMPopupBlocked"),
5275
0
                                   init);
5276
0
5277
0
  event->SetTrusted(true);
5278
0
5279
0
  aDoc->DispatchEvent(*event);
5280
0
}
5281
5282
void
5283
nsGlobalWindowOuter::NotifyContentBlockingState(unsigned aState,
5284
                                                nsIChannel* aChannel)
5285
0
{
5286
0
  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
5287
0
  if (!docShell) {
5288
0
    return;
5289
0
  }
5290
0
  nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
5291
0
  NS_ENSURE_TRUE_VOID(doc);
5292
0
5293
0
  // This event might come after the user has navigated to another page.
5294
0
  // To prevent showing the TrackingProtection UI on the wrong page, we need to
5295
0
  // check that the loading URI for the channel is the same as the URI currently
5296
0
  // loaded in the document.
5297
0
  if (!SameLoadingURI(doc, aChannel)) {
5298
0
    return;
5299
0
  }
5300
0
5301
0
  // Notify nsIWebProgressListeners of this security event.
5302
0
  // Can be used to change the UI state.
5303
0
  nsresult rv = NS_OK;
5304
0
  nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
5305
0
  NS_ENSURE_SUCCESS_VOID(rv);
5306
0
  uint32_t state = 0;
5307
0
  nsCOMPtr<nsISecureBrowserUI> securityUI;
5308
0
  docShell->GetSecurityUI(getter_AddRefs(securityUI));
5309
0
  if (!securityUI) {
5310
0
    return;
5311
0
  }
5312
0
  securityUI->GetState(&state);
5313
0
  if (aState == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
5314
0
    doc->SetHasTrackingContentBlocked(true);
5315
0
  } else if (aState == nsIWebProgressListener::STATE_BLOCKED_SLOW_TRACKING_CONTENT) {
5316
0
    doc->SetHasSlowTrackingContentBlocked(true);
5317
0
  } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION) {
5318
0
    doc->SetHasCookiesBlockedByPermission(true);
5319
0
  } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER) {
5320
0
    doc->SetHasTrackingCookiesBlocked(true);
5321
0
  } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL) {
5322
0
    doc->SetHasAllCookiesBlocked(true);
5323
0
  } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) {
5324
0
    doc->SetHasForeignCookiesBlocked(true);
5325
0
  } else {
5326
0
    // Ignore nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
5327
0
  }
5328
0
  state |= aState;
5329
0
5330
0
  eventSink->OnSecurityChange(aChannel, state);
5331
0
}
5332
5333
//static
5334
bool
5335
nsGlobalWindowOuter::SameLoadingURI(nsIDocument *aDoc, nsIChannel *aChannel)
5336
0
{
5337
0
  nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
5338
0
  nsCOMPtr<nsILoadInfo> channelLoadInfo = aChannel->GetLoadInfo();
5339
0
  if (!channelLoadInfo || !docURI) {
5340
0
    return false;
5341
0
  }
5342
0
5343
0
  nsCOMPtr<nsIPrincipal> channelLoadingPrincipal = channelLoadInfo->LoadingPrincipal();
5344
0
  if (!channelLoadingPrincipal) {
5345
0
    // TYPE_DOCUMENT loads will not have a channelLoadingPrincipal. But top level
5346
0
    // loads should not be blocked by Tracking Protection, so we will return
5347
0
    // false
5348
0
    return false;
5349
0
  }
5350
0
  nsCOMPtr<nsIURI> channelLoadingURI;
5351
0
  channelLoadingPrincipal->GetURI(getter_AddRefs(channelLoadingURI));
5352
0
  if (!channelLoadingURI) {
5353
0
    return false;
5354
0
  }
5355
0
  bool equals = false;
5356
0
  nsresult rv = docURI->EqualsExceptRef(channelLoadingURI, &equals);
5357
0
  return NS_SUCCEEDED(rv) && equals;
5358
0
}
5359
5360
// static
5361
bool
5362
nsGlobalWindowOuter::CanSetProperty(const char *aPrefName)
5363
0
{
5364
0
  // Chrome can set any property.
5365
0
  if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
5366
0
    return true;
5367
0
  }
5368
0
5369
0
  // If the pref is set to true, we can not set the property
5370
0
  // and vice versa.
5371
0
  return !Preferences::GetBool(aPrefName, true);
5372
0
}
5373
5374
bool
5375
nsGlobalWindowOuter::PopupWhitelisted()
5376
0
{
5377
0
  if (mDoc && nsContentUtils::CanShowPopup(mDoc->NodePrincipal()))
5378
0
  {
5379
0
    return true;
5380
0
  }
5381
0
5382
0
  nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
5383
0
  if (parent == this)
5384
0
  {
5385
0
    return false;
5386
0
  }
5387
0
5388
0
  return nsGlobalWindowOuter::Cast(parent)->PopupWhitelisted();
5389
0
}
5390
5391
/*
5392
 * Examine the current document state to see if we're in a way that is
5393
 * typically abused by web designers. The window.open code uses this
5394
 * routine to determine whether to allow the new window.
5395
 * Returns a value from the PopupControlState enum.
5396
 */
5397
PopupControlState
5398
nsGlobalWindowOuter::RevisePopupAbuseLevel(PopupControlState aControl)
5399
0
{
5400
0
  NS_ASSERTION(mDocShell, "Must have docshell");
5401
0
5402
0
  if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
5403
0
    return openAllowed;
5404
0
  }
5405
0
5406
0
  PopupControlState abuse = aControl;
5407
0
  switch (abuse) {
5408
0
  case openControlled:
5409
0
  case openBlocked:
5410
0
  case openOverridden:
5411
0
    if (PopupWhitelisted())
5412
0
      abuse = PopupControlState(abuse - 1);
5413
0
    break;
5414
0
  case openAbused:
5415
0
    if (PopupWhitelisted())
5416
0
      //Skip openBlocked
5417
0
      abuse = openControlled;
5418
0
    break;
5419
0
  case openAllowed: break;
5420
0
  default:
5421
0
    NS_WARNING("Strange PopupControlState!");
5422
0
  }
5423
0
5424
0
  // limit the number of simultaneously open popups
5425
0
  if (abuse == openAbused ||
5426
0
      abuse == openBlocked ||
5427
0
      abuse == openControlled) {
5428
0
    int32_t popupMax = Preferences::GetInt("dom.popup_maximum", -1);
5429
0
    if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
5430
0
      abuse = openOverridden;
5431
0
  }
5432
0
5433
0
  return abuse;
5434
0
}
5435
5436
/* If a window open is blocked, fire the appropriate DOM events. */
5437
void
5438
nsGlobalWindowOuter::FireAbuseEvents(const nsAString &aPopupURL,
5439
                                     const nsAString &aPopupWindowName,
5440
                                     const nsAString &aPopupWindowFeatures)
5441
0
{
5442
0
  // fetch the URI of the window requesting the opened window
5443
0
5444
0
  nsCOMPtr<nsPIDOMWindowOuter> window = GetTop();
5445
0
  if (!window) {
5446
0
    return;
5447
0
  }
5448
0
5449
0
  nsCOMPtr<nsIDocument> topDoc = window->GetDoc();
5450
0
  nsCOMPtr<nsIURI> popupURI;
5451
0
5452
0
  // build the URI of the would-have-been popup window
5453
0
  // (see nsWindowWatcher::URIfromURL)
5454
0
5455
0
  // first, fetch the opener's base URI
5456
0
5457
0
  nsIURI *baseURL = nullptr;
5458
0
5459
0
  nsCOMPtr<nsIDocument> doc = GetEntryDocument();
5460
0
  if (doc)
5461
0
    baseURL = doc->GetDocBaseURI();
5462
0
5463
0
  // use the base URI to build what would have been the popup's URI
5464
0
  nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
5465
0
  if (ios)
5466
0
    ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), nullptr, baseURL,
5467
0
                getter_AddRefs(popupURI));
5468
0
5469
0
  // fire an event chock full of informative URIs
5470
0
  FirePopupBlockedEvent(topDoc, popupURI, aPopupWindowName,
5471
0
                        aPopupWindowFeatures);
5472
0
}
5473
5474
already_AddRefed<nsPIDOMWindowOuter>
5475
nsGlobalWindowOuter::OpenOuter(const nsAString& aUrl, const nsAString& aName,
5476
                               const nsAString& aOptions, ErrorResult& aError)
5477
0
{
5478
0
  nsCOMPtr<nsPIDOMWindowOuter> window;
5479
0
  aError = OpenJS(aUrl, aName, aOptions, getter_AddRefs(window));
5480
0
  return window.forget();
5481
0
}
5482
5483
nsresult
5484
nsGlobalWindowOuter::Open(const nsAString& aUrl, const nsAString& aName,
5485
                          const nsAString& aOptions, nsDocShellLoadInfo* aLoadInfo,
5486
                          bool aForceNoOpener, nsPIDOMWindowOuter **_retval)
5487
0
{
5488
0
  return OpenInternal(aUrl, aName, aOptions,
5489
0
                      false,          // aDialog
5490
0
                      false,          // aContentModal
5491
0
                      true,           // aCalledNoScript
5492
0
                      false,          // aDoJSFixups
5493
0
                      true,           // aNavigate
5494
0
                      nullptr, nullptr,  // No args
5495
0
                      aLoadInfo,
5496
0
                      aForceNoOpener,
5497
0
                      _retval);
5498
0
}
5499
5500
nsresult
5501
nsGlobalWindowOuter::OpenJS(const nsAString& aUrl, const nsAString& aName,
5502
                            const nsAString& aOptions, nsPIDOMWindowOuter **_retval)
5503
0
{
5504
0
  return OpenInternal(aUrl, aName, aOptions,
5505
0
                      false,          // aDialog
5506
0
                      false,          // aContentModal
5507
0
                      false,          // aCalledNoScript
5508
0
                      true,           // aDoJSFixups
5509
0
                      true,           // aNavigate
5510
0
                      nullptr, nullptr,  // No args
5511
0
                      nullptr,        // aLoadInfo
5512
0
                      false,          // aForceNoOpener
5513
0
                      _retval);
5514
0
}
5515
5516
// like Open, but attaches to the new window any extra parameters past
5517
// [features] as a JS property named "arguments"
5518
nsresult
5519
nsGlobalWindowOuter::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5520
                                const nsAString& aOptions,
5521
                                nsISupports* aExtraArgument,
5522
                                nsPIDOMWindowOuter** _retval)
5523
0
{
5524
0
  return OpenInternal(aUrl, aName, aOptions,
5525
0
                      true,                    // aDialog
5526
0
                      false,                   // aContentModal
5527
0
                      true,                    // aCalledNoScript
5528
0
                      false,                   // aDoJSFixups
5529
0
                      true,                    // aNavigate
5530
0
                      nullptr, aExtraArgument, // Arguments
5531
0
                      nullptr,                 // aLoadInfo
5532
0
                      false,                   // aForceNoOpener
5533
0
                      _retval);
5534
0
}
5535
5536
// Like Open, but passes aNavigate=false.
5537
/* virtual */ nsresult
5538
nsGlobalWindowOuter::OpenNoNavigate(const nsAString& aUrl,
5539
                                    const nsAString& aName,
5540
                                    const nsAString& aOptions,
5541
                                    nsPIDOMWindowOuter **_retval)
5542
0
{
5543
0
  return OpenInternal(aUrl, aName, aOptions,
5544
0
                      false,          // aDialog
5545
0
                      false,          // aContentModal
5546
0
                      true,           // aCalledNoScript
5547
0
                      false,          // aDoJSFixups
5548
0
                      false,          // aNavigate
5549
0
                      nullptr, nullptr,  // No args
5550
0
                      nullptr,        // aLoadInfo
5551
0
                      false,          // aForceNoOpener
5552
0
                      _retval);
5553
0
5554
0
}
5555
5556
already_AddRefed<nsPIDOMWindowOuter>
5557
nsGlobalWindowOuter::OpenDialogOuter(JSContext* aCx, const nsAString& aUrl,
5558
                                     const nsAString& aName, const nsAString& aOptions,
5559
                                     const Sequence<JS::Value>& aExtraArgument,
5560
                                     ErrorResult& aError)
5561
0
{
5562
0
  nsCOMPtr<nsIJSArgArray> argvArray;
5563
0
  aError = NS_CreateJSArgv(aCx, aExtraArgument.Length(),
5564
0
                           aExtraArgument.Elements(),
5565
0
                           getter_AddRefs(argvArray));
5566
0
  if (aError.Failed()) {
5567
0
    return nullptr;
5568
0
  }
5569
0
5570
0
  nsCOMPtr<nsPIDOMWindowOuter> dialog;
5571
0
  aError = OpenInternal(aUrl, aName, aOptions,
5572
0
                        true,             // aDialog
5573
0
                        false,            // aContentModal
5574
0
                        false,            // aCalledNoScript
5575
0
                        false,            // aDoJSFixups
5576
0
                        true,                // aNavigate
5577
0
                        argvArray, nullptr,  // Arguments
5578
0
                        nullptr,          // aLoadInfo
5579
0
                        false,            // aForceNoOpener
5580
0
                        getter_AddRefs(dialog));
5581
0
  return dialog.forget();
5582
0
}
5583
5584
already_AddRefed<nsPIDOMWindowOuter>
5585
nsGlobalWindowOuter::GetFramesOuter()
5586
0
{
5587
0
  RefPtr<nsPIDOMWindowOuter> frames(this);
5588
0
  FlushPendingNotifications(FlushType::ContentAndNotify);
5589
0
  return frames.forget();
5590
0
}
5591
5592
nsGlobalWindowInner*
5593
nsGlobalWindowOuter::CallerInnerWindow()
5594
0
{
5595
0
  JSContext *cx = nsContentUtils::GetCurrentJSContext();
5596
0
  NS_ENSURE_TRUE(cx, nullptr);
5597
0
  nsIGlobalObject* global = GetIncumbentGlobal();
5598
0
  NS_ENSURE_TRUE(global, nullptr);
5599
0
  JS::Rooted<JSObject*> scope(cx, global->GetGlobalJSObject());
5600
0
  NS_ENSURE_TRUE(scope, nullptr);
5601
0
5602
0
  // When Jetpack runs content scripts inside a sandbox, it uses
5603
0
  // sandboxPrototype to make them appear as though they're running in the
5604
0
  // scope of the page. So when a content script invokes postMessage, it expects
5605
0
  // the |source| of the received message to be the window set as the
5606
0
  // sandboxPrototype. This used to work incidentally for unrelated reasons, but
5607
0
  // now we need to do some special handling to support it.
5608
0
  if (xpc::IsSandbox(scope)) {
5609
0
    JSAutoRealm ar(cx, scope);
5610
0
    JS::Rooted<JSObject*> scopeProto(cx);
5611
0
    bool ok = JS_GetPrototype(cx, scope, &scopeProto);
5612
0
    NS_ENSURE_TRUE(ok, nullptr);
5613
0
    if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
5614
0
        (scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtWindowProxy = */ false)))
5615
0
    {
5616
0
      global = xpc::NativeGlobal(scopeProto);
5617
0
      NS_ENSURE_TRUE(global, nullptr);
5618
0
    }
5619
0
  }
5620
0
5621
0
  // The calling window must be holding a reference, so we can return a weak
5622
0
  // pointer.
5623
0
  nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(global);
5624
0
  return nsGlobalWindowInner::Cast(win);
5625
0
}
5626
5627
void
5628
nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessage,
5629
                                         const nsAString& aTargetOrigin,
5630
                                         JS::Handle<JS::Value> aTransfer,
5631
                                         nsIPrincipal& aSubjectPrincipal,
5632
                                         ErrorResult& aError)
5633
0
{
5634
0
  //
5635
0
  // Window.postMessage is an intentional subversion of the same-origin policy.
5636
0
  // As such, this code must be particularly careful in the information it
5637
0
  // exposes to calling code.
5638
0
  //
5639
0
  // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5640
0
  //
5641
0
5642
0
  // First, get the caller's window
5643
0
  RefPtr<nsGlobalWindowInner> callerInnerWin = CallerInnerWindow();
5644
0
  nsIPrincipal* callerPrin;
5645
0
  if (callerInnerWin) {
5646
0
    // Compute the caller's origin either from its principal or, in the case the
5647
0
    // principal doesn't carry a URI (e.g. the system principal), the caller's
5648
0
    // document.  We must get this now instead of when the event is created and
5649
0
    // dispatched, because ultimately it is the identity of the calling window
5650
0
    // *now* that determines who sent the message (and not an identity which might
5651
0
    // have changed due to intervening navigations).
5652
0
    callerPrin = callerInnerWin->GetPrincipal();
5653
0
  }
5654
0
  else {
5655
0
    // In case the global is not a window, it can be a sandbox, and the sandbox's
5656
0
    // principal can be used for the security check.
5657
0
    nsIGlobalObject* global = GetIncumbentGlobal();
5658
0
    NS_ASSERTION(global, "Why is there no global object?");
5659
0
    callerPrin = global->PrincipalOrNull();
5660
0
  }
5661
0
  if (!callerPrin) {
5662
0
    return;
5663
0
  }
5664
0
5665
0
  nsCOMPtr<nsIURI> callerOuterURI;
5666
0
  if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI)))) {
5667
0
    return;
5668
0
  }
5669
0
5670
0
  nsAutoString origin;
5671
0
  if (callerOuterURI) {
5672
0
    // if the principal has a URI, use that to generate the origin
5673
0
    nsContentUtils::GetUTFOrigin(callerPrin, origin);
5674
0
  }
5675
0
  else if (callerInnerWin) {
5676
0
    // otherwise use the URI of the document to generate origin
5677
0
    nsCOMPtr<nsIDocument> doc = callerInnerWin->GetExtantDoc();
5678
0
    if (!doc) {
5679
0
      return;
5680
0
    }
5681
0
    callerOuterURI = doc->GetDocumentURI();
5682
0
    // if the principal has a URI, use that to generate the origin
5683
0
    nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
5684
0
  }
5685
0
  else {
5686
0
    // in case of a sandbox with a system principal origin can be empty
5687
0
    if (!nsContentUtils::IsSystemPrincipal(callerPrin)) {
5688
0
      return;
5689
0
    }
5690
0
  }
5691
0
5692
0
  // Convert the provided origin string into a URI for comparison purposes.
5693
0
  nsCOMPtr<nsIPrincipal> providedPrincipal;
5694
0
5695
0
  if (aTargetOrigin.EqualsASCII("/")) {
5696
0
    providedPrincipal = callerPrin;
5697
0
  }
5698
0
  // "*" indicates no specific origin is required.
5699
0
  else if (!aTargetOrigin.EqualsASCII("*")) {
5700
0
    nsCOMPtr<nsIURI> originURI;
5701
0
    if (NS_FAILED(NS_NewURI(getter_AddRefs(originURI), aTargetOrigin))) {
5702
0
      aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
5703
0
      return;
5704
0
    }
5705
0
5706
0
    nsresult rv = NS_MutateURI(originURI)
5707
0
                    .SetUserPass(EmptyCString())
5708
0
                    .SetPathQueryRef(EmptyCString())
5709
0
                    .Finalize(originURI);
5710
0
    if (NS_FAILED(rv)) {
5711
0
      return;
5712
0
    }
5713
0
5714
0
    OriginAttributes attrs = aSubjectPrincipal.OriginAttributesRef();
5715
0
    if (aSubjectPrincipal.GetIsSystemPrincipal()) {
5716
0
      auto principal = BasePrincipal::Cast(GetPrincipal());
5717
0
5718
0
      if (attrs != principal->OriginAttributesRef()) {
5719
0
        nsCOMPtr<nsIURI> targetURI;
5720
0
        nsAutoCString targetURL;
5721
0
        nsAutoCString sourceOrigin;
5722
0
        nsAutoCString targetOrigin;
5723
0
5724
0
        if (NS_FAILED(principal->GetURI(getter_AddRefs(targetURI))) ||
5725
0
            NS_FAILED(targetURI->GetAsciiSpec(targetURL)) ||
5726
0
            NS_FAILED(principal->GetOrigin(targetOrigin)) ||
5727
0
            NS_FAILED(aSubjectPrincipal.GetOrigin(sourceOrigin))) {
5728
0
          NS_WARNING("Failed to get source and target origins");
5729
0
          return;
5730
0
        }
5731
0
5732
0
        nsContentUtils::LogSimpleConsoleError(
5733
0
          NS_ConvertUTF8toUTF16(nsPrintfCString(
5734
0
            R"(Attempting to post a message to window with url "%s" and )"
5735
0
            R"(origin "%s" from a system principal scope with mismatched )"
5736
0
            R"(origin "%s".)",
5737
0
            targetURL.get(), targetOrigin.get(), sourceOrigin.get())),
5738
0
          "DOM",
5739
0
          !!principal->PrivateBrowsingId());
5740
0
5741
0
        attrs = principal->OriginAttributesRef();
5742
0
      }
5743
0
    }
5744
0
5745
0
    // Create a nsIPrincipal inheriting the app/browser attributes from the
5746
0
    // caller.
5747
0
    providedPrincipal = BasePrincipal::CreateCodebasePrincipal(originURI, attrs);
5748
0
    if (NS_WARN_IF(!providedPrincipal)) {
5749
0
      return;
5750
0
    }
5751
0
  }
5752
0
5753
0
  // Create and asynchronously dispatch a runnable which will handle actual DOM
5754
0
  // event creation and dispatch.
5755
0
  RefPtr<PostMessageEvent> event =
5756
0
    new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin
5757
0
                         ? nullptr
5758
0
                         : callerInnerWin->GetOuterWindowInternal(),
5759
0
                         origin,
5760
0
                         this,
5761
0
                         providedPrincipal,
5762
0
                         callerInnerWin
5763
0
                         ? callerInnerWin->GetDoc()
5764
0
                         : nullptr,
5765
0
                         nsContentUtils::IsCallerChrome());
5766
0
5767
0
  JS::Rooted<JS::Value> message(aCx, aMessage);
5768
0
  JS::Rooted<JS::Value> transfer(aCx, aTransfer);
5769
0
5770
0
  event->Write(aCx, message, transfer, JS::CloneDataPolicy(), aError);
5771
0
  if (NS_WARN_IF(aError.Failed())) {
5772
0
    return;
5773
0
  }
5774
0
5775
0
  aError = Dispatch(TaskCategory::Other, event.forget());
5776
0
}
5777
5778
class nsCloseEvent : public Runnable {
5779
5780
  RefPtr<nsGlobalWindowOuter> mWindow;
5781
  bool mIndirect;
5782
5783
  nsCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect)
5784
    : mozilla::Runnable("nsCloseEvent")
5785
    , mWindow(aWindow)
5786
    , mIndirect(aIndirect)
5787
0
  {}
5788
5789
public:
5790
5791
  static nsresult
5792
0
  PostCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect) {
5793
0
    nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
5794
0
    nsresult rv =
5795
0
      aWindow->Dispatch(TaskCategory::Other, ev.forget());
5796
0
    if (NS_SUCCEEDED(rv))
5797
0
      aWindow->MaybeForgiveSpamCount();
5798
0
    return rv;
5799
0
  }
5800
5801
0
  NS_IMETHOD Run() override {
5802
0
    if (mWindow) {
5803
0
      if (mIndirect) {
5804
0
        return PostCloseEvent(mWindow, false);
5805
0
      }
5806
0
      mWindow->ReallyCloseWindow();
5807
0
    }
5808
0
    return NS_OK;
5809
0
  }
5810
5811
};
5812
5813
bool
5814
nsGlobalWindowOuter::CanClose()
5815
0
{
5816
0
  if (mIsChrome) {
5817
0
    nsCOMPtr<nsIBrowserDOMWindow> bwin;
5818
0
    GetBrowserDOMWindow(getter_AddRefs(bwin));
5819
0
5820
0
    bool canClose = true;
5821
0
    if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))) {
5822
0
      return canClose;
5823
0
    }
5824
0
  }
5825
0
5826
0
  if (!mDocShell) {
5827
0
    return true;
5828
0
  }
5829
0
5830
0
  // Ask the content viewer whether the toplevel window can close.
5831
0
  // If the content viewer returns false, it is responsible for calling
5832
0
  // Close() as soon as it is possible for the window to close.
5833
0
  // This allows us to not close the window while printing is happening.
5834
0
5835
0
  nsCOMPtr<nsIContentViewer> cv;
5836
0
  mDocShell->GetContentViewer(getter_AddRefs(cv));
5837
0
  if (cv) {
5838
0
    bool canClose;
5839
0
    nsresult rv = cv->PermitUnload(&canClose);
5840
0
    if (NS_SUCCEEDED(rv) && !canClose)
5841
0
      return false;
5842
0
5843
0
    rv = cv->RequestWindowClose(&canClose);
5844
0
    if (NS_SUCCEEDED(rv) && !canClose)
5845
0
      return false;
5846
0
  }
5847
0
5848
0
  return true;
5849
0
}
5850
5851
void
5852
nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller)
5853
0
{
5854
0
  if (!mDocShell || IsInModalState() ||
5855
0
      (IsFrame() && !mDocShell->GetIsMozBrowser())) {
5856
0
    // window.close() is called on a frame in a frameset, on a window
5857
0
    // that's already closed, or on a window for which there's
5858
0
    // currently a modal dialog open. Ignore such calls.
5859
0
    return;
5860
0
  }
5861
0
5862
0
  if (mHavePendingClose) {
5863
0
    // We're going to be closed anyway; do nothing since we don't want
5864
0
    // to double-close
5865
0
    return;
5866
0
  }
5867
0
5868
0
  if (mBlockScriptedClosingFlag)
5869
0
  {
5870
0
    // A script's popup has been blocked and we don't want
5871
0
    // the window to be closed directly after this event,
5872
0
    // so the user can see that there was a blocked popup.
5873
0
    return;
5874
0
  }
5875
0
5876
0
  // Don't allow scripts from content to close non-neterror windows that
5877
0
  // were not opened by script.
5878
0
  if (mDoc) {
5879
0
    nsAutoString url;
5880
0
    nsresult rv = mDoc->GetURL(url);
5881
0
    NS_ENSURE_SUCCESS_VOID(rv);
5882
0
5883
0
    if (!StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
5884
0
        !mHadOriginalOpener && !aTrustedCaller) {
5885
0
      bool allowClose = mAllowScriptsToClose ||
5886
0
        Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
5887
0
      if (!allowClose) {
5888
0
        // We're blocking the close operation
5889
0
        // report localized error msg in JS console
5890
0
        nsContentUtils::ReportToConsole(
5891
0
            nsIScriptError::warningFlag,
5892
0
            NS_LITERAL_CSTRING("DOM Window"), mDoc,  // Better name for the category?
5893
0
            nsContentUtils::eDOM_PROPERTIES,
5894
0
            "WindowCloseBlockedWarning");
5895
0
5896
0
        return;
5897
0
      }
5898
0
    }
5899
0
  }
5900
0
5901
0
  if (!mInClose && !mIsClosed && !CanClose()) {
5902
0
    return;
5903
0
  }
5904
0
5905
0
  // Fire a DOM event notifying listeners that this window is about to
5906
0
  // be closed. The tab UI code may choose to cancel the default
5907
0
  // action for this event, if so, we won't actually close the window
5908
0
  // (since the tab UI code will close the tab in stead). Sure, this
5909
0
  // could be abused by content code, but do we care? I don't think
5910
0
  // so...
5911
0
5912
0
  bool wasInClose = mInClose;
5913
0
  mInClose = true;
5914
0
5915
0
  if (!DispatchCustomEvent(NS_LITERAL_STRING("DOMWindowClose"))) {
5916
0
    // Someone chose to prevent the default action for this event, if
5917
0
    // so, let's not close this window after all...
5918
0
5919
0
    mInClose = wasInClose;
5920
0
    return;
5921
0
  }
5922
0
5923
0
  FinalClose();
5924
0
}
5925
5926
nsresult
5927
nsGlobalWindowOuter::Close()
5928
0
{
5929
0
  CloseOuter(/* aTrustedCaller = */ true);
5930
0
  return NS_OK;
5931
0
}
5932
5933
void
5934
nsGlobalWindowOuter::ForceClose()
5935
0
{
5936
0
  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
5937
0
5938
0
  if (IsFrame() || !mDocShell) {
5939
0
    // This may be a frame in a frameset, or a window that's already closed.
5940
0
    // Ignore such calls.
5941
0
    return;
5942
0
  }
5943
0
5944
0
  if (mHavePendingClose) {
5945
0
    // We're going to be closed anyway; do nothing since we don't want
5946
0
    // to double-close
5947
0
    return;
5948
0
  }
5949
0
5950
0
  mInClose = true;
5951
0
5952
0
  DispatchCustomEvent(NS_LITERAL_STRING("DOMWindowClose"));
5953
0
5954
0
  FinalClose();
5955
0
}
5956
5957
void
5958
nsGlobalWindowOuter::FinalClose()
5959
0
{
5960
0
  // Flag that we were closed.
5961
0
  mIsClosed = true;
5962
0
5963
0
  // If we get here from CloseOuter then it means that the parent process is
5964
0
  // going to close our window for us. It's just important to set mIsClosed.
5965
0
  if (XRE_GetProcessType() == GeckoProcessType_Content) {
5966
0
    return;
5967
0
  }
5968
0
5969
0
  // This stuff is non-sensical but incredibly fragile. The reasons for the
5970
0
  // behavior here don't make sense today and may not have ever made sense,
5971
0
  // but various bits of frontend code break when you change them. If you need
5972
0
  // to fix up this behavior, feel free to. It's a righteous task, but involves
5973
0
  // wrestling with various download manager tests, frontend code, and possible
5974
0
  // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
5975
0
  // testing ground.
5976
0
  //
5977
0
  // In particular, if some inner of |win| is the entry global, we must
5978
0
  // complete _two_ round-trips to the event loop before the call to
5979
0
  // ReallyCloseWindow. This allows setTimeout handlers that are set after
5980
0
  // FinalClose() is called to run before the window is torn down.
5981
0
  nsCOMPtr<nsPIDOMWindowInner> entryWindow =
5982
0
    do_QueryInterface(GetEntryGlobal());
5983
0
  bool indirect =
5984
0
    entryWindow && entryWindow->GetOuterWindow() == this;
5985
0
  if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))) {
5986
0
    ReallyCloseWindow();
5987
0
  } else {
5988
0
    mHavePendingClose = true;
5989
0
  }
5990
0
}
5991
5992
5993
void
5994
nsGlobalWindowOuter::ReallyCloseWindow()
5995
0
{
5996
0
  // Make sure we never reenter this method.
5997
0
  mHavePendingClose = true;
5998
0
5999
0
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6000
0
6001
0
  // If there's no treeOwnerAsWin, this window must already be closed.
6002
0
6003
0
  if (treeOwnerAsWin) {
6004
0
6005
0
    // but if we're a browser window we could be in some nasty
6006
0
    // self-destroying cascade that we should mostly ignore
6007
0
6008
0
    if (mDocShell) {
6009
0
      nsCOMPtr<nsIBrowserDOMWindow> bwin;
6010
0
      nsCOMPtr<nsIDocShellTreeItem> rootItem;
6011
0
      mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
6012
0
      nsCOMPtr<nsPIDOMWindowOuter> rootWin =
6013
0
       rootItem ? rootItem->GetWindow() : nullptr;
6014
0
      nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
6015
0
      if (chromeWin)
6016
0
        chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
6017
0
6018
0
      if (rootWin) {
6019
0
        /* Normally we destroy the entire window, but not if
6020
0
           this DOM window belongs to a tabbed browser and doesn't
6021
0
           correspond to a tab. This allows a well-behaved tab
6022
0
           to destroy the container as it should but is a final measure
6023
0
           to prevent an errant tab from doing so when it shouldn't.
6024
0
           This works because we reach this code when we shouldn't only
6025
0
           in the particular circumstance that we belong to a tab
6026
0
           that has just been closed (and is therefore already missing
6027
0
           from the list of browsers) (and has an unload handler
6028
0
           that closes the window). */
6029
0
        // XXXbz now that we have mHavePendingClose, is this needed?
6030
0
        bool isTab;
6031
0
        if (rootWin == this ||
6032
0
            !bwin ||
6033
0
            (NS_SUCCEEDED(bwin->IsTabContentWindow(GetOuterWindowInternal(),
6034
0
                                                   &isTab)) && isTab)) {
6035
0
          treeOwnerAsWin->Destroy();
6036
0
        }
6037
0
      }
6038
0
    }
6039
0
6040
0
    CleanUp();
6041
0
  }
6042
0
}
6043
6044
void
6045
nsGlobalWindowOuter::EnterModalState()
6046
0
{
6047
0
  // GetScriptableTop, not GetTop, so that EnterModalState works properly with
6048
0
  // <iframe mozbrowser>.
6049
0
  nsGlobalWindowOuter* topWin = GetScriptableTopInternal();
6050
0
6051
0
  if (!topWin) {
6052
0
    NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
6053
0
    return;
6054
0
  }
6055
0
6056
0
  // If there is an active ESM in this window, clear it. Otherwise, this can
6057
0
  // cause a problem if a modal state is entered during a mouseup event.
6058
0
  EventStateManager* activeESM =
6059
0
    static_cast<EventStateManager*>(
6060
0
      EventStateManager::GetActiveEventStateManager());
6061
0
  if (activeESM && activeESM->GetPresContext()) {
6062
0
    nsIPresShell* activeShell = activeESM->GetPresContext()->GetPresShell();
6063
0
    if (activeShell && (
6064
0
        nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(), mDoc) ||
6065
0
        nsContentUtils::ContentIsCrossDocDescendantOf(mDoc, activeShell->GetDocument()))) {
6066
0
      EventStateManager::ClearGlobalActiveContent(activeESM);
6067
0
6068
0
      nsIPresShell::SetCapturingContent(nullptr, 0);
6069
0
6070
0
      if (activeShell) {
6071
0
        RefPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
6072
0
        frameSelection->SetDragState(false);
6073
0
      }
6074
0
    }
6075
0
  }
6076
0
6077
0
  // If there are any drag and drop operations in flight, try to end them.
6078
0
  nsCOMPtr<nsIDragService> ds =
6079
0
    do_GetService("@mozilla.org/widget/dragservice;1");
6080
0
  if (ds) {
6081
0
    ds->EndDragSession(true, 0);
6082
0
  }
6083
0
6084
0
  // Clear the capturing content if it is under topDoc.
6085
0
  // Usually the activeESM check above does that, but there are cases when
6086
0
  // we don't have activeESM, or it is for different document.
6087
0
  nsIDocument* topDoc = topWin->GetExtantDoc();
6088
0
  nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
6089
0
  if (capturingContent && topDoc &&
6090
0
      nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
6091
0
    nsIPresShell::SetCapturingContent(nullptr, 0);
6092
0
  }
6093
0
6094
0
  if (topWin->mModalStateDepth == 0) {
6095
0
    NS_ASSERTION(!topWin->mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
6096
0
6097
0
    topWin->mSuspendedDoc = topDoc;
6098
0
    if (topDoc) {
6099
0
      topDoc->SuppressEventHandling();
6100
0
    }
6101
0
6102
0
    nsGlobalWindowInner* inner = topWin->GetCurrentInnerWindowInternal();
6103
0
    if (inner) {
6104
0
      topWin->GetCurrentInnerWindowInternal()->Suspend();
6105
0
    }
6106
0
  }
6107
0
  topWin->mModalStateDepth++;
6108
0
}
6109
6110
void
6111
nsGlobalWindowOuter::LeaveModalState()
6112
0
{
6113
0
  nsGlobalWindowOuter* topWin = GetScriptableTopInternal();
6114
0
6115
0
  if (!topWin) {
6116
0
    NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
6117
0
    return;
6118
0
  }
6119
0
6120
0
  MOZ_ASSERT(topWin->mModalStateDepth != 0);
6121
0
  MOZ_ASSERT(IsSuspended());
6122
0
  MOZ_ASSERT(topWin->IsSuspended());
6123
0
  topWin->mModalStateDepth--;
6124
0
6125
0
  nsGlobalWindowInner* inner = topWin->GetCurrentInnerWindowInternal();
6126
0
6127
0
  if (topWin->mModalStateDepth == 0) {
6128
0
    if (inner) {
6129
0
      inner->Resume();
6130
0
    }
6131
0
6132
0
    if (topWin->mSuspendedDoc) {
6133
0
      nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
6134
0
      topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc == topWin->mSuspendedDoc);
6135
0
      topWin->mSuspendedDoc = nullptr;
6136
0
    }
6137
0
  }
6138
0
6139
0
  // Remember the time of the last dialog quit.
6140
0
  if (inner) {
6141
0
    inner->mLastDialogQuitTime = TimeStamp::Now();
6142
0
  }
6143
0
6144
0
  if (topWin->mModalStateDepth == 0) {
6145
0
    RefPtr<Event> event = NS_NewDOMEvent(inner, nullptr, nullptr);
6146
0
    event->InitEvent(NS_LITERAL_STRING("endmodalstate"), true, false);
6147
0
    event->SetTrusted(true);
6148
0
    event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
6149
0
    topWin->DispatchEvent(*event);
6150
0
  }
6151
0
}
6152
6153
bool
6154
nsGlobalWindowOuter::IsInModalState()
6155
0
{
6156
0
  nsGlobalWindowOuter *topWin = GetScriptableTopInternal();
6157
0
6158
0
  if (!topWin) {
6159
0
    // IsInModalState() getting called w/o a reachable top window is a bit
6160
0
    // iffy, but valid enough not to make noise about it.  See bug 404828
6161
0
    return false;
6162
0
  }
6163
0
6164
0
  return topWin->mModalStateDepth != 0;
6165
0
}
6166
6167
void
6168
nsGlobalWindowOuter::NotifyWindowIDDestroyed(const char* aTopic)
6169
0
{
6170
0
  nsCOMPtr<nsIRunnable> runnable =
6171
0
    new WindowDestroyedEvent(this, mWindowID, aTopic);
6172
0
  Dispatch(TaskCategory::Other, runnable.forget());
6173
0
}
6174
6175
Element*
6176
nsGlobalWindowOuter::GetFrameElementOuter(nsIPrincipal& aSubjectPrincipal)
6177
0
{
6178
0
  if (!mDocShell || mDocShell->GetIsMozBrowser()) {
6179
0
    return nullptr;
6180
0
  }
6181
0
6182
0
  // Per HTML5, the frameElement getter returns null in cross-origin situations.
6183
0
  Element* element = GetRealFrameElementOuter();
6184
0
  if (!element) {
6185
0
    return nullptr;
6186
0
  }
6187
0
6188
0
  if (!aSubjectPrincipal.SubsumesConsideringDomain(element->NodePrincipal())) {
6189
0
    return nullptr;
6190
0
  }
6191
0
6192
0
  return element;
6193
0
}
6194
6195
Element*
6196
nsGlobalWindowOuter::GetRealFrameElementOuter()
6197
0
{
6198
0
  if (!mDocShell) {
6199
0
    return nullptr;
6200
0
  }
6201
0
6202
0
  nsCOMPtr<nsIDocShell> parent;
6203
0
  mDocShell->GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent));
6204
0
6205
0
  if (!parent || parent == mDocShell) {
6206
0
    // We're at a chrome boundary, don't expose the chrome iframe
6207
0
    // element to content code.
6208
0
    return nullptr;
6209
0
  }
6210
0
6211
0
  return mFrameElement;
6212
0
}
6213
6214
/**
6215
 * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper
6216
 * around GetRealFrameElement.
6217
 */
6218
Element*
6219
nsGlobalWindowOuter::GetFrameElement()
6220
0
{
6221
0
  FORWARD_TO_INNER(GetFrameElement, (), nullptr);
6222
0
}
6223
6224
namespace {
6225
class ChildCommandDispatcher : public Runnable
6226
{
6227
public:
6228
  ChildCommandDispatcher(nsPIWindowRoot* aRoot,
6229
                         nsITabChild* aTabChild,
6230
                         const nsAString& aAction)
6231
    : mozilla::Runnable("ChildCommandDispatcher")
6232
    , mRoot(aRoot)
6233
    , mTabChild(aTabChild)
6234
    , mAction(aAction)
6235
0
  {
6236
0
  }
6237
6238
  NS_IMETHOD Run() override
6239
0
  {
6240
0
    nsTArray<nsCString> enabledCommands, disabledCommands;
6241
0
    mRoot->GetEnabledDisabledCommands(enabledCommands, disabledCommands);
6242
0
    if (enabledCommands.Length() || disabledCommands.Length()) {
6243
0
      mTabChild->EnableDisableCommands(mAction, enabledCommands, disabledCommands);
6244
0
    }
6245
0
6246
0
    return NS_OK;
6247
0
  }
6248
6249
private:
6250
  nsCOMPtr<nsPIWindowRoot>             mRoot;
6251
  nsCOMPtr<nsITabChild>                mTabChild;
6252
  nsString                             mAction;
6253
};
6254
6255
class CommandDispatcher : public Runnable
6256
{
6257
public:
6258
  CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6259
                    const nsAString& aAction)
6260
    : mozilla::Runnable("CommandDispatcher")
6261
    , mDispatcher(aDispatcher)
6262
    , mAction(aAction)
6263
0
  {
6264
0
  }
6265
6266
  NS_IMETHOD Run() override
6267
0
  {
6268
0
    return mDispatcher->UpdateCommands(mAction);
6269
0
  }
6270
6271
  nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6272
  nsString                             mAction;
6273
};
6274
} // anonymous namespace
6275
6276
void
6277
nsGlobalWindowOuter::UpdateCommands(const nsAString& anAction,
6278
                                    Selection* aSel,
6279
                                    int16_t aReason)
6280
0
{
6281
0
  // If this is a child process, redirect to the parent process.
6282
0
  if (nsIDocShell* docShell = GetDocShell()) {
6283
0
    if (nsCOMPtr<nsITabChild> child = docShell->GetTabChild()) {
6284
0
      nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
6285
0
      if (root) {
6286
0
        nsContentUtils::AddScriptRunner(
6287
0
          new ChildCommandDispatcher(root, child, anAction));
6288
0
      }
6289
0
      return;
6290
0
    }
6291
0
  }
6292
0
6293
0
  nsPIDOMWindowOuter *rootWindow = GetPrivateRoot();
6294
0
  if (!rootWindow) {
6295
0
    return;
6296
0
  }
6297
0
6298
0
  nsIDocument* doc = rootWindow->GetExtantDoc();
6299
0
6300
0
  if (!doc) {
6301
0
    return;
6302
0
  }
6303
0
  // selectionchange action is only used for mozbrowser, not for XUL. So we bypass
6304
0
  // XUL command dispatch if anAction is "selectionchange".
6305
0
  if (!anAction.EqualsLiteral("selectionchange")) {
6306
0
    // Retrieve the command dispatcher and call updateCommands on it.
6307
0
    nsIDOMXULCommandDispatcher* xulCommandDispatcher =
6308
0
      doc->GetCommandDispatcher();
6309
0
    if (xulCommandDispatcher) {
6310
0
      nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
6311
0
                                                            anAction));
6312
0
    }
6313
0
  }
6314
0
}
6315
6316
Selection*
6317
nsGlobalWindowOuter::GetSelectionOuter()
6318
0
{
6319
0
  if (!mDocShell) {
6320
0
    return nullptr;
6321
0
  }
6322
0
6323
0
  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
6324
0
  if (!presShell) {
6325
0
    return nullptr;
6326
0
  }
6327
0
  return presShell->GetCurrentSelection(SelectionType::eNormal);
6328
0
}
6329
6330
already_AddRefed<Selection>
6331
nsGlobalWindowOuter::GetSelection()
6332
0
{
6333
0
  RefPtr<Selection> selection = GetSelectionOuter();
6334
0
  return selection.forget();
6335
0
}
6336
6337
bool
6338
nsGlobalWindowOuter::FindOuter(const nsAString& aString, bool aCaseSensitive,
6339
                               bool aBackwards, bool aWrapAround, bool aWholeWord,
6340
                               bool aSearchInFrames, bool aShowDialog,
6341
                               ErrorResult& aError)
6342
0
{
6343
0
  Unused << aShowDialog;
6344
0
6345
0
  if (Preferences::GetBool("dom.disable_window_find", false)) {
6346
0
    aError.Throw(NS_ERROR_NOT_AVAILABLE);
6347
0
    return false;
6348
0
  }
6349
0
6350
0
  nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6351
0
  if (!finder) {
6352
0
    aError.Throw(NS_ERROR_NOT_AVAILABLE);
6353
0
    return false;
6354
0
  }
6355
0
6356
0
  // Set the options of the search
6357
0
  aError = finder->SetSearchString(aString);
6358
0
  if (aError.Failed()) {
6359
0
    return false;
6360
0
  }
6361
0
  finder->SetMatchCase(aCaseSensitive);
6362
0
  finder->SetFindBackwards(aBackwards);
6363
0
  finder->SetWrapFind(aWrapAround);
6364
0
  finder->SetEntireWord(aWholeWord);
6365
0
  finder->SetSearchFrames(aSearchInFrames);
6366
0
6367
0
  // the nsIWebBrowserFind is initialized to use this window
6368
0
  // as the search root, but uses focus to set the current search
6369
0
  // frame. If we're being called from JS (as here), this window
6370
0
  // should be the current search frame.
6371
0
  nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6372
0
  if (framesFinder) {
6373
0
    framesFinder->SetRootSearchFrame(this);   // paranoia
6374
0
    framesFinder->SetCurrentSearchFrame(this);
6375
0
  }
6376
0
6377
0
  if (aString.IsEmpty()) {
6378
0
    return false;
6379
0
  }
6380
0
6381
0
  // Launch the search with the passed in search string
6382
0
  bool didFind = false;
6383
0
  aError = finder->FindNext(&didFind);
6384
0
  return didFind;
6385
0
}
6386
6387
//*****************************************************************************
6388
// EventTarget
6389
//*****************************************************************************
6390
6391
nsPIDOMWindowOuter*
6392
nsGlobalWindowOuter::GetOwnerGlobalForBindings()
6393
0
{
6394
0
  return this;
6395
0
}
6396
6397
bool
6398
nsGlobalWindowOuter::DispatchEvent(Event& aEvent,
6399
                                   CallerType aCallerType,
6400
                                   ErrorResult& aRv)
6401
0
{
6402
0
  FORWARD_TO_INNER(DispatchEvent, (aEvent, aCallerType, aRv), false);
6403
0
}
6404
6405
bool
6406
nsGlobalWindowOuter::ComputeDefaultWantsUntrusted(ErrorResult& aRv)
6407
0
{
6408
0
  // It's OK that we just return false here on failure to create an
6409
0
  // inner.  GetOrCreateListenerManager() will likewise fail, and then
6410
0
  // we won't be adding any listeners anyway.
6411
0
  FORWARD_TO_INNER_CREATE(ComputeDefaultWantsUntrusted, (aRv), false);
6412
0
}
6413
6414
EventListenerManager*
6415
nsGlobalWindowOuter::GetOrCreateListenerManager()
6416
0
{
6417
0
  FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager, (), nullptr);
6418
0
}
6419
6420
EventListenerManager*
6421
nsGlobalWindowOuter::GetExistingListenerManager() const
6422
0
{
6423
0
  FORWARD_TO_INNER(GetExistingListenerManager, (), nullptr);
6424
0
}
6425
6426
//*****************************************************************************
6427
// nsGlobalWindowOuter::nsPIDOMWindow
6428
//*****************************************************************************
6429
6430
nsPIDOMWindowOuter*
6431
nsGlobalWindowOuter::GetPrivateParent()
6432
0
{
6433
0
  nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
6434
0
6435
0
  if (this == parent) {
6436
0
    nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6437
0
    if (!chromeElement)
6438
0
      return nullptr;             // This is ok, just means a null parent.
6439
0
6440
0
    nsIDocument* doc = chromeElement->GetComposedDoc();
6441
0
    if (!doc)
6442
0
      return nullptr;             // This is ok, just means a null parent.
6443
0
6444
0
    return doc->GetWindow();
6445
0
  }
6446
0
6447
0
  return parent;
6448
0
}
6449
6450
nsPIDOMWindowOuter*
6451
nsGlobalWindowOuter::GetPrivateRoot()
6452
0
{
6453
0
  nsCOMPtr<nsPIDOMWindowOuter> top = GetTop();
6454
0
6455
0
  nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6456
0
  if (chromeElement) {
6457
0
    nsIDocument* doc = chromeElement->GetComposedDoc();
6458
0
    if (doc) {
6459
0
      nsCOMPtr<nsPIDOMWindowOuter> parent = doc->GetWindow();
6460
0
      if (parent) {
6461
0
        top = parent->GetTop();
6462
0
      }
6463
0
    }
6464
0
  }
6465
0
6466
0
  return top;
6467
0
}
6468
6469
// This has a caller in Windows-only code (nsNativeAppSupportWin).
6470
Location*
6471
nsGlobalWindowOuter::GetLocation()
6472
0
{
6473
0
  // This method can be called on the outer window as well.
6474
0
  FORWARD_TO_INNER(GetLocation, (), nullptr);
6475
0
}
6476
6477
void
6478
nsGlobalWindowOuter::ActivateOrDeactivate(bool aActivate)
6479
0
{
6480
0
  if (!mDoc) {
6481
0
    return;
6482
0
  }
6483
0
6484
0
  // Set / unset mIsActive on the top level window, which is used for the
6485
0
  // :-moz-window-inactive pseudoclass, and its sheet (if any).
6486
0
  nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
6487
0
  nsCOMPtr<nsIWidget> topLevelWidget;
6488
0
  if (mainWidget) {
6489
0
    // Get the top level widget (if the main widget is a sheet, this will
6490
0
    // be the sheet's top (non-sheet) parent).
6491
0
    topLevelWidget = mainWidget->GetSheetWindowParent();
6492
0
    if (!topLevelWidget) {
6493
0
      topLevelWidget = mainWidget;
6494
0
    }
6495
0
  }
6496
0
6497
0
  SetActive(aActivate);
6498
0
6499
0
  if (mainWidget != topLevelWidget) {
6500
0
    // This is a workaround for the following problem:
6501
0
    // When a window with an open sheet gains or loses focus, only the sheet
6502
0
    // window receives the NS_ACTIVATE/NS_DEACTIVATE event.  However the
6503
0
    // styling of the containing top level window also needs to change.  We
6504
0
    // get around this by calling nsPIDOMWindow::SetActive() on both windows.
6505
0
6506
0
    // Get the top level widget's nsGlobalWindowOuter
6507
0
    nsCOMPtr<nsPIDOMWindowOuter> topLevelWindow;
6508
0
6509
0
    // widgetListener should be a nsXULWindow
6510
0
    nsIWidgetListener* listener = topLevelWidget->GetWidgetListener();
6511
0
    if (listener) {
6512
0
      nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
6513
0
      nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
6514
0
      topLevelWindow = do_GetInterface(req);
6515
0
    }
6516
0
6517
0
    if (topLevelWindow) {
6518
0
      topLevelWindow->SetActive(aActivate);
6519
0
    }
6520
0
  }
6521
0
}
6522
6523
static bool
6524
NotifyDocumentTree(nsIDocument* aDocument, void* aData)
6525
0
{
6526
0
  aDocument->EnumerateSubDocuments(NotifyDocumentTree, nullptr);
6527
0
  aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
6528
0
  return true;
6529
0
}
6530
6531
void
6532
nsGlobalWindowOuter::SetActive(bool aActive)
6533
0
{
6534
0
  nsPIDOMWindowOuter::SetActive(aActive);
6535
0
  if (mDoc) {
6536
0
    NotifyDocumentTree(mDoc, nullptr);
6537
0
  }
6538
0
}
6539
6540
bool
6541
nsGlobalWindowOuter::IsTopLevelWindowActive()
6542
0
{
6543
0
   nsCOMPtr<nsIDocShellTreeItem> treeItem(GetDocShell());
6544
0
   if (!treeItem) {
6545
0
     return false;
6546
0
   }
6547
0
6548
0
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
6549
0
   treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
6550
0
   if (!rootItem) {
6551
0
     return false;
6552
0
   }
6553
0
6554
0
   nsCOMPtr<nsPIDOMWindowOuter> domWindow = rootItem->GetWindow();
6555
0
   return domWindow && domWindow->IsActive();
6556
0
}
6557
6558
void
6559
nsGlobalWindowOuter::SetIsBackground(bool aIsBackground)
6560
0
{
6561
0
  bool changed = aIsBackground != IsBackground();
6562
0
  SetIsBackgroundInternal(aIsBackground);
6563
0
6564
0
  nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal();
6565
0
6566
0
  if (inner && changed) {
6567
0
    inner->mTimeoutManager->UpdateBackgroundState();
6568
0
  }
6569
0
6570
0
  if (aIsBackground) {
6571
0
    // Notify gamepadManager we are at the background window,
6572
0
    // we need to stop vibrate.
6573
0
    // Stop the vr telemery time spent when it switches to
6574
0
    // the background window.
6575
0
    if (inner && changed) {
6576
0
      inner->StopGamepadHaptics();
6577
0
      // true is for asking to set the delta time to
6578
0
      // the telemetry.
6579
0
      inner->ResetVRTelemetry(true);
6580
0
    }
6581
0
    return;
6582
0
  }
6583
0
6584
0
  if (inner) {
6585
0
    // When switching to be as a top tab, restart the telemetry.
6586
0
    // false is for only resetting the timestamp.
6587
0
    inner->ResetVRTelemetry(false);
6588
0
    inner->SyncGamepadState();
6589
0
  }
6590
0
}
6591
6592
void
6593
nsGlobalWindowOuter::SetIsBackgroundInternal(bool aIsBackground)
6594
0
{
6595
0
  if (mIsBackground != aIsBackground) {
6596
0
    TabGroup()->WindowChangedBackgroundStatus(aIsBackground);
6597
0
  }
6598
0
  mIsBackground = aIsBackground;
6599
0
}
6600
6601
void
6602
nsGlobalWindowOuter::SetChromeEventHandler(EventTarget* aChromeEventHandler)
6603
0
{
6604
0
  SetChromeEventHandlerInternal(aChromeEventHandler);
6605
0
  // update the chrome event handler on all our inner windows
6606
0
  RefPtr<nsGlobalWindowInner> inner;
6607
0
  for (PRCList* node = PR_LIST_HEAD(this);
6608
0
       node != this;
6609
0
       node = PR_NEXT_LINK(inner)) {
6610
0
    // This cast is only safe if `node != this`, as nsGlobalWindowOuter is also
6611
0
    // in the list.
6612
0
    inner = static_cast<nsGlobalWindowInner*>(node);
6613
0
    NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
6614
0
                 "bad outer window pointer");
6615
0
    inner->SetChromeEventHandlerInternal(aChromeEventHandler);
6616
0
  }
6617
0
}
6618
6619
void
6620
nsGlobalWindowOuter::SetFocusedElement(Element* aElement,
6621
                                       uint32_t aFocusMethod,
6622
                                       bool aNeedsFocus)
6623
0
{
6624
0
  FORWARD_TO_INNER_VOID(SetFocusedElement,
6625
0
                        (aElement, aFocusMethod, aNeedsFocus));
6626
0
}
6627
6628
uint32_t
6629
nsGlobalWindowOuter::GetFocusMethod()
6630
0
{
6631
0
  FORWARD_TO_INNER(GetFocusMethod, (), 0);
6632
0
}
6633
6634
bool
6635
nsGlobalWindowOuter::ShouldShowFocusRing()
6636
0
{
6637
0
  FORWARD_TO_INNER(ShouldShowFocusRing, (), false);
6638
0
}
6639
6640
void
6641
nsGlobalWindowOuter::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
6642
                                           UIStateChangeType aShowFocusRings)
6643
0
{
6644
0
  nsPIDOMWindowOuter* piWin = GetPrivateRoot();
6645
0
  if (!piWin) {
6646
0
    return;
6647
0
  }
6648
0
6649
0
  MOZ_ASSERT(piWin == this);
6650
0
6651
0
  bool oldShouldShowFocusRing = ShouldShowFocusRing();
6652
0
6653
0
  // only change the flags that have been modified
6654
0
  nsCOMPtr<nsPIWindowRoot> windowRoot = do_QueryInterface(mChromeEventHandler);
6655
0
  if (!windowRoot) {
6656
0
    return;
6657
0
  }
6658
0
6659
0
  if (aShowAccelerators != UIStateChangeType_NoChange) {
6660
0
    windowRoot->SetShowAccelerators(aShowAccelerators == UIStateChangeType_Set);
6661
0
  }
6662
0
  if (aShowFocusRings != UIStateChangeType_NoChange) {
6663
0
    windowRoot->SetShowFocusRings(aShowFocusRings == UIStateChangeType_Set);
6664
0
  }
6665
0
6666
0
  nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(GetOuterWindow(),
6667
0
                                                        aShowAccelerators,
6668
0
                                                        aShowFocusRings);
6669
0
6670
0
  bool newShouldShowFocusRing = ShouldShowFocusRing();
6671
0
  if (mInnerWindow && nsGlobalWindowInner::Cast(mInnerWindow)->mHasFocus &&
6672
0
      mInnerWindow->mFocusedElement &&
6673
0
      oldShouldShowFocusRing != newShouldShowFocusRing) {
6674
0
    // Update focusedNode's state.
6675
0
    if (newShouldShowFocusRing) {
6676
0
      mInnerWindow->mFocusedElement->AddStates(NS_EVENT_STATE_FOCUSRING);
6677
0
    } else {
6678
0
      mInnerWindow->mFocusedElement->RemoveStates(NS_EVENT_STATE_FOCUSRING);
6679
0
    }
6680
0
  }
6681
0
}
6682
6683
bool
6684
nsGlobalWindowOuter::TakeFocus(bool aFocus, uint32_t aFocusMethod)
6685
0
{
6686
0
  FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false);
6687
0
}
6688
6689
void
6690
nsGlobalWindowOuter::SetReadyForFocus()
6691
0
{
6692
0
  FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
6693
0
}
6694
6695
void
6696
nsGlobalWindowOuter::PageHidden()
6697
0
{
6698
0
  FORWARD_TO_INNER_VOID(PageHidden, ());
6699
0
}
6700
6701
already_AddRefed<nsICSSDeclaration>
6702
nsGlobalWindowOuter::GetComputedStyleHelperOuter(Element& aElt,
6703
                                                 const nsAString& aPseudoElt,
6704
                                                 bool aDefaultStylesOnly)
6705
0
{
6706
0
  if (!mDoc) {
6707
0
    return nullptr;
6708
0
  }
6709
0
6710
0
  RefPtr<nsICSSDeclaration> compStyle =
6711
0
    NS_NewComputedDOMStyle(&aElt, aPseudoElt, mDoc,
6712
0
                           aDefaultStylesOnly ? nsComputedDOMStyle::eDefaultOnly :
6713
0
                                                nsComputedDOMStyle::eAll);
6714
0
6715
0
  return compStyle.forget();
6716
0
}
6717
6718
//*****************************************************************************
6719
// nsGlobalWindowOuter::nsIInterfaceRequestor
6720
//*****************************************************************************
6721
6722
nsresult
6723
nsGlobalWindowOuter::GetInterfaceInternal(const nsIID& aIID, void** aSink)
6724
0
{
6725
0
  NS_ENSURE_ARG_POINTER(aSink);
6726
0
  *aSink = nullptr;
6727
0
6728
0
  if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
6729
0
    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
6730
0
    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
6731
0
6732
0
    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(outer->mDocShell));
6733
0
    webNav.forget(aSink);
6734
0
  }
6735
0
  else if (aIID.Equals(NS_GET_IID(nsIDocShell))) {
6736
0
    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
6737
0
    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
6738
0
6739
0
    nsCOMPtr<nsIDocShell> docShell = outer->mDocShell;
6740
0
    docShell.forget(aSink);
6741
0
  }
6742
0
#ifdef NS_PRINTING
6743
0
  else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
6744
0
    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
6745
0
    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
6746
0
6747
0
    if (outer->mDocShell) {
6748
0
      nsCOMPtr<nsIContentViewer> viewer;
6749
0
      outer->mDocShell->GetContentViewer(getter_AddRefs(viewer));
6750
0
      if (viewer) {
6751
0
        nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
6752
0
        webBrowserPrint.forget(aSink);
6753
0
      }
6754
0
    }
6755
0
  }
6756
0
#endif
6757
0
  else if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
6758
0
    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
6759
0
    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
6760
0
6761
0
    nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(outer->mDocShell));
6762
0
    loadContext.forget(aSink);
6763
0
  }
6764
0
6765
0
  return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
6766
0
}
6767
6768
NS_IMETHODIMP
6769
nsGlobalWindowOuter::GetInterface(const nsIID & aIID, void **aSink)
6770
0
{
6771
0
  nsresult rv = GetInterfaceInternal(aIID, aSink);
6772
0
  if (rv == NS_ERROR_NO_INTERFACE) {
6773
0
    return QueryInterface(aIID, aSink);
6774
0
  }
6775
0
  return rv;
6776
0
}
6777
6778
bool
6779
nsGlobalWindowOuter::IsSuspended() const
6780
0
{
6781
0
  MOZ_ASSERT(NS_IsMainThread());
6782
0
  // No inner means we are effectively suspended
6783
0
  if (!mInnerWindow) {
6784
0
    return true;
6785
0
  }
6786
0
  return mInnerWindow->IsSuspended();
6787
0
}
6788
6789
bool
6790
nsGlobalWindowOuter::IsFrozen() const
6791
0
{
6792
0
  MOZ_ASSERT(NS_IsMainThread());
6793
0
  // No inner means we are effectively frozen
6794
0
  if (!mInnerWindow) {
6795
0
    return true;
6796
0
  }
6797
0
  return mInnerWindow->IsFrozen();
6798
0
}
6799
6800
nsresult
6801
nsGlobalWindowOuter::FireDelayedDOMEvents()
6802
0
{
6803
0
  FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
6804
0
}
6805
6806
//*****************************************************************************
6807
// nsGlobalWindowOuter: Window Control Functions
6808
//*****************************************************************************
6809
6810
nsPIDOMWindowOuter*
6811
nsGlobalWindowOuter::GetParentInternal()
6812
0
{
6813
0
  nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
6814
0
6815
0
  if (parent && parent != this) {
6816
0
    return parent;
6817
0
  }
6818
0
6819
0
  return nullptr;
6820
0
}
6821
6822
void
6823
nsGlobalWindowOuter::UnblockScriptedClosing()
6824
0
{
6825
0
  mBlockScriptedClosingFlag = false;
6826
0
}
6827
6828
class AutoUnblockScriptClosing
6829
{
6830
private:
6831
  RefPtr<nsGlobalWindowOuter> mWin;
6832
public:
6833
  explicit AutoUnblockScriptClosing(nsGlobalWindowOuter* aWin)
6834
    : mWin(aWin)
6835
0
  {
6836
0
    MOZ_ASSERT(mWin);
6837
0
  }
6838
  ~AutoUnblockScriptClosing()
6839
0
  {
6840
0
    void (nsGlobalWindowOuter::*run)() = &nsGlobalWindowOuter::UnblockScriptedClosing;
6841
0
    nsCOMPtr<nsIRunnable> caller = NewRunnableMethod(
6842
0
      "AutoUnblockScriptClosing::~AutoUnblockScriptClosing", mWin, run);
6843
0
    mWin->Dispatch(TaskCategory::Other, caller.forget());
6844
0
  }
6845
};
6846
6847
nsresult
6848
nsGlobalWindowOuter::OpenInternal(const nsAString& aUrl, const nsAString& aName,
6849
                                  const nsAString& aOptions, bool aDialog,
6850
                                  bool aContentModal, bool aCalledNoScript,
6851
                                  bool aDoJSFixups, bool aNavigate,
6852
                                  nsIArray *argv,
6853
                                  nsISupports *aExtraArgument,
6854
                                  nsDocShellLoadInfo* aLoadInfo,
6855
                                  bool aForceNoOpener,
6856
                                  nsPIDOMWindowOuter **aReturn)
6857
0
{
6858
#ifdef DEBUG
6859
  uint32_t argc = 0;
6860
  if (argv)
6861
      argv->GetLength(&argc);
6862
#endif
6863
6864
0
  MOZ_ASSERT(!aExtraArgument || (!argv && argc == 0),
6865
0
             "Can't pass in arguments both ways");
6866
0
  MOZ_ASSERT(!aCalledNoScript || (!argv && argc == 0),
6867
0
             "Can't pass JS args when called via the noscript methods");
6868
0
6869
0
  mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
6870
0
6871
0
  // Calls to window.open from script should navigate.
6872
0
  MOZ_ASSERT(aCalledNoScript || aNavigate);
6873
0
6874
0
  *aReturn = nullptr;
6875
0
6876
0
  nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
6877
0
  if (!chrome) {
6878
0
    // No chrome means we don't want to go through with this open call
6879
0
    // -- see nsIWindowWatcher.idl
6880
0
    return NS_ERROR_NOT_AVAILABLE;
6881
0
  }
6882
0
6883
0
  NS_ASSERTION(mDocShell, "Must have docshell here");
6884
0
6885
0
  nsAutoCString options;
6886
0
  bool forceNoOpener = aForceNoOpener;
6887
0
  // Unlike other window flags, "noopener" comes from splitting on commas with
6888
0
  // HTML whitespace trimming...
6889
0
  nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(
6890
0
    aOptions, ',');
6891
0
  while (tok.hasMoreTokens()) {
6892
0
    auto nextTok = tok.nextToken();
6893
0
    if (nextTok.EqualsLiteral("noopener")) {
6894
0
      forceNoOpener = true;
6895
0
      continue;
6896
0
    }
6897
0
    // Want to create a copy of the options without 'noopener' because having
6898
0
    // 'noopener' in the options affects other window features.
6899
0
    if (!options.IsEmpty()) {
6900
0
      options.Append(',');
6901
0
    }
6902
0
    AppendUTF16toUTF8(nextTok, options);
6903
0
  }
6904
0
6905
0
  bool windowExists = WindowExists(aName, forceNoOpener, !aCalledNoScript);
6906
0
6907
0
  // XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
6908
0
  // (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
6909
0
  // But note that if you change this to GetEntryGlobal(), say, then
6910
0
  // OnLinkClickEvent::Run will need a full-blown AutoEntryScript.
6911
0
  const bool checkForPopup = !nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
6912
0
    !aDialog && !windowExists;
6913
0
6914
0
  // Note: the Void handling here is very important, because the window watcher
6915
0
  // expects a null URL string (not an empty string) if there is no URL to load.
6916
0
  nsCString url;
6917
0
  url.SetIsVoid(true);
6918
0
  nsresult rv = NS_OK;
6919
0
6920
0
  nsCOMPtr<nsIURI> uri;
6921
0
6922
0
  // It's important to do this security check before determining whether this
6923
0
  // window opening should be blocked, to ensure that we don't FireAbuseEvents
6924
0
  // for a window opening that wouldn't have succeeded in the first place.
6925
0
  if (!aUrl.IsEmpty()) {
6926
0
    AppendUTF16toUTF8(aUrl, url);
6927
0
6928
0
    // It's safe to skip the security check below if we're not a dialog
6929
0
    // because window.openDialog is not callable from content script.  See bug
6930
0
    // 56851.
6931
0
    //
6932
0
    // If we're not navigating, we assume that whoever *does* navigate the
6933
0
    // window will do a security check of their own.
6934
0
    if (!url.IsVoid() && !aDialog && aNavigate)
6935
0
      rv = SecurityCheckURL(url.get(), getter_AddRefs(uri));
6936
0
  }
6937
0
6938
0
  if (NS_FAILED(rv))
6939
0
    return rv;
6940
0
6941
0
  PopupControlState abuseLevel = GetPopupControlState();
6942
0
  if (checkForPopup) {
6943
0
    abuseLevel = RevisePopupAbuseLevel(abuseLevel);
6944
0
    if (abuseLevel >= openBlocked) {
6945
0
      if (!aCalledNoScript) {
6946
0
        // If script in some other window is doing a window.open on us and
6947
0
        // it's being blocked, then it's OK to close us afterwards, probably.
6948
0
        // But if we're doing a window.open on ourselves and block the popup,
6949
0
        // prevent this window from closing until after this script terminates
6950
0
        // so that whatever popup blocker UI the app has will be visible.
6951
0
        nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6952
0
          do_QueryInterface(GetEntryGlobal());
6953
0
        // Note that entryWindow can be null here if some JS component was the
6954
0
        // place where script was entered for this JS execution.
6955
0
        if (entryWindow &&
6956
0
            entryWindow->GetOuterWindow() == this) {
6957
0
          mBlockScriptedClosingFlag = true;
6958
0
          closeUnblocker.emplace(this);
6959
0
        }
6960
0
      }
6961
0
6962
0
      FireAbuseEvents(aUrl, aName, aOptions);
6963
0
      return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
6964
0
    }
6965
0
  }
6966
0
6967
0
  nsCOMPtr<mozIDOMWindowProxy> domReturn;
6968
0
6969
0
  nsCOMPtr<nsIWindowWatcher> wwatch =
6970
0
    do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
6971
0
  NS_ENSURE_TRUE(wwatch, rv);
6972
0
6973
0
  NS_ConvertUTF16toUTF8 name(aName);
6974
0
6975
0
  const char *options_ptr  = options.IsEmpty() ? nullptr : options.get();
6976
0
  const char *name_ptr = aName.IsEmpty() ? nullptr : name.get();
6977
0
6978
0
  nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
6979
0
  NS_ENSURE_STATE(pwwatch);
6980
0
6981
0
  MOZ_ASSERT_IF(checkForPopup, abuseLevel < openBlocked);
6982
0
  // At this point we should know for a fact that if checkForPopup then
6983
0
  // abuseLevel < openBlocked, so we could just check for abuseLevel ==
6984
0
  // openControlled.  But let's be defensive just in case and treat anything
6985
0
  // that fails the above assert as a spam popup too, if it ever happens.
6986
0
  bool isPopupSpamWindow = checkForPopup && (abuseLevel >= openControlled);
6987
0
6988
0
  {
6989
0
    // Reset popup state while opening a window to prevent the
6990
0
    // current state from being active the whole time a modal
6991
0
    // dialog is open.
6992
0
    nsAutoPopupStatePusher popupStatePusher(openAbused, true);
6993
0
6994
0
    if (!aCalledNoScript) {
6995
0
      // We asserted at the top of this function that aNavigate is true for
6996
0
      // !aCalledNoScript.
6997
0
      rv = pwwatch->OpenWindow2(this, url.IsVoid() ? nullptr : url.get(),
6998
0
                                name_ptr,
6999
0
                                options_ptr, /* aCalledFromScript = */ true,
7000
0
                                aDialog, aNavigate, argv,
7001
0
                                isPopupSpamWindow,
7002
0
                                forceNoOpener,
7003
0
                                aLoadInfo,
7004
0
                                getter_AddRefs(domReturn));
7005
0
    } else {
7006
0
      // Force a system caller here so that the window watcher won't screw us
7007
0
      // up.  We do NOT want this case looking at the JS context on the stack
7008
0
      // when searching.  Compare comments on
7009
0
      // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
7010
0
7011
0
      // Note: Because nsWindowWatcher is so broken, it's actually important
7012
0
      // that we don't force a system caller here, because that screws it up
7013
0
      // when it tries to compute the caller principal to associate with dialog
7014
0
      // arguments. That whole setup just really needs to be rewritten. :-(
7015
0
      Maybe<AutoNoJSAPI> nojsapi;
7016
0
      if (!aContentModal) {
7017
0
        nojsapi.emplace();
7018
0
      }
7019
0
7020
0
      rv = pwwatch->OpenWindow2(this, url.IsVoid() ? nullptr : url.get(),
7021
0
                                name_ptr,
7022
0
                                options_ptr, /* aCalledFromScript = */ false,
7023
0
                                aDialog, aNavigate, aExtraArgument,
7024
0
                                isPopupSpamWindow,
7025
0
                                forceNoOpener,
7026
0
                                aLoadInfo,
7027
0
                                getter_AddRefs(domReturn));
7028
0
7029
0
    }
7030
0
  }
7031
0
7032
0
  NS_ENSURE_SUCCESS(rv, rv);
7033
0
7034
0
  // success!
7035
0
7036
0
  if (!aCalledNoScript && !windowExists && uri && !forceNoOpener) {
7037
0
    MaybeAllowStorageForOpenedWindow(uri);
7038
0
  }
7039
0
7040
0
  NS_ENSURE_TRUE(domReturn, NS_OK);
7041
0
  nsCOMPtr<nsPIDOMWindowOuter> outerReturn =
7042
0
    nsPIDOMWindowOuter::From(domReturn);
7043
0
  outerReturn.swap(*aReturn);
7044
0
7045
0
  if (aDoJSFixups) {
7046
0
    nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
7047
0
    if (!chrome_win) {
7048
0
      // A new non-chrome window was created from a call to
7049
0
      // window.open() from JavaScript, make sure there's a document in
7050
0
      // the new window. We do this by simply asking the new window for
7051
0
      // its document, this will synchronously create an empty document
7052
0
      // if there is no document in the window.
7053
0
      // XXXbz should this just use EnsureInnerWindow()?
7054
0
7055
0
      // Force document creation.
7056
0
      nsCOMPtr<nsIDocument> doc = (*aReturn)->GetDoc();
7057
0
      Unused << doc;
7058
0
    }
7059
0
  }
7060
0
7061
0
  return rv;
7062
0
}
7063
7064
void
7065
nsGlobalWindowOuter::MaybeAllowStorageForOpenedWindow(nsIURI* aURI)
7066
0
{
7067
0
  nsGlobalWindowInner *inner = GetCurrentInnerWindowInternal();
7068
0
  if (NS_WARN_IF(!inner)) {
7069
0
    return;
7070
0
  }
7071
0
7072
0
  // No 3rd party URL/window.
7073
0
  if (!nsContentUtils::IsThirdPartyWindowOrChannel(inner, nullptr, aURI)) {
7074
0
    return;
7075
0
  }
7076
0
7077
0
  nsAutoString origin;
7078
0
  nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
7079
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
7080
0
    return;
7081
0
  }
7082
0
7083
0
  // We don't care when the asynchronous work finishes here.
7084
0
  Unused << AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(origin,
7085
0
                                                                     inner,
7086
0
                                                                     AntiTrackingCommon::eHeuristic);
7087
0
}
7088
7089
//*****************************************************************************
7090
// nsGlobalWindowOuter: Helper Functions
7091
//*****************************************************************************
7092
7093
already_AddRefed<nsIDocShellTreeOwner>
7094
nsGlobalWindowOuter::GetTreeOwner()
7095
0
{
7096
0
  // If there's no docShellAsItem, this window must have been closed,
7097
0
  // in that case there is no tree owner.
7098
0
7099
0
  if (!mDocShell) {
7100
0
    return nullptr;
7101
0
  }
7102
0
7103
0
  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
7104
0
  mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
7105
0
  return treeOwner.forget();
7106
0
}
7107
7108
already_AddRefed<nsIBaseWindow>
7109
nsGlobalWindowOuter::GetTreeOwnerWindow()
7110
0
{
7111
0
  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
7112
0
7113
0
  // If there's no mDocShell, this window must have been closed,
7114
0
  // in that case there is no tree owner.
7115
0
7116
0
  if (mDocShell) {
7117
0
    mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
7118
0
  }
7119
0
7120
0
  nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
7121
0
  return baseWindow.forget();
7122
0
}
7123
7124
already_AddRefed<nsIWebBrowserChrome>
7125
nsGlobalWindowOuter::GetWebBrowserChrome()
7126
0
{
7127
0
  nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
7128
0
7129
0
  nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
7130
0
  return browserChrome.forget();
7131
0
}
7132
7133
nsIScrollableFrame *
7134
nsGlobalWindowOuter::GetScrollFrame()
7135
0
{
7136
0
  if (!mDocShell) {
7137
0
    return nullptr;
7138
0
  }
7139
0
7140
0
  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
7141
0
  if (presShell) {
7142
0
    return presShell->GetRootScrollFrameAsScrollable();
7143
0
  }
7144
0
  return nullptr;
7145
0
}
7146
7147
nsresult
7148
nsGlobalWindowOuter::SecurityCheckURL(const char *aURL, nsIURI** aURI)
7149
0
{
7150
0
  nsCOMPtr<nsPIDOMWindowInner> sourceWindow = do_QueryInterface(GetEntryGlobal());
7151
0
  if (!sourceWindow) {
7152
0
    sourceWindow = GetCurrentInnerWindow();
7153
0
  }
7154
0
  AutoJSContext cx;
7155
0
  nsGlobalWindowInner* sourceWin = nsGlobalWindowInner::Cast(sourceWindow);
7156
0
  JSAutoRealm ar(cx, sourceWin->GetGlobalJSObject());
7157
0
7158
0
  // Resolve the baseURI, which could be relative to the calling window.
7159
0
  //
7160
0
  // Note the algorithm to get the base URI should match the one
7161
0
  // used to actually kick off the load in nsWindowWatcher.cpp.
7162
0
  nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
7163
0
  nsIURI* baseURI = nullptr;
7164
0
  auto encoding = UTF_8_ENCODING; // default to utf-8
7165
0
  if (doc) {
7166
0
    baseURI = doc->GetDocBaseURI();
7167
0
    encoding = doc->GetDocumentCharacterSet();
7168
0
  }
7169
0
  nsCOMPtr<nsIURI> uri;
7170
0
  nsresult rv = NS_NewURI(getter_AddRefs(uri), nsDependentCString(aURL),
7171
0
                          encoding, baseURI);
7172
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
7173
0
    return NS_ERROR_DOM_SYNTAX_ERR;
7174
0
  }
7175
0
7176
0
  if (NS_FAILED(nsContentUtils::GetSecurityManager()->
7177
0
        CheckLoadURIFromScript(cx, uri))) {
7178
0
    return NS_ERROR_FAILURE;
7179
0
  }
7180
0
7181
0
  uri.forget(aURI);
7182
0
  return NS_OK;
7183
0
}
7184
7185
void
7186
nsGlobalWindowOuter::FlushPendingNotifications(FlushType aType)
7187
0
{
7188
0
  if (mDoc) {
7189
0
    mDoc->FlushPendingNotifications(aType);
7190
0
  }
7191
0
}
7192
7193
void
7194
nsGlobalWindowOuter::EnsureSizeAndPositionUpToDate()
7195
0
{
7196
0
  // If we're a subframe, make sure our size is up to date.  It's OK that this
7197
0
  // crosses the content/chrome boundary, since chrome can have pending reflows
7198
0
  // too.
7199
0
  nsGlobalWindowOuter *parent = nsGlobalWindowOuter::Cast(GetPrivateParent());
7200
0
  if (parent) {
7201
0
    parent->FlushPendingNotifications(FlushType::Layout);
7202
0
  }
7203
0
}
7204
7205
already_AddRefed<nsISupports>
7206
nsGlobalWindowOuter::SaveWindowState()
7207
0
{
7208
0
  if (!mContext || !GetWrapperPreserveColor()) {
7209
0
    // The window may be getting torn down; don't bother saving state.
7210
0
    return nullptr;
7211
0
  }
7212
0
7213
0
  nsGlobalWindowInner *inner = GetCurrentInnerWindowInternal();
7214
0
  NS_ASSERTION(inner, "No inner window to save");
7215
0
7216
0
  // Don't do anything else to this inner window! After this point, all
7217
0
  // calls to SetTimeoutOrInterval will create entries in the timeout
7218
0
  // list that will only run after this window has come out of the bfcache.
7219
0
  // Also, while we're frozen, we won't dispatch online/offline events
7220
0
  // to the page.
7221
0
  inner->Freeze();
7222
0
7223
0
  nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
7224
0
7225
#ifdef DEBUG_PAGE_CACHE
7226
  printf("saving window state, state = %p\n", (void*)state);
7227
#endif
7228
7229
0
  return state.forget();
7230
0
}
7231
7232
nsresult
7233
nsGlobalWindowOuter::RestoreWindowState(nsISupports *aState)
7234
0
{
7235
0
  if (!mContext || !GetWrapperPreserveColor()) {
7236
0
    // The window may be getting torn down; don't bother restoring state.
7237
0
    return NS_OK;
7238
0
  }
7239
0
7240
0
  nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
7241
0
  NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
7242
0
7243
#ifdef DEBUG_PAGE_CACHE
7244
  printf("restoring window state, state = %p\n", (void*)holder);
7245
#endif
7246
7247
0
  // And we're ready to go!
7248
0
  nsGlobalWindowInner *inner = GetCurrentInnerWindowInternal();
7249
0
7250
0
  // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
7251
0
  // it easy to tell which link was last clicked when going back a page.
7252
0
  Element* focusedElement = inner->GetFocusedElement();
7253
0
  if (nsContentUtils::ContentIsLink(focusedElement)) {
7254
0
    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7255
0
    if (fm) {
7256
0
      // XXXbz Do we need the stack strong ref here?
7257
0
      RefPtr<Element> kungFuDeathGrip(focusedElement);
7258
0
      fm->SetFocus(kungFuDeathGrip, nsIFocusManager::FLAG_NOSCROLL |
7259
0
                                    nsIFocusManager::FLAG_SHOWRING);
7260
0
    }
7261
0
  }
7262
0
7263
0
  inner->Thaw();
7264
0
7265
0
  holder->DidRestoreWindow();
7266
0
7267
0
  return NS_OK;
7268
0
}
7269
7270
void
7271
nsGlobalWindowOuter::AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const
7272
0
{
7273
0
  aWindowSizes.mDOMOtherSize += aWindowSizes.mState.mMallocSizeOf(this);
7274
0
}
7275
7276
uint32_t
7277
nsGlobalWindowOuter::GetAutoActivateVRDisplayID()
7278
0
{
7279
0
  uint32_t retVal = mAutoActivateVRDisplayID;
7280
0
  mAutoActivateVRDisplayID = 0;
7281
0
  return retVal;
7282
0
}
7283
7284
void
7285
nsGlobalWindowOuter::SetAutoActivateVRDisplayID(uint32_t aAutoActivateVRDisplayID)
7286
0
{
7287
0
  mAutoActivateVRDisplayID = aAutoActivateVRDisplayID;
7288
0
}
7289
7290
already_AddRefed<nsWindowRoot>
7291
nsGlobalWindowOuter::GetWindowRootOuter()
7292
0
{
7293
0
  nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
7294
0
  return root.forget().downcast<nsWindowRoot>();
7295
0
}
7296
7297
nsIDOMWindowUtils*
7298
nsGlobalWindowOuter::WindowUtils()
7299
0
{
7300
0
  if (!mWindowUtils) {
7301
0
    mWindowUtils = new nsDOMWindowUtils(this);
7302
0
  }
7303
0
  return mWindowUtils;
7304
0
}
7305
7306
//Note: This call will lock the cursor, it will not change as it moves.
7307
//To unlock, the cursor must be set back to CURSOR_AUTO.
7308
void
7309
nsGlobalWindowOuter::SetCursorOuter(const nsAString& aCursor, ErrorResult& aError)
7310
0
{
7311
0
  int32_t cursor;
7312
0
7313
0
  if (aCursor.EqualsLiteral("auto"))
7314
0
    cursor = NS_STYLE_CURSOR_AUTO;
7315
0
  else {
7316
0
    nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
7317
0
    if (!nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
7318
0
      return;
7319
0
    }
7320
0
  }
7321
0
7322
0
  RefPtr<nsPresContext> presContext;
7323
0
  if (mDocShell) {
7324
0
    mDocShell->GetPresContext(getter_AddRefs(presContext));
7325
0
  }
7326
0
7327
0
  if (presContext) {
7328
0
    // Need root widget.
7329
0
    nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
7330
0
    if (!presShell) {
7331
0
      aError.Throw(NS_ERROR_FAILURE);
7332
0
      return;
7333
0
    }
7334
0
7335
0
    nsViewManager* vm = presShell->GetViewManager();
7336
0
    if (!vm) {
7337
0
      aError.Throw(NS_ERROR_FAILURE);
7338
0
      return;
7339
0
    }
7340
0
7341
0
    nsView* rootView = vm->GetRootView();
7342
0
    if (!rootView) {
7343
0
      aError.Throw(NS_ERROR_FAILURE);
7344
0
      return;
7345
0
    }
7346
0
7347
0
    nsIWidget* widget = rootView->GetNearestWidget(nullptr);
7348
0
    if (!widget) {
7349
0
      aError.Throw(NS_ERROR_FAILURE);
7350
0
      return;
7351
0
    }
7352
0
7353
0
    // Call esm and set cursor.
7354
0
    aError = presContext->EventStateManager()->SetCursor(cursor, nullptr,
7355
0
                                                         false, 0.0f, 0.0f,
7356
0
                                                         widget, true);
7357
0
  }
7358
0
}
7359
7360
NS_IMETHODIMP
7361
nsGlobalWindowOuter::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
7362
0
{
7363
0
  MOZ_RELEASE_ASSERT(IsChromeWindow());
7364
0
  FORWARD_TO_INNER(GetBrowserDOMWindow, (aBrowserWindow), NS_ERROR_UNEXPECTED);
7365
0
}
7366
7367
nsIBrowserDOMWindow*
7368
nsGlobalWindowOuter::GetBrowserDOMWindowOuter()
7369
0
{
7370
0
  MOZ_ASSERT(IsChromeWindow());
7371
0
  return mChromeFields.mBrowserDOMWindow;
7372
0
}
7373
7374
void
7375
nsGlobalWindowOuter::SetBrowserDOMWindowOuter(nsIBrowserDOMWindow* aBrowserWindow)
7376
0
{
7377
0
  MOZ_ASSERT(IsChromeWindow());
7378
0
  mChromeFields.mBrowserDOMWindow = aBrowserWindow;
7379
0
}
7380
7381
ChromeMessageBroadcaster*
7382
nsGlobalWindowOuter::GetMessageManager()
7383
0
{
7384
0
  if (!mInnerWindow) {
7385
0
    NS_WARNING("No inner window available!");
7386
0
    return nullptr;
7387
0
  }
7388
0
  return GetCurrentInnerWindowInternal()->MessageManager();
7389
0
}
7390
7391
ChromeMessageBroadcaster*
7392
nsGlobalWindowOuter::GetGroupMessageManager(const nsAString& aGroup)
7393
0
{
7394
0
  if (!mInnerWindow) {
7395
0
    NS_WARNING("No inner window available!");
7396
0
    return nullptr;
7397
0
  }
7398
0
  return GetCurrentInnerWindowInternal()->GetGroupMessageManager(aGroup);
7399
0
}
7400
7401
void
7402
nsPIDOMWindowOuter::SetOpenerForInitialContentBrowser(nsPIDOMWindowOuter* aOpenerWindow)
7403
0
{
7404
0
  MOZ_ASSERT(!mOpenerForInitialContentBrowser,
7405
0
             "Don't set OpenerForInitialContentBrowser twice!");
7406
0
  mOpenerForInitialContentBrowser = aOpenerWindow;
7407
0
}
7408
7409
already_AddRefed<nsPIDOMWindowOuter>
7410
nsPIDOMWindowOuter::TakeOpenerForInitialContentBrowser()
7411
0
{
7412
0
  // Intentionally forget our own member
7413
0
  return mOpenerForInitialContentBrowser.forget();
7414
0
}
7415
7416
void
7417
nsGlobalWindowOuter::InitWasOffline()
7418
0
{
7419
0
  mWasOffline = NS_IsOffline();
7420
0
}
7421
7422
#if defined(MOZ_WIDGET_ANDROID)
7423
int16_t
7424
nsGlobalWindowOuter::Orientation(CallerType aCallerType) const
7425
{
7426
  return nsContentUtils::ResistFingerprinting(aCallerType) ?
7427
           0 : WindowOrientationObserver::OrientationAngle();
7428
}
7429
#endif
7430
7431
void
7432
nsPIDOMWindowOuter::SetLargeAllocStatus(LargeAllocStatus aStatus)
7433
0
{
7434
0
  MOZ_ASSERT(mLargeAllocStatus == LargeAllocStatus::NONE);
7435
0
  mLargeAllocStatus = aStatus;
7436
0
}
7437
7438
bool
7439
nsPIDOMWindowOuter::IsTopLevelWindow()
7440
0
{
7441
0
  return nsGlobalWindowOuter::Cast(this)->IsTopLevelWindow();
7442
0
}
7443
7444
bool
7445
nsPIDOMWindowOuter::HadOriginalOpener() const
7446
0
{
7447
0
  return nsGlobalWindowOuter::Cast(this)->HadOriginalOpener();
7448
0
}
7449
7450
void
7451
nsGlobalWindowOuter::ReportLargeAllocStatus()
7452
0
{
7453
0
  uint32_t errorFlags = nsIScriptError::warningFlag;
7454
0
  const char* message = nullptr;
7455
0
7456
0
  switch (mLargeAllocStatus) {
7457
0
    case LargeAllocStatus::SUCCESS:
7458
0
      // Override the error flags such that the success message isn't reported
7459
0
      // as a warning.
7460
0
      errorFlags = nsIScriptError::infoFlag;
7461
0
      message = "LargeAllocationSuccess";
7462
0
      break;
7463
0
    case LargeAllocStatus::NON_WIN32:
7464
0
      errorFlags = nsIScriptError::infoFlag;
7465
0
      message = "LargeAllocationNonWin32";
7466
0
      break;
7467
0
    case LargeAllocStatus::NON_GET:
7468
0
      message = "LargeAllocationNonGetRequest";
7469
0
      break;
7470
0
    case LargeAllocStatus::NON_E10S:
7471
0
      message = "LargeAllocationNonE10S";
7472
0
      break;
7473
0
    case LargeAllocStatus::NOT_ONLY_TOPLEVEL_IN_TABGROUP:
7474
0
      message = "LargeAllocationNotOnlyToplevelInTabGroup";
7475
0
      break;
7476
0
    default: // LargeAllocStatus::NONE
7477
0
      return; // Don't report a message to the console
7478
0
  }
7479
0
7480
0
  nsContentUtils::ReportToConsole(errorFlags,
7481
0
                                  NS_LITERAL_CSTRING("DOM"),
7482
0
                                  mDoc,
7483
0
                                  nsContentUtils::eDOM_PROPERTIES,
7484
0
                                  message);
7485
0
}
7486
7487
#ifdef _WINDOWS_
7488
#error "Never include windows.h in this file!"
7489
#endif
7490
7491
// Helper called by methods that move/resize the window,
7492
// to ensure the presContext (if any) is aware of resolution
7493
// change that may happen in multi-monitor configuration.
7494
void
7495
nsGlobalWindowOuter::CheckForDPIChange()
7496
0
{
7497
0
  if (mDocShell) {
7498
0
    RefPtr<nsPresContext> presContext;
7499
0
    mDocShell->GetPresContext(getter_AddRefs(presContext));
7500
0
    if (presContext) {
7501
0
      if (presContext->DeviceContext()->CheckDPIChange()) {
7502
0
        presContext->UIResolutionChanged();
7503
0
      }
7504
0
    }
7505
0
  }
7506
0
}
7507
7508
mozilla::dom::TabGroup*
7509
nsGlobalWindowOuter::TabGroupOuter()
7510
0
{
7511
0
  // Outer windows lazily join TabGroups when requested. This is usually done
7512
0
  // because a document is getting its NodePrincipal, and asking for the
7513
0
  // TabGroup to determine its DocGroup.
7514
0
  if (!mTabGroup) {
7515
0
    // Get mOpener ourselves, instead of relying on GetOpenerWindowOuter,
7516
0
    // because that way we dodge the LegacyIsCallerChromeOrNativeCode() call
7517
0
    // which we want to return false.
7518
0
    nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
7519
0
    nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
7520
0
    nsPIDOMWindowOuter* parent = GetScriptableParentOrNull();
7521
0
    MOZ_ASSERT(!parent || !opener, "Only one of parent and opener may be provided");
7522
0
7523
0
    mozilla::dom::TabGroup* toJoin = nullptr;
7524
0
    if (GetDocShell()->ItemType() == nsIDocShellTreeItem::typeChrome) {
7525
0
      toJoin = TabGroup::GetChromeTabGroup();
7526
0
    } else if (opener) {
7527
0
      toJoin = opener->TabGroup();
7528
0
    } else if (parent) {
7529
0
      toJoin = parent->TabGroup();
7530
0
    } else {
7531
0
      toJoin = TabGroup::GetFromWindow(this);
7532
0
    }
7533
0
7534
#ifdef DEBUG
7535
    // Make sure that, if we have a tab group from the actor, it matches the one
7536
    // we're planning to join.
7537
    mozilla::dom::TabGroup* testGroup = TabGroup::GetFromWindow(this);
7538
    MOZ_ASSERT_IF(testGroup, testGroup == toJoin);
7539
#endif
7540
7541
0
    mTabGroup = mozilla::dom::TabGroup::Join(this, toJoin);
7542
0
  }
7543
0
  MOZ_ASSERT(mTabGroup);
7544
0
7545
#ifdef DEBUG
7546
  // Ensure that we don't recurse forever
7547
  if (!mIsValidatingTabGroup) {
7548
    mIsValidatingTabGroup = true;
7549
    // We only need to do this check if we aren't in the chrome tab group
7550
    if (mIsChrome) {
7551
      MOZ_ASSERT(mTabGroup == TabGroup::GetChromeTabGroup());
7552
    } else {
7553
      // Sanity check that our tabgroup matches our opener or parent.
7554
      RefPtr<nsPIDOMWindowOuter> parent = GetScriptableParentOrNull();
7555
      MOZ_ASSERT_IF(parent, parent->TabGroup() == mTabGroup);
7556
      nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
7557
      nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
7558
      MOZ_ASSERT_IF(opener && nsGlobalWindowOuter::Cast(opener) != this,
7559
                    opener->TabGroup() == mTabGroup);
7560
    }
7561
    mIsValidatingTabGroup = false;
7562
  }
7563
#endif
7564
7565
0
  return mTabGroup;
7566
0
}
7567
7568
nsresult
7569
nsGlobalWindowOuter::Dispatch(TaskCategory aCategory,
7570
                              already_AddRefed<nsIRunnable>&& aRunnable)
7571
0
{
7572
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
7573
0
  if (GetDocGroup()) {
7574
0
    return GetDocGroup()->Dispatch(aCategory, std::move(aRunnable));
7575
0
  }
7576
0
  return DispatcherTrait::Dispatch(aCategory, std::move(aRunnable));
7577
0
}
7578
7579
nsISerialEventTarget*
7580
nsGlobalWindowOuter::EventTargetFor(TaskCategory aCategory) const
7581
0
{
7582
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
7583
0
  if (GetDocGroup()) {
7584
0
    return GetDocGroup()->EventTargetFor(aCategory);
7585
0
  }
7586
0
  return DispatcherTrait::EventTargetFor(aCategory);
7587
0
}
7588
7589
AbstractThread*
7590
nsGlobalWindowOuter::AbstractMainThreadFor(TaskCategory aCategory)
7591
0
{
7592
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
7593
0
  if (GetDocGroup()) {
7594
0
    return GetDocGroup()->AbstractMainThreadFor(aCategory);
7595
0
  }
7596
0
  return DispatcherTrait::AbstractMainThreadFor(aCategory);
7597
0
}
7598
7599
nsGlobalWindowOuter::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
7600
  nsGlobalWindowOuter* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
7601
  : mSavedDialogsEnabled(false)
7602
0
{
7603
0
  MOZ_GUARD_OBJECT_NOTIFIER_INIT;
7604
0
7605
0
  MOZ_ASSERT(aWindow);
7606
0
  nsGlobalWindowOuter* topWindowOuter = aWindow->GetScriptableTopInternal();
7607
0
  if (!topWindowOuter) {
7608
0
    NS_ERROR("nsGlobalWindowOuter::TemporarilyDisableDialogs used without a top "
7609
0
             "window?");
7610
0
    return;
7611
0
  }
7612
0
7613
0
  // TODO: Warn if no top window?
7614
0
  nsGlobalWindowInner* topWindow =
7615
0
    topWindowOuter->GetCurrentInnerWindowInternal();
7616
0
  if (topWindow) {
7617
0
    mTopWindow = topWindow;
7618
0
    mSavedDialogsEnabled = mTopWindow->mAreDialogsEnabled;
7619
0
    mTopWindow->mAreDialogsEnabled = false;
7620
0
  }
7621
0
}
7622
7623
nsGlobalWindowOuter::TemporarilyDisableDialogs::~TemporarilyDisableDialogs()
7624
0
{
7625
0
  if (mTopWindow) {
7626
0
    mTopWindow->mAreDialogsEnabled = mSavedDialogsEnabled;
7627
0
  }
7628
0
}
7629
7630
mozilla::dom::TabGroup*
7631
nsPIDOMWindowOuter::TabGroup()
7632
0
{
7633
0
  return nsGlobalWindowOuter::Cast(this)->TabGroupOuter();
7634
0
}
7635
7636
/* static */ already_AddRefed<nsGlobalWindowOuter>
7637
nsGlobalWindowOuter::Create(bool aIsChrome)
7638
0
{
7639
0
  RefPtr<nsGlobalWindowOuter> window = new nsGlobalWindowOuter();
7640
0
  if (aIsChrome) {
7641
0
    window->mIsChrome = true;
7642
0
  }
7643
0
7644
0
  window->InitWasOffline();
7645
0
  return window.forget();
7646
0
}
7647
7648
nsIURI*
7649
nsPIDOMWindowOuter::GetDocumentURI() const
7650
0
{
7651
0
  return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
7652
0
}
7653
7654
7655
void
7656
nsPIDOMWindowOuter::MaybeCreateDoc()
7657
0
{
7658
0
  MOZ_ASSERT(!mDoc);
7659
0
  if (nsIDocShell* docShell = GetDocShell()) {
7660
0
    // Note that |document| here is the same thing as our mDoc, but we
7661
0
    // don't have to explicitly set the member variable because the docshell
7662
0
    // has already called SetNewDocument().
7663
0
    nsCOMPtr<nsIDocument> document = docShell->GetDocument();
7664
0
    Unused << document;
7665
0
  }
7666
0
}
7667
7668
void
7669
nsPIDOMWindowOuter::SetChromeEventHandlerInternal(EventTarget* aChromeEventHandler)
7670
0
{
7671
0
  // Out-of-line so we don't need to include ContentFrameMessageManager.h in
7672
0
  // nsPIDOMWindow.h.
7673
0
  mChromeEventHandler = aChromeEventHandler;
7674
0
7675
0
  // mParentTarget and mMessageManager will be set when the next event is
7676
0
  // dispatched or someone asks for our message manager.
7677
0
  mParentTarget = nullptr;
7678
0
  mMessageManager = nullptr;
7679
0
}
7680
7681
mozilla::dom::DocGroup*
7682
nsPIDOMWindowOuter::GetDocGroup() const
7683
0
{
7684
0
  nsIDocument* doc = GetExtantDoc();
7685
0
  if (doc) {
7686
0
    return doc->GetDocGroup();
7687
0
  }
7688
0
  return nullptr;
7689
0
}
7690
7691
// XXX: Can we define this in a header instead of here?
7692
namespace mozilla {
7693
namespace dom {
7694
extern uint64_t
7695
NextWindowID();
7696
} // namespace dom
7697
} // namespace mozilla
7698
7699
nsPIDOMWindowOuter::nsPIDOMWindowOuter()
7700
  : mFrameElement(nullptr)
7701
  , mDocShell(nullptr)
7702
  , mModalStateDepth(0)
7703
  , mIsActive(false)
7704
  , mIsBackground(false)
7705
  , mMediaSuspend(
7706
      Preferences::GetBool("media.block-autoplay-until-in-foreground", true)
7707
        ? nsISuspendedTypes::SUSPENDED_BLOCK
7708
        : nsISuspendedTypes::NONE_SUSPENDED)
7709
  , mAudioMuted(false)
7710
  , mAudioVolume(1.0)
7711
  , mDesktopModeViewport(false)
7712
  , mIsRootOuterWindow(false)
7713
  , mInnerWindow(nullptr)
7714
  ,
7715
  // Make sure no actual window ends up with mWindowID == 0
7716
  mWindowID(NextWindowID())
7717
  , mMarkedCCGeneration(0)
7718
  , mServiceWorkersTestingEnabled(false)
7719
  , mLargeAllocStatus(LargeAllocStatus::NONE)
7720
0
{
7721
0
}
7722
7723
0
nsPIDOMWindowOuter::~nsPIDOMWindowOuter() {}
7724
7725
nsAutoPopupStatePusherInternal::nsAutoPopupStatePusherInternal(PopupControlState aState, bool aForce)
7726
  : mOldState(nsContentUtils::PushPopupControlState(aState, aForce))
7727
0
{
7728
0
}
7729
7730
nsAutoPopupStatePusherInternal::~nsAutoPopupStatePusherInternal()
7731
0
{
7732
0
  nsContentUtils::PopPopupControlState(mOldState);
7733
0
}