Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpfe/appshell/nsAppShellService.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
7
#include "nsIAppShellService.h"
8
#include "nsIComponentManager.h"
9
#include "nsIURL.h"
10
#include "nsNetUtil.h"
11
#include "nsIServiceManager.h"
12
#include "nsIObserverService.h"
13
#include "nsIObserver.h"
14
#include "nsIXPConnect.h"
15
#include "nsIXULRuntime.h"
16
17
#include "nsIWindowMediator.h"
18
#include "nsIWindowWatcher.h"
19
#include "nsPIWindowWatcher.h"
20
#include "nsIDOMWindow.h"
21
#include "nsPIDOMWindow.h"
22
#include "nsWebShellWindow.h"
23
24
#include "nsWidgetInitData.h"
25
#include "nsWidgetsCID.h"
26
#include "nsIWidget.h"
27
#include "nsIRequestObserver.h"
28
#include "nsIEmbeddingSiteWindow.h"
29
30
#include "nsAppShellService.h"
31
#include "nsContentUtils.h"
32
#include "nsThreadUtils.h"
33
#include "nsISupportsPrimitives.h"
34
#include "nsILoadContext.h"
35
#include "nsIWebNavigation.h"
36
#include "nsIWindowlessBrowser.h"
37
38
#include "mozilla/Attributes.h"
39
#include "mozilla/Preferences.h"
40
#include "mozilla/Services.h"
41
#include "mozilla/StartupTimeline.h"
42
#include "mozilla/intl/LocaleService.h"
43
44
#include "nsEmbedCID.h"
45
#include "nsIWebBrowser.h"
46
#include "nsIDocShell.h"
47
#include "gfxPlatform.h"
48
49
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
50
#include "EventTracer.h"
51
#endif
52
53
using namespace mozilla;
54
using mozilla::intl::LocaleService;
55
56
// Default URL for the hidden window, can be overridden by a pref on Mac
57
0
#define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
58
59
class nsIAppShell;
60
61
nsAppShellService::nsAppShellService() :
62
  mXPCOMWillShutDown(false),
63
  mXPCOMShuttingDown(false),
64
  mModalWindowCount(0),
65
  mApplicationProvidedHiddenWindow(false),
66
  mScreenId(0)
67
0
{
68
0
  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
69
0
70
0
  if (obs) {
71
0
    obs->AddObserver(this, "xpcom-will-shutdown", false);
72
0
    obs->AddObserver(this, "xpcom-shutdown", false);
73
0
  }
74
0
}
75
76
nsAppShellService::~nsAppShellService()
77
0
{
78
0
}
79
80
81
/*
82
 * Implement the nsISupports methods...
83
 */
84
NS_IMPL_ISUPPORTS(nsAppShellService,
85
                  nsIAppShellService,
86
                  nsIObserver)
87
88
NS_IMETHODIMP
89
nsAppShellService::CreateHiddenWindow()
90
0
{
91
0
  return CreateHiddenWindowHelper(false);
92
0
}
93
94
NS_IMETHODIMP
95
nsAppShellService::SetScreenId(uint32_t aScreenId)
96
0
{
97
0
  mScreenId = aScreenId;
98
0
  return NS_OK;
99
0
}
100
101
void
102
nsAppShellService::EnsurePrivateHiddenWindow()
103
0
{
104
0
  if (!mHiddenPrivateWindow) {
105
0
    CreateHiddenWindowHelper(true);
106
0
  }
107
0
}
108
109
nsresult
110
nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate)
111
0
{
112
0
  nsresult rv;
113
0
  int32_t initialHeight = 100, initialWidth = 100;
114
0
115
#ifdef XP_MACOSX
116
  uint32_t    chromeMask = 0;
117
  nsAutoCString prefVal;
118
  rv = Preferences::GetCString("browser.hiddenWindowChromeURL", prefVal);
119
  const char* hiddenWindowURL =
120
    NS_SUCCEEDED(rv) ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL;
121
  if (aIsPrivate) {
122
    hiddenWindowURL = DEFAULT_HIDDENWINDOW_URL;
123
  } else {
124
    mApplicationProvidedHiddenWindow = prefVal.get() ? true : false;
125
  }
126
#else
127
0
  static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL;
128
0
  uint32_t    chromeMask =  nsIWebBrowserChrome::CHROME_ALL;
129
0
#endif
130
0
131
0
  nsCOMPtr<nsIURI> url;
132
0
  rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
133
0
  NS_ENSURE_SUCCESS(rv, rv);
134
0
135
0
  if (aIsPrivate) {
136
0
    chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
137
0
  }
138
0
139
0
  RefPtr<nsWebShellWindow> newWindow;
140
0
  rv = JustCreateTopWindow(nullptr, url,
141
0
                           chromeMask, initialWidth, initialHeight,
142
0
                           true, nullptr, nullptr, getter_AddRefs(newWindow));
143
0
  NS_ENSURE_SUCCESS(rv, rv);
144
0
145
0
  nsCOMPtr<nsIDocShell> docShell;
146
0
  newWindow->GetDocShell(getter_AddRefs(docShell));
147
0
  if (docShell) {
148
0
    docShell->SetIsActive(false);
149
0
    if (aIsPrivate) {
150
0
      docShell->SetAffectPrivateSessionLifetime(false);
151
0
    }
152
0
  }
153
0
154
0
  if (aIsPrivate) {
155
0
    mHiddenPrivateWindow.swap(newWindow);
156
0
  } else {
157
0
    mHiddenWindow.swap(newWindow);
158
0
  }
159
0
160
0
  return NS_OK;
161
0
}
162
163
NS_IMETHODIMP
164
nsAppShellService::DestroyHiddenWindow()
165
0
{
166
0
  if (mHiddenWindow) {
167
0
    mHiddenWindow->Destroy();
168
0
169
0
    mHiddenWindow = nullptr;
170
0
  }
171
0
172
0
  if (mHiddenPrivateWindow) {
173
0
    mHiddenPrivateWindow->Destroy();
174
0
175
0
    mHiddenPrivateWindow = nullptr;
176
0
  }
177
0
178
0
  return NS_OK;
179
0
}
180
181
/*
182
 * Create a new top level window and display the given URL within it...
183
 */
