michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=8 et tw=80 : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/dom/TabContext.h" michael@0: #include "mozilla/dom/PTabContext.h" michael@0: #include "mozilla/dom/TabParent.h" michael@0: #include "mozilla/dom/TabChild.h" michael@0: #include "nsIAppsService.h" michael@0: #include "nsIScriptSecurityManager.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: michael@0: #define NO_APP_ID (nsIScriptSecurityManager::NO_APP_ID) michael@0: michael@0: using namespace mozilla::dom::ipc; michael@0: using namespace mozilla::layout; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: TabContext::TabContext() michael@0: : mInitialized(false) michael@0: , mOwnAppId(NO_APP_ID) michael@0: , mContainingAppId(NO_APP_ID) michael@0: , mScrollingBehavior(DEFAULT_SCROLLING) michael@0: , mIsBrowser(false) michael@0: { michael@0: } michael@0: michael@0: bool michael@0: TabContext::IsBrowserElement() const michael@0: { michael@0: return mIsBrowser; michael@0: } michael@0: michael@0: bool michael@0: TabContext::IsBrowserOrApp() const michael@0: { michael@0: return HasOwnApp() || IsBrowserElement(); michael@0: } michael@0: michael@0: uint32_t michael@0: TabContext::OwnAppId() const michael@0: { michael@0: return mOwnAppId; michael@0: } michael@0: michael@0: already_AddRefed michael@0: TabContext::GetOwnApp() const michael@0: { michael@0: nsCOMPtr ownApp = mOwnApp; michael@0: return ownApp.forget(); michael@0: } michael@0: michael@0: bool michael@0: TabContext::HasOwnApp() const michael@0: { michael@0: nsCOMPtr ownApp = GetOwnApp(); michael@0: return !!ownApp; michael@0: } michael@0: michael@0: uint32_t michael@0: TabContext::BrowserOwnerAppId() const michael@0: { michael@0: if (IsBrowserElement()) { michael@0: return mContainingAppId; michael@0: } michael@0: return NO_APP_ID; michael@0: } michael@0: michael@0: already_AddRefed michael@0: TabContext::GetBrowserOwnerApp() const michael@0: { michael@0: nsCOMPtr ownerApp; michael@0: if (IsBrowserElement()) { michael@0: ownerApp = mContainingApp; michael@0: } michael@0: return ownerApp.forget(); michael@0: } michael@0: michael@0: bool michael@0: TabContext::HasBrowserOwnerApp() const michael@0: { michael@0: nsCOMPtr ownerApp = GetBrowserOwnerApp(); michael@0: return !!ownerApp; michael@0: } michael@0: michael@0: uint32_t michael@0: TabContext::AppOwnerAppId() const michael@0: { michael@0: if (HasOwnApp()) { michael@0: return mContainingAppId; michael@0: } michael@0: return NO_APP_ID; michael@0: } michael@0: michael@0: already_AddRefed michael@0: TabContext::GetAppOwnerApp() const michael@0: { michael@0: nsCOMPtr ownerApp; michael@0: if (HasOwnApp()) { michael@0: ownerApp = mContainingApp; michael@0: } michael@0: return ownerApp.forget(); michael@0: } michael@0: michael@0: bool michael@0: TabContext::HasAppOwnerApp() const michael@0: { michael@0: nsCOMPtr ownerApp = GetAppOwnerApp(); michael@0: return !!ownerApp; michael@0: } michael@0: michael@0: uint32_t michael@0: TabContext::OwnOrContainingAppId() const michael@0: { michael@0: if (HasOwnApp()) { michael@0: return mOwnAppId; michael@0: } michael@0: michael@0: return mContainingAppId; michael@0: } michael@0: michael@0: already_AddRefed michael@0: TabContext::GetOwnOrContainingApp() const michael@0: { michael@0: nsCOMPtr ownOrContainingApp; michael@0: if (HasOwnApp()) { michael@0: ownOrContainingApp = mOwnApp; michael@0: } else { michael@0: ownOrContainingApp = mContainingApp; michael@0: } michael@0: michael@0: return ownOrContainingApp.forget(); michael@0: } michael@0: michael@0: bool michael@0: TabContext::HasOwnOrContainingApp() const michael@0: { michael@0: nsCOMPtr ownOrContainingApp = GetOwnOrContainingApp(); michael@0: return !!ownOrContainingApp; michael@0: } michael@0: michael@0: bool michael@0: TabContext::SetTabContext(const TabContext& aContext) michael@0: { michael@0: NS_ENSURE_FALSE(mInitialized, false); michael@0: michael@0: *this = aContext; michael@0: mInitialized = true; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabContext::SetTabContextForAppFrame(mozIApplication* aOwnApp, michael@0: mozIApplication* aAppFrameOwnerApp, michael@0: ScrollingBehavior aRequestedBehavior) michael@0: { michael@0: NS_ENSURE_FALSE(mInitialized, false); michael@0: michael@0: // Get ids for both apps and only write to our member variables after we've michael@0: // verified that this worked. michael@0: uint32_t ownAppId = NO_APP_ID; michael@0: if (aOwnApp) { michael@0: nsresult rv = aOwnApp->GetLocalId(&ownAppId); michael@0: NS_ENSURE_SUCCESS(rv, false); michael@0: NS_ENSURE_TRUE(ownAppId != NO_APP_ID, false); michael@0: } michael@0: michael@0: uint32_t containingAppId = NO_APP_ID; michael@0: if (aAppFrameOwnerApp) { michael@0: nsresult rv = aAppFrameOwnerApp->GetLocalId(&containingAppId); michael@0: NS_ENSURE_SUCCESS(rv, false); michael@0: NS_ENSURE_TRUE(containingAppId != NO_APP_ID, false); michael@0: } michael@0: michael@0: mInitialized = true; michael@0: mIsBrowser = false; michael@0: mOwnAppId = ownAppId; michael@0: mContainingAppId = containingAppId; michael@0: mScrollingBehavior = aRequestedBehavior; michael@0: mOwnApp = aOwnApp; michael@0: mContainingApp = aAppFrameOwnerApp; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabContext::SetTabContextForBrowserFrame(mozIApplication* aBrowserFrameOwnerApp, michael@0: ScrollingBehavior aRequestedBehavior) michael@0: { michael@0: NS_ENSURE_FALSE(mInitialized, false); michael@0: michael@0: uint32_t containingAppId = NO_APP_ID; michael@0: if (aBrowserFrameOwnerApp) { michael@0: nsresult rv = aBrowserFrameOwnerApp->GetLocalId(&containingAppId); michael@0: NS_ENSURE_SUCCESS(rv, false); michael@0: NS_ENSURE_TRUE(containingAppId != NO_APP_ID, false); michael@0: } michael@0: michael@0: mInitialized = true; michael@0: mIsBrowser = true; michael@0: mOwnAppId = NO_APP_ID; michael@0: mContainingAppId = containingAppId; michael@0: mScrollingBehavior = aRequestedBehavior; michael@0: mContainingApp = aBrowserFrameOwnerApp; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabContext::SetTabContextForNormalFrame(ScrollingBehavior aRequestedBehavior) michael@0: { michael@0: NS_ENSURE_FALSE(mInitialized, false); michael@0: michael@0: mInitialized = true; michael@0: mScrollingBehavior = aRequestedBehavior; michael@0: return true; michael@0: } michael@0: michael@0: IPCTabContext michael@0: TabContext::AsIPCTabContext() const michael@0: { michael@0: if (mIsBrowser) { michael@0: return IPCTabContext(BrowserFrameIPCTabContext(mContainingAppId), michael@0: mScrollingBehavior); michael@0: } michael@0: michael@0: return IPCTabContext(AppFrameIPCTabContext(mOwnAppId, mContainingAppId), michael@0: mScrollingBehavior); michael@0: } michael@0: michael@0: static already_AddRefed michael@0: GetAppForId(uint32_t aAppId) michael@0: { michael@0: nsCOMPtr appsService = do_GetService(APPS_SERVICE_CONTRACTID); michael@0: NS_ENSURE_TRUE(appsService, nullptr); michael@0: michael@0: nsCOMPtr app; michael@0: appsService->GetAppByLocalId(aAppId, getter_AddRefs(app)); michael@0: michael@0: return app.forget(); michael@0: } michael@0: michael@0: MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams) michael@0: : mInvalidReason(nullptr) michael@0: { michael@0: bool isBrowser = false; michael@0: uint32_t ownAppId = NO_APP_ID; michael@0: uint32_t containingAppId = NO_APP_ID; michael@0: michael@0: const IPCTabAppBrowserContext& appBrowser = aParams.appBrowserContext(); michael@0: switch(appBrowser.type()) { michael@0: case IPCTabAppBrowserContext::TPopupIPCTabContext: { michael@0: const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext(); michael@0: michael@0: TabContext *context; michael@0: if (ipcContext.openerParent()) { michael@0: context = static_cast(ipcContext.openerParent()); michael@0: if (context->IsBrowserElement() && !ipcContext.isBrowserElement()) { michael@0: // If the TabParent corresponds to a browser element, then it can only michael@0: // open other browser elements, for security reasons. We should have michael@0: // checked this before calling the TabContext constructor, so this is michael@0: // a fatal error. michael@0: mInvalidReason = "Child is-browser process tried to " michael@0: "open a non-browser tab."; michael@0: return; michael@0: } michael@0: } else if (ipcContext.openerChild()) { michael@0: context = static_cast(ipcContext.openerChild()); michael@0: } else { michael@0: // This should be unreachable because PopupIPCTabContext::opener is not a michael@0: // nullable field. michael@0: mInvalidReason = "PopupIPCTabContext::opener was null (?!)."; michael@0: return; michael@0: } michael@0: michael@0: // Browser elements can't nest other browser elements. So if michael@0: // our opener is browser element, we must be a new DOM window michael@0: // opened by it. In that case we inherit our containing app ID michael@0: // (if any). michael@0: // michael@0: // Otherwise, we're a new app window and we inherit from our michael@0: // opener app. michael@0: if (ipcContext.isBrowserElement()) { michael@0: isBrowser = true; michael@0: ownAppId = NO_APP_ID; michael@0: containingAppId = context->OwnOrContainingAppId(); michael@0: } else { michael@0: isBrowser = false; michael@0: ownAppId = context->mOwnAppId; michael@0: containingAppId = context->mContainingAppId; michael@0: } michael@0: break; michael@0: } michael@0: case IPCTabAppBrowserContext::TAppFrameIPCTabContext: { michael@0: const AppFrameIPCTabContext &ipcContext = michael@0: appBrowser.get_AppFrameIPCTabContext(); michael@0: michael@0: isBrowser = false; michael@0: ownAppId = ipcContext.ownAppId(); michael@0: containingAppId = ipcContext.appFrameOwnerAppId(); michael@0: break; michael@0: } michael@0: case IPCTabAppBrowserContext::TBrowserFrameIPCTabContext: { michael@0: const BrowserFrameIPCTabContext &ipcContext = michael@0: appBrowser.get_BrowserFrameIPCTabContext(); michael@0: michael@0: isBrowser = true; michael@0: ownAppId = NO_APP_ID; michael@0: containingAppId = ipcContext.browserFrameOwnerAppId(); michael@0: break; michael@0: } michael@0: case IPCTabAppBrowserContext::TVanillaFrameIPCTabContext: { michael@0: isBrowser = false; michael@0: ownAppId = NO_APP_ID; michael@0: containingAppId = NO_APP_ID; michael@0: break; michael@0: } michael@0: default: { michael@0: MOZ_CRASH(); michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr ownApp = GetAppForId(ownAppId); michael@0: if ((ownApp == nullptr) != (ownAppId == NO_APP_ID)) { michael@0: mInvalidReason = "Got an ownAppId that didn't correspond to an app."; michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr containingApp = GetAppForId(containingAppId); michael@0: if ((containingApp == nullptr) != (containingAppId == NO_APP_ID)) { michael@0: mInvalidReason = "Got a containingAppId that didn't correspond to an app."; michael@0: return; michael@0: } michael@0: michael@0: bool rv; michael@0: if (isBrowser) { michael@0: rv = mTabContext.SetTabContextForBrowserFrame(containingApp, michael@0: aParams.scrollingBehavior()); michael@0: } else { michael@0: rv = mTabContext.SetTabContextForAppFrame(ownApp, michael@0: containingApp, michael@0: aParams.scrollingBehavior()); michael@0: } michael@0: michael@0: if (!rv) { michael@0: mInvalidReason = "Couldn't initialize TabContext."; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: MaybeInvalidTabContext::IsValid() michael@0: { michael@0: return mInvalidReason == nullptr; michael@0: } michael@0: michael@0: const char* michael@0: MaybeInvalidTabContext::GetInvalidReason() michael@0: { michael@0: return mInvalidReason; michael@0: } michael@0: michael@0: const TabContext& michael@0: MaybeInvalidTabContext::GetTabContext() michael@0: { michael@0: if (!IsValid()) { michael@0: MOZ_CRASH("Can't GetTabContext() if !IsValid()."); michael@0: } michael@0: michael@0: return mTabContext; michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla