зеркало из https://github.com/mozilla/gecko-dev.git
304 строки
11 KiB
C++
304 строки
11 KiB
C++
/* -*- 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"
|
|
#endif
|
|
|
|
#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();
|
|
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(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, const layers::LayersObserverEpoch& aEpoch) {
|
|
Unused << mBrowserParent->SendRenderLayers(aEnabled, aEpoch);
|
|
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");
|
|
}
|
|
|
|
WidgetMouseEvent event = aEvent;
|
|
// 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();
|
|
}
|
|
|
|
IPCResult BrowserBridgeParent::RecvSetIsUnderHiddenEmbedderElement(
|
|
const bool& aIsUnderHiddenEmbedderElement) {
|
|
Unused << mBrowserParent->SendSetIsUnderHiddenEmbedderElement(
|
|
aIsUnderHiddenEmbedderElement);
|
|
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) {
|
|
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
|