184
NS_IMETHODIMP
185
nsAppShellService::CreateTopLevelWindow(nsIXULWindow *aParent,
186
                                        nsIURI *aUrl,
187
                                        uint32_t aChromeMask,
188
                                        int32_t aInitialWidth,
189
                                        int32_t aInitialHeight,
190
                                        nsITabParent *aOpeningTab,
191
                                        mozIDOMWindowProxy *aOpenerWindow,
192
                                        nsIXULWindow **aResult)
193
194
0
{
195
0
  nsresult rv;
196
0
197
0
  StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW);
198
0
199
0
  RefPtr<nsWebShellWindow> newWindow;
200
0
  rv = JustCreateTopWindow(aParent, aUrl,
201
0
                           aChromeMask, aInitialWidth, aInitialHeight,
202
0
                           false, aOpeningTab, aOpenerWindow,
203
0
                           getter_AddRefs(newWindow));
204
0
  newWindow.forget(aResult);
205
0
206
0
  if (NS_SUCCEEDED(rv)) {
207
0
    // the addref resulting from this is the owning addref for this window
208
0
    RegisterTopLevelWindow(*aResult);
209
0
    nsCOMPtr<nsIXULWindow> parent;
210
0
    if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
211
0
      parent = aParent;
212
0
    (*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask));
213
0
  }
214
0
215
0
  return rv;
216
0
}
217
218
/*
219
 * This class provides a stub implementation of nsIWebBrowserChrome2, as needed
220
 * by nsAppShellService::CreateWindowlessBrowser
221
 */
222
class WebBrowserChrome2Stub : public nsIWebBrowserChrome2,
223
                              public nsIEmbeddingSiteWindow,
224
                              public nsIInterfaceRequestor,
225
                              public nsSupportsWeakReference {
226
protected:
227
    nsCOMPtr<nsIWebBrowser> mBrowser;
228
0
    virtual ~WebBrowserChrome2Stub() {}
229
public:
230
0
    explicit WebBrowserChrome2Stub(nsIWebBrowser *aBrowser) : mBrowser(aBrowser) {}
231
    NS_DECL_ISUPPORTS
232
    NS_DECL_NSIWEBBROWSERCHROME
233
    NS_DECL_NSIWEBBROWSERCHROME2
234
    NS_DECL_NSIINTERFACEREQUESTOR
235
    NS_DECL_NSIEMBEDDINGSITEWINDOW
236
};
237
238
0
NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub)
239
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
240
0
  NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
241
0
  NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
242
0
  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
243
0
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
244
0
  NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
245
0
NS_INTERFACE_MAP_END
246
247
NS_IMPL_ADDREF(WebBrowserChrome2Stub)
248
NS_IMPL_RELEASE(WebBrowserChrome2Stub)
249
250
NS_IMETHODIMP
251
WebBrowserChrome2Stub::SetStatus(uint32_t aStatusType, const char16_t* aStatus)
252
0
{
253
0
  return NS_OK;
254
0
}
255
256
NS_IMETHODIMP
257
WebBrowserChrome2Stub::GetWebBrowser(nsIWebBrowser** aWebBrowser)
258
0
{
259
0
  MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::GetWebBrowser is "
260
0
                         "not supported");
261
0
  return NS_ERROR_NOT_IMPLEMENTED;
262
0
}
263
264
NS_IMETHODIMP
265
WebBrowserChrome2Stub::SetWebBrowser(nsIWebBrowser* aWebBrowser)
266
0
{
267
0
  MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::SetWebBrowser is "
268
0
                         "not supported");
