/* -*- 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/. */
NS_IMETHODIMP
nsAppShellService::CreateHiddenWindow() { #ifdefined(XP_MACOSX) if (!XRE_IsParentProcess()) { return NS_ERROR_NOT_IMPLEMENTED;
}
if (mXPCOMShuttingDown) { return NS_ERROR_FAILURE;
}
if (mHiddenWindow) { return NS_OK;
}
nsCOMPtr<nsIFile> profileDir;
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(profileDir)); if (!profileDir) { // This is too early on startup to create the hidden window return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsAppShellService::DestroyHiddenWindow() { if (mHiddenWindow) {
mHiddenWindow->Destroy();
mHiddenWindow = nullptr;
}
return NS_OK;
}
/* * Create a new top level window and display the given URL within it...
*/
NS_IMETHODIMP
nsAppShellService::CreateTopLevelWindow(nsIAppWindow* aParent, nsIURI* aUrl,
uint32_t aChromeMask,
int32_t aInitialWidth,
int32_t aInitialHeight,
nsIAppWindow** aResult) {
nsresult rv;
if (NS_SUCCEEDED(rv)) { // the addref resulting from this is the owning addref for this window
RegisterTopLevelWindow(*aResult);
}
return rv;
}
/* * This class provides a stub implementation of nsIWebBrowserChrome, as needed * by nsAppShellService::CreateWindowlessBrowser
*/ class WebBrowserChrome2Stub final : public nsIWebBrowserChrome, public nsIInterfaceRequestor, public nsSupportsWeakReference { protected:
nsCOMPtr<nsIWebBrowser> mBrowser; virtual ~WebBrowserChrome2Stub() = default;
NS_IMETHODIMP
WebBrowserChrome2Stub::ShowAsModal() {
MOZ_ASSERT_UNREACHABLE("WebBrowserChrome2Stub::ShowAsModal is not supported"); return NS_ERROR_NOT_IMPLEMENTED;
}
// This is the "stub" we return from CreateWindowlessBrowser - it exists // to manage the lifetimes of the nsIWebBrowser and container window. // In particular, it keeps a strong reference to both, to prevent them from // being collected while this object remains alive, and ensures that they // aren't destroyed when it's not safe to run scripts. class WindowlessBrowser final : public nsIWindowlessBrowser, public nsIInterfaceRequestor { public:
WindowlessBrowser(nsIWebBrowser* aBrowser, nsISupports* aContainer)
: mBrowser(aBrowser), mContainer(aContainer), mClosed(false) {
mWebNavigation = do_QueryInterface(aBrowser);
mInterfaceRequestor = do_QueryInterface(aBrowser);
}
NS_DECL_ISUPPORTS
NS_DECL_NSIWINDOWLESSBROWSER
NS_FORWARD_SAFE_NSIWEBNAVIGATION(RefPtr{mWebNavigation.get()})
NS_FORWARD_SAFE_NSIINTERFACEREQUESTOR(mInterfaceRequestor)
private:
~WindowlessBrowser() { if (mClosed) { return;
}
NS_WARNING("Windowless browser was not closed prior to destruction");
// The docshell destructor needs to dispatch events, and can only run // when it's safe to run scripts. If this was triggered by GC, it may // not always be safe to run scripts, in which cases we need to delay // destruction until it is. auto runnable = MakeRefPtr<BrowserDestroyer>(mBrowser, mContainer);
nsContentUtils::AddScriptRunner(runnable.forget());
}
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_IMETHODIMP
WindowlessBrowser::Close() {
NS_ENSURE_TRUE(!mClosed, NS_ERROR_UNEXPECTED);
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "WindowlessBrowser::Close called when not safe to run scripts");
/* First, 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 nsIWebBrowserChrome.
*/
RefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub();
/* 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 HeadlessWidget/PuppetWidget, which provide * a stub implementation of nsIWidget.
*/
nsCOMPtr<nsIWidget> widget; if (gfxPlatform::IsHeadless()) {
widget = nsIWidget::CreateHeadlessWidget();
} else {
widget = nsIWidget::CreatePuppetWidget(nullptr);
} if (!widget) {
NS_ERROR("Couldn't create instance of stub widget"); return NS_ERROR_FAILURE;
}
// Create a BrowsingContext for our windowless browser.
RefPtr<BrowsingContext> browsingContext = BrowsingContext::CreateIndependent(
aIsChrome ? BrowsingContext::Type::Chrome
: BrowsingContext::Type::Content, true);
if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
browsingContext->SetRemoteTabs(true);
} if (aChromeMask & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) {
browsingContext->SetRemoteSubframes(true);
} if (aChromeMask & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) {
browsingContext->SetPrivateBrowsing(true);
}
/* Next, 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 = nsWebBrowser::Create(
stub, widget, browsingContext, nullptr /* initialWindowChild */);
if (NS_WARN_IF(!browser)) {
NS_ERROR("Couldn't create instance of nsWebBrowser!"); return NS_ERROR_FAILURE;
}
// Make sure the container window owns the the nsWebBrowser instance.
stub->SetBrowser(browser);
nsISupports* isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome*, stub);
RefPtr<nsIWindowlessBrowser> result = new WindowlessBrowser(browser, isstub);
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(result);
docshell->SetInvisible(true);
result.forget(aResult); return NS_OK;
}
/* * Just do the window-making part of CreateTopLevelWindow
*/
nsresult nsAppShellService::JustCreateTopWindow(
nsIAppWindow* aParent, nsIURI* aUrl, uint32_t aChromeMask,
int32_t aInitialWidth, int32_t aInitialHeight, bool aIsHiddenWindow,
AppWindow** aResult) { using BorderStyle = widget::BorderStyle;
*aResult = nullptr;
NS_ENSURE_STATE(!mXPCOMWillShutDown);
nsCOMPtr<nsIAppWindow> parent; if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) parent = aParent;
RefPtr<AppWindow> window = new AppWindow(aChromeMask);
#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 (nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(aParent)) {
nsCOMPtr<nsIWidget> widget;
baseWin->GetMainWidget(getter_AddRefs(widget)); if (widget && widget->SizeMode() == nsSizeMode_Fullscreen) {
window->IgnoreXULSizeMode(true);
}
} #endif
if (aChromeMask & nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION) {
widgetInitData.mIsAnimationSuppressed = true;
}
if (aChromeMask & nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP) {
widgetInitData.mAlwaysOnTop = true;
}
if (aChromeMask & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) {
widgetInitData.mHasRemoteContent = true;
}
#ifdefined(MOZ_WIDGET_GTK) || defined(XP_WIN) // Windows/Gtk PIP window support. It's Chrome dialog window, always on top // and without any bar.
uint32_t pipMask = nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP |
nsIWebBrowserChrome::CHROME_OPENAS_CHROME |
nsIWebBrowserChrome::CHROME_WINDOW_RESIZE;
uint32_t barMask = nsIWebBrowserChrome::CHROME_MENUBAR |
nsIWebBrowserChrome::CHROME_TOOLBAR |
nsIWebBrowserChrome::CHROME_LOCATIONBAR |
nsIWebBrowserChrome::CHROME_TITLEBAR |
nsIWebBrowserChrome::CHROME_STATUSBAR; if (widgetInitData.mWindowType == widget::WindowType::Dialog &&
((aChromeMask & pipMask) == pipMask) && !(aChromeMask & barMask)) {
widgetInitData.mPIPWindow = true;
} #endif
// alert=yes is expected to be used along with dialogs, not other window // types.
MOZ_ASSERT_IF(aChromeMask & nsIWebBrowserChrome::CHROME_ALERT,
widgetInitData.mWindowType == widget::WindowType::Dialog);
widgetInitData.mIsAlert =
!!(aChromeMask & nsIWebBrowserChrome::CHROME_ALERT) &&
widgetInitData.mWindowType == widget::WindowType::Dialog;
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 (RefPtr<nsDocShell> docShell = window->GetDocShell()) {
MOZ_ASSERT(docShell->GetBrowsingContext()->IsChrome());
// Eagerly create an about:blank content viewer with the right principal // here, rather than letting it happen in the upcoming call to // SetInitialPrincipal. This avoids creating the about:blank document and // then blowing it away with a second one, which can cause problems for the // top-level chrome window case. See bug 789773. // Toplevel chrome windows always have a system principal, so ensure the // initial window is created with that principal. // We need to do this even when creating a chrome window to load a content // window, see bug 799348 comment 13 for details about what previously // happened here due to it using the subject principal. if (nsContentUtils::IsInitialized()) { // Sometimes this happens really // early. See bug 793370.
MOZ_DIAGNOSTIC_ASSERT(
nsContentUtils::LegacyIsCallerChromeOrNativeCode(), "Previously, this method would use the subject principal rather than " "hardcoding the system principal"); // Use the system principal as the storage principal too until the new // window finishes navigating and gets a real storage principal.
rv = docShell->CreateAboutBlankDocumentViewer(
nsContentUtils::GetSystemPrincipal(),
nsContentUtils::GetSystemPrincipal(), /* aCsp = */ nullptr, /* aBaseURI = */ nullptr, /* aIsInitialDocument = */ true);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<dom::Document> doc = docShell->GetDocument();
NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE);
MOZ_ASSERT(doc->IsInitialDocument(), "Document should be an initial document");
}
// Begin loading the URL provided. if (aUrl) {
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aUrl);
loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
loadState->SetFirstParty(true);
rv = docShell->LoadURI(loadState, /* aSetNavigating */ true);
NS_ENSURE_SUCCESS(rv, rv);
}
}
// Toplevel chrome windows always have a system principal, so ensure the // initial window is created with that principal. // We need to do this even when creating a chrome window to load a content // window, see bug 799348 comment 13 for details about what previously // happened here due to it using the subject principal.
MOZ_DIAGNOSTIC_ASSERT(
nsContentUtils::LegacyIsCallerChromeOrNativeCode(), "Previously, this method would use the subject principal rather than " "hardcoding the system principal");
domWindow->SetInitialPrincipal(nsContentUtils::GetSystemPrincipal(), nullptr,
Nothing());
// 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.");
NS_IMETHODIMP
nsAppShellService::UnregisterTopLevelWindow(nsIAppWindow* 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;
}
// 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<nsPIDOMWindowOuter> domWindow(docShell->GetWindow()); if (domWindow) wwatcher->RemoveWindow(domWindow);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.