Files
palemoon27/xpfe/appshell/nsAppShellService.cpp
T
roytam1 8a0a002cf2 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1148708: Add missing 'override' annotations in DocAccessibleChild.h. rs=ehsan (d606358545)
- Bug 1210408 - make nsMaiInterfaceAction work with proxies, r=tbsaunde (f7c819c6ae)
- Bug 1210407 - teach nsMaiInterfaceTable to use proxies, r=tbsaunde (4ca4f10b5f)
- bug 1185157 make sure we don't send an event to a destroyed ipc document r=billm (23acf53f75)
- bug 1214864 - make SetCarretOffset() async r=davidb (e3079e9b2d)
- missing of Bug 1139972 - IPC Proxy for charAt, r=tbsaunde (e9593ed752)
- bug 1191598 - Pass MOZ_CURRENT_PROJECT in environment when running post-build automation steps for universal mac builds. r=gps (fc342c6ced)
- Bug 1164596 - Add mach android-emulator command; r=ahal (afeb9b27d1)
- Bug 1223149 - Add basic usage documentation for mach build; r=glandium (bfb802d175)
- Bug 1182301 - Improve 'mach build' notifications. r=gps (2c65a122d1)
- Bug 1184696 - Add clobber targets to |mach clobber|; Ability to clobber compiled python files, r=gps (35d8be292e)
- Bug 1117958 - Allow any debugging options to the run or gtest mach subcommands to automatically enable debugging. r=gps (32f986af4b)
- Bug 1180081 - Properly rebuild gtest/libxul before running gtests. r=gps (80db9a3d49)
- Bug 1171647, part 1 - Define a new function to convert the mode to a string. r=njn (61ad16f5ba)
- Bug 1171647, part 2 - Remove redundant assertion for dark matter mode. r=njn (b5ac9519f3)
- Bug 1058178, part 1 - Implement DMD heap scanning mode. r=njn (60e1079536)
- Bug 1058178, part 2 - Implement address clamping analysis for DMD scan logs. r=njn (45c0326b93)
- Bug 1102388 - Fix DMD static constructor ordering dependency. r=mccr8 (59b87897a1)
- Bug 1128705 - Don't redefine PAGE_SIZE in DMD if it's already defined. r=erahm (49216348ee)
- Bug 1179042 - Add a script for analyzing memory blocks using a heap scan DMD log. r=njn DONTBUILD (1c08d2d66e)
- Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat (1c999d139b)
- Bug 1158772 - fix non-idiomatic memset call in nsDeque.cpp; r=erahm (de6b555245)
- Bug 1199400 - Part 1: Use CheckedInt when growing nsDeque capacity. r=froydnj (dfdf6814a3)
- Bug 1199400 - Part 0: Remove unused nsDequeIterator. r=froydnj (38d69d7f47)
- Bug 1199400 - Part 2: Add tests for possible nsDeque corner cases. r=froydnj (931baff195)
- Bug 1201997 - Part 1 - Converted compiled test to gtest for nsDeque class. Added tests to test untested methods. r=froydn (e893916651)
- Bug 1201997 - Part 2 - Removing unused methods from the nsDeque class. r=froydn (41595a90ac)
- Bug 1201997 - Part 3 - Make internally used methods private. r=froydn (8cd3afd96f)
- Bug 1201997 - Part 4 - Change size and offset variables to size_t.r=froydn (73eabc8d60)
- Bug 1215140 P1 Add an nsIConsoleReportCollector interface to support navigation channel logging. r=bz (8a41535e2b)
- Bug 1215140 P2 Make HttpBaseChannel implement nsIConsoleReportCollector. r=bz (75fca301f2)
- Bug 1197679 - If nsUnknownDecoder is involved in e10s DivertToParent can break. r=jduell (5d94a12504)
- Bug 1178991 - smartptr for http converter r=hurley (8e7fbc8443)
- bug 366559 - patch 2, fix nsHTTPCompressConv indentation r=bagder (ba762da587)
- bug 366559 - patch 3, fix nsHTTPCompressConv bracing style r=bagder (54195ab451)
- bits of  bug 366559 - patch 7, content-encoding brotli for http (f0b4051022)
- Bug 1205112 - Make PushEvent.data nullable. r=mt,smaug (775db32856)
- Bug 1193414 - SharedWorkers thread should be kept alive also when the SharedWorker object is CCed, r=khuey (b77ea8125c)
- Bug 1206520: Add about:config prefs to enable throwing on asm.js validation failures; r=bz (c42126665d)
- Bug 1193414 - Telemetry for SharedWorker spawning. r=bkelly (77984b7bcc)
- Bug 1205676 - Enable WPT service-worker/unregister-then-register-new-script.https.html in e10s, r=nsm (ec24939cf6)
- Bug 1193133 - Throw when calling postMessage from a Service Worker dom object with no global. r=bkelly (526dcacfab)
- Bug 1181871 P1 Only enforce Cache Context shared data destruction on target thread after init. r=ehsan (cdbf3ed3a8)
- Bug 1181871 P2 Fix ServiceWorkerManager usage of stack-based ErrorResult. r=ehsan (c449195d90)
- minor cleanup and missing bit of 1198230 (02f459db05)
- Bug 1143717 - Implement the ServiceWorkerMessageEvent interface. r=baku (027b3465f2)
- fix misspatch (708eee4e84)
- Bug 1188545 - Disentangle service workers from shared workers and refactor event dispatching code into a separate class. r=nsm,mrbkap (fb5b5341c9)
- Bug 1205228 - Change PackagedAppVerifier to notify the verification result asynchronously. r=valentin. (9edda0fa00)
- Bug 1178518 - Packaged App Utils. r=valentin (f60f3b7a93)
- Bug 1213150 - Part 1: Add a nsContentUtils::IsNonSubresourceRequest helper; r=jdm (b509cc3cc9)
- Bug 1213150 - Part 2: Rework ShouldPrepareForIntercept() in terms of subresource requests; r=jdm (2e92fe8780)
- Bug 1213150 - Part 3: Remove nsIInterceptedChannel.isNavigation; r=jdm (becf1cc12f)
- Bug 1213150 follow-up: fix build bustage (8d73d6ca73)
- Bug 1198394 - Part 1: Allow interception of HSTS upgraded connections in non-e10s mode; r=mcmanus (f504c5be08)
- Bug 1198394 - Part 2: Add a test for interception of HSTS upgraded connections; r=jdm (054e984eef)
- Bug 1187011 - Don't allow response body with null body status. r=bkelly (b1860741d1)
- missing bit of 1140788 (29d319712e)
- Bug 1213436 - Reject core dumps with node IDs that don't fit in an IEEE 754 double; r=sfink (3c1f6fdda0)
- Bug 1211006 - Add Debugger.Source.prototype.canonicalId; r=ejpbruel (eef7b79fce)
- Bug 1199218 - Implement JS::ubi::Node::size for js::LazyScript referents; r=sfink (098a48d240)
- Bug 1220031 - Add JS::ubi::Node::scriptFilename; r=sfink (6b824ae680)
- Bug 1143575. Remove unused MediaQueue::Empty. r=cpearce (de737f3433)
- Bug 1209933 - Make sure all parent runtime pointers are the topmost parent, r=billm. (fe824d967d)
- Bug 1197012 - Fix ThrowTypeError in Notification. r=mccr8 (0b1a097526)
- Bug 1197893 - Check the number of arguments for ThrowTypeError() and ThrowRangeError() at compile time. r=peterv (d98c7d78a0)
- Bug 1142083 - Add test for IDN Unicode domain redirect. r=mcmanus (0c8961fe17)
- Bug 1187159 - Add mochitest for loading packaged apps (iframe+fetch+mozapp) r=jduell (ce90ea561b)
- Bug 1186290 - Notify TabParent to switch process when loading a signed package. r=honzab, r=kanru. (c58a14554a)
- fix (15e2df75eb)
- Bug 1206124 P1 Fix "same-origin" CORS credentials in FetchDriver. r=ehsan (fae1bb6ab3)
- Bug 1206124 P2 Test fetch() with credentials and redirects. r=ehsan (ffc6254112)
- Bug 1211751: Remove nsIChannelEventSink-forwarding from EventSource and FetchDriver. It's never needed. r=smaug (adafe5737a)
- Bug 1212433 Fail fetch() calls that require preflight and also redirect. r=sicking a=abillings (c0d6742b9e)
- Bug 1193128 - Fix base64 decoding when fetching data URIs. r=baku (80bafa291a)
- Bug 1195167 part 1: Let necko handle all protocols. r=bkelly (bb932b0ada)
- Bug 1195167 part 2: Remove redundant aCORSFlag argument and instead use mCORSFlagEverSet. r=bkelly (beadafcad0)
- Bug 1195167 part 3: Remove more scheme-specific handling from FetchDriver. r=bkelly (d00b38db9e)
- Bug 1195167 part 4: Remove FetchDriver::BasicFetch since it is empty. r=bkelly (c5ed097267)
- Bug 1210413 P2 Test CORS credentials on cross-origin redirects. r=sicking a=dveditz (b4eeb8aac0)
- Bug 1210413 P1 Propagate new channel load flags from child to parent on redirect. r=jduell a=dveditz (8b329af4fa)
- Bug 1195167 part 5: Make FetchDriver use AsyncOpen2. r=bkelly (cc217c4cc1)
- Bug 1195167 part 6: Some code simplification since necko handles fetch recursion. r=bkelly (f3b6da2262)
- Bug 1195167: Followup to fix test which I forgot to change (81e7439a2e)
- Bug 1215746: Remove RequestMode::Cors_with_forced_preflight. r=bkelly (0336e812b6)
- Bug 1211000: Move CORS preflight logic from nsCORSListenerProxy to nsCORSPreflightListener. r=ehsan (bf2f71cf22)
- missing bit of Bug 1211443 - Drop scheduled update if decoder initialization isn't done yet. r=jya (f6bc074e33)
- Bug 1182571: Fix nsILoadInfo->GetContentPolicyType API to be less ambigious. Audit and fix all users of it. r=ckerschb (5af6fa7442)
- fix (e40c8e7625)
- Bug 1173811 - Part 1: Propagate the response URL to intercepted channels when necessary (non-e10s). r=mayhemer,bkelly (26f4f13c28)
- Bug 1173811 - Part 2: Propagate the response URL to intercepted channels when necessary (e10s). r=mayhemer,bkelly (a603fe1df2)
- Bug 1154309 - Add New Resource Timing Fields r=bz,hurley (1d14eb6bef)
- Bug 1175685 - add OriginAttribute to LoadInfo. r=jonas, r=ckerschb, r=michal (a5d18bb637)
- Bug 1175685 - add OriginAttribute to LoadInfo. r=jonas, r=ckerschb, r=michal (fb07d2c8aa)
- Bug 1212904 P1 Add a LoadTainting enumeration. r=jduell (a1db8a3e99)
- Bug 1212904 P2 Add LoadTainting information to nsILoadInfo. r=jduell (2482e5e334)
- Bug 1221151 - use [infallible] in nsILoadInfo.idl instead of manual %{C++ blocks; r=jduell (aae73129b6)
- Bug 1045891 - CSP 2 child-src implementation r=ckerschb (792920aeb9)
- Bug 1219931 - CSP: Don't allow removing a policy (r=sicking) (9daaab4186)
- Bug 1208661 - Dump client-side layer textures. r=BenWa (1f2d17d515)
2022-10-17 11:08:37 +08:00

928 lines
28 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIAppShellService.h"
#include "nsIComponentManager.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsIServiceManager.h"
#include "nsIObserverService.h"
#include "nsIObserver.h"
#include "nsIXPConnect.h"
#include "nsIXULRuntime.h"
#include "nsIWindowMediator.h"
#include "nsIWindowWatcher.h"
#include "nsPIWindowWatcher.h"
#include "nsIDOMWindow.h"
#include "nsPIDOMWindow.h"
#include "nsWebShellWindow.h"
#include "prprf.h"
#include "nsWidgetInitData.h"
#include "nsWidgetsCID.h"
#include "nsIWidget.h"
#include "nsIRequestObserver.h"
/* For implementing GetHiddenWindowAndJSContext */
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsAppShellService.h"
#include "nsISupportsPrimitives.h"
#include "nsIChromeRegistry.h"
#include "nsILoadContext.h"
#include "nsIWebNavigation.h"
#include "mozilla/Attributes.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/StartupTimeline.h"
#include "nsEmbedCID.h"
#include "nsIWebBrowser.h"
#include "nsIDocShell.h"
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
#include "EventTracer.h"
#endif
using namespace mozilla;
// Default URL for the hidden window, can be overridden by a pref on Mac
#define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
class nsIAppShell;
nsAppShellService::nsAppShellService() :
mXPCOMWillShutDown(false),
mXPCOMShuttingDown(false),
mModalWindowCount(0),
mApplicationProvidedHiddenWindow(false),
mScreenId(0)
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->AddObserver(this, "xpcom-will-shutdown", false);
obs->AddObserver(this, "xpcom-shutdown", false);
}
}
nsAppShellService::~nsAppShellService()
{
}
/*
* Implement the nsISupports methods...
*/
NS_IMPL_ISUPPORTS(nsAppShellService,
nsIAppShellService,
nsIObserver)
NS_IMETHODIMP
nsAppShellService::CreateHiddenWindow()
{
return CreateHiddenWindowHelper(false);
}
NS_IMETHODIMP
nsAppShellService::SetScreenId(uint32_t aScreenId)
{
mScreenId = aScreenId;
return NS_OK;
}
void
nsAppShellService::EnsurePrivateHiddenWindow()
{
if (!mHiddenPrivateWindow) {
CreateHiddenWindowHelper(true);
}
}
nsresult
nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate)
{
if (!aIsPrivate && mHiddenWindow) {
return NS_OK;
}
if (aIsPrivate && mHiddenPrivateWindow) {
return NS_OK;
}
nsresult rv;
int32_t initialHeight = 100, initialWidth = 100;
#ifdef XP_MACOSX
uint32_t chromeMask = 0;
nsAdoptingCString prefVal =
Preferences::GetCString("browser.hiddenWindowChromeURL");
const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL;
if (aIsPrivate) {
hiddenWindowURL = DEFAULT_HIDDENWINDOW_URL;
} else {
mApplicationProvidedHiddenWindow = prefVal.get() ? true : false;
}
#else
static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL;
uint32_t chromeMask = nsIWebBrowserChrome::CHROME_ALL;
#endif
nsCOMPtr<nsIURI> url;
rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<nsWebShellWindow> newWindow;
if (!aIsPrivate) {
rv = JustCreateTopWindow(nullptr, url,
chromeMask, initialWidth, initialHeight,
true, nullptr, getter_AddRefs(newWindow));
NS_ENSURE_SUCCESS(rv, rv);
mHiddenWindow.swap(newWindow);
} else {
// Create the hidden private window
chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
rv = JustCreateTopWindow(nullptr, url,
chromeMask, initialWidth, initialHeight,
true, nullptr, getter_AddRefs(newWindow));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocShell> docShell;
newWindow->GetDocShell(getter_AddRefs(docShell));
if (docShell) {
docShell->SetAffectPrivateSessionLifetime(false);
}
mHiddenPrivateWindow.swap(newWindow);
}
// RegisterTopLevelWindow(newWindow); -- Mac only
return NS_OK;
}
NS_IMETHODIMP
nsAppShellService::DestroyHiddenWindow()
{
if (mHiddenWindow) {
mHiddenWindow->Destroy();
mHiddenWindow = nullptr;
}
if (mHiddenPrivateWindow) {
mHiddenPrivateWindow->Destroy();
mHiddenPrivateWindow = nullptr;
}
return NS_OK;
}
/*
* Create a new top level window and display the given URL within it...
*/
NS_IMETHODIMP
nsAppShellService::CreateTopLevelWindow(nsIXULWindow *aParent,
nsIURI *aUrl,
uint32_t aChromeMask,
int32_t aInitialWidth,
int32_t aInitialHeight,
nsITabParent *aOpeningTab,
nsIXULWindow **aResult)
{
nsresult rv;
StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW);
nsWebShellWindow *newWindow = nullptr;
rv = JustCreateTopWindow(aParent, aUrl,
aChromeMask, aInitialWidth, aInitialHeight,
false, aOpeningTab, &newWindow); // addrefs
*aResult = newWindow; // transfer ref
if (NS_SUCCEEDED(rv)) {
// the addref resulting from this is the owning addref for this window
RegisterTopLevelWindow(*aResult);
nsCOMPtr<nsIXULWindow> parent;
if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
parent = aParent;
(*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask));
}
return rv;
}
/*
* This class provides a stub implementation of nsIWebBrowserChrome2, as needed
* by nsAppShellService::CreateWindowlessBrowser
*/
class WebBrowserChrome2Stub : public nsIWebBrowserChrome2,
public nsIInterfaceRequestor,
public nsSupportsWeakReference {
protected:
virtual ~WebBrowserChrome2Stub() {}
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBBROWSERCHROME
NS_DECL_NSIWEBBROWSERCHROME2
NS_DECL_NSIINTERFACEREQUESTOR
};
NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(WebBrowserChrome2Stub)
NS_IMPL_RELEASE(WebBrowserChrome2Stub)
NS_IMETHODIMP
WebBrowserChrome2Stub::SetStatus(uint32_t aStatusType, const char16_t* aStatus)
{
return NS_OK;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::GetWebBrowser(nsIWebBrowser** aWebBrowser)
{
NS_NOTREACHED("WebBrowserChrome2Stub::GetWebBrowser is not supported");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::SetWebBrowser(nsIWebBrowser* aWebBrowser)
{
NS_NOTREACHED("WebBrowserChrome2Stub::SetWebBrowser is not supported");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::GetChromeFlags(uint32_t* aChromeFlags)
{
*aChromeFlags = 0;
return NS_OK;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::SetChromeFlags(uint32_t aChromeFlags)
{
NS_NOTREACHED("WebBrowserChrome2Stub::SetChromeFlags is not supported");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::DestroyBrowserWindow()
{
NS_NOTREACHED("WebBrowserChrome2Stub::DestroyBrowserWindow is not supported");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::SizeBrowserTo(int32_t aCX, int32_t aCY)
{
NS_NOTREACHED("WebBrowserChrome2Stub::SizeBrowserTo is not supported");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::ShowAsModal()
{
NS_NOTREACHED("WebBrowserChrome2Stub::ShowAsModal is not supported");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::IsWindowModal(bool* aResult)
{
*aResult = false;
return NS_OK;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::ExitModalEventLoop(nsresult aStatus)
{
NS_NOTREACHED("WebBrowserChrome2Stub::ExitModalEventLoop is not supported");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::SetStatusWithContext(uint32_t aStatusType,
const nsAString& aStatusText,
nsISupports* aStatusContext)
{
return NS_OK;
}
NS_IMETHODIMP
WebBrowserChrome2Stub::GetInterface(const nsIID & aIID, void **aSink)
{
return QueryInterface(aIID, aSink);
}
// This is the "stub" we return from CreateWindowlessBrowser - it exists
// purely to keep a strong reference to the browser and the container to
// prevent the container being collected while the stub remains alive.
class WindowlessBrowserStub final : public nsIWebNavigation,
public nsIInterfaceRequestor
{
public:
WindowlessBrowserStub(nsIWebBrowser *aBrowser, nsISupports *aContainer) {
mBrowser = aBrowser;
mWebNavigation = do_QueryInterface(aBrowser);
mInterfaceRequestor = do_QueryInterface(aBrowser);
mContainer = aContainer;
}
NS_DECL_ISUPPORTS
NS_FORWARD_NSIWEBNAVIGATION(mWebNavigation->)
NS_FORWARD_NSIINTERFACEREQUESTOR(mInterfaceRequestor->)
private:
~WindowlessBrowserStub() {}
nsCOMPtr<nsIWebBrowser> mBrowser;
nsCOMPtr<nsIWebNavigation> mWebNavigation;
nsCOMPtr<nsIInterfaceRequestor> mInterfaceRequestor;
// we don't use the container but just hold a reference to it.
nsCOMPtr<nsISupports> mContainer;
};
NS_INTERFACE_MAP_BEGIN(WindowlessBrowserStub)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebNavigation)
NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(WindowlessBrowserStub)
NS_IMPL_RELEASE(WindowlessBrowserStub)
NS_IMETHODIMP
nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWebNavigation **aResult)
{
/* First, we create an instance of nsWebBrowser. Instances of this class have
* an associated doc shell, which is what we're interested in.
*/
nsCOMPtr<nsIWebBrowser> browser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
if (!browser) {
NS_ERROR("Couldn't create instance of nsWebBrowser!");
return NS_ERROR_FAILURE;
}
/* Next, we set the container window for our instance of nsWebBrowser. Since
* we don't actually have a window, we instead set the container window to be
* an instance of WebBrowserChrome2Stub, which provides a stub implementation
* of nsIWebBrowserChrome2.
*/
RefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub();
if (!stub) {
NS_ERROR("Couldn't create instance of WebBrowserChrome2Stub!");
return NS_ERROR_FAILURE;
}
browser->SetContainerWindow(stub);
nsCOMPtr<nsIWebNavigation> navigation = do_QueryInterface(browser);
nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(navigation);
item->SetItemType(aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
: nsIDocShellTreeItem::typeContentWrapper);
/* A windowless web browser doesn't have an associated OS level window. To
* accomplish this, we initialize the window associated with our instance of
* nsWebBrowser with an instance of PuppetWidget, which provides a stub
* implementation of nsIWidget.
*/
nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(nullptr);
if (!widget) {
NS_ERROR("Couldn't create instance of PuppetWidget");
return NS_ERROR_FAILURE;
}
widget->Create(nullptr, 0, gfx::IntRect(gfx::IntPoint(0, 0), gfx::IntSize(0, 0)),
nullptr);
nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(navigation);
window->InitWindow(0, widget, 0, 0, 0, 0);
window->Create();
nsISupports *isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome2*, stub);
RefPtr<nsIWebNavigation> result = new WindowlessBrowserStub(browser, isstub);
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(result);
docshell->SetInvisible(true);
result.forget(aResult);
return NS_OK;
}
uint32_t
nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent,
uint32_t aChromeMask)
{
uint32_t zLevel;
zLevel = nsIXULWindow::normalZ;
if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
zLevel = nsIXULWindow::raisedZ;
else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
zLevel = nsIXULWindow::loweredZ;
#ifdef XP_MACOSX
/* Platforms on which modal windows are always application-modal, not
window-modal (that's just the Mac, right?) want modal windows to
be stacked on top of everyone else.
On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
*/
uint32_t modalDepMask = nsIWebBrowserChrome::CHROME_MODAL |
nsIWebBrowserChrome::CHROME_DEPENDENT;
if (aParent && (aChromeMask & modalDepMask)) {
aParent->GetZLevel(&zLevel);
}
#else
/* Platforms with native support for dependent windows (that's everyone
but pre-Mac OS X, right?) know how to stack dependent windows. On these
platforms, give the dependent window the same level as its parent,
so we won't try to override the normal platform behaviour. */
if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent)
aParent->GetZLevel(&zLevel);
#endif
return zLevel;
}
#ifdef XP_WIN
/*
* Checks to see if any existing window is currently in fullscreen mode.
*/
static bool
CheckForFullscreenWindow()
{
nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
if (!wm)
return false;
nsCOMPtr<nsISimpleEnumerator> windowList;
wm->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList));
if (!windowList)
return false;
for (;;) {
bool more = false;
windowList->HasMoreElements(&more);
if (!more)
return false;
nsCOMPtr<nsISupports> supportsWindow;
windowList->GetNext(getter_AddRefs(supportsWindow));
nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
if (baseWin) {
nsCOMPtr<nsIWidget> widget;
baseWin->GetMainWidget(getter_AddRefs(widget));
if (widget && widget->SizeMode() == nsSizeMode_Fullscreen) {
return true;
}
}
}
return false;
}
#endif
/*
* Just do the window-making part of CreateTopLevelWindow
*/
nsresult
nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent,
nsIURI *aUrl,
uint32_t aChromeMask,
int32_t aInitialWidth,
int32_t aInitialHeight,
bool aIsHiddenWindow,
nsITabParent *aOpeningTab,
nsWebShellWindow **aResult)
{
*aResult = nullptr;
NS_ENSURE_STATE(!mXPCOMWillShutDown);
nsCOMPtr<nsIXULWindow> parent;
if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT)
parent = aParent;
RefPtr<nsWebShellWindow> window = new nsWebShellWindow(aChromeMask);
NS_ENSURE_TRUE(window, NS_ERROR_OUT_OF_MEMORY);
#ifdef XP_WIN
// If the parent is currently fullscreen, tell the child to ignore persisted
// full screen states. This way new browser windows open on top of fullscreen
// windows normally.
if (window && CheckForFullscreenWindow())
window->IgnoreXULSizeMode(true);
#endif
nsWidgetInitData widgetInitData;
if (aIsHiddenWindow)
widgetInitData.mWindowType = eWindowType_invisible;
else
widgetInitData.mWindowType = aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG ?
eWindowType_dialog : eWindowType_toplevel;
if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)
widgetInitData.mWindowType = eWindowType_popup;
if (aChromeMask & nsIWebBrowserChrome::CHROME_MAC_SUPPRESS_ANIMATION)
widgetInitData.mIsAnimationSuppressed = true;
#ifdef XP_MACOSX
// Mac OS X sheet support
// Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from
// nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal
// windows opened from nsPromptService::DoDialog() still are sheets. This
// fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and
// nsCocoaWindow::SetModal()).
uint32_t sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
nsIWebBrowserChrome::CHROME_MODAL |
nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
if (parent &&
(parent != mHiddenWindow && parent != mHiddenPrivateWindow) &&
((aChromeMask & sheetMask) == sheetMask)) {
widgetInitData.mWindowType = eWindowType_sheet;
}
#endif
#if defined(XP_WIN)
if (widgetInitData.mWindowType == eWindowType_toplevel ||
widgetInitData.mWindowType == eWindowType_dialog)
widgetInitData.clipChildren = true;
#endif
// note default chrome overrides other OS chrome settings, but
// not internal chrome
if (aChromeMask & nsIWebBrowserChrome::CHROME_DEFAULT)
widgetInitData.mBorderStyle = eBorderStyle_default;
else if ((aChromeMask & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL)
widgetInitData.mBorderStyle = eBorderStyle_all;
else {
widgetInitData.mBorderStyle = eBorderStyle_none; // assumes none == 0x00
if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_BORDERS)
widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_border);
if (aChromeMask & nsIWebBrowserChrome::CHROME_TITLEBAR)
widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_title);
if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_CLOSE)
widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_close);
if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_resizeh);
// only resizable windows get the maximize button (but not dialogs)
if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_maximize);
}
// all windows (except dialogs) get minimize buttons and the system menu
if (!(aChromeMask & nsIWebBrowserChrome::CHROME_OPENAS_DIALOG))
widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize | eBorderStyle_menu);
// but anyone can explicitly ask for a minimize button
if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_MIN) {
widgetInitData.mBorderStyle = static_cast<enum nsBorderStyle>(widgetInitData.mBorderStyle | eBorderStyle_minimize);
}
}
if (aInitialWidth == nsIAppShellService::SIZE_TO_CONTENT ||
aInitialHeight == nsIAppShellService::SIZE_TO_CONTENT) {
aInitialWidth = 1;
aInitialHeight = 1;
window->SetIntrinsicallySized(true);
}
bool center = aChromeMask & nsIWebBrowserChrome::CHROME_CENTER_SCREEN;
nsCOMPtr<nsIXULChromeRegistry> reg =
mozilla::services::GetXULChromeRegistryService();
if (reg) {
nsAutoCString package;
package.AssignLiteral("global");
bool isRTL = false;
reg->IsLocaleRTL(package, &isRTL);
widgetInitData.mRTL = isRTL;
}
#ifdef MOZ_WIDGET_GONK
// B2G multi-screen support. Screen ID is for differentiating screens of
// windows, and due to the hardware limitation, it is platform-specific for
// now, which align with the value of display type defined in HWC.
widgetInitData.mScreenId = mScreenId;
#endif
nsresult rv = window->Initialize(parent, center ? aParent : nullptr,
aUrl, aInitialWidth, aInitialHeight,
aIsHiddenWindow, aOpeningTab, widgetInitData);
NS_ENSURE_SUCCESS(rv, rv);
// Enforce the Private Browsing autoStart pref first.
bool isPrivateBrowsingWindow =
Preferences::GetBool("browser.privatebrowsing.autostart");
bool isUsingRemoteTabs = mozilla::BrowserTabsRemoteAutostart();
if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
// Caller requested a private window
isPrivateBrowsingWindow = true;
}
if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
isUsingRemoteTabs = true;
}
nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(aParent);
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(domWin);
nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(webNav);
if (!isPrivateBrowsingWindow && parentContext) {
// Ensure that we propagate any existing private browsing status
// from the parent, even if it will not actually be used
// as a parent value.
isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
}
if (parentContext) {
isUsingRemoteTabs = parentContext->UseRemoteTabs();
}
nsCOMPtr<nsIDOMWindow> newDomWin =
do_GetInterface(NS_ISUPPORTS_CAST(nsIBaseWindow*, window));
nsCOMPtr<nsIWebNavigation> newWebNav = do_GetInterface(newDomWin);
nsCOMPtr<nsILoadContext> thisContext = do_GetInterface(newWebNav);
if (thisContext) {
thisContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
thisContext->SetRemoteTabs(isUsingRemoteTabs);
}
window.swap(*aResult); // transfer reference
if (parent)
parent->AddChildWindow(*aResult);
if (center)
rv = (*aResult)->Center(parent, parent ? false : true, false);
return rv;
}
NS_IMETHODIMP
nsAppShellService::GetHiddenWindow(nsIXULWindow **aWindow)
{
NS_ENSURE_ARG_POINTER(aWindow);
*aWindow = mHiddenWindow;
NS_IF_ADDREF(*aWindow);
return *aWindow ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsAppShellService::GetHiddenDOMWindow(nsIDOMWindow **aWindow)
{
nsresult rv;
nsCOMPtr<nsIDocShell> docShell;
NS_ENSURE_TRUE(mHiddenWindow, NS_ERROR_FAILURE);
rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMWindow> hiddenDOMWindow(docShell->GetWindow());
hiddenDOMWindow.forget(aWindow);
return *aWindow ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsAppShellService::GetHiddenPrivateWindow(nsIXULWindow **aWindow)
{
NS_ENSURE_ARG_POINTER(aWindow);
EnsurePrivateHiddenWindow();
*aWindow = mHiddenPrivateWindow;
NS_IF_ADDREF(*aWindow);
return *aWindow ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsAppShellService::GetHiddenPrivateDOMWindow(nsIDOMWindow **aWindow)
{
EnsurePrivateHiddenWindow();
nsresult rv;
nsCOMPtr<nsIDocShell> docShell;
NS_ENSURE_TRUE(mHiddenPrivateWindow, NS_ERROR_FAILURE);
rv = mHiddenPrivateWindow->GetDocShell(getter_AddRefs(docShell));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMWindow> hiddenPrivateDOMWindow(docShell->GetWindow());
hiddenPrivateDOMWindow.forget(aWindow);
return *aWindow ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsAppShellService::GetHasHiddenPrivateWindow(bool* aHasPrivateWindow)
{
NS_ENSURE_ARG_POINTER(aHasPrivateWindow);
*aHasPrivateWindow = !!mHiddenPrivateWindow;
return NS_OK;
}
NS_IMETHODIMP
nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindow **aWindow,
JSContext **aJSContext)
{
nsresult rv = NS_OK;
if ( aWindow && aJSContext ) {
*aWindow = nullptr;
*aJSContext = nullptr;
if ( mHiddenWindow ) {
// Convert hidden window to nsIDOMWindow and extract its JSContext.
do {
// 1. Get doc for hidden window.
nsCOMPtr<nsIDocShell> docShell;
rv = mHiddenWindow->GetDocShell(getter_AddRefs(docShell));
if (NS_FAILED(rv)) break;
if (!docShell) {
break;
}
// 2. Convert that to an nsIDOMWindow.
nsCOMPtr<nsIDOMWindow> hiddenDOMWindow(docShell->GetWindow());
if(!hiddenDOMWindow) break;
// 3. Get script global object for the window.
nsCOMPtr<nsIScriptGlobalObject> sgo = docShell->GetScriptGlobalObject();
if (!sgo) { rv = NS_ERROR_FAILURE; break; }
// 4. Get script context from that.
nsIScriptContext *scriptContext = sgo->GetContext();
if (!scriptContext) { rv = NS_ERROR_FAILURE; break; }
// 5. Get JSContext from the script context.
JSContext *jsContext = scriptContext->GetNativeContext();
if (!jsContext) { rv = NS_ERROR_FAILURE; break; }
// Now, give results to caller.
*aWindow = hiddenDOMWindow.get();
NS_IF_ADDREF( *aWindow );
*aJSContext = jsContext;
} while (0);
} else {
rv = NS_ERROR_FAILURE;
}
} else {
rv = NS_ERROR_NULL_POINTER;
}
return rv;
}
NS_IMETHODIMP
nsAppShellService::GetApplicationProvidedHiddenWindow(bool* aAPHW)
{
*aAPHW = mApplicationProvidedHiddenWindow;
return NS_OK;
}
/*
* Register a new top level window (created elsewhere)
*/
NS_IMETHODIMP
nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
{
NS_ENSURE_ARG_POINTER(aWindow);
nsCOMPtr<nsIDocShell> docShell;
aWindow->GetDocShell(getter_AddRefs(docShell));
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
nsCOMPtr<nsPIDOMWindow> domWindow(docShell->GetWindow());
NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
domWindow->SetInitialPrincipalToSubject();
// tell the window mediator about the new window
nsCOMPtr<nsIWindowMediator> mediator
( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
NS_ASSERTION(mediator, "Couldn't get window mediator.");
if (mediator)
mediator->RegisterWindow(aWindow);
// tell the window watcher about the new window
nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
NS_ASSERTION(wwatcher, "No windowwatcher?");
if (wwatcher && domWindow) {
wwatcher->AddWindow(domWindow, 0);
}
// an ongoing attempt to quit is stopped by a newly opened window
nsCOMPtr<nsIObserverService> obssvc = services::GetObserverService();
NS_ASSERTION(obssvc, "Couldn't get observer service.");
if (obssvc)
obssvc->NotifyObservers(aWindow, "xul-window-registered", nullptr);
return NS_OK;
}
NS_IMETHODIMP
nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow)
{
if (mXPCOMShuttingDown) {
/* return an error code in order to:
- avoid doing anything with other member variables while we are in
the destructor
- notify the caller not to release the AppShellService after
unregistering the window
(we don't want to be deleted twice consecutively to
mHiddenWindow->Destroy() in our destructor)
*/
return NS_ERROR_FAILURE;
}
NS_ENSURE_ARG_POINTER(aWindow);
if (aWindow == mHiddenWindow) {
// CreateHiddenWindow() does not register the window, so we're done.
return NS_OK;
}
if (aWindow == mHiddenPrivateWindow) {
// CreateHiddenWindow() does not register the window, so we're done.
return NS_OK;
}
// tell the window mediator
nsCOMPtr<nsIWindowMediator> mediator
( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
NS_ASSERTION(mediator, "Couldn't get window mediator. Doing xpcom shutdown?");
if (mediator)
mediator->UnregisterWindow(aWindow);
// tell the window watcher
nsCOMPtr<nsPIWindowWatcher> wwatcher ( do_GetService(NS_WINDOWWATCHER_CONTRACTID) );
NS_ASSERTION(wwatcher, "Couldn't get windowwatcher, doing xpcom shutdown?");
if (wwatcher) {
nsCOMPtr<nsIDocShell> docShell;
aWindow->GetDocShell(getter_AddRefs(docShell));
if (docShell) {
nsCOMPtr<nsIDOMWindow> domWindow(docShell->GetWindow());
if (domWindow)
wwatcher->RemoveWindow(domWindow);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsAppShellService::Observe(nsISupports* aSubject, const char *aTopic,
const char16_t *aData)
{
if (!strcmp(aTopic, "xpcom-will-shutdown")) {
mXPCOMWillShutDown = true;
} else if (!strcmp(aTopic, "xpcom-shutdown")) {
mXPCOMShuttingDown = true;
if (mHiddenWindow) {
mHiddenWindow->Destroy();
}
if (mHiddenPrivateWindow) {
mHiddenPrivateWindow->Destroy();
}
} else {
NS_ERROR("Unexpected observer topic!");
}
return NS_OK;
}
NS_IMETHODIMP
nsAppShellService::StartEventLoopLagTracking(bool* aResult)
{
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
*aResult = mozilla::InitEventTracing(true);
#endif
return NS_OK;
}
NS_IMETHODIMP
nsAppShellService::StopEventLoopLagTracking()
{
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
mozilla::ShutdownEventTracing();
#endif
return NS_OK;
}