269
0
  return NS_ERROR_NOT_IMPLEMENTED;
270
0
}
271
272
NS_IMETHODIMP
273
WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags)
274
0
{
275
0
  *aChromeFlags = 0;
276
0
  return NS_OK;
277
0
}
278
279
NS_IMETHODIMP
280
WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags)
281
0
{
282
0
  MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::SetChromeFlags is "
283
0
                         "not supported");
284
0
  return NS_ERROR_NOT_IMPLEMENTED;
285
0
}
286
287
NS_IMETHODIMP
288
WebBrowserChrome2Stub::DestroyBrowserWindow()
289
0
{
290
0
  MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::DestroyBrowserWindow is "
291
0
                         "not supported");
292
0
  return NS_ERROR_NOT_IMPLEMENTED;
293
0
}
294
295
NS_IMETHODIMP
296
WebBrowserChrome2Stub::SizeBrowserTo(int32_t aCX, int32_t aCY)
297
0
{
298
0
  MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::SizeBrowserTo is "
299
0
                         "not supported");
300
0
  return NS_ERROR_NOT_IMPLEMENTED;
301
0
}
302
303
NS_IMETHODIMP
304
WebBrowserChrome2Stub::ShowAsModal()
305
0
{
306
0
  MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::ShowAsModal is not supported");
307
0
  return NS_ERROR_NOT_IMPLEMENTED;
308
0
}
309
310
NS_IMETHODIMP
311
WebBrowserChrome2Stub::IsWindowModal(bool* aResult)
312
0
{
313
0
  *aResult = false;
314
0
  return NS_OK;
315
0
}
316
317
NS_IMETHODIMP
318
WebBrowserChrome2Stub::ExitModalEventLoop(nsresult aStatus)
319
0
{
320
0
  MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::ExitModalEventLoop is "
321
0
                         "not supported");
322
0
  return NS_ERROR_NOT_IMPLEMENTED;
323
0
}
324
325
NS_IMETHODIMP
326
WebBrowserChrome2Stub::SetStatusWithContext(uint32_t aStatusType,
327
                                            const nsAString& aStatusText,
328
                                            nsISupports* aStatusContext)
329
0
{
330
0
  return NS_OK;
331
0
}
332
333
NS_IMETHODIMP
334
WebBrowserChrome2Stub::GetInterface(const nsIID& aIID, void** aSink)
335
0
{
336
0
    return QueryInterface(aIID, aSink);
337
0
}
338
339
// nsIEmbeddingSiteWindow impl
340
NS_IMETHODIMP
341
WebBrowserChrome2Stub::GetDimensions(uint32_t flags, int32_t* x, int32_t* y, int32_t* cx, int32_t* cy)
342
0
{
343
0
  if (x) {
344
0
    *x = 0;
345
0
  }
346
0
347
0
  if (y) {
348
0
    *y = 0;
349
0
  }
350
0
351
0
  if (cx) {
352
0
    *cx = 0;
353
0
  }
354
0
355
0
  if (cy) {
356
0
    *cy = 0;
357
0
  }
358
0
359
0
  return NS_OK;
360
0
}
361
362
NS_IMETHODIMP
363
WebBrowserChrome2Stub::SetDimensions(uint32_t flags, int32_t x, int32_t y, int32_t cx, int32_t cy)
364
0
{
365
0
  nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(mBrowser);
366
0
  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
367
0
  window->SetSize(cx, cy, true);
368
0
  return NS_OK;
369
0
}
370
371
NS_IMETHODIMP
372
WebBrowserChrome2Stub::SetFocus()
373
0
{
374
0
  return NS_ERROR_NOT_IMPLEMENTED;
375
0
}
376
377
NS_IMETHODIMP
378
WebBrowserChrome2Stub::GetVisibility(bool* aVisibility)
379
0
{
380
0
  return NS_ERROR_NOT_IMPLEMENTED;
381
0
}
382
NS_IMETHODIMP
383
WebBrowserChrome2Stub::SetVisibility(bool aVisibility)
384
0
{
385
0
  return NS_ERROR_NOT_IMPLEMENTED;
386
0
}
387
388
NS_IMETHODIMP
389
WebBrowserChrome2Stub::GetTitle(nsAString& aTitle)
390
0
{
391
0
  return NS_ERROR_NOT_IMPLEMENTED;
392
0
}
393
NS_IMETHODIMP
394
WebBrowserChrome2Stub::SetTitle(const nsAString& aTitle)
395
0
{
396
0
  return NS_ERROR_NOT_IMPLEMENTED;
397
0
}
398
399
NS_IMETHODIMP
400
WebBrowserChrome2Stub::GetSiteWindow(void** aSiteWindow)
401
0
{
402
0
  return NS_ERROR_NOT_IMPLEMENTED;
403
0
}
404
405
NS_IMETHODIMP
406
WebBrowserChrome2Stub::Blur()
407
0
{
408
0
  return NS_ERROR_NOT_IMPLEMENTED;
409
0
}
410
411
class BrowserDestroyer final : public Runnable
412
{
413
public:
414
  BrowserDestroyer(nsIWebBrowser* aBrowser, nsISupports* aContainer)
415
    : mozilla::Runnable("BrowserDestroyer")
416
    , mBrowser(aBrowser)
417
    , mContainer(aContainer)
418
0
  {
419
0
  }
420
421
  NS_IMETHOD
422
  Run() override
423
0
  {
424
0
    // Explicitly destroy the browser, in case this isn't the last reference.
425
0
    nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(mBrowser);
426
0
    return window->Destroy();
427
0
  }
428
429
protected:
430
0
  virtual ~BrowserDestroyer() {}
431
432
private:
433
  nsCOMPtr<nsIWebBrowser> mBrowser;
434
  nsCOMPtr<nsISupports> mContainer;
435
};
436
437
// This is the "stub" we return from CreateWindowlessBrowser - it exists
438
// to manage the lifetimes of the nsIWebBrowser and container window.
439
// In particular, it keeps a strong reference to both, to prevent them from
440
// being collected while this object remains alive, and ensures that they
441
// aren't destroyed when it's not safe to run scripts.
442
class WindowlessBrowser final : public nsIWindowlessBrowser,
443
                                public nsIInterfaceRequestor
