/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/DocumentRendererChild.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 <algorithm> #ifdef MOZ_CRASHREPORTER #include "nsExceptionHandler.h" #endif #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 "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 "nsDatePickerProxy.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 "VRManagerChild.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<nsUint64HashKey, TabChild*> 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_SCRIPT_OBJECTS 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<nsIDocument> TabChildBase::GetDocument() const { nsCOMPtr<nsIDOMDocument> domDoc; WebNavigation()->GetDocument(getter_AddRefs(domDoc)); nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc)); return doc.forget(); } already_AddRefed<nsIPresShell> TabChildBase::GetPresShell() const { nsCOMPtr<nsIPresShell> result; if (nsCOMPtr<nsIDocument> doc = GetDocument()) { result = doc->GetShell(); } return result.forget(); } void TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName, const nsAString& aJSONData) { AutoSafeJSContext cx; JS::Rooted<JS::Value> json(cx, JS::NullValue()); StructuredCloneData data; if (JS_ParseJSON(cx, static_cast<const char16_t*>(aJSONData.BeginReading()), aJSONData.Length(), &json)) { ErrorResult rv; data.Write(cx, json, rv); if (NS_WARN_IF(rv.Failed())) { rv.SuppressException(); return; } } nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal()); // Let the BrowserElementScrolling helper (if it exists) for this // content manipulate the frame state. RefPtr<nsFrameMessageManager> mm = static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get()); mm->ReceiveMessage(static_cast<EventTarget*>(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<nsIPresShell> 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<TabChild> 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<TabChild> sPreallocatedTab; std::map<TabId, RefPtr<TabChild>>& NestedTabChildMap() { MOZ_ASSERT(NS_IsMainThread()); static std::map<TabId, RefPtr<TabChild>> sNestedTabChildMap; return sNestedTabChildMap; } } // namespace already_AddRefed<TabChild> TabChild::FindTabChild(const TabId& aTabId) { auto iter = NestedTabChildMap().find(aTabId); if (iter == NestedTabChildMap().end()) { return nullptr; } RefPtr<TabChild> tabChild = iter->second; return tabChild.forget(); } static void PreloadSlowThingsPostFork(void* aUnused) { nsCOMPtr<nsIObserverService> 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<nsIDocShell> 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<TabChild> 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> TabChild::Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext &aContext, uint32_t aChromeFlags) { if (sPreallocatedTab && sPreallocatedTab->mChromeFlags == aChromeFlags && aContext.IsMozBrowserOrApp()) { RefPtr<TabChild> 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<TabChild> 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<nsITabChild*>(this))); // for capture by the lambda mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aFlags) { if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) { static_cast<TabChild*>(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<nsIObserverService> 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<nsIDocument> subject(do_QueryInterface(aSubject)); nsCOMPtr<nsIDocument> doc(GetDocument()); if (SameCOMIdentity(subject, doc)) { nsCOMPtr<nsIPresShell> 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<nsISupportsPRUint64> 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<nsPIDOMWindowOuter> 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<ScrollableLayerGuid>& aTargets) const { if (mApzcTreeManager) { mApzcTreeManager->SetTargetAPZC(aInputBlockId, aTargets); } } void TabChild::SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aTargets) const { if (mApzcTreeManager) { mApzcTreeManager->SetAllowedTouchBehavior(aInputBlockId, aTargets); } } bool TabChild::DoUpdateZoomConstraints(const uint32_t& aPresShellId, const ViewID& aViewId, const Maybe<ZoomConstraints>& 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<nsIWebBrowser> 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<nsIDocShellTreeItem> docShellItem(do_QueryInterface(WebNavigation())); docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper); nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation()); if (!baseWindow) { NS_ERROR("mWebNav doesn't QI to nsIBaseWindow"); return NS_ERROR_FAILURE; } nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(this); mPuppetWidget = static_cast<PuppetWidget*>(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<nsIWebBrowserSetup> 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<nsIDocShell> docShell = do_GetInterface(WebNavigation()); MOZ_ASSERT(docShell); docShell->SetAffectPrivateSessionLifetime( mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME); nsCOMPtr<nsILoadContext> 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<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); nsCOMPtr<EventTarget> 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<nsITabChild*>(this)); // for capture by the lambda ContentReceivedInputBlockCallback callback( [weakPtrThis](const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId, bool aPreventDefault) { if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) { static_cast<TabChild*>(tabChild.get())->ContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault); } }); mAPZEventState = new APZEventState(mPuppetWidget, Move(callback)); mIPCOpen = true; if (GroupedSHistory::GroupedHistoryEnabled()) { // Set session history listener. nsCOMPtr<nsISHistory> shistory; mWebNav->GetSessionHistory(getter_AddRefs(shistory)); if (!shistory) { return NS_ERROR_FAILURE; } mHistoryListener = new TabChildSHistoryListener(this); nsCOMPtr<nsISHistoryListener> listener(do_QueryObject(mHistoryListener)); shistory->AddSHistoryListener(listener); nsCOMPtr<nsIPartialSHistoryListener> partialListener(do_QueryObject(mHistoryListener)); shistory->SetPartialSHistoryListener(partialListener); } return NS_OK; } void TabChild::NotifyTabContextUpdated(bool aIsPreallocated) { nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); MOZ_ASSERT(docShell); if (!docShell) { return; } UpdateFrameType(); if (aIsPreallocated) { nsDocShell::Cast(docShell)->SetOriginAttributes(OriginAttributesRef()); } // Set SANDBOXED_AUXILIARY_NAVIGATION flag if this is a receiver page. if (!PresentationURL().IsEmpty()) { docShell->SetSandboxFlags(SANDBOXED_AUXILIARY_NAVIGATION); } } void TabChild::UpdateFrameType() { nsCOMPtr<nsIDocShell> 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<const nsString &>(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<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation()); nsCOMPtr<nsIBaseWindow> 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<nsString> 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 <iframe mozbrowser> or <iframe mozapp> and this // isn't a request to open a modal-type window, we're going to create a new // <iframe mozbrowser/mozapp> and return its window here. nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent); bool iframeMoz = (docshell && docshell->GetIsInMozBrowserOrApp() && !(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_OPENAS_DIALOG | nsIWebBrowserChrome::CHROME_OPENAS_CHROME))); if (!iframeMoz) { int32_t openLocation = nsWindowWatcher::GetWindowOpenLocation(nsPIDOMWindowOuter::From(aParent), aChromeFlags, aCalledFromJS, aPositionSpecified, aSizeSpecified); // If it turns out we're opening in the current browser, just hand over the // current browser's docshell. if (openLocation == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) { nsCOMPtr<nsIWebBrowser> browser = do_GetInterface(WebNavigation()); *aWindowIsNew = false; return browser->GetContentDOMWindow(aReturn); } } // Note that ProvideWindowCommon may return NS_ERROR_ABORT if the // open window call was canceled. It's important that we pass this error // code back to our caller. ContentChild* cc = ContentChild::GetSingleton(); return cc->ProvideWindowCommon(this, aParent, iframeMoz, aChromeFlags, aCalledFromJS, aPositionSpecified, aSizeSpecified, aURI, aName, aFeatures, aForceNoOpener, aWindowIsNew, aReturn); } void TabChild::DestroyWindow() { nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation()); if (baseWindow) baseWindow->Destroy(); // NB: the order of mPuppetWidget->Destroy() and mRemoteFrame->Destroy() // is important: we want to kill off remote layers before their // frames if (mPuppetWidget) { mPuppetWidget->Destroy(); } if (mRemoteFrame) { mRemoteFrame->Destroy(); mRemoteFrame = nullptr; } if (mLayersId != 0) { MOZ_ASSERT(sTabChildren); sTabChildren->Remove(mLayersId); if (!sTabChildren->Count()) { delete sTabChildren; sTabChildren = nullptr; } mLayersId = 0; } } void TabChild::ActorDestroy(ActorDestroyReason why) { mIPCOpen = false; DestroyWindow(); if (mTabChildGlobal) { // We should have a message manager if the global is alive, but it // seems sometimes we don't. Assert in aurora/nightly, but don't // crash in release builds. MOZ_DIAGNOSTIC_ASSERT(mTabChildGlobal->mMessageManager); if (mTabChildGlobal->mMessageManager) { // The messageManager relays messages via the TabChild which // no longer exists. static_cast<nsFrameMessageManager*> (mTabChildGlobal->mMessageManager.get())->Disconnect(); mTabChildGlobal->mMessageManager = nullptr; } } CompositorBridgeChild* compositorChild = static_cast<CompositorBridgeChild*>(CompositorBridgeChild::Get()); compositorChild->CancelNotifyAfterRemotePaint(this); if (GetTabId() != 0) { NestedTabChildMap().erase(GetTabId()); } } TabChild::~TabChild() { DestroyWindow(); nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation()); if (webBrowser) { webBrowser->SetContainerWindow(nullptr); } if (mHistoryListener) { mHistoryListener->ClearTabChild(); } } void TabChild::SetProcessNameToAppName() { nsCOMPtr<mozIApplication> app = GetOwnApp(); if (!app) { return; } nsAutoString appName; nsresult rv = app->GetName(appName); if (NS_FAILED(rv)) { NS_WARNING("Failed to retrieve app name"); return; } ContentChild::GetSingleton()->SetProcessName(appName, true); } bool TabChild::RecvLoadURL(const nsCString& aURI, const ShowInfo& aInfo) { if (!mDidLoadURLInit) { mDidLoadURLInit = true; if (!InitTabChildGlobal()) { return false; } ApplyShowInfo(aInfo); SetProcessNameToAppName(); } nsresult rv = WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(aURI).get(), nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL, nullptr, nullptr, nullptr); if (NS_FAILED(rv)) { NS_WARNING("WebNavigation()->LoadURI failed. Eating exception, what else can I do?"); } #ifdef MOZ_CRASHREPORTER CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), aURI); #endif return true; } void TabChild::DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier, const uint64_t& aLayersId, PRenderFrameChild* aRenderFrame, const ShowInfo& aShowInfo) { RecvShow(ScreenIntSize(0, 0), aShowInfo, aTextureFactoryIdentifier, aLayersId, aRenderFrame, mParentIsActive, nsSizeMode_Normal); mDidFakeShow = true; } void TabChild::ApplyShowInfo(const ShowInfo& aInfo) { if (mDidSetRealShowInfo) { return; } if (!aInfo.fakeShowInfo()) { // Once we've got one ShowInfo from parent, no need to update the values // anymore. mDidSetRealShowInfo = true; } nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); if (docShell) { nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell); if (IsMozBrowserOrApp()) { // B2G allows window.name to be set by changing the name attribute on the // <iframe mozbrowser> element. window.open calls cause this attribute to // be set to the correct value. A normal <xul:browser> element has no such // attribute. The data we get here comes from reading the attribute, so we // shouldn't trust it for <xul:browser> elements. item->SetName(aInfo.name()); } docShell->SetFullscreenAllowed(aInfo.fullscreenAllowed()); if (aInfo.isPrivate()) { nsCOMPtr<nsILoadContext> context = do_GetInterface(docShell); // No need to re-set private browsing mode. if (!context->UsePrivateBrowsing()) { if (docShell->GetHasLoadedNonBlankURI()) { nsContentUtils::ReportToConsoleNonLocalized( NS_LITERAL_STRING("We should not switch to Private Browsing after loading a document."), nsIScriptError::warningFlag, NS_LITERAL_CSTRING("mozprivatebrowsing"), nullptr); } else { DocShellOriginAttributes attrs(nsDocShell::Cast(docShell)->GetOriginAttributes()); attrs.SyncAttributesWithPrivateBrowsing(true); nsDocShell::Cast(docShell)->SetOriginAttributes(attrs); } } } } mDPI = aInfo.dpi(); mRounding = aInfo.widgetRounding(); mDefaultScale = aInfo.defaultScale(); mIsTransparent = aInfo.isTransparent(); } bool TabChild::RecvShow(const ScreenIntSize& aSize, const ShowInfo& aInfo, const TextureFactoryIdentifier& aTextureFactoryIdentifier, const uint64_t& aLayersId, PRenderFrameChild* aRenderFrame, const bool& aParentIsActive, const nsSizeMode& aSizeMode) { MOZ_ASSERT((!mDidFakeShow && aRenderFrame) || (mDidFakeShow && !aRenderFrame)); mPuppetWidget->SetSizeMode(aSizeMode); if (mDidFakeShow) { ApplyShowInfo(aInfo); RecvParentActivated(aParentIsActive); return true; } nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation()); if (!baseWindow) { NS_ERROR("WebNavigation() doesn't QI to nsIBaseWindow"); return false; } if (!InitRenderingState(aTextureFactoryIdentifier, aLayersId, aRenderFrame)) { // We can fail to initialize our widget if the <browser // remote> has already been destroyed, and we couldn't hook // into the parent-process's layer system. That's not a fatal // error. return true; } baseWindow->SetVisibility(true); bool res = InitTabChildGlobal(); ApplyShowInfo(aInfo); RecvParentActivated(aParentIsActive); return res; } bool TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size, const ScreenOrientationInternal& orientation, const LayoutDeviceIntPoint& clientOffset, const LayoutDeviceIntPoint& chromeDisp) { if (!mRemoteFrame) { return true; } mUnscaledOuterRect = rect; mClientOffset = clientOffset; mChromeDisp = chromeDisp; mOrientation = orientation; SetUnscaledInnerSize(size); if (!mHasValidInnerSize && size.width != 0 && size.height != 0) { mHasValidInnerSize = true; } ScreenIntSize screenSize = GetInnerSize(); ScreenIntRect screenRect = GetOuterRect(); // Set the size on the document viewer before we update the widget and // trigger a reflow. Otherwise the MobileViewportManager reads the stale // size from the content viewer when it computes a new CSS viewport. nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation()); baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height, nsIBaseWindow::eRepaint); mPuppetWidget->Resize(screenRect.x + clientOffset.x + chromeDisp.x, screenRect.y + clientOffset.y + chromeDisp.y, screenSize.width, screenSize.height, true); return true; } bool TabChild::RecvSizeModeChanged(const nsSizeMode& aSizeMode) { mPuppetWidget->SetSizeMode(aSizeMode); if (!mPuppetWidget->IsVisible()) { return true; } nsCOMPtr<nsIDocument> document(GetDocument()); nsCOMPtr<nsIPresShell> presShell = document->GetShell(); if (presShell) { nsPresContext* presContext = presShell->GetPresContext(); if (presContext) { presContext->SizeModeChanged(aSizeMode); } } return true; } bool TabChild::UpdateFrame(const FrameMetrics& aFrameMetrics) { return TabChildBase::UpdateFrameHandler(aFrameMetrics); } bool TabChild::RecvSuppressDisplayport(const bool& aEnabled) { if (aEnabled) { mActiveSuppressDisplayport++; } else { mActiveSuppressDisplayport--; } MOZ_ASSERT(mActiveSuppressDisplayport >= 0); APZCCallbackHelper::SuppressDisplayport(aEnabled, GetPresShell()); return true; } void TabChild::HandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid) { TABC_LOG("Handling double tap at %s with %p %p\n", Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get()); if (!mGlobal || !mTabChildGlobal) { return; } // Note: there is nothing to do with the modifiers here, as we are not // synthesizing any sort of mouse event. nsCOMPtr<nsIDocument> document = GetDocument(); CSSRect zoomToRect = CalculateRectToZoomTo(document, aPoint); // The double-tap can be dispatched by any scroll frame (so |aGuid| could be // the guid of any scroll frame), but the zoom-to-rect operation must be // performed by the root content scroll frame, so query its identifiers // for the SendZoomToRect() call rather than using the ones from |aGuid|. uint32_t presShellId; ViewID viewId; if (APZCCallbackHelper::GetOrCreateScrollIdentifiers( document->GetDocumentElement(), &presShellId, &viewId) && mApzcTreeManager) { ScrollableLayerGuid guid(mLayersId, presShellId, viewId); mApzcTreeManager->ZoomToRect(guid, zoomToRect, DEFAULT_BEHAVIOR); } } bool TabChild::RecvHandleTap(const GeckoContentController::TapType& aType, const LayoutDevicePoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId) { nsCOMPtr<nsIPresShell> presShell = GetPresShell(); if (!presShell) { return true; } if (!presShell->GetPresContext()) { return true; } CSSToLayoutDeviceScale scale(presShell->GetPresContext()->CSSToDevPixelScale()); CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint / scale, aGuid); switch (aType) { case GeckoContentController::TapType::eSingleTap: if (mGlobal && mTabChildGlobal) { mAPZEventState->ProcessSingleTap(point, scale, aModifiers, aGuid, 1); } break; case GeckoContentController::TapType::eDoubleTap: HandleDoubleTap(point, aModifiers, aGuid); break; case GeckoContentController::TapType::eSecondTap: if (mGlobal && mTabChildGlobal) { mAPZEventState->ProcessSingleTap(point, scale, aModifiers, aGuid, 2); } break; case GeckoContentController::TapType::eLongTap: if (mGlobal && mTabChildGlobal) { mAPZEventState->ProcessLongTap(presShell, point, scale, aModifiers, aGuid, aInputBlockId); } break; case GeckoContentController::TapType::eLongTapUp: if (mGlobal && mTabChildGlobal) { mAPZEventState->ProcessLongTapUp(presShell, point, scale, aModifiers); } break; case GeckoContentController::TapType::eSentinel: // Should never happen, but we need to handle this case to make the compiler // happy. MOZ_ASSERT(false); break; } return true; } bool TabChild::NotifyAPZStateChange(const ViewID& aViewId, const layers::GeckoContentController::APZStateChange& aChange, const int& aArg) { mAPZEventState->ProcessAPZStateChange(aViewId, aChange, aArg); if (aChange == layers::GeckoContentController::APZStateChange::eTransformEnd) { // This is used by tests to determine when the APZ is done doing whatever // it's doing. XXX generify this as needed when writing additional tests. nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); observerService->NotifyObservers(nullptr, "APZ:TransformEnd", nullptr); } return true; } void TabChild::StartScrollbarDrag(const layers::AsyncDragMetrics& aDragMetrics) { ScrollableLayerGuid guid(mLayersId, aDragMetrics.mPresShellId, aDragMetrics.mViewId); if (mApzcTreeManager) { mApzcTreeManager->StartScrollbarDrag(guid, aDragMetrics); } } void TabChild::ZoomToRect(const uint32_t& aPresShellId, const FrameMetrics::ViewID& aViewId, const CSSRect& aRect, const uint32_t& aFlags) { ScrollableLayerGuid guid(mLayersId, aPresShellId, aViewId); if (mApzcTreeManager) { mApzcTreeManager->ZoomToRect(guid, aRect, aFlags); } } bool TabChild::RecvActivate() { nsCOMPtr<nsIWebBrowserFocus> browser = do_QueryInterface(WebNavigation()); browser->Activate(); return true; } bool TabChild::RecvDeactivate() { nsCOMPtr<nsIWebBrowserFocus> browser = do_QueryInterface(WebNavigation()); browser->Deactivate(); return true; } bool TabChild::RecvParentActivated(const bool& aActivated) { mParentIsActive = aActivated; nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, true); nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); fm->ParentActivated(window, aActivated); return true; } bool TabChild::RecvSetKeyboardIndicators(const UIStateChangeType& aShowAccelerators, const UIStateChangeType& aShowFocusRings) { nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); NS_ENSURE_TRUE(window, true); window->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings); return true; } bool TabChild::RecvStopIMEStateManagement() { IMEStateManager::StopIMEStateManagement(); return true; } bool TabChild::RecvMenuKeyboardListenerInstalled(const bool& aInstalled) { IMEStateManager::OnInstalledMenuKeyboardListener(aInstalled); return true; } bool TabChild::RecvNotifyAttachGroupedSessionHistory(const uint32_t& aOffset) { // nsISHistory uses int32_t if (NS_WARN_IF(aOffset > INT32_MAX)) { return false; } nsCOMPtr<nsISHistory> shistory; mWebNav->GetSessionHistory(getter_AddRefs(shistory)); NS_ENSURE_TRUE(shistory, false); return NS_SUCCEEDED(shistory->OnAttachGroupedSessionHistory(aOffset)); } bool TabChild::RecvNotifyPartialSessionHistoryActive(const uint32_t& aGlobalLength, const uint32_t& aTargetLocalIndex) { // nsISHistory uses int32_t if (NS_WARN_IF(aGlobalLength > INT32_MAX || aTargetLocalIndex > INT32_MAX)) { return false; } nsCOMPtr<nsISHistory> shistory; mWebNav->GetSessionHistory(getter_AddRefs(shistory)); NS_ENSURE_TRUE(shistory, false); return NS_SUCCEEDED(shistory->OnPartialSessionHistoryActive(aGlobalLength, aTargetLocalIndex)); } bool TabChild::RecvNotifyPartialSessionHistoryDeactive() { nsCOMPtr<nsISHistory> shistory; mWebNav->GetSessionHistory(getter_AddRefs(shistory)); NS_ENSURE_TRUE(shistory, false); return NS_SUCCEEDED(shistory->OnPartialSessionHistoryDeactive()); } bool TabChild::RecvMouseEvent(const nsString& aType, const float& aX, const float& aY, const int32_t& aButton, const int32_t& aClickCount, const int32_t& aModifiers, const bool& aIgnoreRootScrollFrame) { APZCCallbackHelper::DispatchMouseEvent(GetPresShell(), aType, CSSPoint(aX, aY), aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN); return true; } bool TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId) { return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId); } bool TabChild::RecvSynthMouseMoveEvent(const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId) { return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId); } bool TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId) { // Mouse events like eMouseEnterIntoWidget, that are created in the parent // process EventStateManager code, have an input block id which they get from // the InputAPZContext in the parent process stack. However, they did not // actually go through the APZ code and so their mHandledByAPZ flag is false. // Since thos events didn't go through APZ, we don't need to send notifications // for them. if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) { nsCOMPtr<nsIDocument> document(GetDocument()); APZCCallbackHelper::SendSetTargetAPZCNotification( mPuppetWidget, document, aEvent, aGuid, aInputBlockId); } nsEventStatus unused; InputAPZContext context(aGuid, aInputBlockId, unused); WidgetMouseEvent localEvent(aEvent); localEvent.mWidget = mPuppetWidget; APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid, mPuppetWidget->GetDefaultScale()); APZCCallbackHelper::DispatchWidgetEvent(localEvent); if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) { mAPZEventState->ProcessMouseEvent(aEvent, aGuid, aInputBlockId); } return true; } bool TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId) { if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) { nsCOMPtr<nsIDocument> document(GetDocument()); APZCCallbackHelper::SendSetTargetAPZCNotification( mPuppetWidget, document, aEvent, aGuid, aInputBlockId); } WidgetWheelEvent localEvent(aEvent); localEvent.mWidget = mPuppetWidget; APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid, mPuppetWidget->GetDefaultScale()); APZCCallbackHelper::DispatchWidgetEvent(localEvent); if (localEvent.mCanTriggerSwipe) { SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe()); } if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) { mAPZEventState->ProcessWheelEvent(localEvent, aGuid, aInputBlockId); } return true; } bool TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) { TABC_LOG("Receiving touch event of type %d\n", aEvent.mMessage); WidgetTouchEvent localEvent(aEvent); localEvent.mWidget = mPuppetWidget; APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid, mPuppetWidget->GetDefaultScale()); if (localEvent.mMessage == eTouchStart && AsyncPanZoomEnabled()) { nsCOMPtr<nsIDocument> document = GetDocument(); if (gfxPrefs::TouchActionEnabled()) { APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(mPuppetWidget, document, localEvent, aInputBlockId, mSetAllowedTouchBehaviorCallback); } APZCCallbackHelper::SendSetTargetAPZCNotification(mPuppetWidget, document, localEvent, aGuid, aInputBlockId); } // Dispatch event to content (potentially a long-running operation) nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent); if (!AsyncPanZoomEnabled()) { // We shouldn't have any e10s platforms that have touch events enabled // without APZ. MOZ_ASSERT(false); return true; } mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId, aApzResponse, status); return true; } bool TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) { return RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse); } bool TabChild::RecvRealDragEvent(const WidgetDragEvent& aEvent, const uint32_t& aDragAction, const uint32_t& aDropEffect) { WidgetDragEvent localEvent(aEvent); localEvent.mWidget = mPuppetWidget; nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); if (dragSession) { dragSession->SetDragAction(aDragAction); nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer; dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer)); if (initialDataTransfer) { initialDataTransfer->SetDropEffectInt(aDropEffect); } } if (aEvent.mMessage == eDrop) { bool canDrop = true; if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) || !canDrop) { localEvent.mMessage = eDragExit; } } else if (aEvent.mMessage == eDragOver) { nsCOMPtr<nsIDragService> dragService = do_GetService("@mozilla.org/widget/dragservice;1"); if (dragService) { // This will dispatch 'drag' event at the source if the // drag transaction started in this process. dragService->FireDragEventAtSource(eDrag); } } APZCCallbackHelper::DispatchWidgetEvent(localEvent); return true; } bool TabChild::RecvPluginEvent(const WidgetPluginEvent& aEvent) { WidgetPluginEvent localEvent(aEvent); localEvent.mWidget = mPuppetWidget; nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent); if (status != nsEventStatus_eConsumeNoDefault) { // If not consumed, we should call default action SendDefaultProcOfPluginEvent(aEvent); } return true; } void TabChild::RequestNativeKeyBindings(AutoCacheNativeKeyCommands* aAutoCache, const WidgetKeyboardEvent* aEvent) { MaybeNativeKeyBinding maybeBindings; if (!SendRequestNativeKeyBindings(*aEvent, &maybeBindings)) { return; } if (maybeBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) { const NativeKeyBinding& bindings = maybeBindings; aAutoCache->Cache(bindings.singleLineCommands(), bindings.multiLineCommands(), bindings.richTextCommands()); } else { aAutoCache->CacheNoCommands(); } } bool TabChild::RecvNativeSynthesisResponse(const uint64_t& aObserverId, const nsCString& aResponse) { mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId, aResponse.get()); return true; } bool TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event, const MaybeNativeKeyBinding& aBindings) { AutoCacheNativeKeyCommands autoCache(mPuppetWidget); if (event.mMessage == eKeyPress) { // If content code called preventDefault() on a keydown event, then we don't // want to process any following keypress events. if (mIgnoreKeyPressEvent) { return true; } if (aBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) { const NativeKeyBinding& bindings = aBindings; autoCache.Cache(bindings.singleLineCommands(), bindings.multiLineCommands(), bindings.richTextCommands()); } else { autoCache.CacheNoCommands(); } } WidgetKeyboardEvent localEvent(event); localEvent.mWidget = mPuppetWidget; nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent); if (event.mMessage == eKeyDown) { mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault; } if (localEvent.mFlags.mIsSuppressedOrDelayed) { localEvent.PreventDefault(); } // If a response is desired from the content process, resend the key event. // If mAccessKeyForwardedToChild is set, then don't resend the key event yet // as RecvHandleAccessKey will do this. if (localEvent.mFlags.mWantReplyFromContentProcess) { SendReplyKeyEvent(localEvent); } if (localEvent.mAccessKeyForwardedToChild) { SendAccessKeyNotHandled(localEvent); } if (PresShell::BeforeAfterKeyboardEventEnabled()) { SendDispatchAfterKeyboardEvent(localEvent); } return true; } bool TabChild::RecvKeyEvent(const nsString& aType, const int32_t& aKeyCode, const int32_t& aCharCode, const int32_t& aModifiers, const bool& aPreventDefault) { bool ignored = false; nsContentUtils::SendKeyEvent(mPuppetWidget, aType, aKeyCode, aCharCode, aModifiers, aPreventDefault, &ignored); return true; } bool TabChild::RecvCompositionEvent(const WidgetCompositionEvent& event) { WidgetCompositionEvent localEvent(event); localEvent.mWidget = mPuppetWidget; APZCCallbackHelper::DispatchWidgetEvent(localEvent); Unused << SendOnEventNeedingAckHandled(event.mMessage); return true; } bool TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event) { WidgetSelectionEvent localEvent(event); localEvent.mWidget = mPuppetWidget; APZCCallbackHelper::DispatchWidgetEvent(localEvent); Unused << SendOnEventNeedingAckHandled(event.mMessage); return true; } bool TabChild::RecvPasteTransferable(const IPCDataTransfer& aDataTransfer, const bool& aIsPrivateData, const IPC::Principal& aRequestingPrincipal) { nsresult rv; nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv); NS_ENSURE_SUCCESS(rv, true); trans->Init(nullptr); rv = nsContentUtils::IPCTransferableToTransferable(aDataTransfer, aIsPrivateData, aRequestingPrincipal, trans, nullptr, this); NS_ENSURE_SUCCESS(rv, true); nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation()); if (NS_WARN_IF(!ourDocShell)) { return true; } nsCOMPtr<nsICommandParams> params = do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv); NS_ENSURE_SUCCESS(rv, true); rv = params->SetISupportsValue("transferable", trans); NS_ENSURE_SUCCESS(rv, true); ourDocShell->DoCommandWithParams("cmd_pasteTransferable", params); return true; } a11y::PDocAccessibleChild* TabChild::AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&, const uint32_t&, const IAccessibleHolder&) { MOZ_ASSERT(false, "should never call this!"); return nullptr; } bool TabChild::DeallocPDocAccessibleChild(a11y::PDocAccessibleChild* aChild) { #ifdef ACCESSIBILITY delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild); #endif return true; } PDocumentRendererChild* TabChild::AllocPDocumentRendererChild(const nsRect& documentRect, const mozilla::gfx::Matrix& transform, const nsString& bgcolor, const uint32_t& renderFlags, const bool& flushLayout, const nsIntSize& renderSize) { return new DocumentRendererChild(); } bool TabChild::DeallocPDocumentRendererChild(PDocumentRendererChild* actor) { delete actor; return true; } bool TabChild::RecvPDocumentRendererConstructor(PDocumentRendererChild* actor, const nsRect& documentRect, const mozilla::gfx::Matrix& transform, const nsString& bgcolor, const uint32_t& renderFlags, const bool& flushLayout, const nsIntSize& renderSize) { DocumentRendererChild *render = static_cast<DocumentRendererChild *>(actor); nsCOMPtr<nsIWebBrowser> browser = do_QueryInterface(WebNavigation()); if (!browser) return true; // silently ignore nsCOMPtr<mozIDOMWindowProxy> window; if (NS_FAILED(browser->GetContentDOMWindow(getter_AddRefs(window))) || !window) { return true; // silently ignore } nsCString data; bool ret = render->RenderDocument(nsPIDOMWindowOuter::From(window), documentRect, transform, bgcolor, renderFlags, flushLayout, renderSize, data); if (!ret) return true; // silently ignore return PDocumentRendererChild::Send__delete__(actor, renderSize, data); } PColorPickerChild* TabChild::AllocPColorPickerChild(const nsString&, const nsString&) { NS_RUNTIMEABORT("unused"); return nullptr; } bool TabChild::DeallocPColorPickerChild(PColorPickerChild* aColorPicker) { nsColorPickerProxy* picker = static_cast<nsColorPickerProxy*>(aColorPicker); NS_RELEASE(picker); return true; } PDatePickerChild* TabChild::AllocPDatePickerChild(const nsString&, const nsString&) { NS_RUNTIMEABORT("unused"); return nullptr; } bool TabChild::DeallocPDatePickerChild(PDatePickerChild* aDatePicker) { nsDatePickerProxy* picker = static_cast<nsDatePickerProxy*>(aDatePicker); NS_RELEASE(picker); return true; } PFilePickerChild* TabChild::AllocPFilePickerChild(const nsString&, const int16_t&) { NS_RUNTIMEABORT("unused"); return nullptr; } bool TabChild::DeallocPFilePickerChild(PFilePickerChild* actor) { nsFilePickerProxy* filePicker = static_cast<nsFilePickerProxy*>(actor); NS_RELEASE(filePicker); return true; } auto TabChild::AllocPIndexedDBPermissionRequestChild(const Principal& aPrincipal) -> PIndexedDBPermissionRequestChild* { MOZ_CRASH("PIndexedDBPermissionRequestChild actors should always be created " "manually!"); } bool TabChild::DeallocPIndexedDBPermissionRequestChild( PIndexedDBPermissionRequestChild* aActor) { MOZ_ASSERT(aActor); delete aActor; return true; } bool TabChild::RecvActivateFrameEvent(const nsString& aType, const bool& capture) { nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); NS_ENSURE_TRUE(window, true); nsCOMPtr<EventTarget> chromeHandler = do_QueryInterface(window->GetChromeEventHandler()); NS_ENSURE_TRUE(chromeHandler, true); RefPtr<ContentListener> listener = new ContentListener(this); chromeHandler->AddEventListener(aType, listener, capture); return true; } bool TabChild::RecvLoadRemoteScript(const nsString& aURL, const bool& aRunInGlobalScope) { if (!mGlobal && !InitTabChildGlobal()) // This can happen if we're half-destroyed. It's not a fatal // error. return true; LoadScriptInternal(aURL, aRunInGlobalScope); return true; } bool TabChild::RecvAsyncMessage(const nsString& aMessage, InfallibleTArray<CpowEntry>&& aCpows, const IPC::Principal& aPrincipal, const ClonedMessageData& aData) { if (!mTabChildGlobal) { return true; } // We should have a message manager if the global is alive, but it // seems sometimes we don't. Assert in aurora/nightly, but don't // crash in release builds. MOZ_DIAGNOSTIC_ASSERT(mTabChildGlobal->mMessageManager); if (!mTabChildGlobal->mMessageManager) { return true; } nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal()); StructuredCloneData data; UnpackClonedMessageDataForChild(aData, data); RefPtr<nsFrameMessageManager> mm = static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get()); CrossProcessCpowHolder cpows(Manager(), aCpows); mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal), nullptr, aMessage, false, &data, &cpows, aPrincipal, nullptr); return true; } bool TabChild::RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext) { nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation()); if (NS_WARN_IF(!ourDocShell)) { return true; } nsCOMPtr<nsPIDOMWindowOuter> ourWindow = ourDocShell->GetWindow(); if (NS_WARN_IF(!ourWindow)) { return true; } RefPtr<nsDocShell> docShell = static_cast<nsDocShell*>(ourDocShell.get()); nsCOMPtr<EventTarget> ourEventTarget = ourWindow->GetParentTarget(); docShell->SetInFrameSwap(true); nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, false); nsContentUtils::FirePageHideEvent(ourDocShell, ourEventTarget); // Owner content type may have changed, so store the possibly updated context // and notify others. MaybeInvalidTabContext maybeContext(aContext); if (!maybeContext.IsValid()) { NS_ERROR(nsPrintfCString("Received an invalid TabContext from " "the parent process. (%s)", maybeContext.GetInvalidReason()).get()); MOZ_CRASH("Invalid TabContext received from the parent process."); } if (!UpdateTabContextAfterSwap(maybeContext.GetTabContext())) { MOZ_CRASH("Update to TabContext after swap was denied."); } // Since mIsMozBrowserElement may change in UpdateTabContextAfterSwap, so we // call UpdateFrameType here to make sure the frameType on the docshell is // correct. UpdateFrameType(); // Ignore previous value of mTriedBrowserInit since owner content has changed. mTriedBrowserInit = true; // Initialize the child side of the browser element machinery, if appropriate. if (IsMozBrowserOrApp()) { RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true); } nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, true); docShell->SetInFrameSwap(false); return true; } bool TabChild::RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent, nsTArray<uint32_t>&& aCharCodes, const int32_t& aModifierMask) { nsCOMPtr<nsIDocument> document(GetDocument()); nsCOMPtr<nsIPresShell> presShell = document->GetShell(); if (presShell) { nsPresContext* pc = presShell->GetPresContext(); if (pc) { if (!pc->EventStateManager()-> HandleAccessKey(&(const_cast<WidgetKeyboardEvent&>(aEvent)), pc, aCharCodes, aModifierMask, true)) { // If no accesskey was found, inform the parent so that accesskeys on // menus can be handled. WidgetKeyboardEvent localEvent(aEvent); localEvent.mWidget = mPuppetWidget; SendAccessKeyNotHandled(localEvent); } } } return true; } bool TabChild::RecvAudioChannelChangeNotification(const uint32_t& aAudioChannel, const float& aVolume, const bool& aMuted) { nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); if (window) { RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate(); MOZ_ASSERT(service); service->SetAudioChannelVolume(window, static_cast<AudioChannel>(aAudioChannel), aVolume); service->SetAudioChannelMuted(window, static_cast<AudioChannel>(aAudioChannel), aMuted); } return true; } bool TabChild::RecvSetUseGlobalHistory(const bool& aUse) { nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); MOZ_ASSERT(docShell); nsresult rv = docShell->SetUseGlobalHistory(aUse); if (NS_FAILED(rv)) { NS_WARNING("Failed to set UseGlobalHistory on TabChild docShell"); } return true; } bool TabChild::RecvPrint(const uint64_t& aOuterWindowID, const PrintData& aPrintData) { #ifdef NS_PRINTING nsGlobalWindow* outerWindow = nsGlobalWindow::GetOuterWindowWithId(aOuterWindowID); if (NS_WARN_IF(!outerWindow)) { return true; } nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint = do_GetInterface(outerWindow->AsOuter()); if (NS_WARN_IF(!webBrowserPrint)) { return true; } nsCOMPtr<nsIPrintSettingsService> printSettingsSvc = do_GetService("@mozilla.org/gfx/printsettings-service;1"); if (NS_WARN_IF(!printSettingsSvc)) { return true; } nsCOMPtr<nsIPrintSettings> printSettings; nsresult rv = printSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings)); if (NS_WARN_IF(NS_FAILED(rv))) { return true; } nsCOMPtr<nsIPrintSession> printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return true; } printSettings->SetPrintSession(printSession); printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings); rv = webBrowserPrint->Print(printSettings, nullptr); if (NS_WARN_IF(NS_FAILED(rv))) { return true; } #endif return true; } bool TabChild::RecvUpdateNativeWindowHandle(const uintptr_t& aNewHandle) { #if defined(XP_WIN) && defined(ACCESSIBILITY) mNativeWindowHandle = aNewHandle; return true; #else return false; #endif } bool TabChild::RecvDestroy() { MOZ_ASSERT(mDestroyed == false); mDestroyed = true; nsTArray<PContentPermissionRequestChild*> childArray = nsContentPermissionUtils::GetContentPermissionRequestChildById(GetTabId()); // Need to close undeleted ContentPermissionRequestChilds before tab is closed. for (auto& permissionRequestChild : childArray) { auto child = static_cast<RemotePermissionRequest*>(permissionRequestChild); child->Destroy(); } while (mActiveSuppressDisplayport > 0) { APZCCallbackHelper::SuppressDisplayport(false, nullptr); mActiveSuppressDisplayport--; } if (mTabChildGlobal) { // Message handlers are called from the event loop, so it better be safe to // run script. MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); mTabChildGlobal->DispatchTrustedEvent(NS_LITERAL_STRING("unload")); } nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); observerService->RemoveObserver(this, BEFORE_FIRST_PAINT); 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->RemoveObserver(this, topic.get()); } // XXX what other code in ~TabChild() should we be running here? DestroyWindow(); // Bounce through the event loop once to allow any delayed teardown runnables // that were just generated to have a chance to run. nsCOMPtr<nsIRunnable> deleteRunnable = new DelayedDeleteRunnable(this); MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(deleteRunnable)); return true; } bool TabChild::RecvSetDocShellIsActive(const bool& aIsActive, const bool& aPreserveLayers, const uint64_t& aLayerObserverEpoch) { // Since SetDocShellIsActive requests come in from both the hang monitor // channel and the PContent channel, we have an ordering problem. This code // ensures that we respect the order in which the requests were made and // ignore stale requests. if (mLayerObserverEpoch >= aLayerObserverEpoch) { return true; } mLayerObserverEpoch = aLayerObserverEpoch; MOZ_ASSERT(mPuppetWidget); MOZ_ASSERT(mPuppetWidget->GetLayerManager()); MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT); auto clearForcePaint = MakeScopeExit([&] { // We might force a paint, or we might already have painted and this is a // no-op. In either case, once we exit this scope, we need to alert the // ProcessHangMonitor that we've finished responding to what might have // been a request to force paint. This is so that the BackgroundHangMonitor // for force painting can be made to wait again. if (aIsActive) { ProcessHangMonitor::ClearForcePaint(); } }); // We send the current layer observer epoch to the compositor so that // TabParent knows whether a layer update notification corresponds to the // latest SetDocShellIsActive request that was made. if (ClientLayerManager* clm = mPuppetWidget->GetLayerManager()->AsClientLayerManager()) { clm->SetLayerObserverEpoch(aLayerObserverEpoch); } // docshell is consider prerendered only if not active yet mIsPrerendered &= !aIsActive; nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); if (docShell) { bool wasActive; docShell->GetIsActive(&wasActive); if (aIsActive && wasActive) { // This request is a no-op. In this case, we still want a MozLayerTreeReady // notification to fire in the parent (so that it knows that the child has // updated its epoch). ForcePaintNoOp does that. if (IPCOpen()) { Unused << SendForcePaintNoOp(aLayerObserverEpoch); return true; } } docShell->SetIsActive(aIsActive); } if (aIsActive) { MakeVisible(); // We don't use TabChildBase::GetPresShell() here because that would create // a content viewer if one doesn't exist yet. Creating a content viewer can // cause JS to run, which we want to avoid. nsIDocShell::GetPresShell // returns null if no content viewer exists yet. if (nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell()) { if (nsIFrame* root = presShell->FrameConstructor()->GetRootFrame()) { FrameLayerBuilder::InvalidateAllLayersForFrame( nsLayoutUtils::GetDisplayRootFrame(root)); root->SchedulePaint(); } Telemetry::AutoTimer<Telemetry::TABCHILD_PAINT_TIME> timer; // If we need to repaint, let's do that right away. No sense waiting until // we get back to the event loop again. We suppress the display port so that // we only paint what's visible. This ensures that the tab we're switching // to paints as quickly as possible. APZCCallbackHelper::SuppressDisplayport(true, presShell); if (nsContentUtils::IsSafeToRunScript()) { WebWidget()->PaintNowIfNeeded(); } else { RefPtr<nsViewManager> vm = presShell->GetViewManager(); if (nsView* view = vm->GetRootView()) { presShell->Paint(view, view->GetBounds(), nsIPresShell::PAINT_LAYERS); } } APZCCallbackHelper::SuppressDisplayport(false, presShell); } } else if (!aPreserveLayers) { MakeHidden(); } return true; } bool TabChild::RecvNavigateByKey(const bool& aForward, const bool& aForDocumentNavigation) { nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) { nsCOMPtr<nsIDOMElement> result; nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); // Move to the first or last document. uint32_t type = aForward ? (aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRSTDOC) : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_ROOT)) : (aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LASTDOC) : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LAST)); fm->MoveFocus(window, nullptr, type, nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result)); // No valid root element was found, so move to the first focusable element. if (!result && aForward && !aForDocumentNavigation) { fm->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_FIRST, nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result)); } SendRequestFocus(false); } return true; } bool TabChild::RecvHandledWindowedPluginKeyEvent( const NativeEventData& aKeyEventData, const bool& aIsConsumed) { if (NS_WARN_IF(!mPuppetWidget)) { return true; } mPuppetWidget->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed); return true; } PRenderFrameChild* TabChild::AllocPRenderFrameChild() { return new RenderFrameChild(); } bool TabChild::DeallocPRenderFrameChild(PRenderFrameChild* aFrame) { delete aFrame; return true; } bool TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading) { if (!mGlobal && !mTabChildGlobal) { nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); NS_ENSURE_TRUE(window, false); nsCOMPtr<EventTarget> chromeHandler = do_QueryInterface(window->GetChromeEventHandler()); NS_ENSURE_TRUE(chromeHandler, false); RefPtr<TabChildGlobal> scope = new TabChildGlobal(this); mTabChildGlobal = scope; nsISupports* scopeSupports = NS_ISUPPORTS_CAST(EventTarget*, scope); NS_NAMED_LITERAL_CSTRING(globalId, "outOfProcessTabChildGlobal"); NS_ENSURE_TRUE(InitChildGlobalInternal(scopeSupports, globalId), false); scope->Init(); nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler); NS_ENSURE_TRUE(root, false); root->SetParentTarget(scope); } if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) { mTriedBrowserInit = true; // Initialize the child side of the browser element machinery, // if appropriate. if (IsMozBrowserOrApp()) { RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true); } } return true; } bool TabChild::InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIdentifier, const uint64_t& aLayersId, PRenderFrameChild* aRenderFrame) { mPuppetWidget->InitIMEState(); RenderFrameChild* remoteFrame = static_cast<RenderFrameChild*>(aRenderFrame); if (!remoteFrame) { NS_WARNING("failed to construct RenderFrame"); return false; } MOZ_ASSERT(aLayersId != 0); mTextureFactoryIdentifier = aTextureFactoryIdentifier; // Pushing layers transactions directly to a separate // compositor context. PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get(); if (!compositorChild) { NS_WARNING("failed to get CompositorBridgeChild instance"); PRenderFrameChild::Send__delete__(remoteFrame); return false; } ShadowLayerForwarder* lf = mPuppetWidget->GetLayerManager( nullptr, mTextureFactoryIdentifier.mParentBackend) ->AsShadowForwarder(); // As long as we are creating a ClientLayerManager for the puppet widget, // lf must be non-null here. MOZ_ASSERT(lf); if (lf) { nsTArray<LayersBackend> backends; backends.AppendElement(mTextureFactoryIdentifier.mParentBackend); bool success; PLayerTransactionChild* shadowManager = compositorChild->SendPLayerTransactionConstructor(backends, aLayersId, &mTextureFactoryIdentifier, &success); if (!success) { NS_WARNING("failed to properly allocate layer transaction"); PRenderFrameChild::Send__delete__(remoteFrame); return false; } if (!shadowManager) { NS_WARNING("failed to construct LayersChild"); // This results in |remoteFrame| being deleted. PRenderFrameChild::Send__delete__(remoteFrame); return false; } lf->SetShadowManager(shadowManager); lf->IdentifyTextureHost(mTextureFactoryIdentifier); ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier); gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier); } mRemoteFrame = remoteFrame; if (aLayersId != 0) { if (!sTabChildren) { sTabChildren = new TabChildMap; } MOZ_ASSERT(!sTabChildren->Get(aLayersId)); sTabChildren->Put(aLayersId, this); mLayersId = aLayersId; } mApzcTreeManager = CompositorBridgeChild::Get()->GetAPZCTreeManager(mLayersId); nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); if (observerService) { observerService->AddObserver(this, BEFORE_FIRST_PAINT, false); } return true; } void TabChild::GetDPI(float* aDPI) { *aDPI = -1.0; if (!mRemoteFrame) { return; } if (mDPI > 0) { *aDPI = mDPI; return; } // Fallback to a sync call if needed. SendGetDPI(aDPI); } void TabChild::GetDefaultScale(double* aScale) { *aScale = -1.0; if (!mRemoteFrame) { return; } if (mDefaultScale > 0) { *aScale = mDefaultScale; return; } // Fallback to a sync call if needed. SendGetDefaultScale(aScale); } void TabChild::GetWidgetRounding(int32_t* aRounding) { *aRounding = 1; if (!mRemoteFrame) { return; } if (mRounding > 0) { *aRounding = mRounding; return; } // Fallback to a sync call if needed. SendGetWidgetRounding(aRounding); } void TabChild::GetMaxTouchPoints(uint32_t* aTouchPoints) { // Fallback to a sync call. SendGetMaxTouchPoints(aTouchPoints); } void TabChild::NotifyPainted() { if (!mNotified) { mRemoteFrame->SendNotifyCompositorTransaction(); mNotified = true; } } void TabChild::MakeVisible() { if (mPuppetWidget && mPuppetWidget->IsVisible()) { return; } if (mPuppetWidget) { mPuppetWidget->Show(true); } } void TabChild::MakeHidden() { if (mPuppetWidget && !mPuppetWidget->IsVisible()) { return; } CompositorBridgeChild* compositor = CompositorBridgeChild::Get(); // Clear cached resources directly. This avoids one extra IPC // round-trip from CompositorBridgeChild to CompositorBridgeParent. compositor->RecvClearCachedResources(mLayersId); if (mPuppetWidget) { mPuppetWidget->Show(false); } } NS_IMETHODIMP TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult) { if (mTabChildGlobal) { NS_ADDREF(*aResult = mTabChildGlobal); return NS_OK; } *aResult = nullptr; return NS_ERROR_FAILURE; } NS_IMETHODIMP TabChild::GetWebBrowserChrome(nsIWebBrowserChrome3** aWebBrowserChrome) { NS_IF_ADDREF(*aWebBrowserChrome = mWebBrowserChrome); return NS_OK; } NS_IMETHODIMP TabChild::SetWebBrowserChrome(nsIWebBrowserChrome3* aWebBrowserChrome) { mWebBrowserChrome = aWebBrowserChrome; return NS_OK; } void TabChild::SendRequestFocus(bool aCanFocus) { PBrowserChild::SendRequestFocus(aCanFocus); } void TabChild::SendGetTabCount(uint32_t* tabCount) { PBrowserChild::SendGetTabCount(tabCount); } void TabChild::EnableDisableCommands(const nsAString& aAction, nsTArray<nsCString>& aEnabledCommands, nsTArray<nsCString>& aDisabledCommands) { PBrowserChild::SendEnableDisableCommands(PromiseFlatString(aAction), aEnabledCommands, aDisabledCommands); } NS_IMETHODIMP TabChild::GetTabId(uint64_t* aId) { *aId = GetTabId(); return NS_OK; } void TabChild::SetTabId(const TabId& aTabId) { MOZ_ASSERT(mUniqueId == 0); mUniqueId = aTabId; NestedTabChildMap()[mUniqueId] = this; } bool TabChild::DoSendBlockingMessage(JSContext* aCx, const nsAString& aMessage, StructuredCloneData& aData, JS::Handle<JSObject *> aCpows, nsIPrincipal* aPrincipal, nsTArray<StructuredCloneData>* aRetVal, bool aIsSync) { ClonedMessageData data; if (!BuildClonedMessageDataForChild(Manager(), aData, data)) { return false; } InfallibleTArray<CpowEntry> cpows; if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { return false; } if (aIsSync) { return SendSyncMessage(PromiseFlatString(aMessage), data, cpows, Principal(aPrincipal), aRetVal); } return SendRpcMessage(PromiseFlatString(aMessage), data, cpows, Principal(aPrincipal), aRetVal); } nsresult TabChild::DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, StructuredCloneData& aData, JS::Handle<JSObject *> aCpows, nsIPrincipal* aPrincipal) { ClonedMessageData data; if (!BuildClonedMessageDataForChild(Manager(), aData, data)) { return NS_ERROR_DOM_DATA_CLONE_ERR; } InfallibleTArray<CpowEntry> cpows; if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { return NS_ERROR_UNEXPECTED; } if (!SendAsyncMessage(PromiseFlatString(aMessage), cpows, Principal(aPrincipal), data)) { return NS_ERROR_UNEXPECTED; } return NS_OK; } /* static */ nsTArray<RefPtr<TabChild>> TabChild::GetAll() { nsTArray<RefPtr<TabChild>> list; if (!sTabChildren) { return list; } for (auto iter = sTabChildren->Iter(); !iter.Done(); iter.Next()) { list.AppendElement(iter.Data()); } return list; } TabChild* TabChild::GetFrom(nsIPresShell* aPresShell) { nsIDocument* doc = aPresShell->GetDocument(); if (!doc) { return nullptr; } nsCOMPtr<nsIDocShell> docShell(doc->GetDocShell()); return GetFrom(docShell); } TabChild* TabChild::GetFrom(uint64_t aLayersId) { if (!sTabChildren) { return nullptr; } return sTabChildren->Get(aLayersId); } void TabChild::DidComposite(uint64_t aTransactionId, const TimeStamp& aCompositeStart, const TimeStamp& aCompositeEnd) { MOZ_ASSERT(mPuppetWidget); MOZ_ASSERT(mPuppetWidget->GetLayerManager()); MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT); RefPtr<ClientLayerManager> manager = mPuppetWidget->GetLayerManager()->AsClientLayerManager(); manager->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd); } void TabChild::DidRequestComposite(const TimeStamp& aCompositeReqStart, const TimeStamp& aCompositeReqEnd) { nsCOMPtr<nsIDocShell> docShellComPtr = do_GetInterface(WebNavigation()); if (!docShellComPtr) { return; } nsDocShell* docShell = static_cast<nsDocShell*>(docShellComPtr.get()); RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get(); if (timelines && timelines->HasConsumer(docShell)) { // Since we're assuming that it's impossible for content JS to directly // trigger a synchronous paint, we can avoid capturing a stack trace here, // which means we won't run into JS engine reentrancy issues like bug // 1310014. timelines->AddMarkerForDocShell(docShell, "CompositeForwardTransaction", aCompositeReqStart, MarkerTracingType::START, MarkerStackRequest::NO_STACK); timelines->AddMarkerForDocShell(docShell, "CompositeForwardTransaction", aCompositeReqEnd, MarkerTracingType::END, MarkerStackRequest::NO_STACK); } } void TabChild::ClearCachedResources() { MOZ_ASSERT(mPuppetWidget); MOZ_ASSERT(mPuppetWidget->GetLayerManager()); MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT); ClientLayerManager *manager = mPuppetWidget->GetLayerManager()->AsClientLayerManager(); manager->ClearCachedResources(); } void TabChild::InvalidateLayers() { MOZ_ASSERT(mPuppetWidget); MOZ_ASSERT(mPuppetWidget->GetLayerManager()); MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT); RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager(); FrameLayerBuilder::InvalidateAllLayers(lm); } void TabChild::ReinitRendering() { MOZ_ASSERT(mLayersId); // Before we establish a new PLayerTransaction, we must connect our layer tree // id, CompositorBridge, and the widget compositor all together again. // Normally this happens in TabParent before TabChild is given rendering // information. // // In this case, we will send a sync message to our TabParent, which in turn // will send a sync message to the Compositor of the widget owning this tab. // This guarantees the correct association is in place before our // PLayerTransaction constructor message arrives on the cross-process // compositor bridge. SendEnsureLayersConnected(); RefPtr<CompositorBridgeChild> cb = CompositorBridgeChild::Get(); bool success; nsTArray<LayersBackend> ignored; PLayerTransactionChild* shadowManager = cb->SendPLayerTransactionConstructor(ignored, LayersId(), &mTextureFactoryIdentifier, &success); if (!success) { NS_WARNING("failed to re-allocate layer transaction"); return; } if (!shadowManager) { NS_WARNING("failed to re-construct LayersChild"); return; } RefPtr<LayerManager> lm = mPuppetWidget->RecreateLayerManager(shadowManager); ShadowLayerForwarder* lf = lm->AsShadowForwarder(); lf->IdentifyTextureHost(mTextureFactoryIdentifier); mApzcTreeManager = CompositorBridgeChild::Get()->GetAPZCTreeManager(mLayersId); if (mApzcTreeManager) { APZChild* apz = ContentProcessController::Create(mUniqueId); CompositorBridgeChild::Get()->SendPAPZConstructor(apz, mLayersId); } nsCOMPtr<nsIDocument> doc(GetDocument()); doc->NotifyLayerManagerRecreated(); } void TabChild::CompositorUpdated(const TextureFactoryIdentifier& aNewIdentifier) { gfxPlatform::GetPlatform()->CompositorUpdated(); RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager(); ClientLayerManager* clm = lm->AsClientLayerManager(); MOZ_ASSERT(clm); mTextureFactoryIdentifier = aNewIdentifier; clm->UpdateTextureFactoryIdentifier(aNewIdentifier); FrameLayerBuilder::InvalidateAllLayers(clm); } NS_IMETHODIMP TabChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText, const char16_t *aTipDir) { nsString str(aTipText); nsString dir(aTipDir); SendShowTooltip(aXCoords, aYCoords, str, dir); return NS_OK; } NS_IMETHODIMP TabChild::OnHideTooltip() { SendHideTooltip(); return NS_OK; } bool TabChild::RecvRequestNotifyAfterRemotePaint() { // Get the CompositorBridgeChild instance for this content thread. CompositorBridgeChild* compositor = CompositorBridgeChild::Get(); // Tell the CompositorBridgeChild that, when it gets a RemotePaintIsReady // message that it should forward it us so that we can bounce it to our // RenderFrameParent. compositor->RequestNotifyAfterRemotePaint(this); return true; } bool TabChild::RecvUIResolutionChanged(const float& aDpi, const int32_t& aRounding, const double& aScale) { ScreenIntSize oldScreenSize = GetInnerSize(); mDPI = 0; mRounding = 0; mDefaultScale = 0; static_cast<PuppetWidget*>(mPuppetWidget.get())->UpdateBackingScaleCache(aDpi, aRounding, aScale); nsCOMPtr<nsIDocument> document(GetDocument()); nsCOMPtr<nsIPresShell> presShell = document->GetShell(); if (presShell) { RefPtr<nsPresContext> presContext = presShell->GetPresContext(); if (presContext) { presContext->UIResolutionChangedSync(); } } ScreenIntSize screenSize = GetInnerSize(); if (mHasValidInnerSize && oldScreenSize != screenSize) { ScreenIntRect screenRect = GetOuterRect(); mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeDisp.x, screenRect.y + mClientOffset.y + mChromeDisp.y, screenSize.width, screenSize.height, true); nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation()); baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height, nsIBaseWindow::eRepaint); } return true; } bool TabChild::RecvThemeChanged(nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) { LookAndFeel::SetIntCache(aLookAndFeelIntCache); nsCOMPtr<nsIDocument> document(GetDocument()); nsCOMPtr<nsIPresShell> presShell = document->GetShell(); if (presShell) { RefPtr<nsPresContext> presContext = presShell->GetPresContext(); if (presContext) { presContext->ThemeChanged(); } } return true; } bool TabChild::RecvSetFreshProcess() { mIsFreshProcess = true; return true; } mozilla::plugins::PPluginWidgetChild* TabChild::AllocPPluginWidgetChild() { return new mozilla::plugins::PluginWidgetChild(); } bool TabChild::DeallocPPluginWidgetChild(mozilla::plugins::PPluginWidgetChild* aActor) { delete aActor; return true; } nsresult TabChild::CreatePluginWidget(nsIWidget* aParent, nsIWidget** aOut) { *aOut = nullptr; mozilla::plugins::PluginWidgetChild* child = static_cast<mozilla::plugins::PluginWidgetChild*>(SendPPluginWidgetConstructor()); if (!child) { NS_ERROR("couldn't create PluginWidgetChild"); return NS_ERROR_UNEXPECTED; } nsCOMPtr<nsIWidget> pluginWidget = nsIWidget::CreatePluginProxyWidget(this, child); if (!pluginWidget) { NS_ERROR("couldn't create PluginWidgetProxy"); return NS_ERROR_UNEXPECTED; } nsWidgetInitData initData; initData.mWindowType = eWindowType_plugin_ipc_content; initData.mUnicode = false; initData.clipChildren = true; initData.clipSiblings = true; nsresult rv = pluginWidget->Create(aParent, nullptr, LayoutDeviceIntRect(0, 0, 0, 0), &initData); if (NS_FAILED(rv)) { NS_WARNING("Creating native plugin widget on the chrome side failed."); } pluginWidget.forget(aOut); return rv; } ScreenIntSize TabChild::GetInnerSize() { LayoutDeviceIntSize innerSize = RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale()); return ViewAs<ScreenPixel>(innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims); }; ScreenIntRect TabChild::GetOuterRect() { LayoutDeviceIntRect outerRect = RoundedToInt(mUnscaledOuterRect * mPuppetWidget->GetDefaultScale()); return ViewAs<ScreenPixel>(outerRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims); } void TabChild::ForcePaint(uint64_t aLayerObserverEpoch) { if (!IPCOpen()) { // Don't bother doing anything now. Better to wait until we receive the // message on the PContent channel. return; } nsAutoScriptBlocker scriptBlocker; RecvSetDocShellIsActive(true, false, aLayerObserverEpoch); } /******************************************************************************* * nsISHistoryListener ******************************************************************************/ NS_IMETHODIMP TabChildSHistoryListener::OnHistoryNewEntry(nsIURI *aNewURI, int32_t aOldIndex) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChildSHistoryListener::OnHistoryGoBack(nsIURI *aBackURI, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChildSHistoryListener::OnHistoryGoForward(nsIURI *aForwardURI, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChildSHistoryListener::OnHistoryReload(nsIURI *aReloadURI, uint32_t aReloadFlags, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChildSHistoryListener::OnHistoryGotoIndex(int32_t aIndex, nsIURI *aGotoURI, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChildSHistoryListener::OnHistoryPurge(int32_t aNumEntries, bool *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChildSHistoryListener::OnHistoryReplaceEntry(int32_t aIndex) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChildSHistoryListener::OnLengthChange(int32_t aCount) { RefPtr<TabChild> tabChild(mTabChild); if (!tabChild) { return NS_ERROR_FAILURE; } if (aCount < 0) { return NS_ERROR_FAILURE; } return tabChild->SendNotifySessionHistoryChange(aCount) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP TabChildSHistoryListener::OnRequestCrossBrowserNavigation(uint32_t aIndex) { RefPtr<TabChild> tabChild(mTabChild); if (!tabChild) { return NS_ERROR_FAILURE; } return tabChild->SendRequestCrossBrowserNavigation(aIndex) ? NS_OK : NS_ERROR_FAILURE; } TabChildGlobal::TabChildGlobal(TabChildBase* aTabChild) : mTabChild(aTabChild) { SetIsNotDOMBinding(); } TabChildGlobal::~TabChildGlobal() { } void TabChildGlobal::Init() { NS_ASSERTION(!mMessageManager, "Re-initializing?!?"); mMessageManager = new nsFrameMessageManager(mTabChild, nullptr, MM_CHILD); } NS_IMPL_CYCLE_COLLECTION_CLASS(TabChildGlobal) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TabChildGlobal, DOMEventTargetHelper) NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager); NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild); tmp->UnlinkHostObjectURIs(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TabChildGlobal, DOMEventTargetHelper) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild) tmp->TraverseHostObjectURIs(cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChildGlobal) NS_INTERFACE_MAP_ENTRY(nsIMessageListenerManager) NS_INTERFACE_MAP_ENTRY(nsIMessageSender) NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender) NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager) NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal) NS_INTERFACE_MAP_ENTRY(nsIGlobalObject) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentFrameMessageManager) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(TabChildGlobal, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(TabChildGlobal, DOMEventTargetHelper) // This method isn't automatically forwarded safely because it's notxpcom, so // the IDL binding doesn't know what value to return. NS_IMETHODIMP_(bool) TabChildGlobal::MarkForCC() { if (mTabChild) { mTabChild->MarkScopesForCC(); } EventListenerManager* elm = GetExistingListenerManager(); if (elm) { elm->MarkForCC(); } return mMessageManager ? mMessageManager->MarkForCC() : false; } NS_IMETHODIMP TabChildGlobal::GetContent(mozIDOMWindowProxy** aContent) { *aContent = nullptr; if (!mTabChild) return NS_ERROR_NULL_POINTER; nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(mTabChild->WebNavigation()); window.forget(aContent); return NS_OK; } NS_IMETHODIMP TabChildGlobal::GetDocShell(nsIDocShell** aDocShell) { *aDocShell = nullptr; if (!mTabChild) return NS_ERROR_NULL_POINTER; nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mTabChild->WebNavigation()); docShell.swap(*aDocShell); return NS_OK; } nsIPrincipal* TabChildGlobal::GetPrincipal() { if (!mTabChild) return nullptr; return mTabChild->GetPrincipal(); } JSObject* TabChildGlobal::GetGlobalJSObject() { NS_ENSURE_TRUE(mTabChild, nullptr); nsCOMPtr<nsIXPConnectJSObjectHolder> ref = mTabChild->GetGlobal(); NS_ENSURE_TRUE(ref, nullptr); return ref->GetJSObject(); }