/* -*- Mode: C++; tab-width: 8; 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 "base/basictypes.h" #include "TabChild.h" #include "gfxPrefs.h" #ifdef ACCESSIBILITY #include "mozilla/a11y/DocAccessibleChild.h" #endif #include "Layers.h" #include "ContentChild.h" #include "TabParent.h" #include "mozilla/Preferences.h" #include "mozilla/BrowserElementParent.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/EventListenerManager.h" #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h" #include "mozilla/plugins/PluginWidgetChild.h" #include "mozilla/IMEStateManager.h" #include "mozilla/ipc/URIUtils.h" #include "mozilla/layers/APZChild.h" #include "mozilla/layers/APZCCallbackHelper.h" #include "mozilla/layers/APZCTreeManager.h" #include "mozilla/layers/APZEventState.h" #include "mozilla/layers/ContentProcessController.h" #include "mozilla/layers/CompositorBridgeChild.h" #include "mozilla/layers/DoubleTapToZoom.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/InputAPZContext.h" #include "mozilla/layers/ShadowLayers.h" #include "mozilla/layout/RenderFrameChild.h" #include "mozilla/layout/RenderFrameParent.h" #include "mozilla/LookAndFeel.h" #include "mozilla/MouseEvents.h" #include "mozilla/Move.h" #include "mozilla/ProcessHangMonitor.h" #include "mozilla/ScopeExit.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" #include "mozilla/TextEvents.h" #include "mozilla/TouchEvents.h" #include "mozilla/Unused.h" #include "mozIApplication.h" #include "nsContentUtils.h" #include "nsCSSFrameConstructor.h" #include "nsDocShell.h" #include "nsEmbedCID.h" #include "nsGlobalWindow.h" #include #include "nsFilePickerProxy.h" #include "mozilla/dom/Element.h" #include "nsGlobalWindow.h" #include "nsIBaseWindow.h" #include "nsIBrowserDOMWindow.h" #include "nsIDocumentInlines.h" #include "nsIDocShellTreeOwner.h" #include "nsIDOMChromeWindow.h" #include "nsIDOMDocument.h" #include "nsIDOMEvent.h" #include "nsIDOMWindow.h" #include "nsIDOMWindowUtils.h" #include "nsFocusManager.h" #include "EventStateManager.h" #include "nsIDocShell.h" #include "nsIFrame.h" #include "nsIURI.h" #include "nsIURIFixup.h" #include "nsCDefaultURIFixup.h" #include "nsISupportsPrimitives.h" #include "nsIWebBrowser.h" #include "nsIWebBrowserFocus.h" #include "nsIWebBrowserSetup.h" #include "nsIWebProgress.h" #include "nsIXULRuntime.h" #include "nsPIDOMWindow.h" #include "nsPIWindowRoot.h" #include "nsLayoutUtils.h" #include "nsPrintfCString.h" #include "nsThreadUtils.h" #include "nsViewManager.h" #include "nsWeakReference.h" #include "nsWindowWatcher.h" #include "PermissionMessageUtils.h" #include "PuppetWidget.h" #include "StructuredCloneData.h" #include "nsViewportInfo.h" #include "nsILoadContext.h" #include "ipc/nsGUIEventIPC.h" #include "mozilla/gfx/Matrix.h" #include "UnitTransforms.h" #include "ClientLayerManager.h" #include "LayersLogging.h" #include "nsDOMClassInfoID.h" #include "nsColorPickerProxy.h" #include "nsContentPermissionHelper.h" #include "nsPresShell.h" #include "nsIAppsService.h" #include "nsNetUtil.h" #include "nsIPermissionManager.h" #include "nsIURILoader.h" #include "nsIScriptError.h" #include "mozilla/EventForwards.h" #include "nsDeviceContext.h" #include "nsSandboxFlags.h" #include "FrameLayerBuilder.h" #include "nsICommandParams.h" #include "nsISHistory.h" #include "nsQueryObject.h" #include "GroupedSHistory.h" #include "nsIHttpChannel.h" #include "mozilla/dom/DocGroup.h" #ifdef NS_PRINTING #include "nsIPrintSession.h" #include "nsIPrintSettings.h" #include "nsIPrintSettingsService.h" #include "nsIWebBrowserPrint.h" #endif #define BROWSER_ELEMENT_CHILD_SCRIPT \ NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js") #define TABC_LOG(...) // #define TABC_LOG(...) printf_stderr("TABC: " __VA_ARGS__) using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::ipc; using namespace mozilla::dom::workers; using namespace mozilla::ipc; using namespace mozilla::layers; using namespace mozilla::layout; using namespace mozilla::docshell; using namespace mozilla::widget; using namespace mozilla::jsipc; using mozilla::layers::GeckoContentController; NS_IMPL_ISUPPORTS(ContentListener, nsIDOMEventListener) NS_IMPL_ISUPPORTS(TabChildSHistoryListener, nsISHistoryListener, nsIPartialSHistoryListener, nsISupportsWeakReference) static const CSSSize kDefaultViewportSize(980, 480); static const char BEFORE_FIRST_PAINT[] = "before-first-paint"; typedef nsDataHashtable TabChildMap; static TabChildMap* sTabChildren; TabChildBase::TabChildBase() : mTabChildGlobal(nullptr) { mozilla::HoldJSObjects(this); } TabChildBase::~TabChildBase() { mAnonymousGlobalScopes.Clear(); mozilla::DropJSObjects(this); } NS_IMPL_CYCLE_COLLECTION_CLASS(TabChildBase) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TabChildBase) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChildGlobal) NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal) NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousGlobalScopes) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebBrowserChrome) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TabChildBase) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChildGlobal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebBrowserChrome) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TabChildBase) tmp->nsMessageManagerScriptExecutor::Trace(aCallbacks, aClosure); NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TabChildBase) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(TabChildBase) NS_IMPL_CYCLE_COLLECTING_RELEASE(TabChildBase) already_AddRefed TabChildBase::GetDocument() const { nsCOMPtr domDoc; WebNavigation()->GetDocument(getter_AddRefs(domDoc)); nsCOMPtr doc(do_QueryInterface(domDoc)); return doc.forget(); } already_AddRefed TabChildBase::GetPresShell() const { nsCOMPtr result; if (nsCOMPtr doc = GetDocument()) { result = doc->GetShell(); } return result.forget(); } void TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName, const nsAString& aJSONData) { AutoSafeJSContext cx; JS::Rooted json(cx, JS::NullValue()); StructuredCloneData data; if (JS_ParseJSON(cx, static_cast(aJSONData.BeginReading()), aJSONData.Length(), &json)) { ErrorResult rv; data.Write(cx, json, rv); if (NS_WARN_IF(rv.Failed())) { rv.SuppressException(); return; } } nsCOMPtr kungFuDeathGrip(GetGlobal()); // Let the BrowserElementScrolling helper (if it exists) for this // content manipulate the frame state. RefPtr mm = static_cast(mTabChildGlobal->mMessageManager.get()); mm->ReceiveMessage(static_cast(mTabChildGlobal), nullptr, aMessageName, false, &data, nullptr, nullptr, nullptr); } bool TabChildBase::UpdateFrameHandler(const FrameMetrics& aFrameMetrics) { MOZ_ASSERT(aFrameMetrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID); if (aFrameMetrics.IsRootContent()) { if (nsCOMPtr shell = GetPresShell()) { // Guard against stale updates (updates meant for a pres shell which // has since been torn down and destroyed). if (aFrameMetrics.GetPresShellId() == shell->GetPresShellId()) { ProcessUpdateFrame(aFrameMetrics); return true; } } } else { // aFrameMetrics.mIsRoot is false, so we are trying to update a subframe. // This requires special handling. FrameMetrics newSubFrameMetrics(aFrameMetrics); APZCCallbackHelper::UpdateSubFrame(newSubFrameMetrics); return true; } return true; } void TabChildBase::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics) { if (!mGlobal || !mTabChildGlobal) { return; } FrameMetrics newMetrics = aFrameMetrics; APZCCallbackHelper::UpdateRootFrame(newMetrics); } NS_IMETHODIMP ContentListener::HandleEvent(nsIDOMEvent* aEvent) { RemoteDOMEvent remoteEvent; remoteEvent.mEvent = do_QueryInterface(aEvent); NS_ENSURE_STATE(remoteEvent.mEvent); mTabChild->SendEvent(remoteEvent); return NS_OK; } class TabChild::DelayedDeleteRunnable final : public Runnable { RefPtr mTabChild; public: explicit DelayedDeleteRunnable(TabChild* aTabChild) : mTabChild(aTabChild) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aTabChild); } private: ~DelayedDeleteRunnable() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!mTabChild); } NS_IMETHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mTabChild); // Check in case ActorDestroy was called after RecvDestroy message. if (mTabChild->IPCOpen()) { Unused << PBrowserChild::Send__delete__(mTabChild); } mTabChild = nullptr; return NS_OK; } }; namespace { StaticRefPtr sPreallocatedTab; std::map>& NestedTabChildMap() { MOZ_ASSERT(NS_IsMainThread()); static std::map> sNestedTabChildMap; return sNestedTabChildMap; } } // namespace already_AddRefed TabChild::FindTabChild(const TabId& aTabId) { auto iter = NestedTabChildMap().find(aTabId); if (iter == NestedTabChildMap().end()) { return nullptr; } RefPtr tabChild = iter->second; return tabChild.forget(); } static void PreloadSlowThingsPostFork(void* aUnused) { nsCOMPtr observerService = mozilla::services::GetObserverService(); observerService->NotifyObservers(nullptr, "preload-postfork", nullptr); MOZ_ASSERT(sPreallocatedTab); // Initialize initial reflow of the PresShell has to happen after fork // because about:blank content viewer is created in the above observer // notification. nsCOMPtr docShell = do_GetInterface(sPreallocatedTab->WebNavigation()); if (nsIPresShell* presShell = docShell->GetPresShell()) { // Initialize and do an initial reflow of the about:blank // PresShell to let it preload some things for us. presShell->Initialize(0, 0); nsIDocument* doc = presShell->GetDocument(); doc->FlushPendingNotifications(Flush_Layout); // ... but after it's done, make sure it doesn't do any more // work. presShell->MakeZombie(); } } static bool sPreloaded = false; /*static*/ void TabChild::PreloadSlowThings() { if (sPreloaded) { // If we are alredy initialized in Nuwa, don't redo preloading. return; } sPreloaded = true; // Pass nullptr to aManager since at this point the TabChild is // not connected to any manager. Any attempt to use the TabChild // in IPC will crash. RefPtr tab(new TabChild(nullptr, TabId(0), TabContext(), /* chromeFlags */ 0)); if (!NS_SUCCEEDED(tab->Init()) || !tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) { return; } // Just load and compile these scripts, but don't run them. tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT, true); // Load, compile, and run these scripts. tab->RecvLoadRemoteScript( NS_LITERAL_STRING("chrome://global/content/preload.js"), true); sPreallocatedTab = tab; ClearOnShutdown(&sPreallocatedTab); PreloadSlowThingsPostFork(nullptr); } /*static*/ already_AddRefed TabChild::Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext &aContext, uint32_t aChromeFlags) { if (sPreallocatedTab && sPreallocatedTab->mChromeFlags == aChromeFlags && aContext.IsMozBrowserOrApp()) { RefPtr child = sPreallocatedTab.get(); sPreallocatedTab = nullptr; MOZ_ASSERT(!child->mTriedBrowserInit); child->mManager = aManager; child->SetTabId(aTabId); child->SetTabContext(aContext); child->NotifyTabContextUpdated(true); return child.forget(); } RefPtr iframe = new TabChild(aManager, aTabId, aContext, aChromeFlags); return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr; } TabChild::TabChild(nsIContentChild* aManager, const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags) : TabContext(aContext) , mRemoteFrame(nullptr) , mManager(aManager) , mChromeFlags(aChromeFlags) , mActiveSuppressDisplayport(0) , mLayersId(0) , mDidFakeShow(false) , mNotified(false) , mTriedBrowserInit(false) , mOrientation(eScreenOrientation_PortraitPrimary) , mIgnoreKeyPressEvent(false) , mHasValidInnerSize(false) , mDestroyed(false) , mUniqueId(aTabId) , mDPI(0) , mRounding(0) , mDefaultScale(0) , mIsTransparent(false) , mIPCOpen(false) , mParentIsActive(false) , mDidSetRealShowInfo(false) , mDidLoadURLInit(false) , mIsFreshProcess(false) , mLayerObserverEpoch(0) #if defined(XP_WIN) && defined(ACCESSIBILITY) , mNativeWindowHandle(0) #endif { // In the general case having the TabParent tell us if APZ is enabled or not // doesn't really work because the TabParent itself may not have a reference // to the owning widget during initialization. Instead we assume that this // TabChild corresponds to a widget type that would have APZ enabled, and just // check the other conditions necessary for enabling APZ. mAsyncPanZoomEnabled = gfxPlatform::AsyncPanZoomEnabled(); nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast(this))); // for capture by the lambda mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId, const nsTArray& aFlags) { if (nsCOMPtr tabChild = do_QueryReferent(weakPtrThis)) { static_cast(tabChild.get())->SetAllowedTouchBehavior(aInputBlockId, aFlags); } }; // preloaded TabChild should not be added to child map if (mUniqueId) { MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end()); NestedTabChildMap()[mUniqueId] = this; } nsCOMPtr observerService = mozilla::services::GetObserverService(); if (observerService) { const nsAttrValue::EnumTable* table = AudioChannelService::GetAudioChannelTable(); nsAutoCString topic; for (uint32_t i = 0; table[i].tag; ++i) { topic.Assign("audiochannel-activity-"); topic.Append(table[i].tag); observerService->AddObserver(this, topic.get(), false); } } for (uint32_t idx = 0; idx < NUMBER_OF_AUDIO_CHANNELS; idx++) { mAudioChannelsActive.AppendElement(false); } } NS_IMETHODIMP TabChild::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) { if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) { if (AsyncPanZoomEnabled()) { nsCOMPtr subject(do_QueryInterface(aSubject)); nsCOMPtr doc(GetDocument()); if (SameCOMIdentity(subject, doc)) { nsCOMPtr shell(doc->GetShell()); if (shell) { shell->SetIsFirstPaint(true); } APZCCallbackHelper::InitializeRootDisplayport(shell); } } } const nsAttrValue::EnumTable* table = AudioChannelService::GetAudioChannelTable(); nsAutoCString topic; int16_t audioChannel = -1; for (uint32_t i = 0; table[i].tag; ++i) { topic.Assign("audiochannel-activity-"); topic.Append(table[i].tag); if (topic.Equals(aTopic)) { audioChannel = table[i].value; break; } } if (audioChannel != -1 && mIPCOpen) { // If the subject is not a wrapper, it is sent by the TabParent and we // should ignore it. nsCOMPtr wrapper = do_QueryInterface(aSubject); if (!wrapper) { return NS_OK; } // We must have a window in order to compare the windowID contained into the // wrapper. nsCOMPtr window = do_GetInterface(WebNavigation()); if (!window) { return NS_OK; } uint64_t windowID = 0; nsresult rv = wrapper->GetData(&windowID); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // In theory a tabChild should contain just 1 top window, but let's double // check it comparing the windowID. if (window->WindowID() != windowID) { MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, ("TabChild, Observe, different windowID, owner ID = %lld, " "ID from wrapper = %lld", window->WindowID(), windowID)); return NS_OK; } nsAutoString activeStr(aData); bool active = activeStr.EqualsLiteral("active"); if (active != mAudioChannelsActive[audioChannel]) { mAudioChannelsActive[audioChannel] = active; Unused << SendAudioChannelActivityNotification(audioChannel, active); } } return NS_OK; } void TabChild::ContentReceivedInputBlock(const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId, bool aPreventDefault) const { if (mApzcTreeManager) { mApzcTreeManager->ContentReceivedInputBlock(aInputBlockId, aPreventDefault); } } void TabChild::SetTargetAPZC(uint64_t aInputBlockId, const nsTArray& aTargets) const { if (mApzcTreeManager) { mApzcTreeManager->SetTargetAPZC(aInputBlockId, aTargets); } } void TabChild::SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray& aTargets) const { if (mApzcTreeManager) { mApzcTreeManager->SetAllowedTouchBehavior(aInputBlockId, aTargets); } } bool TabChild::DoUpdateZoomConstraints(const uint32_t& aPresShellId, const ViewID& aViewId, const Maybe& aConstraints) { if (sPreallocatedTab == this) { // If we're the preallocated tab, bail out because doing IPC will crash. // Once we get used for something we'll get another zoom constraints update // and all will be well. return true; } if (!mApzcTreeManager) { return false; } ScrollableLayerGuid guid = ScrollableLayerGuid(mLayersId, aPresShellId, aViewId); mApzcTreeManager->UpdateZoomConstraints(guid, aConstraints); return true; } nsresult TabChild::Init() { nsCOMPtr webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID); if (!webBrowser) { NS_ERROR("Couldn't create a nsWebBrowser?"); return NS_ERROR_FAILURE; } webBrowser->SetContainerWindow(this); webBrowser->SetOriginAttributes(OriginAttributesRef()); mWebNav = do_QueryInterface(webBrowser); NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?"); nsCOMPtr docShellItem(do_QueryInterface(WebNavigation())); docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper); nsCOMPtr baseWindow = do_QueryInterface(WebNavigation()); if (!baseWindow) { NS_ERROR("mWebNav doesn't QI to nsIBaseWindow"); return NS_ERROR_FAILURE; } nsCOMPtr widget = nsIWidget::CreatePuppetWidget(this); mPuppetWidget = static_cast(widget.get()); if (!mPuppetWidget) { NS_ERROR("couldn't create fake widget"); return NS_ERROR_FAILURE; } mPuppetWidget->InfallibleCreate( nullptr, 0, // no parents LayoutDeviceIntRect(0, 0, 0, 0), nullptr // HandleWidgetEvent ); baseWindow->InitWindow(0, mPuppetWidget, 0, 0, 0, 0); baseWindow->Create(); // Set the tab context attributes then pass to docShell NotifyTabContextUpdated(false); // IPC uses a WebBrowser object for which DNS prefetching is turned off // by default. But here we really want it, so enable it explicitly nsCOMPtr webBrowserSetup = do_QueryInterface(baseWindow); if (webBrowserSetup) { webBrowserSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH, true); } else { NS_WARNING("baseWindow doesn't QI to nsIWebBrowserSetup, skipping " "DNS prefetching enable step."); } nsCOMPtr docShell = do_GetInterface(WebNavigation()); MOZ_ASSERT(docShell); docShell->SetAffectPrivateSessionLifetime( mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME); nsCOMPtr loadContext = do_GetInterface(WebNavigation()); MOZ_ASSERT(loadContext); loadContext->SetPrivateBrowsing(OriginAttributesRef().mPrivateBrowsingId > 0); loadContext->SetRemoteTabs( mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW); // Few lines before, baseWindow->Create() will end up creating a new // window root in nsGlobalWindow::SetDocShell. // Then this chrome event handler, will be inherited to inner windows. // We want to also set it to the docshell so that inner windows // and any code that has access to the docshell // can all listen to the same chrome event handler. // XXX: ideally, we would set a chrome event handler earlier, // and all windows, even the root one, will use the docshell one. nsCOMPtr window = do_GetInterface(WebNavigation()); NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); nsCOMPtr chromeHandler = do_QueryInterface(window->GetChromeEventHandler()); docShell->SetChromeEventHandler(chromeHandler); if (window->GetCurrentInnerWindow()) { window->SetKeyboardIndicators(ShowAccelerators(), ShowFocusRings()); } else { // Skip ShouldShowFocusRing check if no inner window is available window->SetInitialKeyboardIndicators(ShowAccelerators(), ShowFocusRings()); } // Set prerender flag if necessary. if (mIsPrerendered) { docShell->SetIsPrerendered(); } nsContentUtils::SetScrollbarsVisibility(window->GetDocShell(), !!(mChromeFlags & nsIWebBrowserChrome::CHROME_SCROLLBARS)); nsWeakPtr weakPtrThis = do_GetWeakReference(static_cast(this)); // for capture by the lambda ContentReceivedInputBlockCallback callback( [weakPtrThis](const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId, bool aPreventDefault) { if (nsCOMPtr tabChild = do_QueryReferent(weakPtrThis)) { static_cast(tabChild.get())->ContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault); } }); mAPZEventState = new APZEventState(mPuppetWidget, Move(callback)); mIPCOpen = true; if (GroupedSHistory::GroupedHistoryEnabled()) { // Set session history listener. nsCOMPtr shistory; mWebNav->GetSessionHistory(getter_AddRefs(shistory)); if (!shistory) { return NS_ERROR_FAILURE; } mHistoryListener = new TabChildSHistoryListener(this); nsCOMPtr listener(do_QueryObject(mHistoryListener)); shistory->AddSHistoryListener(listener); nsCOMPtr partialListener(do_QueryObject(mHistoryListener)); shistory->SetPartialSHistoryListener(partialListener); } return NS_OK; } void TabChild::NotifyTabContextUpdated(bool aIsPreallocated) { nsCOMPtr docShell = do_GetInterface(WebNavigation()); MOZ_ASSERT(docShell); if (!docShell) { return; } UpdateFrameType(); if (aIsPreallocated) { nsDocShell::Cast(docShell)->SetOriginAttributes(OriginAttributesRef()); } } void TabChild::UpdateFrameType() { nsCOMPtr docShell = do_GetInterface(WebNavigation()); MOZ_ASSERT(docShell); // TODO: Bug 1252794 - remove frameType from nsIDocShell.idl docShell->SetFrameType(IsMozBrowserElement() ? nsIDocShell::FRAME_TYPE_BROWSER : HasOwnApp() ? nsIDocShell::FRAME_TYPE_APP : nsIDocShell::FRAME_TYPE_REGULAR); } NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChild) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2) NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsIWindowProvider) NS_INTERFACE_MAP_ENTRY(nsITabChild) NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsITooltipListener) NS_INTERFACE_MAP_END_INHERITING(TabChildBase) NS_IMPL_ADDREF_INHERITED(TabChild, TabChildBase); NS_IMPL_RELEASE_INHERITED(TabChild, TabChildBase); NS_IMETHODIMP TabChild::SetStatus(uint32_t aStatusType, const char16_t* aStatus) { return SetStatusWithContext(aStatusType, aStatus ? static_cast(nsDependentString(aStatus)) : EmptyString(), nullptr); } NS_IMETHODIMP TabChild::GetWebBrowser(nsIWebBrowser** aWebBrowser) { NS_WARNING("TabChild::GetWebBrowser not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::SetWebBrowser(nsIWebBrowser* aWebBrowser) { NS_WARNING("TabChild::SetWebBrowser not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::GetChromeFlags(uint32_t* aChromeFlags) { *aChromeFlags = mChromeFlags; return NS_OK; } NS_IMETHODIMP TabChild::SetChromeFlags(uint32_t aChromeFlags) { NS_WARNING("trying to SetChromeFlags from content process?"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::DestroyBrowserWindow() { NS_WARNING("TabChild::DestroyBrowserWindow not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::RemoteSizeShellTo(int32_t aWidth, int32_t aHeight, int32_t aShellItemWidth, int32_t aShellItemHeight) { nsCOMPtr ourDocShell = do_GetInterface(WebNavigation()); nsCOMPtr docShellAsWin(do_QueryInterface(ourDocShell)); int32_t width, height; docShellAsWin->GetSize(&width, &height); uint32_t flags = 0; if (width == aWidth) { flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX; } if (height == aHeight) { flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY; } bool sent = SendSizeShellTo(flags, aWidth, aHeight, aShellItemWidth, aShellItemHeight); return sent ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP TabChild::RemoteDropLinks(uint32_t aLinksCount, nsIDroppedLinkItem** aLinks) { nsTArray linksArray; nsresult rv = NS_OK; for (uint32_t i = 0; i < aLinksCount; i++) { nsString tmp; rv = aLinks[i]->GetUrl(tmp); if (NS_FAILED(rv)) { return rv; } linksArray.AppendElement(tmp); rv = aLinks[i]->GetName(tmp); if (NS_FAILED(rv)) { return rv; } linksArray.AppendElement(tmp); rv = aLinks[i]->GetType(tmp); if (NS_FAILED(rv)) { return rv; } linksArray.AppendElement(tmp); } bool sent = SendDropLinks(linksArray); return sent ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP TabChild::SizeBrowserTo(int32_t aWidth, int32_t aHeight) { NS_WARNING("TabChild::SizeBrowserTo not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::ShowAsModal() { NS_WARNING("TabChild::ShowAsModal not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::IsWindowModal(bool* aRetVal) { *aRetVal = false; return NS_OK; } NS_IMETHODIMP TabChild::ExitModalEventLoop(nsresult aStatus) { NS_WARNING("TabChild::ExitModalEventLoop not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::SetStatusWithContext(uint32_t aStatusType, const nsAString& aStatusText, nsISupports* aStatusContext) { // We can only send the status after the ipc machinery is set up, // mRemoteFrame is a good indicator. if (mRemoteFrame) SendSetStatus(aStatusType, nsString(aStatusText)); return NS_OK; } NS_IMETHODIMP TabChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY, int32_t aCx, int32_t aCy) { // The parent is in charge of the dimension changes. If JS code wants to // change the dimensions (moveTo, screenX, etc.) we send a message to the // parent about the new requested dimension, the parent does the resize/move // then send a message to the child to update itself. For APIs like screenX // this function is called with the current value for the non-changed values. // In a series of calls like window.screenX = 10; window.screenY = 10; for // the second call, since screenX is not yet updated we might accidentally // reset back screenX to it's old value. To avoid this if a parameter did not // change we want the parent to ignore its value. int32_t x, y, cx, cy; GetDimensions(aFlags, &x, &y, &cx, &cy); if (x == aX) { aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_X; } if (y == aY) { aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_Y; } if (cx == aCx) { aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX; } if (cy == aCy) { aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY; } Unused << SendSetDimensions(aFlags, aX, aY, aCx, aCy); return NS_OK; } NS_IMETHODIMP TabChild::GetDimensions(uint32_t aFlags, int32_t* aX, int32_t* aY, int32_t* aCx, int32_t* aCy) { ScreenIntRect rect = GetOuterRect(); if (aX) { *aX = rect.x; } if (aY) { *aY = rect.y; } if (aCx) { *aCx = rect.width; } if (aCy) { *aCy = rect.height; } return NS_OK; } NS_IMETHODIMP TabChild::SetFocus() { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::GetVisibility(bool* aVisibility) { *aVisibility = true; return NS_OK; } NS_IMETHODIMP TabChild::SetVisibility(bool aVisibility) { // should the platform support this? Bug 666365 return NS_OK; } NS_IMETHODIMP TabChild::GetTitle(char16_t** aTitle) { NS_WARNING("TabChild::GetTitle not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::SetTitle(const char16_t* aTitle) { // JavaScript sends the "DOMTitleChanged" event to the parent // via the message manager. return NS_OK; } NS_IMETHODIMP TabChild::GetSiteWindow(void** aSiteWindow) { NS_WARNING("TabChild::GetSiteWindow not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::Blur() { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::FocusNextElement(bool aForDocumentNavigation) { SendMoveFocus(true, aForDocumentNavigation); return NS_OK; } NS_IMETHODIMP TabChild::FocusPrevElement(bool aForDocumentNavigation) { SendMoveFocus(false, aForDocumentNavigation); return NS_OK; } NS_IMETHODIMP TabChild::GetInterface(const nsIID & aIID, void **aSink) { if (aIID.Equals(NS_GET_IID(nsIWebBrowserChrome3))) { NS_IF_ADDREF(((nsISupports *) (*aSink = mWebBrowserChrome))); return NS_OK; } // XXXbz should we restrict the set of interfaces we hand out here? // See bug 537429 return QueryInterface(aIID, aSink); } NS_IMETHODIMP TabChild::ProvideWindow(mozIDOMWindowProxy* aParent, uint32_t aChromeFlags, bool aCalledFromJS, bool aPositionSpecified, bool aSizeSpecified, nsIURI* aURI, const nsAString& aName, const nsACString& aFeatures, bool aForceNoOpener, bool* aWindowIsNew, mozIDOMWindowProxy** aReturn) { *aReturn = nullptr; // If aParent is inside an