444
{
445
public:
446
  WindowlessBrowser(nsIWebBrowser *aBrowser, nsISupports *aContainer) :
447
    mBrowser(aBrowser),
448
    mContainer(aContainer),
449
    mClosed(false)
450
0
  {
451
0
    mWebNavigation = do_QueryInterface(aBrowser);
452
0
    mInterfaceRequestor = do_QueryInterface(aBrowser);
453
0
  }
454
  NS_DECL_ISUPPORTS
455
  NS_DECL_NSIWINDOWLESSBROWSER
456
  NS_FORWARD_SAFE_NSIWEBNAVIGATION(mWebNavigation)
457
  NS_FORWARD_SAFE_NSIINTERFACEREQUESTOR(mInterfaceRequestor)
458
459
protected:
460
  virtual ~WindowlessBrowser()
461
0
  {
462
0
    if (mClosed) {
463
0
      return;
464
0
    }
465
0
466
0
    NS_WARNING("Windowless browser was not closed prior to destruction");
467
0
468
0
    // The docshell destructor needs to dispatch events, and can only run
469
0
    // when it's safe to run scripts. If this was triggered by GC, it may
470
0
    // not always be safe to run scripts, in which cases we need to delay
471
0
    // destruction until it is.
472
0
    nsCOMPtr<nsIRunnable> runnable = new BrowserDestroyer(mBrowser, mContainer);
473
0
    nsContentUtils::AddScriptRunner(runnable);
474
0
  }
475
476
private:
477
  nsCOMPtr<nsIWebBrowser> mBrowser;
478
  nsCOMPtr<nsIWebNavigation> mWebNavigation;
479
  nsCOMPtr<nsIInterfaceRequestor> mInterfaceRequestor;
480
  // we don't use the container but just hold a reference to it.
481
  nsCOMPtr<nsISupports> mContainer;
482
483
  bool mClosed;
484
};
485
486
NS_IMPL_ISUPPORTS(WindowlessBrowser, nsIWindowlessBrowser, nsIWebNavigation, nsIInterfaceRequestor)
487
488
NS_IMETHODIMP
489
WindowlessBrowser::Close()
490
0
{
491
0
  NS_ENSURE_TRUE(!mClosed, NS_ERROR_UNEXPECTED);
492
0
  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
493
0
               "WindowlessBrowser::Close called when not safe to run scripts");
494
0
495
0
  mClosed = true;
496
0
497
0
  mWebNavigation = nullptr;
498
0
  mInterfaceRequestor = nullptr;
499
0
500
0
  nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(mBrowser);
501
0
  return window->Destroy();
502
0
}
503
504
NS_IMETHODIMP
505
WindowlessBrowser::GetDocShell(nsIDocShell** aDocShell)
506
0
{
507
0
  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mInterfaceRequestor);
508
0
  if (!docShell) {
509
0
    return NS_ERROR_NOT_INITIALIZED;
510
0
  }
511
0
  docShell.forget(aDocShell);
512
0
  return NS_OK;
