summaryrefslogtreecommitdiffstats
path: root/dom/ipc/BrowserBridgeParent.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/ipc/BrowserBridgeParent.cpp315
1 files changed, 315 insertions, 0 deletions
diff --git a/dom/ipc/BrowserBridgeParent.cpp b/dom/ipc/BrowserBridgeParent.cpp
new file mode 100644
index 0000000000..4a687d557d
--- /dev/null
+++ b/dom/ipc/BrowserBridgeParent.cpp
@@ -0,0 +1,315 @@
+/* -*- 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/. */
+
+#ifdef ACCESSIBILITY
+# include "mozilla/a11y/DocAccessibleParent.h"
+# include "nsAccessibilityService.h"
+#endif
+
+#include "mozilla/Monitor.h"
+#include "mozilla/MouseEvents.h"
+#include "mozilla/dom/BrowserBridgeParent.h"
+#include "mozilla/dom/BrowserParent.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/ContentProcessManager.h"
+#include "mozilla/dom/CanonicalBrowsingContext.h"
+#include "mozilla/dom/BrowsingContextGroup.h"
+#include "mozilla/dom/WindowGlobalParent.h"
+#include "mozilla/ipc/Endpoint.h"
+#include "mozilla/layers/InputAPZContext.h"
+
+using namespace mozilla::ipc;
+using namespace mozilla::layout;
+using namespace mozilla::hal;
+
+namespace mozilla::dom {
+
+BrowserBridgeParent::BrowserBridgeParent() = default;
+
+BrowserBridgeParent::~BrowserBridgeParent() { Destroy(); }
+
+nsresult BrowserBridgeParent::InitWithProcess(
+ BrowserParent* aParentBrowser, ContentParent* aContentParent,
+ const WindowGlobalInit& aWindowInit, uint32_t aChromeFlags, TabId aTabId) {
+ MOZ_ASSERT(!CanSend(),
+ "This should be called before the object is connected to IPC");
+ MOZ_DIAGNOSTIC_ASSERT(!aContentParent->IsLaunching());
+ MOZ_DIAGNOSTIC_ASSERT(!aContentParent->IsDead());
+
+ RefPtr<CanonicalBrowsingContext> browsingContext =
+ CanonicalBrowsingContext::Get(aWindowInit.context().mBrowsingContextId);
+ if (!browsingContext || browsingContext->IsDiscarded()) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ MOZ_DIAGNOSTIC_ASSERT(
+ !browsingContext->GetBrowserParent(),
+ "BrowsingContext must have had previous BrowserParent cleared");
+
+ MOZ_DIAGNOSTIC_ASSERT(
+ aParentBrowser->Manager() != aContentParent,
+ "Cannot create OOP iframe in the same process as its parent document");
+
+ // Unfortunately, due to the current racy destruction of BrowsingContext
+ // instances when Fission is enabled, while `browsingContext` may not be
+ // discarded, an ancestor might be.
+ //
+ // A discarded ancestor will cause us issues when creating our `BrowserParent`
+ // in the new content process, so abort the attempt if we have one.
+ //
+ // FIXME: We should never have a non-discarded BrowsingContext with discarded
+ // ancestors. (bug 1634759)
+ if (NS_WARN_IF(!browsingContext->AncestorsAreCurrent())) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ // Ensure that our content process is subscribed to our newly created
+ // BrowsingContextGroup.
+ browsingContext->Group()->EnsureHostProcess(aContentParent);
+ browsingContext->SetOwnerProcessId(aContentParent->ChildID());
+
+ // Construct the BrowserParent object for our subframe.
+ auto browserParent = MakeRefPtr<BrowserParent>(
+ aContentParent, aTabId, *aParentBrowser, browsingContext, aChromeFlags);
+ browserParent->SetBrowserBridgeParent(this);
+
+ // Open a remote endpoint for our PBrowser actor.
+ ManagedEndpoint<PBrowserChild> childEp =
+ aContentParent->OpenPBrowserEndpoint(browserParent);
+ if (NS_WARN_IF(!childEp.IsValid())) {
+ MOZ_ASSERT(false, "Browser Open Endpoint Failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
+ if (!cpm) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ cpm->RegisterRemoteFrame(browserParent);
+
+ RefPtr<WindowGlobalParent> windowParent =
+ WindowGlobalParent::CreateDisconnected(aWindowInit);
+ if (!windowParent) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ ManagedEndpoint<PWindowGlobalChild> windowChildEp =
+ browserParent->OpenPWindowGlobalEndpoint(windowParent);
+ if (NS_WARN_IF(!windowChildEp.IsValid())) {
+ MOZ_ASSERT(false, "WindowGlobal Open Endpoint Failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ MOZ_DIAGNOSTIC_ASSERT(!browsingContext->IsDiscarded(),
+ "bc cannot have become discarded");
+
+ // Tell the content process to set up its PBrowserChild.
+ bool ok = aContentParent->SendConstructBrowser(
+ std::move(childEp), std::move(windowChildEp), aTabId,
+ browserParent->AsIPCTabContext(), aWindowInit, aChromeFlags,
+ aContentParent->ChildID(), aContentParent->IsForBrowser(),
+ /* aIsTopLevel */ false);
+ if (NS_WARN_IF(!ok)) {
+ MOZ_ASSERT(false, "Browser Constructor Failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Set our BrowserParent object to the newly created browser.
+ mBrowserParent = std::move(browserParent);
+ mBrowserParent->SetOwnerElement(aParentBrowser->GetOwnerElement());
+ mBrowserParent->InitRendering();
+
+ GetBrowsingContext()->SetCurrentBrowserParent(mBrowserParent);
+
+ windowParent->Init();
+ return NS_OK;
+}
+
+CanonicalBrowsingContext* BrowserBridgeParent::GetBrowsingContext() {
+ return mBrowserParent->GetBrowsingContext();
+}
+
+BrowserParent* BrowserBridgeParent::Manager() {
+ MOZ_ASSERT(CanSend());
+ return static_cast<BrowserParent*>(PBrowserBridgeParent::Manager());
+}
+
+void BrowserBridgeParent::Destroy() {
+ if (mBrowserParent) {
+#ifdef ACCESSIBILITY
+ if (mEmbedderAccessibleDoc && !mEmbedderAccessibleDoc->IsShutdown()) {
+ mEmbedderAccessibleDoc->RemovePendingOOPChildDoc(this);
+ }
+#endif
+ mBrowserParent->Destroy();
+ mBrowserParent->SetBrowserBridgeParent(nullptr);
+ mBrowserParent = nullptr;
+ }
+ if (CanSend()) {
+ Unused << Send__delete__(this);
+ }
+}
+
+IPCResult BrowserBridgeParent::RecvShow(const OwnerShowInfo& aOwnerInfo) {
+ mBrowserParent->AttachWindowRenderer();
+ Unused << mBrowserParent->SendShow(mBrowserParent->GetShowInfo(), aOwnerInfo);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvScrollbarPreferenceChanged(
+ ScrollbarPreference aPref) {
+ Unused << mBrowserParent->SendScrollbarPreferenceChanged(aPref);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvLoadURL(nsDocShellLoadState* aLoadState) {
+ Unused << mBrowserParent->SendLoadURL(WrapNotNull(aLoadState),
+ mBrowserParent->GetShowInfo());
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvResumeLoad(uint64_t aPendingSwitchID) {
+ mBrowserParent->ResumeLoad(aPendingSwitchID);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvUpdateDimensions(
+ const nsIntRect& aRect, const ScreenIntSize& aSize) {
+ mBrowserParent->UpdateDimensions(aRect, aSize);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvUpdateEffects(const EffectsInfo& aEffects) {
+ Unused << mBrowserParent->SendUpdateEffects(aEffects);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvUpdateRemotePrintSettings(
+ const embedding::PrintData& aPrintData) {
+ Unused << mBrowserParent->SendUpdateRemotePrintSettings(aPrintData);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvRenderLayers(const bool& aEnabled) {
+ Unused << mBrowserParent->SendRenderLayers(aEnabled);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvNavigateByKey(
+ const bool& aForward, const bool& aForDocumentNavigation) {
+ Unused << mBrowserParent->SendNavigateByKey(aForward, aForDocumentNavigation);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvBeginDestroy() {
+ Destroy();
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvDispatchSynthesizedMouseEvent(
+ const WidgetMouseEvent& aEvent) {
+ if (aEvent.mMessage != eMouseMove ||
+ aEvent.mReason != WidgetMouseEvent::eSynthesized) {
+ return IPC_FAIL(this, "Unexpected event type");
+ }
+
+ nsCOMPtr<nsIWidget> widget = Manager()->GetWidget();
+ if (!widget) {
+ return IPC_OK();
+ }
+
+ WidgetMouseEvent event = aEvent;
+ event.mWidget = widget;
+ // Convert mRefPoint from the dispatching child process coordinate space
+ // to the parent coordinate space. The SendRealMouseEvent call will convert
+ // it into the dispatchee child process coordinate space
+ event.mRefPoint = Manager()->TransformChildToParent(event.mRefPoint);
+ // We need to set up an InputAPZContext on the stack because
+ // BrowserParent::SendRealMouseEvent requires one. But the only thing in
+ // that context that is actually used in this scenario is the layers id,
+ // and we already have that on the mouse event.
+ layers::InputAPZContext context(
+ layers::ScrollableLayerGuid(event.mLayersId, 0,
+ layers::ScrollableLayerGuid::NULL_SCROLL_ID),
+ 0, nsEventStatus_eIgnore);
+ mBrowserParent->SendRealMouseEvent(event);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvWillChangeProcess() {
+ Unused << mBrowserParent->SendWillChangeProcess();
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvActivate(uint64_t aActionId) {
+ mBrowserParent->Activate(aActionId);
+ return IPC_OK();
+}
+
+IPCResult BrowserBridgeParent::RecvDeactivate(const bool& aWindowLowering,
+ uint64_t aActionId) {
+ mBrowserParent->Deactivate(aWindowLowering, aActionId);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserBridgeParent::RecvUpdateRemoteStyle(
+ const StyleImageRendering& aImageRendering) {
+ Unused << mBrowserParent->SendUpdateRemoteStyle(aImageRendering);
+ return IPC_OK();
+}
+
+#ifdef ACCESSIBILITY
+a11y::DocAccessibleParent* BrowserBridgeParent::GetDocAccessibleParent() {
+ auto* embeddedBrowser = GetBrowserParent();
+ if (!embeddedBrowser) {
+ return nullptr;
+ }
+ a11y::DocAccessibleParent* docAcc =
+ embeddedBrowser->GetTopLevelDocAccessible();
+ return docAcc && !docAcc->IsShutdown() ? docAcc : nullptr;
+}
+
+IPCResult BrowserBridgeParent::RecvSetEmbedderAccessible(
+ PDocAccessibleParent* aDoc, uint64_t aID) {
+# if defined(ANDROID)
+ MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
+# endif
+ MOZ_ASSERT(aDoc || mEmbedderAccessibleDoc,
+ "Embedder doc shouldn't be cleared if it wasn't set");
+ MOZ_ASSERT(!mEmbedderAccessibleDoc || !aDoc || mEmbedderAccessibleDoc == aDoc,
+ "Embedder doc shouldn't change from one doc to another");
+ if (!aDoc && mEmbedderAccessibleDoc &&
+ !mEmbedderAccessibleDoc->IsShutdown()) {
+ // We're clearing the embedder doc, so remove the pending child doc addition
+ // (if any).
+ mEmbedderAccessibleDoc->RemovePendingOOPChildDoc(this);
+ }
+ mEmbedderAccessibleDoc = static_cast<a11y::DocAccessibleParent*>(aDoc);
+ mEmbedderAccessibleID = aID;
+ if (!aDoc) {
+ MOZ_ASSERT(!aID);
+ return IPC_OK();
+ }
+ MOZ_ASSERT(aID);
+ if (GetDocAccessibleParent()) {
+ // The embedded DocAccessibleParent has already been created. This can
+ // happen if, for example, an iframe is hidden and then shown or
+ // an iframe is reflowed by layout.
+ mEmbedderAccessibleDoc->AddChildDoc(this);
+ }
+ return IPC_OK();
+}
+
+a11y::DocAccessibleParent* BrowserBridgeParent::GetEmbedderAccessibleDoc() {
+ return mEmbedderAccessibleDoc && !mEmbedderAccessibleDoc->IsShutdown()
+ ? mEmbedderAccessibleDoc.get()
+ : nullptr;
+}
+#endif
+
+void BrowserBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { Destroy(); }
+
+} // namespace mozilla::dom