Bug 1747279 [wpt PR 32174] - Make Transform::TransformRRectF tolerate values within...
[gecko.git] / xpfe / appshell / nsAppShellService.cpp
blob71a9266caaf72ef4a05978a9774de868b38795fd
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/. */
6 #include "nsIAppShellService.h"
7 #include "nsNetUtil.h"
8 #include "nsIObserverService.h"
9 #include "nsIObserver.h"
10 #include "nsIXULRuntime.h"
12 #include "nsIWindowMediator.h"
13 #include "nsPIWindowWatcher.h"
14 #include "nsPIDOMWindow.h"
15 #include "AppWindow.h"
17 #include "nsWidgetInitData.h"
18 #include "nsWidgetsCID.h"
19 #include "nsIWidget.h"
20 #include "nsIEmbeddingSiteWindow.h"
22 #include "nsAppDirectoryServiceDefs.h"
23 #include "nsAppShellService.h"
24 #include "nsContentUtils.h"
25 #include "nsDirectoryServiceUtils.h"
26 #include "nsThreadUtils.h"
27 #include "nsILoadContext.h"
28 #include "nsIWebNavigation.h"
29 #include "nsIWindowlessBrowser.h"
31 #include "mozilla/Attributes.h"
32 #include "mozilla/Preferences.h"
33 #include "mozilla/Services.h"
34 #include "mozilla/StartupTimeline.h"
35 #include "mozilla/StaticPrefs_fission.h"
36 #include "mozilla/intl/LocaleService.h"
37 #include "mozilla/dom/BrowsingContext.h"
39 #include "nsEmbedCID.h"
40 #include "nsIWebBrowser.h"
41 #include "nsIDocShell.h"
42 #include "gfxPlatform.h"
44 #include "nsWebBrowser.h"
45 #include "nsDocShell.h"
46 #include "nsDocShellLoadState.h"
48 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
49 # include "EventTracer.h"
50 #endif
52 using namespace mozilla;
53 using mozilla::dom::BrowsingContext;
54 using mozilla::intl::LocaleService;
56 // Default URL for the hidden window, can be overridden by a pref on Mac
57 #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
59 class nsIAppShell;
61 nsAppShellService::nsAppShellService()
62 : mXPCOMWillShutDown(false),
63 mXPCOMShuttingDown(false),
64 mModalWindowCount(0),
65 mApplicationProvidedHiddenWindow(false),
66 mScreenId(0) {
67 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
69 if (obs) {
70 obs->AddObserver(this, "xpcom-will-shutdown", false);
71 obs->AddObserver(this, "xpcom-shutdown", false);
75 nsAppShellService::~nsAppShellService() {}
78 * Implement the nsISupports methods...
80 NS_IMPL_ISUPPORTS(nsAppShellService, nsIAppShellService, nsIObserver)
82 NS_IMETHODIMP
83 nsAppShellService::SetScreenId(uint32_t aScreenId) {
84 mScreenId = aScreenId;
85 return NS_OK;
88 void nsAppShellService::EnsureHiddenWindow() {
89 if (!mHiddenWindow) {
90 (void)CreateHiddenWindow();
94 NS_IMETHODIMP
95 nsAppShellService::CreateHiddenWindow() {
96 if (!XRE_IsParentProcess()) {
97 return NS_ERROR_NOT_IMPLEMENTED;
100 if (mXPCOMShuttingDown) {
101 return NS_ERROR_FAILURE;
104 if (mHiddenWindow) {
105 return NS_OK;
108 nsCOMPtr<nsIFile> profileDir;
109 NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
110 getter_AddRefs(profileDir));
111 if (!profileDir) {
112 // This is too early on startup to create the hidden window
113 return NS_ERROR_FAILURE;
116 nsresult rv;
117 int32_t initialHeight = 100, initialWidth = 100;
119 #ifdef XP_MACOSX
120 uint32_t chromeMask = 0;
121 nsAutoCString prefVal;
122 rv = Preferences::GetCString("browser.hiddenWindowChromeURL", prefVal);
123 const char* hiddenWindowURL =
124 NS_SUCCEEDED(rv) ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL;
125 mApplicationProvidedHiddenWindow = prefVal.get() ? true : false;
126 #else
127 static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL;
128 uint32_t chromeMask = nsIWebBrowserChrome::CHROME_ALL;
129 #endif
131 nsCOMPtr<nsIURI> url;
132 rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
133 NS_ENSURE_SUCCESS(rv, rv);
135 RefPtr<AppWindow> newWindow;
136 rv = JustCreateTopWindow(nullptr, url, chromeMask, initialWidth,
137 initialHeight, true, getter_AddRefs(newWindow));
138 NS_ENSURE_SUCCESS(rv, rv);
140 nsCOMPtr<nsIDocShell> docShell;
141 newWindow->GetDocShell(getter_AddRefs(docShell));
142 if (docShell) {
143 Unused << docShell->GetBrowsingContext()->SetExplicitActive(
144 dom::ExplicitActiveStatus::Inactive);
147 mHiddenWindow.swap(newWindow);
149 return NS_OK;
152 NS_IMETHODIMP
153 nsAppShellService::DestroyHiddenWindow() {
154 if (mHiddenWindow) {
155 mHiddenWindow->Destroy();
157 mHiddenWindow = nullptr;
160 return NS_OK;
164 * Create a new top level window and display the given URL within it...
166 NS_IMETHODIMP
167 nsAppShellService::CreateTopLevelWindow(nsIAppWindow* aParent, nsIURI* aUrl,
168 uint32_t aChromeMask,
169 int32_t aInitialWidth,
170 int32_t aInitialHeight,
171 nsIAppWindow** aResult) {
172 nsresult rv;
174 StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW);
176 RefPtr<AppWindow> newWindow;
177 rv = JustCreateTopWindow(aParent, aUrl, aChromeMask, aInitialWidth,
178 aInitialHeight, false, getter_AddRefs(newWindow));
179 newWindow.forget(aResult);
181 if (NS_SUCCEEDED(rv)) {
182 // the addref resulting from this is the owning addref for this window
183 RegisterTopLevelWindow(*aResult);
184 nsCOMPtr<nsIAppWindow> parent;
185 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) parent = aParent;
186 (*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask));
189 return rv;
193 * This class provides a stub implementation of nsIWebBrowserChrome, as needed
194 * by nsAppShellService::CreateWindowlessBrowser
196 class WebBrowserChrome2Stub final : public nsIWebBrowserChrome,
197 public nsIEmbeddingSiteWindow,
198 public nsIInterfaceRequestor,
199 public nsSupportsWeakReference {
200 protected:
201 nsCOMPtr<nsIWebBrowser> mBrowser;
202 virtual ~WebBrowserChrome2Stub() {}
204 public:
205 void SetBrowser(nsIWebBrowser* aBrowser) { mBrowser = aBrowser; }
207 NS_DECL_ISUPPORTS
208 NS_DECL_NSIWEBBROWSERCHROME
209 NS_DECL_NSIINTERFACEREQUESTOR
210 NS_DECL_NSIEMBEDDINGSITEWINDOW
213 NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub)
214 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
215 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
216 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
217 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
218 NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
219 NS_INTERFACE_MAP_END
221 NS_IMPL_ADDREF(WebBrowserChrome2Stub)
222 NS_IMPL_RELEASE(WebBrowserChrome2Stub)
224 NS_IMETHODIMP
225 WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags) {
226 *aChromeFlags = 0;
227 return NS_OK;
230 NS_IMETHODIMP
231 WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags) {
232 MOZ_ASSERT_UNREACHABLE(
233 "WebBrowserChrome2Stub::SetChromeFlags is "
234 "not supported");
235 return NS_ERROR_NOT_IMPLEMENTED;
238 NS_IMETHODIMP
239 WebBrowserChrome2Stub::ShowAsModal() {
240 MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::ShowAsModal is not supported");
241 return NS_ERROR_NOT_IMPLEMENTED;
244 NS_IMETHODIMP
245 WebBrowserChrome2Stub::IsWindowModal(bool* aResult) {
246 *aResult = false;
247 return NS_OK;
250 NS_IMETHODIMP
251 WebBrowserChrome2Stub::SetLinkStatus(const nsAString& aStatusText) {
252 return NS_OK;
255 NS_IMETHODIMP
256 WebBrowserChrome2Stub::GetInterface(const nsIID& aIID, void** aSink) {
257 return QueryInterface(aIID, aSink);
260 // nsIEmbeddingSiteWindow impl
261 NS_IMETHODIMP
262 WebBrowserChrome2Stub::GetDimensions(uint32_t flags, int32_t* x, int32_t* y,
263 int32_t* cx, int32_t* cy) {
264 if (x) {
265 *x = 0;
268 if (y) {
269 *y = 0;
272 if (cx) {
273 *cx = 0;
276 if (cy) {
277 *cy = 0;
280 return NS_OK;
283 NS_IMETHODIMP
284 WebBrowserChrome2Stub::SetDimensions(uint32_t flags, int32_t x, int32_t y,
285 int32_t cx, int32_t cy) {
286 nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(mBrowser);
287 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
288 window->SetSize(cx, cy, true);
289 return NS_OK;
292 NS_IMETHODIMP
293 WebBrowserChrome2Stub::GetVisibility(bool* aVisibility) {
294 return NS_ERROR_NOT_IMPLEMENTED;
296 NS_IMETHODIMP
297 WebBrowserChrome2Stub::SetVisibility(bool aVisibility) {
298 return NS_ERROR_NOT_IMPLEMENTED;
301 NS_IMETHODIMP
302 WebBrowserChrome2Stub::GetTitle(nsAString& aTitle) {
303 return NS_ERROR_NOT_IMPLEMENTED;
305 NS_IMETHODIMP
306 WebBrowserChrome2Stub::SetTitle(const nsAString& aTitle) {
307 return NS_ERROR_NOT_IMPLEMENTED;
310 NS_IMETHODIMP
311 WebBrowserChrome2Stub::GetSiteWindow(void** aSiteWindow) {
312 return NS_ERROR_NOT_IMPLEMENTED;
315 NS_IMETHODIMP
316 WebBrowserChrome2Stub::Blur() { return NS_ERROR_NOT_IMPLEMENTED; }
318 class BrowserDestroyer final : public Runnable {
319 public:
320 BrowserDestroyer(nsIWebBrowser* aBrowser, nsISupports* aContainer)
321 : mozilla::Runnable("BrowserDestroyer"),
322 mBrowser(aBrowser),
323 mContainer(aContainer) {}
325 static nsresult Destroy(nsIWebBrowser* aBrowser) {
326 nsCOMPtr<nsIBaseWindow> window(do_QueryInterface(aBrowser));
327 return window->Destroy();
330 NS_IMETHOD
331 Run() override {
332 // Explicitly destroy the browser, in case this isn't the last reference.
333 return Destroy(mBrowser);
336 protected:
337 virtual ~BrowserDestroyer() {}
339 private:
340 nsCOMPtr<nsIWebBrowser> mBrowser;
341 nsCOMPtr<nsISupports> mContainer;
344 // This is the "stub" we return from CreateWindowlessBrowser - it exists
345 // to manage the lifetimes of the nsIWebBrowser and container window.
346 // In particular, it keeps a strong reference to both, to prevent them from
347 // being collected while this object remains alive, and ensures that they
348 // aren't destroyed when it's not safe to run scripts.
349 class WindowlessBrowser final : public nsIWindowlessBrowser,
350 public nsIInterfaceRequestor {
351 public:
352 WindowlessBrowser(nsIWebBrowser* aBrowser, nsISupports* aContainer)
353 : mBrowser(aBrowser), mContainer(aContainer), mClosed(false) {
354 mWebNavigation = do_QueryInterface(aBrowser);
355 mInterfaceRequestor = do_QueryInterface(aBrowser);
357 NS_DECL_ISUPPORTS
358 NS_DECL_NSIWINDOWLESSBROWSER
359 NS_FORWARD_SAFE_NSIWEBNAVIGATION(mWebNavigation)
360 NS_FORWARD_SAFE_NSIINTERFACEREQUESTOR(mInterfaceRequestor)
362 private:
363 ~WindowlessBrowser() {
364 if (mClosed) {
365 return;
368 NS_WARNING("Windowless browser was not closed prior to destruction");
370 // The docshell destructor needs to dispatch events, and can only run
371 // when it's safe to run scripts. If this was triggered by GC, it may
372 // not always be safe to run scripts, in which cases we need to delay
373 // destruction until it is.
374 auto runnable = MakeRefPtr<BrowserDestroyer>(mBrowser, mContainer);
375 nsContentUtils::AddScriptRunner(runnable.forget());
378 nsCOMPtr<nsIWebBrowser> mBrowser;
379 nsCOMPtr<nsIWebNavigation> mWebNavigation;
380 nsCOMPtr<nsIInterfaceRequestor> mInterfaceRequestor;
381 // we don't use the container but just hold a reference to it.
382 nsCOMPtr<nsISupports> mContainer;
384 bool mClosed;
387 NS_IMPL_ISUPPORTS(WindowlessBrowser, nsIWindowlessBrowser, nsIWebNavigation,
388 nsIInterfaceRequestor)
390 NS_IMETHODIMP
391 WindowlessBrowser::Close() {
392 NS_ENSURE_TRUE(!mClosed, NS_ERROR_UNEXPECTED);
393 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
394 "WindowlessBrowser::Close called when not safe to run scripts");
396 mClosed = true;
398 mWebNavigation = nullptr;
399 mInterfaceRequestor = nullptr;
400 return BrowserDestroyer::Destroy(mBrowser);
403 NS_IMETHODIMP
404 WindowlessBrowser::GetBrowsingContext(BrowsingContext** aBrowsingContext) {
405 nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(mBrowser);
406 if (!docShellTreeItem) {
407 return NS_ERROR_NOT_INITIALIZED;
409 return docShellTreeItem->GetBrowsingContextXPCOM(aBrowsingContext);
412 NS_IMETHODIMP
413 WindowlessBrowser::GetDocShell(nsIDocShell** aDocShell) {
414 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mInterfaceRequestor);
415 if (!docShell) {
416 return NS_ERROR_NOT_INITIALIZED;
418 docShell.forget(aDocShell);
419 return NS_OK;
422 NS_IMETHODIMP
423 nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, uint32_t aChromeMask,
424 nsIWindowlessBrowser** aResult) {
425 if (aChromeMask) {
426 MOZ_DIAGNOSTIC_ASSERT(aIsChrome, "Got chrome flags for non-chrome browser");
427 if (aChromeMask & ~(nsIWebBrowserChrome::CHROME_REMOTE_WINDOW |
428 nsIWebBrowserChrome::CHROME_FISSION_WINDOW |
429 nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW)) {
430 NS_ERROR("Received unexpected chrome flags");
431 return NS_ERROR_FAILURE;
435 /* First, we set the container window for our instance of nsWebBrowser. Since
436 * we don't actually have a window, we instead set the container window to be
437 * an instance of WebBrowserChrome2Stub, which provides a stub implementation
438 * of nsIWebBrowserChrome.
440 RefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub();
442 /* A windowless web browser doesn't have an associated OS level window. To
443 * accomplish this, we initialize the window associated with our instance of
444 * nsWebBrowser with an instance of HeadlessWidget/PuppetWidget, which provide
445 * a stub implementation of nsIWidget.
447 nsCOMPtr<nsIWidget> widget;
448 if (gfxPlatform::IsHeadless()) {
449 widget = nsIWidget::CreateHeadlessWidget();
450 } else {
451 widget = nsIWidget::CreatePuppetWidget(nullptr);
453 if (!widget) {
454 NS_ERROR("Couldn't create instance of stub widget");
455 return NS_ERROR_FAILURE;
458 nsresult rv =
459 widget->Create(nullptr, 0, LayoutDeviceIntRect(0, 0, 0, 0), nullptr);
460 NS_ENSURE_SUCCESS(rv, rv);
462 // Create a BrowsingContext for our windowless browser.
463 RefPtr<BrowsingContext> browsingContext = BrowsingContext::CreateIndependent(
464 aIsChrome ? BrowsingContext::Type::Chrome
465 : BrowsingContext::Type::Content);
467 if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
468 browsingContext->SetRemoteTabs(true);
470 if (aChromeMask & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) {
471 browsingContext->SetRemoteSubframes(true);
473 if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
474 browsingContext->SetPrivateBrowsing(true);
477 /* Next, we create an instance of nsWebBrowser. Instances of this class have
478 * an associated doc shell, which is what we're interested in.
480 nsCOMPtr<nsIWebBrowser> browser = nsWebBrowser::Create(
481 stub, widget, browsingContext, nullptr /* initialWindowChild */);
483 if (NS_WARN_IF(!browser)) {
484 NS_ERROR("Couldn't create instance of nsWebBrowser!");
485 return NS_ERROR_FAILURE;
488 // Make sure the container window owns the the nsWebBrowser instance.
489 stub->SetBrowser(browser);
491 nsISupports* isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome*, stub);
492 RefPtr<nsIWindowlessBrowser> result = new WindowlessBrowser(browser, isstub);
493 nsCOMPtr<nsIDocShell> docshell = do_GetInterface(result);
494 docshell->SetInvisible(true);
496 result.forget(aResult);
497 return NS_OK;
500 uint32_t nsAppShellService::CalculateWindowZLevel(nsIAppWindow* aParent,
501 uint32_t aChromeMask) {
502 uint32_t zLevel;
504 zLevel = nsIAppWindow::normalZ;
505 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
506 zLevel = nsIAppWindow::raisedZ;
507 else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
508 zLevel = nsIAppWindow::loweredZ;
510 #ifdef XP_MACOSX
511 /* Platforms on which modal windows are always application-modal, not
512 window-modal (that's just the Mac, right?) want modal windows to
513 be stacked on top of everyone else.
515 On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
517 uint32_t modalDepMask =
518 nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT;
519 if (aParent && (aChromeMask & modalDepMask)) {
520 aParent->GetZLevel(&zLevel);
522 #else
523 /* Platforms with native support for dependent windows (that's everyone
524 but pre-Mac OS X, right?) know how to stack dependent windows. On these
525 platforms, give the dependent window the same level as its parent,
526 so we won't try to override the normal platform behaviour. */
527 if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent)
528 aParent->GetZLevel(&zLevel);
529 #endif
531 return zLevel;
534 #ifdef XP_WIN
536 * Checks to see if any existing window is currently in fullscreen mode.
538 static bool CheckForFullscreenWindow() {
539 nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
540 if (!wm) return false;
542 nsCOMPtr<nsISimpleEnumerator> windowList;
543 wm->GetAppWindowEnumerator(nullptr, getter_AddRefs(windowList));
544 if (!windowList) return false;
546 for (;;) {
547 bool more = false;
548 windowList->HasMoreElements(&more);
549 if (!more) return false;
551 nsCOMPtr<nsISupports> supportsWindow;
552 windowList->GetNext(getter_AddRefs(supportsWindow));
553 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
554 if (baseWin) {
555 nsCOMPtr<nsIWidget> widget;
556 baseWin->GetMainWidget(getter_AddRefs(widget));
557 if (widget && widget->SizeMode() == nsSizeMode_Fullscreen) {
558 return true;
562 return false;
564 #endif
567 * Just do the window-making part of CreateTopLevelWindow
569 nsresult nsAppShellService::JustCreateTopWindow(
570 nsIAppWindow* aParent, nsIURI* aUrl, uint32_t aChromeMask,
571 int32_t aInitialWidth, int32_t aInitialHeight, bool aIsHiddenWindow,
572 AppWindow** aResult) {
573 *aResult = nullptr;
574 NS_ENSURE_STATE(!mXPCOMWillShutDown);
576 nsCOMPtr<nsIAppWindow> parent;
577 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) parent = aParent;
579 RefPtr<AppWindow> window = new AppWindow(aChromeMask);
581 #ifdef XP_WIN
582 // If the parent is currently fullscreen, tell the child to ignore persisted
583 // full screen states. This way new browser windows open on top of fullscreen
584 // windows normally.
585 if (window && CheckForFullscreenWindow()) window->IgnoreXULSizeMode(true);
586 #endif
588 nsWidgetInitData widgetInitData;
590 if (aIsHiddenWindow)
591 widgetInitData.mWindowType = eWindowType_invisible;
592 else
593 widgetInitData.mWindowType =
594 aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG
595 ? eWindowType_dialog
596 : eWindowType_toplevel;
598 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)
599 widgetInitData.mWindowType = eWindowType_popup;
601 if (aChromeMask & nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION)
602 widgetInitData.mIsAnimationSuppressed = true;
604 if (aChromeMask & nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP)
605 widgetInitData.mAlwaysOnTop = true;
607 if (aChromeMask & nsIWebBrowserChrome::CHROME_FISSION_WINDOW)
608 widgetInitData.mFissionWindow = true;
610 if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW)
611 widgetInitData.mHasRemoteContent = true;
613 #ifdef MOZ_WIDGET_GTK
614 // Linux/Gtk PIP window support. It's Chrome Toplevel window, always on top
615 // and without any bar.
616 uint32_t pipMask = nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP |
617 nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
618 uint32_t barMask = nsIWebBrowserChrome::CHROME_MENUBAR |
619 nsIWebBrowserChrome::CHROME_TOOLBAR |
620 nsIWebBrowserChrome::CHROME_LOCATIONBAR |
621 nsIWebBrowserChrome::CHROME_STATUSBAR;
622 if (widgetInitData.mWindowType == eWindowType_toplevel &&
623 ((aChromeMask & pipMask) == pipMask) && !(aChromeMask & barMask)) {
624 widgetInitData.mPIPWindow = true;
626 #elif defined(XP_WIN)
627 // Windows PIP window support. It's Chrome dialog window, always on top
628 // and without any bar.
629 uint32_t pipMask = nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP |
630 nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
631 uint32_t barMask = nsIWebBrowserChrome::CHROME_MENUBAR |
632 nsIWebBrowserChrome::CHROME_TOOLBAR |
633 nsIWebBrowserChrome::CHROME_LOCATIONBAR |
634 nsIWebBrowserChrome::CHROME_STATUSBAR;
635 if (widgetInitData.mWindowType == eWindowType_dialog &&
636 ((aChromeMask & pipMask) == pipMask) && !(aChromeMask & barMask)) {
637 widgetInitData.mPIPWindow = true;
639 #endif
641 #ifdef XP_MACOSX
642 // Mac OS X sheet support
643 // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from
644 // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal
645 // windows opened from nsPromptService::DoDialog() still are sheets. This
646 // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and
647 // nsCocoaWindow::SetModal()).
648 uint32_t sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
649 nsIWebBrowserChrome::CHROME_MODAL |
650 nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
651 if (parent && (parent != mHiddenWindow) &&
652 ((aChromeMask & sheetMask) == sheetMask)) {
653 widgetInitData.mWindowType = eWindowType_sheet;
655 #endif
657 #if defined(XP_WIN)
658 if (widgetInitData.mWindowType == eWindowType_toplevel ||
659 widgetInitData.mWindowType == eWindowType_dialog)
660 widgetInitData.clipChildren = true;
661 #endif
663 // note default chrome overrides other OS chrome settings, but
664 // not internal chrome
665 if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT)
666 widgetInitData.mBorderStyle = eBorderStyle_default;
667 else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) ==
668 nsIWebBrowserChrome::CHROME_ALL)
669 widgetInitData.mBorderStyle = eBorderStyle_all;
670 else {
671 widgetInitData.mBorderStyle = eBorderStyle_none; // assumes none == 0x00
672 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS)
673 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(
674 widgetInitData.mBorderStyle | eBorderStyle_border);
675 if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR)
676 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(
677 widgetInitData.mBorderStyle | eBorderStyle_title);
678 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE)
679 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(
680 widgetInitData.mBorderStyle | eBorderStyle_close);
681 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
682 widgetInitData.mResizable = true;
683 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(
684 widgetInitData.mBorderStyle | eBorderStyle_resizeh);
685 // only resizable windows get the maximize button (but not dialogs)
686 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
687 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(
688 widgetInitData.mBorderStyle | eBorderStyle_maximize);
690 // all windows (except dialogs) get minimize buttons and the system menu
691 if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
692 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(
693 widgetInitData.mBorderStyle | eBorderStyle_minimize |
694 eBorderStyle_menu);
695 // but anyone can explicitly ask for a minimize button
696 if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MIN) {
697 widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(
698 widgetInitData.mBorderStyle | eBorderStyle_minimize);
702 if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
703 aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
704 aInitialWidth = 1;
705 aInitialHeight = 1;
706 window->SetIntrinsicallySized(true);
709 bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
711 widgetInitData.mRTL = LocaleService::GetInstance()->IsAppLocaleRTL();
713 nsresult rv =
714 window->Initialize(parent, center ? aParent : nullptr, aInitialWidth,
715 aInitialHeight, aIsHiddenWindow, widgetInitData);
717 NS_ENSURE_SUCCESS(rv, rv);
719 // Enforce the Private Browsing autoStart pref first.
720 bool isPrivateBrowsingWindow =
721 Preferences::GetBool("browser.privatebrowsing.autostart");
723 if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
724 // Caller requested a private window
725 isPrivateBrowsingWindow = true;
727 nsCOMPtr<mozIDOMWindowProxy> domWin = do_GetInterface(aParent);
728 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(domWin);
729 nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(webNav);
731 if (!isPrivateBrowsingWindow && parentContext) {
732 // Ensure that we propagate any existing private browsing status
733 // from the parent, even if it will not actually be used
734 // as a parent value.
735 isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
738 if (nsDocShell* docShell = window->GetDocShell()) {
739 MOZ_ASSERT(docShell->GetBrowsingContext()->IsChrome());
741 docShell->SetPrivateBrowsing(isPrivateBrowsingWindow);
742 docShell->SetRemoteTabs(aChromeMask &
743 nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
744 docShell->SetRemoteSubframes(aChromeMask &
745 nsIWebBrowserChrome::CHROME_FISSION_WINDOW);
747 // Eagerly create an about:blank content viewer with the right principal
748 // here, rather than letting it happening in the upcoming call to
749 // SetInitialPrincipalToSubject. This avoids creating the about:blank
750 // document and then blowing it away with a second one, which can cause
751 // problems for the top-level chrome window case. See bug 789773. Note that
752 // we don't accept expanded principals here, similar to
753 // SetInitialPrincipalToSubject.
754 if (nsContentUtils::IsInitialized()) { // Sometimes this happens really
755 // early. See bug 793370.
756 nsCOMPtr<nsIPrincipal> principal =
757 nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
758 if (nsContentUtils::IsExpandedPrincipal(principal)) {
759 principal = nullptr;
761 // Use the subject (or system) principal as the storage principal too
762 // until the new window finishes navigating and gets a real storage
763 // principal.
764 rv = docShell->CreateAboutBlankContentViewer(
765 principal, principal, /* aCsp = */ nullptr, /* aBaseURI = */ nullptr,
766 /* aIsInitialDocument = */ true);
767 NS_ENSURE_SUCCESS(rv, rv);
768 RefPtr<Document> doc = docShell->GetDocument();
769 NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE);
770 MOZ_ASSERT(doc->IsInitialDocument(),
771 "Document should be an initial document");
774 // Begin loading the URL provided.
775 if (aUrl) {
776 RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aUrl);
777 loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
778 loadState->SetFirstParty(true);
779 rv = docShell->LoadURI(loadState, /* aSetNavigating */ true);
780 NS_ENSURE_SUCCESS(rv, rv);
784 window.forget(aResult);
785 if (parent) parent->AddChildWindow(*aResult);
787 if (center) rv = (*aResult)->Center(parent, parent ? false : true, false);
789 return rv;
792 NS_IMETHODIMP
793 nsAppShellService::GetHiddenWindow(nsIAppWindow** aWindow) {
794 NS_ENSURE_ARG_POINTER(aWindow);
796 EnsureHiddenWindow();
798 *aWindow = mHiddenWindow;
799 NS_IF_ADDREF(*aWindow);
800 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
803 NS_IMETHODIMP
804 nsAppShellService::GetHiddenDOMWindow(mozIDOMWindowProxy** aWindow) {
805 NS_ENSURE_ARG_POINTER(aWindow);
807 EnsureHiddenWindow();
809 nsresult rv;
810 nsCOMPtr<nsIDocShell> docShell;
811 NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
813 rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
814 NS_ENSURE_SUCCESS(rv, rv);
815 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
817 nsCOMPtr<nsPIDOMWindowOuter> hiddenDOMWindow(docShell->GetWindow());
818 hiddenDOMWindow.forget(aWindow);
819 return *aWindow ? NS_OK : NS_ERROR_FAILURE;
822 NS_IMETHODIMP
823 nsAppShellService::GetHasHiddenWindow(bool* aHasHiddenWindow) {
824 NS_ENSURE_ARG_POINTER(aHasHiddenWindow);
826 *aHasHiddenWindow = !!mHiddenWindow;
827 return NS_OK;
830 NS_IMETHODIMP
831 nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW) {
832 *aAPHW = mApplicationProvidedHiddenWindow;
833 return NS_OK;
837 * Register a new top level window (created elsewhere)
839 NS_IMETHODIMP
840 nsAppShellService::RegisterTopLevelWindow(nsIAppWindow* aWindow) {
841 NS_ENSURE_ARG_POINTER(aWindow);
843 nsCOMPtr<nsIDocShell> docShell;
844 aWindow->GetDocShell(getter_AddRefs(docShell));
845 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
847 nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
848 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
849 domWindow->SetInitialPrincipalToSubject(nullptr, Nothing());
851 // tell the window mediator about the new window
852 nsCOMPtr<nsIWindowMediator> mediator(
853 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
854 NS_ASSERTION(mediator, "Couldn't get window mediator.");
856 if (mediator) mediator->RegisterWindow(aWindow);
858 // tell the window watcher about the new window
859 nsCOMPtr<nsPIWindowWatcher> wwatcher(
860 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
861 NS_ASSERTION(wwatcher, "No windowwatcher?");
862 if (wwatcher && domWindow) {
863 wwatcher->AddWindow(domWindow, 0);
866 // an ongoing attempt to quit is stopped by a newly opened window
867 nsCOMPtr<nsIObserverService> obssvc = services::GetObserverService();
868 NS_ASSERTION(obssvc, "Couldn't get observer service.");
870 if (obssvc) {
871 obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr);
872 AppWindow* appWindow = static_cast<AppWindow*>(aWindow);
873 appWindow->WasRegistered();
876 return NS_OK;
879 NS_IMETHODIMP
880 nsAppShellService::UnregisterTopLevelWindow(nsIAppWindow* aWindow) {
881 if (mXPCOMShuttingDown) {
882 /* return an error code in order to:
883 - avoid doing anything with other member variables while we are in
884 the destructor
885 - notify the caller not to release the AppShellService after
886 unregistering the window
887 (we don't want to be deleted twice consecutively to
888 mHiddenWindow->Destroy() in our destructor)
890 return NS_ERROR_FAILURE;
893 NS_ENSURE_ARG_POINTER(aWindow);
895 if (aWindow == mHiddenWindow) {
896 // CreateHiddenWindow() does not register the window, so we're done.
897 return NS_OK;
900 // tell the window mediator
901 nsCOMPtr<nsIWindowMediator> mediator(
902 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
903 NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
905 if (mediator) mediator->UnregisterWindow(aWindow);
907 // tell the window watcher
908 nsCOMPtr<nsPIWindowWatcher> wwatcher(
909 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
910 NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
911 if (wwatcher) {
912 nsCOMPtr<nsIDocShell> docShell;
913 aWindow->GetDocShell(getter_AddRefs(docShell));
914 if (docShell) {
915 nsCOMPtr<nsPIDOMWindowOuter> domWindow(docShell->GetWindow());
916 if (domWindow) wwatcher->RemoveWindow(domWindow);
920 return NS_OK;
923 NS_IMETHODIMP
924 nsAppShellService::Observe(nsISupports* aSubject, const char* aTopic,
925 const char16_t* aData) {
926 if (!strcmp(aTopic, "xpcom-will-shutdown")) {
927 mXPCOMWillShutDown = true;
928 } else if (!strcmp(aTopic, "xpcom-shutdown")) {
929 mXPCOMShuttingDown = true;
930 if (mHiddenWindow) {
931 mHiddenWindow->Destroy();
933 } else {
934 NS_ERROR("Unexpected observer topic!");
937 return NS_OK;
940 NS_IMETHODIMP
941 nsAppShellService::StartEventLoopLagTracking(bool* aResult) {
942 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
943 *aResult = mozilla::InitEventTracing(true);
944 #endif
945 return NS_OK;
948 NS_IMETHODIMP
949 nsAppShellService::StopEventLoopLagTracking() {
950 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
951 mozilla::ShutdownEventTracing();
952 #endif
953 return NS_OK;