513
0
}
514
515
516
NS_IMETHODIMP
517
nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWindowlessBrowser **aResult)
518
0
{
519
0
  /* First, we create an instance of nsWebBrowser. Instances of this class have
520
0
   * an associated doc shell, which is what we're interested in.
521
0
   */
522
0
  nsCOMPtr<nsIWebBrowser> browser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
523
0
  if (!browser) {
524
0
    NS_ERROR("Couldn't create instance of nsWebBrowser!");
525
0
    return NS_ERROR_FAILURE;
526
0
  }
527
0
528
0
  /* Next, we set the container window for our instance of nsWebBrowser. Since
529
0
   * we don't actually have a window, we instead set the container window to be
530
0
   * an instance of WebBrowserChrome2Stub, which provides a stub implementation
531
0
   * of nsIWebBrowserChrome2.
532
0
   */
533
0
  RefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub(browser);
534
0
  browser->SetContainerWindow(stub);
535
0
536
0
  nsCOMPtr<nsIWebNavigation> navigation = do_QueryInterface(browser);
537
0
538
0
  nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(navigation);
539
0
  item->SetItemType(aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
540
0
                              : nsIDocShellTreeItem::typeContentWrapper);
541
0
542
0
  /* A windowless web browser doesn't have an associated OS level window. To
543
0
   * accomplish this, we initialize the window associated with our instance of
544
0
   * nsWebBrowser with an instance of HeadlessWidget/PuppetWidget, which provide
545
0
   * a stub implementation of nsIWidget.
546
0
   */
547
0
  nsCOMPtr<nsIWidget> widget;
548
0
  if (gfxPlatform::IsHeadless()) {
549
0
    widget = nsIWidget::CreateHeadlessWidget();
550
0
  } else {
551
0
    widget = nsIWidget::CreatePuppetWidget(nullptr);
552
0
  }
553
0
  if (!widget) {
554
0
    NS_ERROR("Couldn't create instance of stub widget");
555
0
    return NS_ERROR_FAILURE;
556
0
  }
557
0
  nsresult rv =
558
0
    widget->Create(nullptr, 0, LayoutDeviceIntRect(0, 0, 0, 0), nullptr);
559
0
  NS_ENSURE_SUCCESS(rv, rv);
560
0
  nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(navigation);
561
0
  window->InitWindow(0, widget, 0, 0, 0, 0);
562
0
  window->Create();
563
0
564
0
  nsISupports *isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome2*, stub);
565
0
  RefPtr<nsIWindowlessBrowser> result = new WindowlessBrowser(browser, isstub);
566
0
  nsCOMPtr<nsIDocShell> docshell = do_GetInterface(result);
567
0
  docshell->SetInvisible(true);
568
0
569
0
  result.forget(aResult);
570
0
  return NS_OK;
571
0
}
572
573
uint32_t
574
nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent,
575
                                         uint32_t      aChromeMask)
576
0
{
577
0
  uint32_t zLevel;
578
0
579
0
  zLevel = nsIXULWindow::normalZ;
580
0
  if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
581
0
    zLevel = nsIXULWindow::raisedZ;
582
0
  else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
583
0
    zLevel = nsIXULWindow::loweredZ;
584
0
585
#ifdef XP_MACOSX
586
  /* Platforms on which modal windows are always application-modal, not
587
     window-modal (that's just the Mac, right?) want modal windows to
588
     be stacked on top of everyone else.
589
590
     On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
591
  */
592
  uint32_t modalDepMask = nsIWebBrowserChrome::CHROME_MODAL |
593
                          nsIWebBrowserChrome::CHROME_DEPENDENT;
594
  if (aParent && (aChromeMask & modalDepMask)) {
595
    aParent->GetZLevel(&zLevel);
596
  }
597
#else
598
  /* Platforms with native support for dependent windows (that's everyone
599
0
      but pre-Mac OS X, right?) know how to stack dependent windows. On these
600
0
      platforms, give the dependent window the same level as its parent,
601
0
      so we won't try to override the normal platform behaviour. */
602
0
  if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent)
603
0
    aParent->GetZLevel(&zLevel);
604
0
#endif
605
0
606
0
  return zLevel;
607
0
}
608
609
#ifdef XP_WIN
610
/*
611
 * Checks to see if any existing window is currently in fullscreen mode.
612
 */
613
static bool
614
CheckForFullscreenWindow()
615
{
616
  nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
617
  if (!wm)
618
    return false;
619
620
  nsCOMPtr<nsISimpleEnumerator> windowList;
621
  wm->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList));
622
  if (!windowList)
623
    return false;
624
625
  for (;;) {
626
    bool more = false;
627
    windowList->HasMoreElements(&more);
628
    if (!more)
629
      return false;
630
631
    nsCOMPtr<nsISupports> supportsWindow;
632
    windowList->GetNext(getter_AddRefs(supportsWindow));
633
    nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
634
    if (baseWin) {
635
      nsCOMPtr<nsIWidget> widget;
636
      baseWin->GetMainWidget(getter_AddRefs(widget));
637
      if (widget && widget->SizeMode() == nsSizeMode_Fullscreen) {
638
        return true;
639
      }
640
    }
641
  }
642
  return false;
643
}
644
#endif
645
646
/*
647
 * Just do the window-making part of CreateTopLevelWindow
648
 */
