BrowserBridgeParent.cpp (11169B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifdef ACCESSIBILITY 8 # include "mozilla/a11y/DocAccessibleParent.h" 9 # include "nsAccessibilityService.h" 10 #endif 11 12 #include "mozilla/Monitor.h" 13 #include "mozilla/MouseEvents.h" 14 #include "mozilla/dom/BrowserBridgeParent.h" 15 #include "mozilla/dom/BrowserParent.h" 16 #include "mozilla/dom/BrowsingContextGroup.h" 17 #include "mozilla/dom/CanonicalBrowsingContext.h" 18 #include "mozilla/dom/ContentParent.h" 19 #include "mozilla/dom/ContentProcessManager.h" 20 #include "mozilla/dom/WindowGlobalParent.h" 21 #include "mozilla/ipc/Endpoint.h" 22 #include "mozilla/layers/InputAPZContext.h" 23 24 using namespace mozilla::ipc; 25 using namespace mozilla::layout; 26 using namespace mozilla::hal; 27 28 namespace mozilla::dom { 29 30 BrowserBridgeParent::BrowserBridgeParent() = default; 31 32 BrowserBridgeParent::~BrowserBridgeParent() { Destroy(); } 33 34 nsresult BrowserBridgeParent::InitWithProcess( 35 BrowserParent* aParentBrowser, ContentParent* aContentParent, 36 const WindowGlobalInit& aWindowInit, uint32_t aChromeFlags, TabId aTabId) { 37 MOZ_ASSERT(!CanSend(), 38 "This should be called before the object is connected to IPC"); 39 MOZ_DIAGNOSTIC_ASSERT(!aContentParent->IsLaunching()); 40 MOZ_DIAGNOSTIC_ASSERT(!aContentParent->IsDead()); 41 42 RefPtr<CanonicalBrowsingContext> browsingContext = 43 CanonicalBrowsingContext::Get(aWindowInit.context().mBrowsingContextId); 44 if (!browsingContext || browsingContext->IsDiscarded()) { 45 return NS_ERROR_UNEXPECTED; 46 } 47 48 MOZ_DIAGNOSTIC_ASSERT( 49 !browsingContext->GetBrowserParent(), 50 "BrowsingContext must have had previous BrowserParent cleared"); 51 52 MOZ_DIAGNOSTIC_ASSERT( 53 aParentBrowser->Manager() != aContentParent, 54 "Cannot create OOP iframe in the same process as its parent document"); 55 56 // Unfortunately, due to the current racy destruction of BrowsingContext 57 // instances when Fission is enabled, while `browsingContext` may not be 58 // discarded, an ancestor might be. 59 // 60 // A discarded ancestor will cause us issues when creating our `BrowserParent` 61 // in the new content process, so abort the attempt if we have one. 62 // 63 // FIXME: We should never have a non-discarded BrowsingContext with discarded 64 // ancestors. (bug 1634759) 65 if (NS_WARN_IF(!browsingContext->AncestorsAreCurrent())) { 66 return NS_ERROR_UNEXPECTED; 67 } 68 69 // Ensure that our content process is subscribed to our newly created 70 // BrowsingContextGroup. 71 browsingContext->Group()->EnsureHostProcess(aContentParent); 72 browsingContext->SetOwnerProcessId(aContentParent->ChildID()); 73 74 browsingContext->Group()->NotifyFocusedOrActiveBrowsingContextToProcess( 75 aContentParent); 76 77 // Construct the BrowserParent object for our subframe. 78 auto browserParent = MakeRefPtr<BrowserParent>( 79 aContentParent, aTabId, *aParentBrowser, browsingContext, aChromeFlags); 80 browserParent->SetBrowserBridgeParent(this); 81 82 ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); 83 if (!cpm) { 84 return NS_ERROR_UNEXPECTED; 85 } 86 cpm->RegisterRemoteFrame(browserParent); 87 88 // Open a remote endpoint for our PBrowser actor. 89 ManagedEndpoint<PBrowserChild> childEp = 90 aContentParent->OpenPBrowserEndpoint(browserParent); 91 if (NS_WARN_IF(!childEp.IsValid())) { 92 MOZ_ASSERT(false, "Browser Open Endpoint Failed"); 93 return NS_ERROR_FAILURE; 94 } 95 96 RefPtr<WindowGlobalParent> windowParent = 97 WindowGlobalParent::CreateDisconnected(aWindowInit); 98 if (!windowParent) { 99 return NS_ERROR_UNEXPECTED; 100 } 101 102 ManagedEndpoint<PWindowGlobalChild> windowChildEp = 103 browserParent->OpenPWindowGlobalEndpoint(windowParent); 104 if (NS_WARN_IF(!windowChildEp.IsValid())) { 105 MOZ_ASSERT(false, "WindowGlobal Open Endpoint Failed"); 106 return NS_ERROR_FAILURE; 107 } 108 109 MOZ_DIAGNOSTIC_ASSERT(!browsingContext->IsDiscarded(), 110 "bc cannot have become discarded"); 111 112 // Tell the content process to set up its PBrowserChild. 113 bool ok = aContentParent->SendConstructBrowser( 114 std::move(childEp), std::move(windowChildEp), aTabId, 115 browserParent->AsIPCTabContext(), aWindowInit, aChromeFlags, 116 aContentParent->ChildID(), aContentParent->IsForBrowser(), 117 /* aIsTopLevel */ false); 118 if (NS_WARN_IF(!ok)) { 119 MOZ_ASSERT(false, "Browser Constructor Failed"); 120 return NS_ERROR_FAILURE; 121 } 122 123 // Set our BrowserParent object to the newly created browser. 124 mBrowserParent = std::move(browserParent); 125 mBrowserParent->SetOwnerElement(aParentBrowser->GetOwnerElement()); 126 mBrowserParent->InitRendering(); 127 128 GetBrowsingContext()->SetCurrentBrowserParent(mBrowserParent); 129 130 windowParent->Init(); 131 return NS_OK; 132 } 133 134 CanonicalBrowsingContext* BrowserBridgeParent::GetBrowsingContext() { 135 return mBrowserParent->GetBrowsingContext(); 136 } 137 138 BrowserParent* BrowserBridgeParent::Manager() { 139 MOZ_ASSERT(CanSend()); 140 return static_cast<BrowserParent*>(PBrowserBridgeParent::Manager()); 141 } 142 143 void BrowserBridgeParent::Destroy() { 144 if (mBrowserParent) { 145 #ifdef ACCESSIBILITY 146 if (mEmbedderAccessibleDoc && !mEmbedderAccessibleDoc->IsShutdown()) { 147 mEmbedderAccessibleDoc->RemovePendingOOPChildDoc(this); 148 } 149 #endif 150 mBrowserParent->Destroy(); 151 mBrowserParent->SetBrowserBridgeParent(nullptr); 152 mBrowserParent = nullptr; 153 } 154 if (CanSend()) { 155 (void)Send__delete__(this); 156 } 157 } 158 159 IPCResult BrowserBridgeParent::RecvShow(const OwnerShowInfo& aOwnerInfo) { 160 mBrowserParent->AttachWindowRenderer(); 161 (void)mBrowserParent->SendShow(mBrowserParent->GetShowInfo(), aOwnerInfo); 162 return IPC_OK(); 163 } 164 165 IPCResult BrowserBridgeParent::RecvScrollbarPreferenceChanged( 166 ScrollbarPreference aPref) { 167 (void)mBrowserParent->SendScrollbarPreferenceChanged(aPref); 168 return IPC_OK(); 169 } 170 171 IPCResult BrowserBridgeParent::RecvLoadURL(nsDocShellLoadState* aLoadState) { 172 (void)mBrowserParent->SendLoadURL(WrapNotNull(aLoadState), 173 mBrowserParent->GetShowInfo()); 174 return IPC_OK(); 175 } 176 177 IPCResult BrowserBridgeParent::RecvResumeLoad(uint64_t aPendingSwitchID) { 178 mBrowserParent->ResumeLoad(aPendingSwitchID); 179 return IPC_OK(); 180 } 181 182 IPCResult BrowserBridgeParent::RecvUpdateDimensions( 183 const LayoutDeviceIntRect& aRect, const LayoutDeviceIntSize& aSize) { 184 mBrowserParent->UpdateDimensions(aRect, aSize); 185 return IPC_OK(); 186 } 187 188 IPCResult BrowserBridgeParent::RecvUpdateEffects(const EffectsInfo& aEffects) { 189 (void)mBrowserParent->SendUpdateEffects(aEffects); 190 return IPC_OK(); 191 } 192 193 IPCResult BrowserBridgeParent::RecvUpdateRemotePrintSettings( 194 const embedding::PrintData& aPrintData) { 195 (void)mBrowserParent->SendUpdateRemotePrintSettings(aPrintData); 196 return IPC_OK(); 197 } 198 199 IPCResult BrowserBridgeParent::RecvRenderLayers(const bool& aEnabled) { 200 (void)mBrowserParent->SendRenderLayers(aEnabled); 201 return IPC_OK(); 202 } 203 204 IPCResult BrowserBridgeParent::RecvNavigateByKey( 205 const bool& aForward, const bool& aForDocumentNavigation) { 206 (void)mBrowserParent->SendNavigateByKey(aForward, aForDocumentNavigation); 207 return IPC_OK(); 208 } 209 210 IPCResult BrowserBridgeParent::RecvBeginDestroy() { 211 Destroy(); 212 return IPC_OK(); 213 } 214 215 IPCResult BrowserBridgeParent::RecvDispatchSynthesizedMouseEvent( 216 const WidgetMouseEvent& aEvent) { 217 if (aEvent.mMessage != eMouseMove || 218 aEvent.mReason != WidgetMouseEvent::eSynthesized) { 219 return IPC_FAIL(this, "Unexpected event type"); 220 } 221 222 nsCOMPtr<nsIWidget> widget = Manager()->GetWidget(); 223 if (!widget) { 224 return IPC_OK(); 225 } 226 227 WidgetMouseEvent event = aEvent; 228 event.mWidget = widget; 229 // Convert mRefPoint from the dispatching child process coordinate space 230 // to the parent coordinate space. The SendRealMouseEvent call will convert 231 // it into the dispatchee child process coordinate space 232 event.mRefPoint = Manager()->TransformChildToParent(event.mRefPoint); 233 // We need to set up an InputAPZContext on the stack because 234 // BrowserParent::SendRealMouseEvent requires one. But the only thing in 235 // that context that is actually used in this scenario is the layers id, 236 // and we already have that on the mouse event. 237 layers::InputAPZContext context( 238 layers::ScrollableLayerGuid(event.mLayersId, 0, 239 layers::ScrollableLayerGuid::NULL_SCROLL_ID), 240 0, nsEventStatus_eIgnore); 241 mBrowserParent->SendRealMouseEvent(event); 242 return IPC_OK(); 243 } 244 245 IPCResult BrowserBridgeParent::RecvWillChangeProcess() { 246 (void)mBrowserParent->SendWillChangeProcess(); 247 return IPC_OK(); 248 } 249 250 IPCResult BrowserBridgeParent::RecvActivate(uint64_t aActionId) { 251 mBrowserParent->Activate(aActionId); 252 return IPC_OK(); 253 } 254 255 IPCResult BrowserBridgeParent::RecvDeactivate(const bool& aWindowLowering, 256 uint64_t aActionId) { 257 mBrowserParent->Deactivate(aWindowLowering, aActionId); 258 return IPC_OK(); 259 } 260 261 mozilla::ipc::IPCResult BrowserBridgeParent::RecvUpdateRemoteStyle( 262 const StyleImageRendering& aImageRendering) { 263 (void)mBrowserParent->SendUpdateRemoteStyle(aImageRendering); 264 return IPC_OK(); 265 } 266 267 #ifdef ACCESSIBILITY 268 a11y::DocAccessibleParent* BrowserBridgeParent::GetDocAccessibleParent() { 269 auto* embeddedBrowser = GetBrowserParent(); 270 if (!embeddedBrowser) { 271 return nullptr; 272 } 273 a11y::DocAccessibleParent* docAcc = 274 embeddedBrowser->GetTopLevelDocAccessible(); 275 return docAcc && !docAcc->IsShutdown() ? docAcc : nullptr; 276 } 277 278 IPCResult BrowserBridgeParent::RecvSetEmbedderAccessible( 279 PDocAccessibleParent* aDoc, uint64_t aID) { 280 # if defined(ANDROID) 281 MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor()); 282 # endif 283 MOZ_ASSERT(aDoc || mEmbedderAccessibleDoc, 284 "Embedder doc shouldn't be cleared if it wasn't set"); 285 MOZ_ASSERT(!mEmbedderAccessibleDoc || !aDoc || mEmbedderAccessibleDoc == aDoc, 286 "Embedder doc shouldn't change from one doc to another"); 287 if (!aDoc && mEmbedderAccessibleDoc && 288 !mEmbedderAccessibleDoc->IsShutdown()) { 289 // We're clearing the embedder doc, so remove the pending child doc addition 290 // (if any). 291 mEmbedderAccessibleDoc->RemovePendingOOPChildDoc(this); 292 } 293 mEmbedderAccessibleDoc = static_cast<a11y::DocAccessibleParent*>(aDoc); 294 mEmbedderAccessibleID = aID; 295 if (!aDoc) { 296 MOZ_ASSERT(!aID); 297 return IPC_OK(); 298 } 299 MOZ_ASSERT(aID); 300 if (GetDocAccessibleParent()) { 301 // The embedded DocAccessibleParent has already been created. This can 302 // happen if, for example, an iframe is hidden and then shown or 303 // an iframe is reflowed by layout. 304 mEmbedderAccessibleDoc->AddChildDoc(this); 305 } 306 return IPC_OK(); 307 } 308 309 a11y::DocAccessibleParent* BrowserBridgeParent::GetEmbedderAccessibleDoc() { 310 return mEmbedderAccessibleDoc && !mEmbedderAccessibleDoc->IsShutdown() 311 ? mEmbedderAccessibleDoc.get() 312 : nullptr; 313 } 314 #endif 315 316 void BrowserBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { Destroy(); } 317 318 } // namespace mozilla::dom