649
nsresult
650
nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent,
651
                                       nsIURI *aUrl,
652
                                       uint32_t aChromeMask,
653
                                       int32_t aInitialWidth,
654
                                       int32_t aInitialHeight,
655
                                       bool aIsHiddenWindow,
656
                                       nsITabParent *aOpeningTab,
657
                                       mozIDOMWindowProxy *aOpenerWindow,
658
                                       nsWebShellWindow **aResult)
659
0
{
660
0
  *aResult = nullptr;
661
0
  NS_ENSURE_STATE(!mXPCOMWillShutDown);
662
0
663
0
  nsCOMPtr<nsIXULWindow> parent;
664
0
  if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
665
0
    parent = aParent;
666
0
667
0
  RefPtr<nsWebShellWindow> window = new nsWebShellWindow(aChromeMask);
668
0
669
#ifdef XP_WIN
670
  // If the parent is currently fullscreen, tell the child to ignore persisted
671
  // full screen states. This way new browser windows open on top of fullscreen
672
  // windows normally.
673
  if (window && CheckForFullscreenWindow())
674
    window->IgnoreXULSizeMode(true);
675
#endif
676
677
0
  nsWidgetInitData widgetInitData;
678
0
679
0
  if (aIsHiddenWindow)
680
0
    widgetInitData.mWindowType = eWindowType_invisible;
681
0
  else
682
0
    widgetInitData.mWindowType = aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG ?
683
0
      eWindowType_dialog : eWindowType_toplevel;
684
0
685
0
  if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)
686
0
    widgetInitData.mWindowType = eWindowType_popup;
687
0
688
0
  if (aChromeMask & nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION)
689
0
    widgetInitData.mIsAnimationSuppressed = true;
690
0
691
#ifdef XP_MACOSX
692
  // Mac OS X sheet support
693
  // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from
694
  // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal
695
  // windows opened from nsPromptService::DoDialog() still are sheets.  This
696
  // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and
697
  // nsCocoaWindow::SetModal()).
698
  uint32_t sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
699
                       nsIWebBrowserChrome::CHROME_MODAL |
700
                       nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
701
  if (parent &&
702
      (parent != mHiddenWindow && parent != mHiddenPrivateWindow) &&
703
      ((aChromeMask & sheetMask) == sheetMask)) {
704
    widgetInitData.mWindowType = eWindowType_sheet;
705
  }
706
#endif
707
708
#if defined(XP_WIN)
709
  if (widgetInitData.mWindowType == eWindowType_toplevel ||
710
      widgetInitData.mWindowType == eWindowType_dialog)
711
    widgetInitData.clipChildren = true;
712
#endif
713
714
0
  // note default chrome overrides other OS chrome settings, but
715
0
  // not internal chrome
716
0
  if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT)
717
0
    widgetInitData.mBorderStyle = eBorderStyle_default;
718
0
  else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL)
719
0
    widgetInitData.mBorderStyle = eBorderStyle_all;
720
0
  else {
721
0
    widgetInitData.mBorderStyle = eBorderStyle_none; // assumes none == 0x00
722
0
    if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS)
723
0
      widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_border);
724
0
    if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR)
725
0
      widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_title);
726
0
    if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE)
727
0
      widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_close);
728
0
    if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
729
0
      widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_resizeh);
730
0
      // only resizable windows get the maximize button (but not dialogs)
731
0
      if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
732
0
        widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_maximize);
733
0
    }
734
0
    // all windows (except dialogs) get minimize buttons and the system menu
735
0
    if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
736
0
      widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize | eBorderStyle_menu);
737
0
    // but anyone can explicitly ask for a minimize button
738
0
    if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MIN) {
739
0
      widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize);
740
0
    }
741
0
  }
742
0
743
0
  if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
744
0
      aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
745
0
    aInitialWidth = 1;
746
0
    aInitialHeight = 1;
747
0
    window->SetIntrinsicallySized(true);
748
0
  }
749
0
750
0
  bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
751
0
752
0
  widgetInitData.mRTL = LocaleService::GetInstance()->IsAppLocaleRTL();
753
0
754
0
  nsresult rv = window->Initialize(parent, center ? aParent : nullptr,
755
0
                                   aUrl, aInitialWidth, aInitialHeight,
756
0
                                   aIsHiddenWindow, aOpeningTab,
757
0
                                   aOpenerWindow, widgetInitData);
758
0
759
0
  NS_ENSURE_SUCCESS(rv, rv);
760
0
761
0
  // Enforce the Private Browsing autoStart pref first.
762
0
  bool isPrivateBrowsingWindow =
763
0
    Preferences::GetBool("browser.privatebrowsing.autostart");
764
0
  bool isUsingRemoteTabs = mozilla::BrowserTabsRemoteAutostart();
765
0
766
0
  if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
767
0
    // Caller requested a private window
768
0
    isPrivateBrowsingWindow = true;
769
0
  }
770
0
  if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
771
0
    isUsingRemoteTabs = true;
772
0
  }
773
0
774
0
  nsCOMPtr<mozIDOMWindowProxy> domWin = do_GetInterface(aParent);
775
0
  nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(domWin);
776
0
  nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(webNav);
777
0
778
0
  if (!isPrivateBrowsingWindow && parentContext) {
779
0
    // Ensure that we propagate any existing private browsing status
780
0
    // from the parent, even if it will not actually be used
781
0
    // as a parent value.
782
0
    isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
783
0
  }
784
0
785
0
  if (parentContext) {
786
0
    isUsingRemoteTabs = parentContext->UseRemoteTabs();
787
0
  }
788
0
789
0
  nsCOMPtr<mozIDOMWindowProxy> newDomWin =
790
0
      do_GetInterface(NS_ISUPPORTS_CAST(nsIBaseWindow*, window));
791
0
  nsCOMPtr<nsIWebNavigation> newWebNav = do_GetInterface(newDomWin);
792
0
  nsCOMPtr<nsILoadContext> thisContext = do_GetInterface(newWebNav);
793
0
  if (thisContext) {
794
0
    thisContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
795
0
    thisContext->SetRemoteTabs(isUsingRemoteTabs);
796
0
  }
797
0
798
0
  window.forget(aResult);
799
0
  if (parent)
800
0
    parent->AddChildWindow(*aResult);
801
0
802
0
  if (center)
803
0
    rv = (*aResult)->Center(parent, parent ? false : true, false);
804
0
805
0
  return rv;
806
0
}
807
808
NS_IMETHODIMP
809
nsAppShellService::GetHiddenWindow(nsIXULWindow **aWindow)
810
0
{
811
0
  NS_ENSURE_ARG_POINTER(aWindow);
812
0
813
0
  *aWindow = mHiddenWindow;
814
0
  NS_IF_ADDREF(*aWindow);
815
0
  return *aWindow ? NS_OK : NS_ERROR_FAILURE;
816
0
}
817
818
NS_IMETHODIMP
819
nsAppShellService::GetHiddenDOMWindow(mozIDOMWindowProxy **aWindow)
820
0
{
821
0
  nsresult rv;
822
0
  nsCOMPtr<nsIDocShell> docShell;
823
0
  NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
824
0
825
0
  rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
826
0
  NS_ENSURE_SUCCESS(rv, rv);
827
0
  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
828
0
829
0
  nsCOMPtr<nsPIDOMWindowOuter> hiddenDOMWindow(docShell->GetWindow());
830
0
  hiddenDOMWindow.forget(aWindow);
831
0
  return *aWindow ? NS_OK : NS_ERROR_FAILURE;
832
0
}
833
834
NS_IMETHODIMP
835
nsAppShellService::GetHiddenPrivateWindow(nsIXULWindow **aWindow)
836
0
{
837
0
  NS_ENSURE_ARG_POINTER(aWindow);
838
0
839
0
  EnsurePrivateHiddenWindow();
840
0
841
0
  *aWindow = mHiddenPrivateWindow;
842
0
  NS_IF_ADDREF(*aWindow);
843
0
  return *aWindow ? NS_OK : NS_ERROR_FAILURE;
844
0
}
845
846
NS_IMETHODIMP
847
nsAppShellService::GetHiddenPrivateDOMWindow(mozIDOMWindowProxy **aWindow)
848
0
{
849
0
  EnsurePrivateHiddenWindow();
850
0
851
0
  nsresult rv;
852
0
  nsCOMPtr<nsIDocShell> docShell;
853
0
  NS_ENSURE_TRUE(mHiddenPrivateWindow, NS_ERROR_FAILURE);
854
0
855
0
  rv = mHiddenPrivateWindow->GetDocShell(getter_AddRefs(docShell));
856
0
  NS_ENSURE_SUCCESS(rv, rv);
857
0
  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
858
0
859
0
  nsCOMPtr<nsPIDOMWindowOuter> hiddenPrivateDOMWindow(docShell->GetWindow());
860
0
  hiddenPrivateDOMWindow.forget(aWindow);
861
0
  return *aWindow ? NS_OK : NS_ERROR_FAILURE;
862
0
}
863
864
NS_IMETHODIMP
865
nsAppShellService::GetHasHiddenPrivateWindow(bool* aHasPrivateWindow)
866
0
{
867
0
  NS_ENSURE_ARG_POINTER(aHasPrivateWindow);
868
0
869
0
  *aHasPrivateWindow = !!mHiddenPrivateWindow;
870
0
  return NS_OK;
871
0
}
872
873
NS_IMETHODIMP
874
nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW)
875
0
{
876
0
    *aAPHW = mApplicationProvidedHiddenWindow;
877
0
    return NS_OK;
878
0
}
879
880
/*
881
 * Register a new top level window (created elsewhere)
882
 */
883
NS_IMETHODIMP
884
nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
885
0
{
886
0
  NS_ENSURE_ARG_POINTER(aWindow);
887
0
888
0
  nsCOMPtr<nsIDocShell> docShell;
889
0
  aWindow->GetDocShell(getter_AddRefs(docShell));
890
0
  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
891
0
892
0
  nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
893
0
  NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
894
0
  domWindow->SetInitialPrincipalToSubject();
895
0
896
0
  // tell the window mediator about the new window
897
0
  nsCOMPtr<nsIWindowMediator> mediator
898
0
    ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
899
0
  NS_ASSERTION(mediator, "Couldn't get window mediator.");
900
0
901
0
  if (mediator)
902
0
    mediator->RegisterWindow(aWindow);
903
0
904
0
  // tell the window watcher about the new window
905
0
  nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
906
0
  NS_ASSERTION(wwatcher, "No windowwatcher?");
907
0
  if (wwatcher && domWindow) {
908
0
    wwatcher->AddWindow(domWindow, 0);
909
0
  }
910
0
911
0
  // an ongoing attempt to quit is stopped by a newly opened window
912
0
  nsCOMPtr<nsIObserverService> obssvc = services::GetObserverService();
913
0
  NS_ASSERTION(obssvc, "Couldn't get observer service.");
914
0
915
0
  if (obssvc) {
916
0
    obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr);
917
0
    nsXULWindow* xulWindow = static_cast<nsXULWindow*>(aWindow);
918
0
    xulWindow->WasRegistered();
919
0
  }
920
0
921
0
  return NS_OK;
922
0
}
923
924
925
NS_IMETHODIMP
926
nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow)
927
0
{
928
0
  if (mXPCOMShuttingDown) {
929
0
    /* return an error code in order to:
930
0
       - avoid doing anything with other member variables while we are in
931
0
         the destructor
932
0
       - notify the caller not to release the AppShellService after
933
0
         unregistering the window
934
0
         (we don't want to be deleted twice consecutively to
935
0
         mHiddenWindow->Destroy() in our destructor)
936
0
    */
937
0
    return NS_ERROR_FAILURE;
938
0
  }
939
0
940
0
  NS_ENSURE_ARG_POINTER(aWindow);
941
0
942
0
  if (aWindow == mHiddenWindow) {
943
0
    // CreateHiddenWindow() does not register the window, so we're done.
944
0
    return NS_OK;
945
0
  }
946
0
  if (aWindow == mHiddenPrivateWindow) {
947
0
    // CreateHiddenWindow() does not register the window, so we're done.
948
0
    return NS_OK;
949
0
  }
950
0
951
0
  // tell the window mediator
952
0
  nsCOMPtr<nsIWindowMediator> mediator
953
0
    ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
954
0
  NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
955
0
956
0
  if (mediator)
957
0
    mediator->UnregisterWindow(aWindow);
958
0
959
0
  // tell the window watcher
960
0
  nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
961
0
  NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
962
0
  if (wwatcher) {
963
0
    nsCOMPtr<nsIDocShell> docShell;
964
0
    aWindow->GetDocShell(getter_AddRefs(docShell));
965
0
    if (docShell) {
966
0
      nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
967
0
      if (domWindow)
968
0
        wwatcher->RemoveWindow(domWindow);
969
0
    }
970
0
  }
971
0
972
0
  return NS_OK;
973
0
}
974
975
976
NS_IMETHODIMP
977
nsAppShellService::Observe(nsISupports* aSubject, const char *aTopic,
978
                           const char16_t *aData)
979
0
{
980
0
  if (!strcmp(aTopic, "xpcom-will-shutdown")) {
981
0
    mXPCOMWillShutDown = true;
982
0
  } else if (!strcmp(aTopic, "xpcom-shutdown")) {
983
0
    mXPCOMShuttingDown = true;
984
0
    if (mHiddenWindow) {
985
0
      mHiddenWindow->Destroy();
986
0
    }
987
0
    if (mHiddenPrivateWindow) {
988
0
      mHiddenPrivateWindow->Destroy();
989
0
    }
990
0
  } else {
991
0
    NS_ERROR("Unexpected observer topic!");
992
0
  }
993
0
994
0
  return NS_OK;
995
0
}
996
997
NS_IMETHODIMP
998
nsAppShellService::StartEventLoopLagTracking(bool* aResult)
999
0
{
1000
0
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
1001
0
    *aResult = mozilla::InitEventTracing(true);
1002
0
#endif
1003
0
    return NS_OK;
1004
0
}
1005
1006
NS_IMETHODIMP
1007
nsAppShellService::StopEventLoopLagTracking()
1008
0
{
1009
0
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
1010
0
    mozilla::ShutdownEventTracing();
1011
0
#endif
1012
0
    return NS_OK;
1013
0
}